{"cells":[{"metadata":{},"cell_type":"markdown","source":"# A try to the dogs vs cats dataset using a simple CNN\nThis has been one of my first ML projects.\n\nI got inspired by [sentdesk](https://pythonprogramming.net/convolutional-neural-network-deep-learning-python-tensorflow-keras/), [Adrian Rosebrock](https://www.pyimagesearch.com/2018/12/24/how-to-use-keras-fit-and-fit_generator-a-hands-on-tutorial/) and [Uysim Ty](https://www.kaggle.com/uysimty/keras-cnn-dog-or-cat-classification). Thanks!\n\nAny feedback would be great :)"},{"metadata":{},"cell_type":"markdown","source":"# Import necessary packages"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport os\nimport cv2\nimport zipfile\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, accuracy_score\nfrom tensorflow.keras.models import Sequential, load_model\nfrom tensorflow.keras.layers import Dense, Activation, Flatten, Dropout\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, BatchNormalization\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import TensorBoard, EarlyStopping\nimport random\nfrom mlxtend.plotting import plot_confusion_matrix\nfrom tqdm import tqdm","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Let's have a look of where the data is"},{"metadata":{"trusted":true},"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/input/'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# So we need to extract the images in the zip files"},{"metadata":{"trusted":true},"cell_type":"code","source":"with zipfile.ZipFile('../input/dogs-vs-cats-redux-kernels-edition/train.zip') as z:\n    z.extractall(\".\")\n\nwith zipfile.ZipFile('../input/dogs-vs-cats-redux-kernels-edition/test.zip') as z:\n    z.extractall(\".\")\n\nprint(os.listdir('.'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Now, we have two folders containing each train and test images\n# The next step is to load the training data\n## Both features (images) and labels (dog or cat) are loaded into a python list"},{"metadata":{"trusted":true},"cell_type":"code","source":"DATADIR = './train'\ntraining_data = []\nRESIZE = 100\nX = []\ny = []\n\ndef create_training_data():\n    for img in os.listdir(DATADIR):\n        try:\n            img_array = cv2.imread(os.path.join(DATADIR,img), cv2.IMREAD_GRAYSCALE)            \n            img2 = cv2.resize(img_array, (RESIZE,RESIZE))\n            img2 = (img2 - img2.mean())/img2.std()\n            if img[:3] == 'dog':\n                class_num = 0\n            else:\n                class_num = 1\n            X.append(img2)\n            y.append(class_num)\n        except Exception as e:\n            pass\n        \ncreate_training_data()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## The python list containing the loaded data is converted into two numpy arrays, one for features and one for labels"},{"metadata":{"trusted":true},"cell_type":"code","source":"X = np.array(X).reshape(-1, RESIZE, RESIZE, 1)\ny = np.asarray(y)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Now, we divide the training data into two sets, one for training and one for validation"},{"metadata":{"trusted":true},"cell_type":"code","source":"(X_train, X_val, y_train, y_val) = train_test_split(X, y, test_size=0.3, random_state=42)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Now, it is time to build and train a simple CNN model"},{"metadata":{},"cell_type":"markdown","source":"## First, we create generators for augmentation of training data and for normalization of validation data"},{"metadata":{"trusted":true},"cell_type":"code","source":"aug_train = ImageDataGenerator(\n    rotation_range=20,\n    zoom_range=0.15,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.15,\n    horizontal_flip=True,\n    fill_mode=\"nearest\")\n\ngenerator_val = ImageDataGenerator()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## The ImageDataGenerator.fit method is used for feature normalization"},{"metadata":{"trusted":true},"cell_type":"code","source":"aug_train.fit(X_train)\n\ngenerator_val.fit(X_val)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## We build now a CNN. Let's try with a simple one consisnting in 5 Conv layer, one dense layer and one ouput layer"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Sequential()\n\nmodel.add(Conv2D(64, (3, 3), input_shape=X.shape[1:]))\nmodel.add(Activation('relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(64, (3, 3)))\nmodel.add(Activation('relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(64, (3, 3)))\nmodel.add(Activation('relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(64, (3, 3)))\nmodel.add(Activation('relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Conv2D(64, (3, 3)))\nmodel.add(Activation('relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation = \"relu\"))\nmodel.add(Dropout(0.5))\n\nmodel.add(Dense(2, activation='softmax'))\n\nmodel.compile(loss='sparse_categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Ok, let's now train the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"earlystop = EarlyStopping(patience=5)\n\nhistory = model.fit(aug_train.flow(X_train, y_train, batch_size=32), validation_data=generator_val.flow(X_val, y_val, batch_size=32), epochs=100, callbacks=[earlystop])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Evaluate model accuracy on the validation dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"arr = model.predict(X_val.astype(float))\npredicted_label = np.argmax(arr, axis=1)\nprint(\"Model accuracy on validation set: {:.4f}\".format(accuracy_score(y_val, predicted_label)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Let's have a look at the correlation matrix"},{"metadata":{"trusted":true},"cell_type":"code","source":"cm  = confusion_matrix(y_val, predicted_label)\nplot_confusion_matrix(cm,figsize=(6,6), cmap=plt.cm.Blues, colorbar=True)\nplt.xticks(range(2), ['Dogs', 'Cats'], fontsize=16)\nplt.yticks(range(2), ['Dogs', 'Cats'], fontsize=16)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Let's now generate a submission file according to the instructions"},{"metadata":{"trusted":true},"cell_type":"code","source":"TESTDIR = './test'\nLABELS = [\"DOG\", \"CAT\"]\ntest_data = []\nRESIZE = 100\nX_test = []\nX_id = []\n\ndef create_test_data():\n    for img in os.listdir(TESTDIR):\n        try:\n            img_array = cv2.imread(os.path.join(TESTDIR,img), cv2.IMREAD_GRAYSCALE)            \n            img2 = cv2.resize(img_array, (RESIZE,RESIZE))\n            X_test.append(img2)\n            img_num = img.split('.')[0]\n            X_id.append(np.array(img_num))\n            \n        except Exception as e:\n            pass\n        \ncreate_test_data()\nX_test = np.array(X_test).reshape(-1, RESIZE, RESIZE, 1)\n\n\narr_test = model.predict(X_test.astype(float))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = pd.DataFrame({'id':X_id,'label':arr_test[:,0]})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filename = 'Prediction1.csv'\n\nsubmission.to_csv(filename,index=False)\n\nprint('Saved file: ' + filename)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## I'm too late for the competition, but let's see how the model works for some examples of the test data s"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_predicted_label = np.argmax(arr_test, axis=1)\nfig=plt.figure(figsize=(20,20))\n\nfor counter, img in enumerate(X_test[:40]):\n    ax = fig.add_subplot(10,4,counter+1)\n    ax.imshow(X_test[counter,:,:,0], cmap='gray')\n    plt.title(LABELS[test_predicted_label[counter]])\n    ax.axes.get_xaxis().set_visible(False)\n    ax.axes.get_yaxis().set_visible(False)\n    \nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":1}