{"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":"# Introduction \n\nMy Kaggle attempt to classify cats and dogs. This notebook can be run directly in Kaggle platform by importing it there.\n\nSome Updates compared to off-line version:\n- Full data has been used to train model\n- Data Augmentation\n- Prediction function\n- Larger model","metadata":{}},{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\n\nimport random\nimport shutil\n\nimport zipfile\n\nimport tensorflow as tf\nfrom tensorflow.keras.optimizers import RMSprop\nprint(f\"TF version is: {tf.__version__}\")\n\nfrom tensorflow.keras.preprocessing.image import img_to_array, load_img\nfrom tqdm import tqdm\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":"2022-12-02T20:27:00.176112Z","iopub.execute_input":"2022-12-02T20:27:00.176568Z","iopub.status.idle":"2022-12-02T20:27:00.184936Z","shell.execute_reply.started":"2022-12-02T20:27:00.176524Z","shell.execute_reply":"2022-12-02T20:27:00.183613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:37:09.041344Z","iopub.execute_input":"2022-12-02T18:37:09.042270Z","iopub.status.idle":"2022-12-02T18:37:09.048013Z","shell.execute_reply.started":"2022-12-02T18:37:09.042232Z","shell.execute_reply":"2022-12-02T18:37:09.047207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"local_zip = '/kaggle/input/dogs-vs-cats/train.zip'\nzip_ref   = zipfile.ZipFile(local_zip, 'r')\nzip_ref.extractall('/')\nzip_ref.close()","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:38:48.109515Z","iopub.execute_input":"2022-12-02T18:38:48.109892Z","iopub.status.idle":"2022-12-02T18:39:01.878497Z","shell.execute_reply.started":"2022-12-02T18:38:48.109861Z","shell.execute_reply":"2022-12-02T18:39:01.877335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_path = '/train'\nf_names = os.listdir(train_path)\nprint(f\"count of data points: {len(f_names)}\")","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:39:08.524582Z","iopub.execute_input":"2022-12-02T18:39:08.525002Z","iopub.status.idle":"2022-12-02T18:39:08.548477Z","shell.execute_reply.started":"2022-12-02T18:39:08.524965Z","shell.execute_reply":"2022-12-02T18:39:08.547360Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Split data to train and validation sets:","metadata":{}},{"cell_type":"code","source":"random.seed(1)\nsplit_ratio = 0.8\nsample_data = random.sample(f_names, len(f_names))\ntrain_sample  = sample_data[:int(split_ratio * len(f_names))]\nvalidation_sample = sample_data[int(split_ratio * len(f_names)):]\n","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:39:28.728593Z","iopub.execute_input":"2022-12-02T18:39:28.729037Z","iopub.status.idle":"2022-12-02T18:39:28.783301Z","shell.execute_reply.started":"2022-12-02T18:39:28.728987Z","shell.execute_reply":"2022-12-02T18:39:28.781932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Create sub directories for train and validation classes and copy files into correct directories:","metadata":{}},{"cell_type":"code","source":"# Directory with training cat/dog pictures\ntrain_cats_dir = '/train/cat'\ntrain_dogs_dir = '/train/dog'\n\n# Directory with validation cat/dog pictures\nvalidation_cats_dir = '/validation/cat'\nvalidation_dogs_dir = '/validation/dog'\n\n# create directories:\nos.makedirs(train_dogs_dir,exist_ok = True)\nos.makedirs(train_cats_dir,exist_ok = True)\nos.makedirs(validation_dogs_dir,exist_ok = True)\nos.makedirs(validation_cats_dir,exist_ok = True)\n\n# copy the data:\n# train data:\nfor v in train_sample:\n    if 'cat' in v.lower():\n        shutil.copy('/train/'+ v,'/train/cat/'+ v)\n    else:\n         shutil.copy('/train/' + v,'/train/dog/' + v)\n\n# validation data:\nfor v in validation_sample:\n    if 'cat' in v.lower():\n        shutil.copy('/train/'+ v,'/validation/cat/'+ v)\n    else:\n        shutil.copy('/train/'+ v,'/validation/dog/'+ v)\n\nprint(f'count of cats in training: {len(os.listdir(train_cats_dir))}')\nprint(f'count of dogs in training: {len(os.listdir(train_dogs_dir))}')","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:39:55.810474Z","iopub.execute_input":"2022-12-02T18:39:55.810899Z","iopub.status.idle":"2022-12-02T18:40:00.144480Z","shell.execute_reply.started":"2022-12-02T18:39:55.810864Z","shell.execute_reply":"2022-12-02T18:40:00.138337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Baseline model","metadata":{}},{"cell_type":"markdown","source":"### Data pre-processing","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# All images will be rescaled by 1./255.\ntrain_datagen = ImageDataGenerator( rescale = 1.0/255. )\ntest_datagen  = ImageDataGenerator( rescale = 1.0/255. )\n\n# --------------------\n# Flow training images in batches of 20 using train_datagen generator\n# --------------------\ntrain_generator = train_datagen.flow_from_directory('/train',\n                                                    batch_size=50,\n                                                    class_mode='binary',\n                                                    target_size=(150, 150))     \n# --------------------\n# Flow validation images in batches of 20 using test_datagen generator\n# --------------------\nvalidation_generator =  test_datagen.flow_from_directory('/validation',\n                                                         batch_size=50,\n                                                         class_mode  = 'binary',\n                                                         target_size = (150, 150))","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:42:32.463634Z","iopub.execute_input":"2022-12-02T18:42:32.464552Z","iopub.status.idle":"2022-12-02T18:42:33.212367Z","shell.execute_reply.started":"2022-12-02T18:42:32.464516Z","shell.execute_reply":"2022-12-02T18:42:33.211232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create the Model","metadata":{}},{"cell_type":"code","source":"def create_model():\n    '''Creates a CNN with 4 convolutional layers'''\n    model = tf.keras.models.Sequential([\n      tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(150, 150, 3)),\n      tf.keras.layers.MaxPooling2D(2, 2),\n      tf.keras.layers.Conv2D(64, (3,3), activation='relu'),\n      tf.keras.layers.MaxPooling2D(2,2),\n      tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n      tf.keras.layers.MaxPooling2D(2,2),\n      tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n      tf.keras.layers.MaxPooling2D(2,2),\n      tf.keras.layers.Flatten(),\n      tf.keras.layers.Dense(512, activation='relu'),\n      tf.keras.layers.Dense(1, activation='sigmoid')\n    ])\n\n    model.compile(loss='binary_crossentropy',\n                optimizer=RMSprop(learning_rate=1e-4),\n                metrics=['accuracy'])\n\n    return model","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:42:33.638222Z","iopub.execute_input":"2022-12-02T18:42:33.638607Z","iopub.status.idle":"2022-12-02T18:42:33.648799Z","shell.execute_reply.started":"2022-12-02T18:42:33.638576Z","shell.execute_reply":"2022-12-02T18:42:33.647644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model()\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:42:34.588977Z","iopub.execute_input":"2022-12-02T18:42:34.589354Z","iopub.status.idle":"2022-12-02T18:42:34.689192Z","shell.execute_reply.started":"2022-12-02T18:42:34.589324Z","shell.execute_reply":"2022-12-02T18:42:34.687945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n            train_generator,\n            epochs=15,\n            validation_data=validation_generator,\n            verbose=1\n            )","metadata":{"execution":{"iopub.status.busy":"2022-12-02T18:42:39.261307Z","iopub.execute_input":"2022-12-02T18:42:39.262350Z","iopub.status.idle":"2022-12-02T20:19:52.057087Z","shell.execute_reply.started":"2022-12-02T18:42:39.262308Z","shell.execute_reply":"2022-12-02T20:19:52.055761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n# function for plotting the accuracy and loss vs epochs\ndef plot_loss_acc(history):\n  '''Plots the training and validation loss and accuracy from a history object'''\n  acc = history.history['accuracy']\n  val_acc = history.history['val_accuracy']\n  loss = history.history['loss']\n  val_loss = history.history['val_loss']\n\n  epochs = range(len(acc))\n\n  plt.plot(epochs, acc, 'bo', label='Training accuracy')\n  plt.plot(epochs, val_acc, 'b', label='Validation accuracy')\n  plt.title('Training and validation accuracy')\n\n  plt.figure()\n\n  plt.plot(epochs, loss, 'bo', label='Training Loss')\n  plt.plot(epochs, val_loss, 'b', label='Validation Loss')\n  plt.title('Training and validation loss')\n  plt.legend()\n\n  plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-02T20:26:13.587452Z","iopub.execute_input":"2022-12-02T20:26:13.587847Z","iopub.status.idle":"2022-12-02T20:26:13.596713Z","shell.execute_reply.started":"2022-12-02T20:26:13.587811Z","shell.execute_reply":"2022-12-02T20:26:13.595663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot training results\nplot_loss_acc(history)","metadata":{"execution":{"iopub.status.busy":"2022-12-02T20:26:15.655767Z","iopub.execute_input":"2022-12-02T20:26:15.656774Z","iopub.status.idle":"2022-12-02T20:26:16.072792Z","shell.execute_reply.started":"2022-12-02T20:26:15.656737Z","shell.execute_reply":"2022-12-02T20:26:16.071658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Predicting the test data:","metadata":{}},{"cell_type":"code","source":"def model_predict(model, data_path):\n    f_names = os.listdir(data_path)\n    labels =[]\n    ids=[]\n    for v in tqdm(f_names):    \n        img=load_img('/test1/' + v, target_size=(150, 150))\n        x = img_to_array(img)\n        x = x /255\n        x=np.expand_dims(x, axis=0)\n        images = np.vstack([x])\n\n        ids.append(int(v.rsplit( \".\", 1 )[ 0 ]))\n\n        if model.predict(images, batch_size=10) > 0.5:\n            labels.append(1)\n        else:\n            labels.append(0)\n    return ids, labels","metadata":{"execution":{"iopub.status.busy":"2022-12-02T20:27:12.880683Z","iopub.execute_input":"2022-12-02T20:27:12.881104Z","iopub.status.idle":"2022-12-02T20:27:12.891529Z","shell.execute_reply.started":"2022-12-02T20:27:12.881071Z","shell.execute_reply":"2022-12-02T20:27:12.889136Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"local_zip = '/kaggle/input/dogs-vs-cats/test1.zip'\nzip_ref   = zipfile.ZipFile(local_zip, 'r')\nzip_ref.extractall('/')\nzip_ref.close()","metadata":{"execution":{"iopub.status.busy":"2022-12-02T20:27:16.982372Z","iopub.execute_input":"2022-12-02T20:27:16.982806Z","iopub.status.idle":"2022-12-02T20:27:21.811372Z","shell.execute_reply.started":"2022-12-02T20:27:16.982769Z","shell.execute_reply":"2022-12-02T20:27:21.810002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub = pd.DataFrame({'id':[],'label':[]})\nids, labels = model_predict(model, '/test1/')\ndf_sub['id']=ids\ndf_sub['label']= labels\nprint(df_sub.shape)\ndf_sub.head()\n# save the dataframe:\nsub_name = 'cat_dog_predictions_simple_cnn.csv'\ndf_sub.to_csv('/kaggle/working/'+sub_name)","metadata":{"execution":{"iopub.status.busy":"2022-12-02T20:27:21.813086Z","iopub.execute_input":"2022-12-02T20:27:21.813634Z","iopub.status.idle":"2022-12-02T20:41:13.224647Z","shell.execute_reply.started":"2022-12-02T20:27:21.813594Z","shell.execute_reply":"2022-12-02T20:41:13.223488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Augmentation","metadata":{}},{"cell_type":"code","source":"# Create new model\nmodel_for_aug = create_model()\n\n# This code has changed. Now instead of the ImageGenerator just rescaling\n# the image, we also rotate and do other operations\ntrain_datagen = ImageDataGenerator(\n      rescale=1./255,\n      rotation_range=40,\n      width_shift_range=0.2,\n      height_shift_range=0.2,\n      shear_range=0.2,\n      zoom_range=0.2,\n      horizontal_flip=True,\n      fill_mode='nearest')\n\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\n# Flow training images in batches of 20 using train_datagen generator\ntrain_generator = train_datagen.flow_from_directory(\n        '/train',  # This is the source directory for training images\n        target_size=(150, 150),  # All images will be resized to 150x150\n        batch_size=20,\n        # Since we use binary_crossentropy loss, we need binary labels\n        class_mode='binary')\n\n# Flow validation images in batches of 20 using test_datagen generator\nvalidation_generator = test_datagen.flow_from_directory(\n        '/validation',\n        target_size=(150, 150),\n        batch_size=20,\n        class_mode='binary')\n\n# Train the new model\nhistory_with_aug = model_for_aug.fit(\n      train_generator,\n      steps_per_epoch=100,  # 2000 images = batch_size * steps\n      epochs=10,\n      validation_data=validation_generator,\n      validation_steps=50,  # 1000 images = batch_size * steps\n      verbose=2)\n\nplot_loss_acc(history_with_aug)","metadata":{"execution":{"iopub.status.busy":"2022-12-02T20:45:43.526875Z","iopub.execute_input":"2022-12-02T20:45:43.527336Z","iopub.status.idle":"2022-12-02T20:56:57.149826Z","shell.execute_reply.started":"2022-12-02T20:45:43.527287Z","shell.execute_reply":"2022-12-02T20:56:57.148890Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub_aug = pd.DataFrame({'id':[],'label':[]})\nids, labels = model_predict(model_for_aug, '/test1/')\ndf_sub_aug['id']=ids\ndf_sub_aug['label']= labels\nprint(df_sub_aug.shape)\ndf_sub_aug.head()\n# save the dataframe:\nsub_name = 'cat_dog_predictions_cnn_augmentation.csv'\ndf_sub.to_csv('/kaggle/working/'+sub_name)","metadata":{"execution":{"iopub.status.busy":"2022-12-02T20:57:55.176852Z","iopub.execute_input":"2022-12-02T20:57:55.177255Z","iopub.status.idle":"2022-12-02T21:12:07.446736Z","shell.execute_reply.started":"2022-12-02T20:57:55.177222Z","shell.execute_reply":"2022-12-02T21:12:07.445299Z"},"trusted":true},"execution_count":null,"outputs":[]}]}