{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"**Baseline to Image Classification Using CNN (Dogs vs. Cats) with Tensorflow & Keras**\n\n* Intro part.\n* 2nd part: [Intro to CNN: Augmentation & Dropout](https://www.kaggle.com/imcr00z/intro-to-cnn-augmentation-dropout)\n* 3rd part: [Transfer Learning (Dogs vs. Cats) 98% acc.](https://www.kaggle.com/imcr00z/transfer-learning-dogs-vs-cats-98-acc)","metadata":{"execution":{"iopub.status.busy":"2021-11-02T05:13:37.087508Z","iopub.execute_input":"2021-11-02T05:13:37.088368Z","iopub.status.idle":"2021-11-02T05:13:37.096955Z","shell.execute_reply.started":"2021-11-02T05:13:37.088312Z","shell.execute_reply":"2021-11-02T05:13:37.096079Z"}}},{"cell_type":"code","source":"import shutil\nimport tqdm\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nimport logging\nlogger = tf.get_logger()\nlogger.setLevel(logging.ERROR)","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:00.918636Z","iopub.execute_input":"2021-11-02T09:22:00.920014Z","iopub.status.idle":"2021-11-02T09:22:07.366143Z","shell.execute_reply.started":"2021-11-02T09:22:00.919913Z","shell.execute_reply":"2021-11-02T09:22:07.365021Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Unpack & load data\n1. unpack data\n1. split dogs and cats to train and valid datasets\n1. put dogs and cats files according to their catalogs (need for ImageDataGenerator)","metadata":{}},{"cell_type":"code","source":"import os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-11-02T09:22:07.372976Z","iopub.execute_input":"2021-11-02T09:22:07.373656Z","iopub.status.idle":"2021-11-02T09:22:07.382886Z","shell.execute_reply.started":"2021-11-02T09:22:07.373606Z","shell.execute_reply":"2021-11-02T09:22:07.381679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CONTENT_DIR = '/kaggle/content'\n\nTRAIN_DIR = CONTENT_DIR + '/train'\nTRAIN_DIR_DOG = TRAIN_DIR + '/dog'\nTRAIN_DIR_CAT = TRAIN_DIR + '/cat'\n\nVALID_DIR = CONTENT_DIR + '/valid'\nVALID_DIR_DOG = VALID_DIR + '/dog'\nVALID_DIR_CAT = VALID_DIR + '/cat'","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:07.384656Z","iopub.execute_input":"2021-11-02T09:22:07.385258Z","iopub.status.idle":"2021-11-02T09:22:07.402087Z","shell.execute_reply.started":"2021-11-02T09:22:07.385213Z","shell.execute_reply":"2021-11-02T09:22:07.400773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Extract files\nimport zipfile\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats/train.zip', 'r') as zipf:\n    zipf.extractall(CONTENT_DIR)\n    \n# !ls -la ../content/train/\n# -rw-r--r-- 1 root root  12414 Nov  2 03:15 cat.0.jpg\n# ...\n# -rw-r--r-- 1 root root   3339 Nov  2 03:46 dog.9999.jpg","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:07.406215Z","iopub.execute_input":"2021-11-02T09:22:07.406926Z","iopub.status.idle":"2021-11-02T09:22:23.922285Z","shell.execute_reply.started":"2021-11-02T09:22:07.406876Z","shell.execute_reply":"2021-11-02T09:22:23.921255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Split cats and dogs images to train and valid datasets\nimg_filenames = os.listdir(TRAIN_DIR)\nprint('Num of images:', len(img_filenames))\n\ndog_filenames = [fn for fn in img_filenames if fn.startswith('dog')]\ncat_filenames = [fn for fn in img_filenames if fn.startswith('cat')]\n\ndataset_filenames = train_test_split(\n    dog_filenames, cat_filenames, test_size=0.1, shuffle=True, random_state=42\n)\n\ntrain_dog_total, valid_dog_total, train_cat_total, valid_cat_total = [len(fns) for fns in dataset_filenames]\ntrain_total = train_dog_total + train_cat_total\nvalid_total = valid_dog_total + valid_cat_total\nprint('Train: {}, test: {}'.format(train_total, valid_total))","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:23.926243Z","iopub.execute_input":"2021-11-02T09:22:23.926599Z","iopub.status.idle":"2021-11-02T09:22:23.97762Z","shell.execute_reply.started":"2021-11-02T09:22:23.926559Z","shell.execute_reply":"2021-11-02T09:22:23.976267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Move images\nmake_dirs = [TRAIN_DIR_DOG, VALID_DIR_DOG, TRAIN_DIR_CAT, VALID_DIR_CAT]\nfor dir, fns in zip(make_dirs, dataset_filenames):\n    os.makedirs(dir, exist_ok=True)\n    for fn in tqdm.tqdm(fns):\n        shutil.move(os.path.join(TRAIN_DIR, fn), dir)\n    print('elements in {}: {}'.format(dir, len(os.listdir(dir))))","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:23.979626Z","iopub.execute_input":"2021-11-02T09:22:23.979985Z","iopub.status.idle":"2021-11-02T09:22:25.740769Z","shell.execute_reply.started":"2021-11-02T09:22:23.979939Z","shell.execute_reply":"2021-11-02T09:22:25.738152Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Uncomment and run to clear content dir\n# !rm -rf ../content/*","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:25.742897Z","iopub.execute_input":"2021-11-02T09:22:25.743441Z","iopub.status.idle":"2021-11-02T09:22:25.75115Z","shell.execute_reply.started":"2021-11-02T09:22:25.743391Z","shell.execute_reply":"2021-11-02T09:22:25.747567Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocessing\n1. decode images\n1. rescale image layers from [0..255] to [0,1]","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 128\nIMAGE_SHAPE = 128","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:25.752725Z","iopub.execute_input":"2021-11-02T09:22:25.757467Z","iopub.status.idle":"2021-11-02T09:22:25.814326Z","shell.execute_reply.started":"2021-11-02T09:22:25.757412Z","shell.execute_reply":"2021-11-02T09:22:25.813235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator = ImageDataGenerator(rescale=1./255)\nvalid_generator = ImageDataGenerator(rescale=1./255)","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:25.81619Z","iopub.execute_input":"2021-11-02T09:22:25.81687Z","iopub.status.idle":"2021-11-02T09:22:25.826464Z","shell.execute_reply.started":"2021-11-02T09:22:25.816814Z","shell.execute_reply":"2021-11-02T09:22:25.825063Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = train_generator.flow_from_directory(\n    directory=TRAIN_DIR,\n    target_size=(IMAGE_SHAPE, IMAGE_SHAPE),\n    batch_size=BATCH_SIZE,\n    class_mode='binary'\n)\nvalid_data = valid_generator.flow_from_directory(\n    directory=VALID_DIR,\n    target_size=(IMAGE_SHAPE, IMAGE_SHAPE),\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n    shuffle=False\n)","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:25.828233Z","iopub.execute_input":"2021-11-02T09:22:25.829268Z","iopub.status.idle":"2021-11-02T09:22:26.610334Z","shell.execute_reply.started":"2021-11-02T09:22:25.829221Z","shell.execute_reply":"2021-11-02T09:22:26.60937Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Image visualization","metadata":{}},{"cell_type":"code","source":"# show 25 images\nsome_pets = next(train_data)[0][:25]\nfig, axes = plt.subplots(5, 5, figsize=(20, 20))\nfor img, ax in zip(some_pets, axes.flatten()):\n    ax.imshow(img)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:26.613837Z","iopub.execute_input":"2021-11-02T09:22:26.614099Z","iopub.status.idle":"2021-11-02T09:22:32.141116Z","shell.execute_reply.started":"2021-11-02T09:22:26.614067Z","shell.execute_reply":"2021-11-02T09:22:32.139925Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model\n1. create model\n1. compile\n1. summary\n1. training","metadata":{"execution":{"iopub.status.busy":"2021-11-02T05:47:07.472478Z","iopub.execute_input":"2021-11-02T05:47:07.473052Z","iopub.status.idle":"2021-11-02T05:47:07.476971Z","shell.execute_reply.started":"2021-11-02T05:47:07.473009Z","shell.execute_reply":"2021-11-02T05:47:07.476402Z"}}},{"cell_type":"code","source":"model = tf.keras.models.Sequential([\n    tf.keras.layers.Conv2D(\n        filters=32,\n        kernel_size=(3, 3),\n        activation='relu',\n        input_shape=(IMAGE_SHAPE, IMAGE_SHAPE, 3)\n    ),\n    tf.keras.layers.MaxPooling2D(pool_size=2, strides=2),\n\n    tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n\n    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n\n    tf.keras.layers.Conv2D(128, (3, 3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2, 2),\n\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(units=512, activation='relu'),\n    tf.keras.layers.Dense(units=2, activation='softmax')\n])","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:32.142557Z","iopub.execute_input":"2021-11-02T09:22:32.14293Z","iopub.status.idle":"2021-11-02T09:22:35.520943Z","shell.execute_reply.started":"2021-11-02T09:22:32.142874Z","shell.execute_reply":"2021-11-02T09:22:35.519989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='adam',\n              loss='sparse_categorical_crossentropy',\n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:35.525031Z","iopub.execute_input":"2021-11-02T09:22:35.525352Z","iopub.status.idle":"2021-11-02T09:22:35.541537Z","shell.execute_reply.started":"2021-11-02T09:22:35.52532Z","shell.execute_reply":"2021-11-02T09:22:35.540397Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:35.543324Z","iopub.execute_input":"2021-11-02T09:22:35.544003Z","iopub.status.idle":"2021-11-02T09:22:35.563716Z","shell.execute_reply.started":"2021-11-02T09:22:35.543953Z","shell.execute_reply":"2021-11-02T09:22:35.562764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"EPOCHS = 60","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:35.565229Z","iopub.execute_input":"2021-11-02T09:22:35.565631Z","iopub.status.idle":"2021-11-02T09:22:35.571757Z","shell.execute_reply.started":"2021-11-02T09:22:35.565584Z","shell.execute_reply":"2021-11-02T09:22:35.570429Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit_generator(\n    generator=train_data,\n    steps_per_epoch=(train_total + BATCH_SIZE - 1) // BATCH_SIZE,\n    epochs=EPOCHS,\n    validation_data=valid_data,\n    validation_steps=(valid_total + BATCH_SIZE - 1) // BATCH_SIZE,\n)","metadata":{"execution":{"iopub.status.busy":"2021-11-02T09:22:35.573958Z","iopub.execute_input":"2021-11-02T09:22:35.575238Z","iopub.status.idle":"2021-11-02T10:35:32.043867Z","shell.execute_reply.started":"2021-11-02T09:22:35.575192Z","shell.execute_reply":"2021-11-02T10:35:32.042791Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# save model - optional\nmodel.save('./checkpoints/model4_60epoch.h5')","metadata":{"execution":{"iopub.status.busy":"2021-11-02T10:51:56.307951Z","iopub.execute_input":"2021-11-02T10:51:56.308543Z","iopub.status.idle":"2021-11-02T10:51:56.406372Z","shell.execute_reply.started":"2021-11-02T10:51:56.308492Z","shell.execute_reply":"2021-11-02T10:51:56.405088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# download model - optional\n# import os\n# os.chdir(r'/kaggle/working')\n# from IPython.display import FileLink\n# FileLink(r'./checkpoints/model4_60epoch.h5')","metadata":{"execution":{"iopub.status.busy":"2021-11-02T10:53:55.620593Z","iopub.execute_input":"2021-11-02T10:53:55.621266Z","iopub.status.idle":"2021-11-02T10:53:55.626373Z","shell.execute_reply.started":"2021-11-02T10:53:55.62123Z","shell.execute_reply":"2021-11-02T10:53:55.625146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# set finish path\n# os.chdir(r'..')","metadata":{"execution":{"iopub.status.busy":"2021-11-02T10:53:59.225973Z","iopub.execute_input":"2021-11-02T10:53:59.22695Z","iopub.status.idle":"2021-11-02T10:53:59.231447Z","shell.execute_reply.started":"2021-11-02T10:53:59.226885Z","shell.execute_reply":"2021-11-02T10:53:59.230157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train visualization\nLook to validation loss. You see overfitting after ? epoch. Maybe better stay there","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(12, 8))\n\nplt.subplot(1, 2, 1)\nplt.plot(range(EPOCHS), history.history['accuracy'], label='train')\nplt.plot(range(EPOCHS), history.history['val_accuracy'], label='valid')\nplt.legend(loc='lower right')\nplt.title('Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(range(EPOCHS), history.history['loss'], label='train')\nplt.plot(range(EPOCHS), history.history['val_loss'], label='valid')\nplt.legend(loc='upper left')\nplt.title('Loss (sparse_categorical_crossentropy)')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-02T10:47:21.911629Z","iopub.execute_input":"2021-11-02T10:47:21.912015Z","iopub.status.idle":"2021-11-02T10:47:22.365575Z","shell.execute_reply.started":"2021-11-02T10:47:21.911969Z","shell.execute_reply":"2021-11-02T10:47:22.364598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predictions\n1. unzip test data\n1. scale and predict\n1. save results","metadata":{}},{"cell_type":"code","source":"TEST_DIR = CONTENT_DIR + '/test'\n\n# Extract files\nimport zipfile\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats/test1.zip', 'r') as zipf:\n    zipf.extractall(TEST_DIR)","metadata":{"execution":{"iopub.status.busy":"2021-11-02T11:10:51.443675Z","iopub.execute_input":"2021-11-02T11:10:51.44403Z","iopub.status.idle":"2021-11-02T11:10:56.114178Z","shell.execute_reply.started":"2021-11-02T11:10:51.443997Z","shell.execute_reply":"2021-11-02T11:10:56.113221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_generator = ImageDataGenerator(rescale=1./255)\n\ntest_data = test_generator.flow_from_directory(\n    directory=TEST_DIR,\n    target_size=(IMAGE_SHAPE, IMAGE_SHAPE),\n    batch_size=1,\n    class_mode='binary',\n    shuffle=False\n)\ntest_data.reset()\n\ntest_total = len(test_data.filenames)\npredict = model.predict_generator(test_data, steps=test_total, verbose=1)","metadata":{"execution":{"iopub.status.busy":"2021-11-02T11:20:18.027015Z","iopub.execute_input":"2021-11-02T11:20:18.027836Z","iopub.status.idle":"2021-11-02T11:21:22.28168Z","shell.execute_reply.started":"2021-11-02T11:20:18.027801Z","shell.execute_reply":"2021-11-02T11:21:22.280511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# labels = dict((v,k) for k,v in train_data.class_indices.items())\n# predictions = [labels[k] for k in np.argmax(predict,axis=1)]\n# predictions","metadata":{"execution":{"iopub.status.busy":"2021-11-02T11:27:53.542297Z","iopub.execute_input":"2021-11-02T11:27:53.542942Z","iopub.status.idle":"2021-11-02T11:27:53.546864Z","shell.execute_reply.started":"2021-11-02T11:27:53.542906Z","shell.execute_reply":"2021-11-02T11:27:53.545798Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.read_csv('/kaggle/input/dogs-vs-cats/sampleSubmission.csv', index_col='id')\nsubmission['label'] = np.argmax(predict,axis=1)\nsubmission.to_csv('./my_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2021-11-02T11:28:16.826683Z","iopub.execute_input":"2021-11-02T11:28:16.827552Z","iopub.status.idle":"2021-11-02T11:28:16.872286Z","shell.execute_reply.started":"2021-11-02T11:28:16.827509Z","shell.execute_reply":"2021-11-02T11:28:16.871298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}