{"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":"<center><h3 style='color:red'>Keras | CNN Dog or Cat Classification</h3></center>\n\n### Table:\n* **Introduction**\n* **Configuration**\n* **Read & Preprocessing the Data**\n* **CNN Network**\n    * **Training**\n* **Evaluation**\n* **Results**\n* **Testing Visualization**\n* **Other Solutions (TL)**\n\n<hr>\n\n**NEW IN VERSION 7:**\n   * Use ImageDataGenerator to read and preprocess the images directly.\n   * Different custom CNN network.\n   * Add EarlyStoping callback.\n   * Add comments and table.\n    ","metadata":{}},{"cell_type":"markdown","source":"## Introduction\n\n**objective: Distinguish images of dogs from cats** using custom CNN network using keras.","metadata":{}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport matplotlib.pyplot as plt\n\nfrom glob import glob\n\nimport tensorflow as tf\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.utils import to_categorical\n\nfrom keras.models import Sequential, load_model, Model\nfrom keras.layers import Conv2D, MaxPooling2D, BatchNormalization, Dropout\nfrom keras.layers import Dense, Flatten\nfrom keras.callbacks import EarlyStopping\n\n\nimport cv2","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:23:00.446414Z","iopub.execute_input":"2022-03-26T23:23:00.446746Z","iopub.status.idle":"2022-03-26T23:23:02.745187Z","shell.execute_reply.started":"2022-03-26T23:23:00.446687Z","shell.execute_reply":"2022-03-26T23:23:02.744404Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nprint(os.listdir('../input'))","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:23:02.747259Z","iopub.execute_input":"2022-03-26T23:23:02.747573Z","iopub.status.idle":"2022-03-26T23:23:02.754088Z","shell.execute_reply.started":"2022-03-26T23:23:02.747523Z","shell.execute_reply":"2022-03-26T23:23:02.753153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Configuration","metadata":{}},{"cell_type":"code","source":"category = [\"cats\", \"dogs\"]\n\nEPOCHS                  = 50\nIMGSIZE                 = 128\nCHANNELS                = 1 # grayscale\nBATCH_SIZE              = 32\nSTOPPING_PATIENCE       = 8\nVERBOSE                 = 1\nMODEL_NAME              = 'cnn_50epochs_imgsize128.h5'\nOPTIMIZER               = 'adam'\nTRAINING_DIR            = '../input/cat-and-dog/training_set/training_set'\nTEST_DIR                = '../input/cat-and-dog/test_set/test_set'","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:23:02.755321Z","iopub.execute_input":"2022-03-26T23:23:02.755629Z","iopub.status.idle":"2022-03-26T23:23:02.764395Z","shell.execute_reply.started":"2022-03-26T23:23:02.755578Z","shell.execute_reply":"2022-03-26T23:23:02.763329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Read & Preprocessing Data","metadata":{}},{"cell_type":"code","source":"generator = ImageDataGenerator(rescale=1./255, \n                               shear_range=0.15, \n                               zoom_range=0.2, \n                               horizontal_flip=True\n                              ) \n\ntrain_data = generator.flow_from_directory( directory=TRAINING_DIR, \n                                            target_size=(IMGSIZE, IMGSIZE),\n                                            color_mode='grayscale',\n                                            classes=category, \n                                            batch_size=BATCH_SIZE, \n                                            )\n\n\ntest_data = generator.flow_from_directory( directory=TEST_DIR, \n                                           target_size=(IMGSIZE, IMGSIZE), \n                                           color_mode='grayscale',\n                                           classes=category, \n                                           batch_size=BATCH_SIZE,\n                                           shuffle=False\n                                           )","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:23:02.765988Z","iopub.execute_input":"2022-03-26T23:23:02.766639Z","iopub.status.idle":"2022-03-26T23:23:06.912647Z","shell.execute_reply.started":"2022-03-26T23:23:02.766585Z","shell.execute_reply":"2022-03-26T23:23:06.911885Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## CNN Network","metadata":{}},{"cell_type":"code","source":"model = Sequential()\n\nmodel.add(Conv2D(32, (3, 3), activation='relu', input_shape=(IMGSIZE, IMGSIZE, CHANNELS)))\nmodel.add(Conv2D(32, (3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(BatchNormalization())\n\nmodel.add(Conv2D(64, (3, 3), activation='relu'))\nmodel.add(Conv2D(64, (3, 3), activation='relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(BatchNormalization())\n\nmodel.add(Flatten())\nmodel.add(Dropout(0.25))\n\nmodel.add(Dense(2, activation='softmax'))\n\nmodel.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:23:06.914984Z","iopub.execute_input":"2022-03-26T23:23:06.915402Z","iopub.status.idle":"2022-03-26T23:23:09.432469Z","shell.execute_reply.started":"2022-03-26T23:23:06.915232Z","shell.execute_reply":"2022-03-26T23:23:09.431818Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Training","metadata":{}},{"cell_type":"code","source":"es = EarlyStopping(patience=STOPPING_PATIENCE, \n                   monitor='val_accuracy', \n                   mode='max', \n                   verbose=1, \n                   restore_best_weights=True)\n\nhistory = model.fit_generator(train_data, \n                              epochs=EPOCHS, \n                              validation_data=test_data,\n                              shuffle=True,\n                              callbacks=[es]\n                             )","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-03-26T23:23:09.437028Z","iopub.execute_input":"2022-03-26T23:23:09.437256Z","iopub.status.idle":"2022-03-26T23:24:30.128929Z","shell.execute_reply.started":"2022-03-26T23:23:09.437215Z","shell.execute_reply":"2022-03-26T23:24:30.128232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Evaluation","metadata":{}},{"cell_type":"code","source":"train_acc = model.evaluate(train_data)\ntest_acc = model.evaluate(test_data)","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-03-26T23:24:30.130345Z","iopub.execute_input":"2022-03-26T23:24:30.130644Z","iopub.status.idle":"2022-03-26T23:25:14.344643Z","shell.execute_reply.started":"2022-03-26T23:24:30.130597Z","shell.execute_reply":"2022-03-26T23:25:14.343868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Results","metadata":{}},{"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(18, 10))\nax1.plot(history.history['loss'], color='b', label=\"Training loss : {:0.4f}\".format(train_acc[0]))\nax1.plot(history.history['val_loss'], color='r', label=\"validation loss : {:0.4f}\".format(test_acc[0]))\nax1.legend()\n\nax2.plot(history.history['accuracy'], color='b', label=\"Training accuracy : {0:.4f}\".format(train_acc[1]))\nax2.plot(history.history['val_accuracy'], color='r',label=\"Validation accuracy : {0:.4f}\".format(test_acc[1]))\n\nlegend = plt.legend(loc='best', shadow=True)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:25:14.346106Z","iopub.execute_input":"2022-03-26T23:25:14.346382Z","iopub.status.idle":"2022-03-26T23:25:14.763153Z","shell.execute_reply.started":"2022-03-26T23:25:14.346337Z","shell.execute_reply":"2022-03-26T23:25:14.762466Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Testing Visualization","metadata":{}},{"cell_type":"code","source":"test_paths = np.array(glob(TEST_DIR + '/*/*.jpg'))\n\nnp.random.seed(42)\nids = np.random.choice(np.arange(len(test_paths)), size=32)\n\nsamples = test_paths[ids]","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:39:11.962754Z","iopub.execute_input":"2022-03-26T23:39:11.963059Z","iopub.status.idle":"2022-03-26T23:39:11.986706Z","shell.execute_reply.started":"2022-03-26T23:39:11.963011Z","shell.execute_reply":"2022-03-26T23:39:11.985974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"im_test = []\nc = 0\nfor img in samples:\n    c = c + 1\n    img_path =img\n    img_arr = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)\n    img_arr = cv2.resize(img_arr, (IMGSIZE, IMGSIZE))\n    img_arr = img_arr / 255.0\n    im_test.append(img_arr)\n\n    \nim_test = np.array(im_test).reshape(-1, IMGSIZE, IMGSIZE, 1)\nim_pred = model.predict(im_test)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:39:13.468749Z","iopub.execute_input":"2022-03-26T23:39:13.469060Z","iopub.status.idle":"2022-03-26T23:39:13.576747Z","shell.execute_reply.started":"2022-03-26T23:39:13.469004Z","shell.execute_reply":"2022-03-26T23:39:13.575975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig , ax = plt.subplots(4, 4, figsize=(30, 25))\n\nfor i, axis in enumerate(ax.flat):\n    axis.imshow(im_test[i][:, :, 0], cmap='gray')\n    pred_class = im_pred[i].argmax()\n    pred_prob = im_pred[i].max() * 100\n\n    axis.set_title(f'Predict: {category[pred_class]}\\n Confidence: {pred_prob:.1f}%', fontsize=18)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:39:14.120103Z","iopub.execute_input":"2022-03-26T23:39:14.120397Z","iopub.status.idle":"2022-03-26T23:39:16.686418Z","shell.execute_reply.started":"2022-03-26T23:39:14.120347Z","shell.execute_reply":"2022-03-26T23:39:16.685645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# save the model weights\nmodel.save_weights(MODEL_NAME)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T23:33:47.579558Z","iopub.execute_input":"2022-03-26T23:33:47.579890Z","iopub.status.idle":"2022-03-26T23:33:47.712807Z","shell.execute_reply.started":"2022-03-26T23:33:47.579842Z","shell.execute_reply":"2022-03-26T23:33:47.711908Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Other Solution:\n\nRather than using your custom CNN network, you can use a pretrained model.\nThis method called **Transfer Learning**. \n\ncheck out how to implement it: **[Transfer Learning (CATs vs DOGs)](https://www.kaggle.com/code/elcaiseri/transfer-learning-cat-vs-dog)**","metadata":{}},{"cell_type":"markdown","source":"### If you like, <span style='color:red'>UPVOTE</span> it. feel free to ask me anything in the comment section.","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}