{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":31011,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os, cv2, random\nimport numpy as np\nimport pandas as pd\nimport zipfile\nimport matplotlib.pyplot as plt\nfrom matplotlib import ticker\nimport seaborn as sns\n%matplotlib inline\n\nfrom sklearn.model_selection import train_test_split\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, Input, Dropout, Flatten, Convolution2D, MaxPooling2D, Dense, Activation\nfrom keras.optimizers import RMSprop\nfrom keras.callbacks import ModelCheckpoint, Callback, EarlyStopping\nfrom keras.utils import to_categorical","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-06T11:57:44.782568Z","iopub.execute_input":"2025-05-06T11:57:44.783103Z","iopub.status.idle":"2025-05-06T11:57:45.000301Z","shell.execute_reply.started":"2025-05-06T11:57:44.783077Z","shell.execute_reply":"2025-05-06T11:57:44.999307Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TRAIN_DIR       = '/kaggle/working/train/'\nTEST_DIR        = '/kaggle/working/test/'\nTRAIN_ZIP_PATH  = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip'\nTEST_ZIP_PATH   = '/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip'\n\nwith zipfile.ZipFile(TRAIN_ZIP_PATH, 'r') as zip_ref:\n    zip_ref.extractall(TRAIN_DIR)\n\n_subdirs = [d for d in os.listdir(TRAIN_DIR) if os.path.isdir(os.path.join(TRAIN_DIR, d))]\nif len(_subdirs) == 1:\n    TRAIN_DIR = os.path.join(TRAIN_DIR, _subdirs[0]) + '/'\n\nwith zipfile.ZipFile(TEST_ZIP_PATH, 'r') as zip_ref:\n    zip_ref.extractall(TEST_DIR)\n\n_subdirs = [d for d in os.listdir(TEST_DIR) if os.path.isdir(os.path.join(TEST_DIR, d))]\nif len(_subdirs) == 1:\n    TEST_DIR = os.path.join(TEST_DIR, _subdirs[0]) + '/'\n\ntrain_files = [\n    f for f in os.listdir(TRAIN_DIR)\n    if os.path.isfile(os.path.join(TRAIN_DIR, f))\n]\ntest_files = [\n    f for f in os.listdir(TEST_DIR)\n    if os.path.isfile(os.path.join(TEST_DIR, f))\n]\n\ntrain_dogs   = [(os.path.join(TRAIN_DIR, f), 1) for f in train_files if 'dog' in f]\ntrain_cats   = [(os.path.join(TRAIN_DIR, f), 0) for f in train_files if 'cat' in f]\ntest_images  = [(os.path.join(TEST_DIR, f), -1) for f in test_files]\n\nall_train = train_dogs + train_cats\ntrain_images, val_images = train_test_split(\n    all_train,\n    train_size=200,     \n    stratify=[lbl for _, lbl in all_train],  \n    random_state=42\n)\nrandom.shuffle(train_images)\nrandom.shuffle(val_images)\n\ntest_images = [(os.path.join(TEST_DIR, f), -1)\n               for f in os.listdir(TEST_DIR)\n               if os.path.isfile(os.path.join(TEST_DIR, f))]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:13:37.088909Z","iopub.execute_input":"2025-05-06T12:13:37.089170Z","iopub.status.idle":"2025-05-06T12:13:47.382122Z","shell.execute_reply.started":"2025-05-06T12:13:37.089149Z","shell.execute_reply":"2025-05-06T12:13:47.381589Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# To ensure uniform image standards, we resize all the images to 64*64\n\nROWS = 64\nCOLS = 64\n\ndef read_image(tuple_set):\n    file_path, label = tuple_set\n    img = cv2.imread(file_path, cv2.IMREAD_COLOR)\n    img = cv2.resize(img, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\n    return img, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:13:47.383114Z","iopub.execute_input":"2025-05-06T12:13:47.383360Z","iopub.status.idle":"2025-05-06T12:13:47.387373Z","shell.execute_reply.started":"2025-05-06T12:13:47.383342Z","shell.execute_reply":"2025-05-06T12:13:47.386677Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Preprocess the image and turn it into a numpy array\n\nCHANNELS = 3 # RGB\n\ndef prep_data(images):\n    no_images = len(images)\n    data   = np.ndarray((no_images, CHANNELS, ROWS, COLS), dtype=np.uint8)\n    labels = []\n\n    for i, image_file in enumerate(images):\n        image, label = read_image(image_file)\n        data[i] = image.transpose(2, 0, 1)\n        labels.append(label)\n\n    return data, labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:13:47.388060Z","iopub.execute_input":"2025-05-06T12:13:47.388223Z","iopub.status.idle":"2025-05-06T12:13:47.403738Z","shell.execute_reply.started":"2025-05-06T12:13:47.388210Z","shell.execute_reply":"2025-05-06T12:13:47.403178Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_train, y_train = prep_data(train_images)\nx_test, y_t = prep_data(test_images) # y_t is of no use. We don't know the label of the test set\n\ny_train = np.array(y_train)\ny_t     = np.array(y_t)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:13:47.405128Z","iopub.execute_input":"2025-05-06T12:13:47.405573Z","iopub.status.idle":"2025-05-06T12:14:01.273908Z","shell.execute_reply.started":"2025-05-06T12:13:47.405557Z","shell.execute_reply":"2025-05-06T12:14:01.273371Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(x_train.shape)\nprint(x_test.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:14:01.274700Z","iopub.execute_input":"2025-05-06T12:14:01.275177Z","iopub.status.idle":"2025-05-06T12:14:01.279399Z","shell.execute_reply.started":"2025-05-06T12:14:01.275147Z","shell.execute_reply":"2025-05-06T12:14:01.278526Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# CNN Construction (VGG CNN)\n\noptimizer = RMSprop(learning_rate = 1e-4)\nobjective = 'binary_crossentropy'\n\nmodel = Sequential()\n\nmodel.add(Conv2D(32, (3, 3),\n                 padding='same',\n                 data_format='channels_first',\n                 input_shape=(3, ROWS, COLS),\n                 activation='relu'))\nmodel.add(Conv2D(32, (3, 3),\n                 padding='same',\n                 data_format='channels_first',\n                 activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2), data_format='channels_first',))\n\nmodel.add(Conv2D(64, (3, 3), padding='same', data_format='channels_first', activation='relu'))\nmodel.add(Conv2D(64, (3, 3), padding='same', data_format='channels_first', activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2), data_format='channels_first',))\n\nmodel.add(Conv2D(128, (3, 3), padding='same', data_format='channels_first', activation='relu'))\nmodel.add(Conv2D(128, (3, 3), padding='same', data_format='channels_first', activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2), data_format='channels_first',))\n\nmodel.add(Conv2D(256, (3, 3), padding='same', data_format='channels_first', activation='relu'))\nmodel.add(Conv2D(256, (3, 3), padding='same', data_format='channels_first', activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2), data_format='channels_first',))\n\nmodel.add(Flatten(data_format='channels_first'))\nmodel.add(Dense(256, activation='relu'))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(256, activation='relu'))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(1))\nmodel.add(Activation('sigmoid'))\n\nmodel.compile(loss=objective, optimizer=optimizer, metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:14:01.280035Z","iopub.execute_input":"2025-05-06T12:14:01.280363Z","iopub.status.idle":"2025-05-06T12:14:01.455926Z","shell.execute_reply.started":"2025-05-06T12:14:01.280337Z","shell.execute_reply":"2025-05-06T12:14:01.455397Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# train and forecast\n\nnb_epoch = 10\nbatch_size = 10\n\n# Write a class to store the loss after each epoch, which is convenient for drawing graphs\nclass LossHistory(Callback):\n    def on_train_begin(self, logs = {}):\n        self.losses = []\n        self.val_losses = []\n\n    def on_epoch_end(self, batch, logs = {}):\n        self.losses.append(logs.get('loss'))\n        self.val_losses.append(logs.get(('val_loss')))\n\n# overfitting is very easy in image processing, we adopt the early stop mechanism that comes with keras\nearly_stopping = EarlyStopping(monitor = 'val_loss', patience = 3, verbose = 1, mode = 'auto')\n\n# run the model\nhistory = LossHistory()\n\nmodel.fit(x_train, y_train, batch_size = batch_size, epochs = nb_epoch, \n          validation_split = 0.2, verbose = 0, shuffle = True, callbacks = [history, early_stopping])\n\npredictions = model.predict(x_test, verbose = 0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:15:57.062170Z","iopub.execute_input":"2025-05-06T12:15:57.062861Z","iopub.status.idle":"2025-05-06T12:16:07.949549Z","shell.execute_reply.started":"2025-05-06T12:15:57.062837Z","shell.execute_reply":"2025-05-06T12:16:07.948783Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"loss = history.losses\nval_loss = history.val_losses\n\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.title('VGG-16 Loss Trend')\nplt.plot(loss, 'blue', label = 'Training Loss')\nplt.plot(val_loss, 'green', label = 'Validation Loss')\nplt.xticks(range(0, nb_epoch)[0::2])\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:16:07.950863Z","iopub.execute_input":"2025-05-06T12:16:07.951419Z","iopub.status.idle":"2025-05-06T12:16:08.106453Z","shell.execute_reply.started":"2025-05-06T12:16:07.951397Z","shell.execute_reply":"2025-05-06T12:16:08.105748Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Submit the result\n\npreds = predictions.reshape(-1)\n\nimage_ids = [\n    int(os.path.splitext(os.path.basename(path))[0]) \n    for path, _ in test_images\n]\n\nsubmission = pd.DataFrame({\n    'id': image_ids,  \n    'label': preds\n})\n\nsubmission_path = '/kaggle/working/submission.csv'\nsubmission.to_csv(submission_path, index=False)\n\nprint(f\"Submission saved to {submission_path}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-06T12:16:08.107240Z","iopub.execute_input":"2025-05-06T12:16:08.107520Z","iopub.status.idle":"2025-05-06T12:16:08.149608Z","shell.execute_reply.started":"2025-05-06T12:16:08.107496Z","shell.execute_reply":"2025-05-06T12:16:08.148918Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}