{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Image classification\n\nThe objectif is to build a ML algorithm to classify the cats and dogs pictures.\n\nWe'll follow these steps:\n\n1.   Explore the Example Data of Cats and Dogs.\n2.   Build and Train a Neural Network to recognize the difference between the two.\n3.   Evaluate the Training and Validation accuracy.\n\n## Explore the Example Data"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n%matplotlib inline\n\nimport matplotlib.image as mpimg\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras.optimizers import RMSprop\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport 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","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Let's unzip the data**"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\nimport zipfile\n\nlocal_zip = '/kaggle/input/dogs-vs-cats/train.zip'\n\n\n\n\nzip_ref = zipfile.ZipFile(local_zip, 'r')\n\nzip_ref.extractall('/tmp')\nzip_ref.close()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport zipfile\n\nlocal_zip = '/kaggle/input/dogs-vs-cats/test1.zip'\n\nzip_ref = zipfile.ZipFile(local_zip, 'r')\n\nzip_ref.extractall('/tmp')\nzip_ref.close()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now, let's see what the filenames look like in the cats and dogs train and test directories "},{"metadata":{"trusted":true},"cell_type":"code","source":"base_directory = '/tmp'\n\ndir_train=os.path.join(base_directory, 'train')\ntrain_fnames=os.listdir(os.path.join(dir_train))\ntrain_fnames[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dir_test1=os.path.join('/tmp', 'test1')\ntest_fnames=os.listdir(os.path.join(dir_test1))\ntest_fnames[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('total training cat images :', len(os.listdir(      dir_train ) ))\n\nprint('total validation cat images :', len(os.listdir( dir_test1 ) ))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now let's take a look at a few pictures to get a better sense of what the cat and dog datasets look like."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Parameters for our graph; we'll output images in a 4x4 configuration\nnrows = 4\nncols = 4\n\npic_index = 0 # Index for iterating over images\n\n# Set up matplotlib fig, and size it to fit 4x4 pics\nfig = plt.gcf()\nfig.set_size_inches(ncols*4, nrows*4)\n\npic_index+=8\n\nnext_train_pix = [os.path.join(dir_train, fname) \n                for fname in train_fnames[ pic_index-8:pic_index] \n               ]\n\nnext_test_pix = [os.path.join(dir_test1, fname) \n                for fname in test_fnames[ pic_index-8:pic_index] \n               ]\n\nfor i, img_path in enumerate(next_train_pix+next_test_pix):\n    # Set up subplot; subplot indices start at 1\n    sp = plt.subplot(nrows, ncols, i + 1)\n    sp.axis('Off') # Don't show axes (or gridlines)\n    img = mpimg.imread(img_path)\n    plt.imshow(img)\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Building a model\n\nStep 1 will be to import tensorflow."},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"\nWe define a class \"myCallback\" that stops training to avoid overfitting."},{"metadata":{"trusted":true},"cell_type":"code","source":"class myCallback(tf.keras.callbacks.Callback):\n    def on_epoch_end(self, epoch, logs={}):\n        if(logs.get('accuracy')>0.95):\n            print(\"\\nReached 99% accuracy so cancelling training!\")\n            self.model.stop_training = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"callbacks = myCallback()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = tf.keras.models.Sequential([\n    # Note the input shape is the desired size of the image 150x150 with 3 bytes color\n    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150, 3)),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2,2), \n    tf.keras.layers.Conv2D(32, (3,3), activation='relu'), \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(64, (3,3), activation='relu'), \n    tf.keras.layers.MaxPooling2D(2,2),\n    # Flatten the results to feed into a DNN\n    tf.keras.layers.Flatten(), \n    # 512 neuron hidden layer\n    tf.keras.layers.Dense(712, activation='relu'), \n    # Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('cats') and 1 for the other ('dogs')\n    tf.keras.layers.Dense(1, activation='sigmoid')  \n])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The model.summary() method call prints a summary of the NN"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer=RMSprop(lr=0.001),\n              loss='binary_crossentropy',\n              metrics = ['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data Pre-processing\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"fnames=train_fnames\ncategories=[]\nfor filenm in fnames:\n    label=filenm.split('.')[0]\n    if label=='dog':\n        categories.append(1)\n    else:\n        categories.append(0)\n        \ntrain=pd.DataFrame({'fnames':fnames,'category':categories}) \ntrain[0:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_df,validate_df=train_test_split(train,test_size=0.2,random_state=0)\ntrain_df=train_df.reset_index(drop=True)\ntest_df=validate_df.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# 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_dataframe(train_df, \n                                                    '/tmp/train',\n                                                    x_col = 'fnames',\n                                                    y_col='category',\n                                                    batch_size=20, \n                                                    class_mode='raw', \n                                                    target_size=(150, 150))     \n# --------------------\n# Flow validation images in batches of 20 using test_datagen generator\n# --------------------\ntest_generator =  test_datagen.flow_from_dataframe(validate_df,\n                                                   '/tmp/train',\n                                                   x_col = 'fnames',\n                                                   y_col='category',\n                                                   batch_size=20,\n                                                   class_mode  = 'raw',\n                                                   target_size = (150, 150))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"###  "},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit(train_generator,\n                              validation_data=test_generator,\n                              steps_per_epoch=100,\n                              epochs=100,\n                              validation_steps=50,\n                              verbose=2,\n                              callbacks=[callbacks])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Visualizing Intermediate Representations\n\nTo get a feel for what kind of features our convnet has learned, one fun thing to do is to visualize how an input gets transformed as it goes through the convnet.\n\nLet's pick a random cat or dog image from the training set, and then generate a figure where each row is the output of a layer, and each image in the row is a specific filter in that output feature map. Rerun this cell to generate intermediate representations for a variety of training images."},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport random\nfrom   tensorflow.keras.preprocessing.image import img_to_array, load_img\n\n# Let's define a new Model that will take an image as input, and will output\n# intermediate representations for all layers in the previous model after\n# the first.\nsuccessive_outputs = [layer.output for layer in model.layers[1:]]\n\n#visualization_model = Model(img_input, successive_outputs)\nvisualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs)\n\n# Let's prepare a random input image of a cat or dog from the training set.\ntrain_img_files = [os.path.join(dir_train, f) for f in train_fnames]\n\nimg_path = random.choice(train_img_files)\nimg = load_img(img_path, target_size=(150, 150))  # this is a PIL image\n\nx   = img_to_array(img)                           # Numpy array with shape (150, 150, 3)\nx   = x.reshape((1,) + x.shape)                   # Numpy array with shape (1, 150, 150, 3)\n\n# Rescale by 1/255\nx /= 255.0\n\n# Let's run our image through our network, thus obtaining all\n# intermediate representations for this image.\nsuccessive_feature_maps = visualization_model.predict(x)\n\n# These are the names of the layers, so can have them as part of our plot\nlayer_names = [layer.name for layer in model.layers]\n\n# -----------------------------------------------------------------------\n# Now let's display our representations\n# -----------------------------------------------------------------------\nfor layer_name, feature_map in zip(layer_names, successive_feature_maps):\n  \n  if len(feature_map.shape) == 4:\n    \n    #-------------------------------------------\n    # Just do this for the conv / maxpool layers, not the fully-connected layers\n    #-------------------------------------------\n    n_features = feature_map.shape[-1]  # number of features in the feature map\n    size       = feature_map.shape[ 1]  # feature map shape (1, size, size, n_features)\n    \n    # We will tile our images in this matrix\n    display_grid = np.zeros((size, size * n_features))\n    \n    #-------------------------------------------------\n    # Postprocess the feature to be visually palatable\n    #-------------------------------------------------\n    for i in range(n_features):\n      x  = feature_map[0, :, :, i]\n      x -= x.mean()\n      x /= x.std ()\n      x *=  64\n      x += 128\n      x  = np.clip(x, 0, 255).astype('uint8')\n      display_grid[:, i * size : (i + 1) * size] = x # Tile each filter into a horizontal grid\n\n    #-----------------\n    # Display the grid\n    #-----------------\n\n    scale = 20. / n_features\n    plt.figure( figsize=(scale * n_features, scale) )\n    plt.title ( layer_name )\n    plt.grid  ( False )\n    plt.imshow( display_grid, aspect='auto', cmap='viridis' ) ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Evaluating Accuracy and Loss for the Model\n\nLet's plot the training/validation accuracy and loss as collected during training:"},{"metadata":{"trusted":true},"cell_type":"code","source":"#-----------------------------------------------------------\n# Retrieve a list of list results on training and test data\n# sets for each training epoch\n#-----------------------------------------------------------\nacc      = history.history[     'accuracy' ]\nval_acc  = history.history[ 'val_accuracy' ]\nloss     = history.history[    'loss' ]\nval_loss = history.history['val_loss' ]\n\nepochs   = range(len(acc)) # Get number of epochs\n\n#------------------------------------------------\n# Plot training and validation accuracy per epoch\n#------------------------------------------------\nplt.plot  ( epochs,     acc )\nplt.plot  ( epochs, val_acc )\nplt.title ('Training and validation accuracy')\nplt.figure()\n\n#------------------------------------------------\n# Plot training and validation loss per epoch\n#------------------------------------------------\nplt.plot  ( epochs,     loss )\nplt.plot  ( epochs, val_loss )\nplt.title ('Training and validation loss'   )","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":4}