{"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":"# 1. Import all the packages that you will need.\n","metadata":{}},{"cell_type":"code","source":"import os\nimport zipfile\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import models\nfrom tensorflow.keras import optimizers\nfrom tensorflow.keras import regularizers\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import classification_report\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator","metadata":{"execution":{"iopub.status.busy":"2022-05-16T17:22:37.314886Z","iopub.execute_input":"2022-05-16T17:22:37.315135Z","iopub.status.idle":"2022-05-16T17:22:37.466238Z","shell.execute_reply.started":"2022-05-16T17:22:37.315109Z","shell.execute_reply":"2022-05-16T17:22:37.465570Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. Load your data and explore it. Describe how you will divide data for training, validation, and testing","metadata":{}},{"cell_type":"code","source":"%%time\n\nfor zipf in ['test1', 'train']:\n    with zipfile.ZipFile(f\"../input/dogs-vs-cats/{zipf}.zip\",\"r\") as zf:\n        zf.extractall(\".\")\n        print(f\"{zipf} extracted\")\n\nos.listdir('/kaggle/working/train')[:3]","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-16T15:57:08.548889Z","iopub.execute_input":"2022-05-16T15:57:08.549399Z","iopub.status.idle":"2022-05-16T15:57:23.941675Z","shell.execute_reply.started":"2022-05-16T15:57:08.549360Z","shell.execute_reply":"2022-05-16T15:57:23.940822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_lbl = []\nfor i in os.listdir('/kaggle/working/train'):\n    if i.split('.')[0] == 'cat':\n        img_lbl.append('cat')\n    else:\n        img_lbl.append('dog')\n\ndf = pd.DataFrame({\n    'image': os.listdir('/kaggle/working/train'),\n    'label': img_lbl\n})\ndisplay(df.head())\nsns.countplot(data = df, x = 'label');\nprint('(Rows, columns):', df.shape)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T17:23:13.531508Z","iopub.execute_input":"2022-05-16T17:23:13.531759Z","iopub.status.idle":"2022-05-16T17:23:13.725907Z","shell.execute_reply.started":"2022-05-16T17:23:13.531732Z","shell.execute_reply":"2022-05-16T17:23:13.725218Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(1, 2, figsize = (16, 9))\nimg1 = mpimg.imread('/kaggle/working/train/cat.580.jpg')\nimg2 = mpimg.imread('/kaggle/working/train/dog.2303.jpg')\nax[0].imshow(img1)\nax[1].imshow(img2)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:57:24.043316Z","iopub.execute_input":"2022-05-16T15:57:24.045799Z","iopub.status.idle":"2022-05-16T15:57:24.662719Z","shell.execute_reply.started":"2022-05-16T15:57:24.045760Z","shell.execute_reply":"2022-05-16T15:57:24.661277Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train, test_valid = train_test_split(df, test_size=0.2, stratify=df['label'])\n\ntest, valid = train_test_split(test_valid, test_size=0.5,  stratify=test_valid['label'])\nprint(f'Train size: {train.shape}')\nprint(f'Test size: {test.shape}')\nprint(f'Validation size: {valid.shape}')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T17:21:53.151307Z","iopub.execute_input":"2022-05-16T17:21:53.151884Z","iopub.status.idle":"2022-05-16T17:21:53.198009Z","shell.execute_reply.started":"2022-05-16T17:21:53.151847Z","shell.execute_reply":"2022-05-16T17:21:53.197048Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We have balanced dataset with pretty large number of images. As mentioned before, we have equal number of images belonging to both classes.\n\nData was divided in proportion of (80, 10, 10) where major part was given to train set, while test and validation sets were divided equally by 10 percents. I used 'stratify' hyperparameter to make sure that data with our target label was divided equally.","metadata":{}},{"cell_type":"markdown","source":"# 3. Describe your chosen model and its architecture.\n\nAccording to my research(that included reading several articles related to neural networks and deep learning. List of articles is provided in the end of notebook), convolutional neural network(CNN) is the best model that can be used in image classification problem. The main difference between ordinary neural network and CNN lies in the name of latter. CNN has convolutional layer with the filter, from which data goes to fully connected layer(traditional NN) and then generates output. Convolutional layer cuts image to a bunch of pixel, which are then turned to a matrix of numbers from 0 to 255 depending to their color and brightness. Then this matrix is being filtered using another matrix multiplication which allows to extract some useful features from data. This features then are goind to fully connected layers, that in fact are regular NNs.","metadata":{}},{"cell_type":"code","source":"os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' \n\nmodel = models.Sequential()\n\n# convolutional layer \nmodel.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\n# flatten output of conv\nmodel.add(layers.Flatten())\n\n# hidden layer\nmodel.add(layers.Dense(512, activation='relu', kernel_regularizer=regularizers.l2(0.001)))\nmodel.add(layers.Dropout(0.2))\n\n# output layer\nmodel.add(layers.Dense(1, activation='sigmoid'))\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:57:24.664277Z","iopub.execute_input":"2022-05-16T15:57:24.664543Z","iopub.status.idle":"2022-05-16T15:57:27.873869Z","shell.execute_reply.started":"2022-05-16T15:57:24.664508Z","shell.execute_reply":"2022-05-16T15:57:27.873191Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer = optimizers.Adam(learning_rate=5e-4), loss='binary_crossentropy', metrics='acc')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:57:27.875033Z","iopub.execute_input":"2022-05-16T15:57:27.875543Z","iopub.status.idle":"2022-05-16T15:57:27.889530Z","shell.execute_reply.started":"2022-05-16T15:57:27.875504Z","shell.execute_reply":"2022-05-16T15:57:27.888773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. Describe your evaluation metrics.\n\nMy evaluation metrics are the traditional set of metrics for classification: Confusion matrix, f1 score, precision and recall. Confusion matrix gives us such valuable parameters as True Negative rate, True Positive rate, False Negative and False Positive rates. These variables are used to calculate another mentioned metrics. ","metadata":{}},{"cell_type":"code","source":"aug_gen = ImageDataGenerator(rescale=1./255, shear_range = 0.2, zoom_range = 0.2,\n                               rotation_range=40, width_shift_range=0.2,\n                               height_shift_range=0.2, horizontal_flip=True, fill_mode='nearest')\n\ntrain_data = aug_gen.flow_from_dataframe(train, directory='/kaggle/working/train',\n                                           x_col='image', y_col='label', class_mode='binary', target_size=(224,224))\n\nvalid_data = aug_gen.flow_from_dataframe(valid, directory='/kaggle/working/train',\n                                       x_col='image', y_col='label', class_mode='binary', target_size=(224,224))\nhistory = model.fit(train_data, validation_data = valid_data, epochs=10,\n                   callbacks=[EarlyStopping(monitor='val_acc', min_delta=0.001, patience=5, verbose=1)])","metadata":{"execution":{"iopub.status.busy":"2022-05-16T16:09:44.326038Z","iopub.execute_input":"2022-05-16T16:09:44.326292Z","iopub.status.idle":"2022-05-16T16:55:23.748337Z","shell.execute_reply.started":"2022-05-16T16:09:44.326265Z","shell.execute_reply":"2022-05-16T16:55:23.747622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"acc = history.history['acc']\nvalid_acc = history.history['val_acc']\nplt.figure(figsize = (16, 9))\nplt.plot(acc, label = 'Train accuracy')\nplt.plot(valid_acc, '--', label = 'Validation accuracy')\nplt.legend()\nplt.xticks(range(10))\nplt.yticks(np.arange(0.7, 0.9, 0.025))\nplt.ylabel('Accuracy')\nplt.title('Train and validation accuracy')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T17:01:41.322802Z","iopub.execute_input":"2022-05-16T17:01:41.323086Z","iopub.status.idle":"2022-05-16T17:01:41.548495Z","shell.execute_reply.started":"2022-05-16T17:01:41.323054Z","shell.execute_reply":"2022-05-16T17:01:41.547746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('model_cats_vs_gods.h5')\n\nval_gen = ImageDataGenerator(rescale=1./255)\n\ntest_data = val_gen.flow_from_dataframe(test, directory = '/kaggle/working/train', x_col = 'image',\n                                        y_col = 'label', class_mode = 'binary',\n                                        target_size = (224,224), shuffle = False)\n\ntest_pred = model.predict(test_data)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T17:09:37.597265Z","iopub.execute_input":"2022-05-16T17:09:37.597552Z","iopub.status.idle":"2022-05-16T17:09:45.381372Z","shell.execute_reply.started":"2022-05-16T17:09:37.597525Z","shell.execute_reply":"2022-05-16T17:09:45.380619Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Let's evaluate model","metadata":{}},{"cell_type":"code","source":"def conf_matrix(y_true, y_pred):\n    tn, fp, fn, tp = confusion_matrix(y_true, y_pred).ravel()\n    conf_mat_df = pd.DataFrame(data = {'Predicted Positive': [tp, fp], 'Predicted Negative': [fn, tn]}, index = ['Real Positive', 'Real Negative'])\n    return conf_mat_df\n\npred_lbl = test_pred > .5\ntrue_lbl = test_data.classes\ndisplay(conf_matrix(true_lbl, pred_lbl))\nprint(classification_report(true_lbl, pred_lbl))","metadata":{"execution":{"iopub.status.busy":"2022-05-16T17:16:52.656588Z","iopub.execute_input":"2022-05-16T17:16:52.656843Z","iopub.status.idle":"2022-05-16T17:16:52.682827Z","shell.execute_reply.started":"2022-05-16T17:16:52.656815Z","shell.execute_reply":"2022-05-16T17:16:52.682014Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.evaluate(test_data)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T17:13:59.878080Z","iopub.execute_input":"2022-05-16T17:13:59.878440Z","iopub.status.idle":"2022-05-16T17:14:07.905081Z","shell.execute_reply.started":"2022-05-16T17:13:59.878399Z","shell.execute_reply":"2022-05-16T17:14:07.904276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Overall accuracy is 93%","metadata":{}}]}