{"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":"# Residual Networks\n\n### KUMAR GAURAV\n\n##### BRIEF:-\n\n###### - In this notebook we will be implementing a CNN Week2 Assigments of the famous DeepLearning.AI Course on Coursera by AndreNG\n###### - Here you will learn how you can use the learning of a Course to solve a real world problems\n###### - You can run this notebook locally\n\n##### Difficulty faced:-\n- I have faced diffuculty in Loading the inputs and matching them with the training samples of the Model\n- Finetuning and continuous model training\n","metadata":{}},{"cell_type":"markdown","source":"## Table of Content\n\n- [1 - Packages](#1)\n- [2 - The Problem of Very Deep Neural Networks](#2)\n- [3 - Building a Residual Network](#3)\n    - [3.1 - The Identity Block](#3-1)\n        - [Exercise 1 - identity_block](#ex-1)\n    - [3.2 - The Convolutional Block](#3-2)\n        - [Exercise 2 - convolutional_block](#ex-2)\n- [4 - Building Your First ResNet Model (50 layers)](#4)\n    - [Exercise 3 - ResNet50](#ex-3)\n    - [Loading the Datase](#4.1)\n- [5 - Fine-Tunig](#5)\n- [6 - Bibliography](#6)","metadata":{}},{"cell_type":"markdown","source":"<a name='1'></a>\n## 1 - Packages","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport scipy.misc\nfrom tensorflow.keras.applications.resnet_v2 import ResNet50V2\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.applications.resnet_v2 import preprocess_input, decode_predictions\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import Input, Add, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D\nfrom tensorflow.keras.models import Model, load_model\n#from resnets_utils import *\nfrom tensorflow.keras.initializers import random_uniform, glorot_uniform, constant, identity\nfrom tensorflow.python.framework.ops import EagerTensor\nfrom matplotlib.pyplot import imshow\n\n#from test_utils import summary, comparator\n#import public_tests\n\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:00:32.609148Z","iopub.execute_input":"2023-05-31T04:00:32.609676Z","iopub.status.idle":"2023-05-31T04:00:42.666261Z","shell.execute_reply.started":"2023-05-31T04:00:32.609647Z","shell.execute_reply":"2023-05-31T04:00:42.665273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a name='2'></a>\n## 2 - The Problem of Very Deep Neural Networks\n\nLast week, you built your first convolutional neural networks: first manually with numpy, then using Tensorflow and Keras. \n\nIn recent years, neural networks have become much deeper, with state-of-the-art networks evolving from having just a few layers (e.g., AlexNet) to over a hundred layers.\n\n* The main benefit of a very deep network is that it can represent very complex functions. It can also learn features at many different levels of abstraction, from edges (at the shallower layers, closer to the input) to very complex features (at the deeper layers, closer to the output). \n\n* However, using a deeper network doesn't always help. A huge barrier to training them is vanishing gradients: very deep networks often have a gradient signal that goes to zero quickly, thus making gradient descent prohibitively slow.\n\n* More specifically, during gradient descent, as you backpropagate from the final layer back to the first layer, you are multiplying by the weight matrix on each step, and thus the gradient can decrease exponentially quickly to zero (or, in rare cases, grow exponentially quickly and \"explode,\" from gaining very large values). \n\n* During training, you might therefore see the magnitude (or norm) of the gradient for the shallower layers decrease to zero very rapidly as training proceeds, as shown below: ","metadata":{}},{"cell_type":"markdown","source":"<img src=\"https://github.com/GAURAV2567/Kaggle/blob/main/images/vanishing_grad_kiank.png?raw=true\" style=\"width:450px;height:220px;\">\n<caption><center> <u> <font color='purple'> <b>Figure 1</b> </u><font color='purple'>  : <b>Vanishing gradient</b> <br> The speed of learning decreases very rapidly for the shallower layers as the network trains </center></caption>\n\nNot to worry! You are now going to solve this problem by building a Residual Network!","metadata":{}},{"cell_type":"markdown","source":"<a name='3'></a>\n## 3 - Building a Residual Network\n\nIn ResNets, a \"shortcut\" or a \"skip connection\" allows the model to skip layers:  \n\n<img src=\"https://github.com/GAURAV2567/Kaggle/blob/main/images/skip_connection_kiank.png?raw=true\" style=\"width:650px;height:200px;\">\n<caption><center> <u> <font color='purple'> <b>Figure 2</b> </u><font color='purple'>  : A ResNet block showing a skip-connection <br> </center></caption>\n\nThe image on the left shows the \"main path\" through the network. The image on the right adds a shortcut to the main path. By stacking these ResNet blocks on top of each other, you can form a very deep network. \n\nThe lecture mentioned that having ResNet blocks with the shortcut also makes it very easy for one of the blocks to learn an identity function. This means that you can stack on additional ResNet blocks with little risk of harming training set performance.  \n    \nOn that note, there is also some evidence that the ease of learning an identity function accounts for ResNets' remarkable performance even more than skip connections help with vanishing gradients.\n\nTwo main types of blocks are used in a ResNet, depending mainly on whether the input/output dimensions are the same or different. You are going to implement both of them: the \"identity block\" and the \"convolutional block.\"","metadata":{}},{"cell_type":"markdown","source":"<a name='3-1'></a>\n### 3.1 - The Identity Block\n\nThe identity block is the standard block used in ResNets, and corresponds to the case where the input activation (say $a^{[l]}$) has the same dimension as the output activation (say $a^{[l+2]}$). To flesh out the different steps of what happens in a ResNet's identity block, here is an alternative diagram showing the individual steps:\n\n<img src=\"https://github.com/GAURAV2567/Kaggle/blob/main/images/idblock2_kiank.png?raw=true\" style=\"width:650px;height:150px;\">\n<caption><center> <u> <font color='purple'> <b>Figure 3</b> </u><font color='purple'>  : <b>Identity block.</b> Skip connection \"skips over\" 2 layers. </center></caption>\n\nThe upper path is the \"shortcut path.\" The lower path is the \"main path.\" In this diagram, notice the CONV2D and ReLU steps in each layer. To speed up training, a BatchNorm step has been added. Don't worry about this being complicated to implement--you'll see that BatchNorm is just one line of code in Keras! \n\nIn this exercise, you'll actually implement a slightly more powerful version of this identity block, in which the skip connection \"skips over\" 3 hidden layers rather than 2 layers. It looks like this: \n\n<img src=\"https://github.com/GAURAV2567/Kaggle/blob/main/images/idblock3_kiank.png?raw=true\" style=\"width:650px;height:150px;\">\n    <caption><center> <u> <font color='purple'> <b>Figure 4</b> </u><font color='purple'>  : <b>Identity block.</b> Skip connection \"skips over\" 3 layers.</center></caption>","metadata":{}},{"cell_type":"markdown","source":"These are the individual steps:\n\nFirst component of main path: \n- The first CONV2D has $F_1$ filters of shape (1,1) and a stride of (1,1). Its padding is \"valid\". Use 0 as the seed for the random uniform initialization: `kernel_initializer = initializer(seed=0)`. \n- The first BatchNorm is normalizing the 'channels' axis.\n- Then apply the ReLU activation function. This has no hyperparameters. \n\nSecond component of main path:\n- The second CONV2D has $F_2$ filters of shape $(f,f)$ and a stride of (1,1). Its padding is \"same\". Use 0 as the seed for the random uniform initialization: `kernel_initializer = initializer(seed=0)`.\n- The second BatchNorm is normalizing the 'channels' axis.\n- Then apply the ReLU activation function. This has no hyperparameters.\n\nThird component of main path:\n- The third CONV2D has $F_3$ filters of shape (1,1) and a stride of (1,1). Its padding is \"valid\". Use 0 as the seed for the random uniform initialization: `kernel_initializer = initializer(seed=0)`. \n- The third BatchNorm is normalizing the 'channels' axis.\n- Note that there is **no** ReLU activation function in this component. \n\nFinal step: \n- The `X_shortcut` and the output from the 3rd layer `X` are added together.\n- **Hint**: The syntax will look something like `Add()([var1,var2])`\n- Then apply the ReLU activation function. This has no hyperparameters. \n\n<a name='ex-1'></a>\n### Exercise 1 - identity_block\n\nImplement the ResNet identity block. The first component of the main path has been implemented for you already! First, you should read these docs carefully to make sure you understand what's happening. Then, implement the rest. \n- To implement the Conv2D step: [Conv2D](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D)\n- To implement BatchNorm: [BatchNormalization](https://www.tensorflow.org/api_docs/python/tf/keras/layers/BatchNormalization) `BatchNormalization(axis = 3)(X, training = training)`. If training is set to False, its weights are not updated with the new examples. I.e when the model is used in prediction mode.\n- For the activation, use:  `Activation('relu')(X)`\n- To add the value passed forward by the shortcut: [Add](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Add)\n\nWe have added the initializer argument to our functions. This parameter receives an initializer function like the ones included in the package [tensorflow.keras.initializers](https://www.tensorflow.org/api_docs/python/tf/keras/initializers) or any other custom initializer. By default it will be set to [random_uniform](https://www.tensorflow.org/api_docs/python/tf/keras/initializers/RandomUniform)\n\nRemember that these functions accept a `seed` argument that can be any value you want, but that in this notebook must set to 0 for **grading purposes**.","metadata":{}},{"cell_type":"markdown","source":" Here is where you're actually using the power of the Functional API to create a shortcut path: ","metadata":{}},{"cell_type":"code","source":"# UNQ_C1\n# GRADED FUNCTION: identity_block\n\ndef identity_block(X, f, filters, training=True, initializer=random_uniform):\n    \"\"\"\n    Implementation of the identity block as defined in Figure 4\n    \n    Arguments:\n    X -- input tensor of shape (m, n_H_prev, n_W_prev, n_C_prev)\n    f -- integer, specifying the shape of the middle CONV's window for the main path\n    filters -- python list of integers, defining the number of filters in the CONV layers of the main path\n    training -- True: Behave in training mode\n                False: Behave in inference mode\n    initializer -- to set up the initial weights of a layer. Equals to random uniform initializer\n    \n    Returns:\n    X -- output of the identity block, tensor of shape (m, n_H, n_W, n_C)\n    \"\"\"\n    \n    # Retrieve Filters\n    F1, F2, F3 = filters\n    \n    # Save the input value. You'll need this later to add back to the main path. \n    X_shortcut = X\n    \n    # First component of main path\n    X = Conv2D(filters = F1, kernel_size = 1, strides = (1,1), padding = 'valid', kernel_initializer = initializer(seed=0))(X)\n    X = BatchNormalization(axis = 3)(X, training = training) # Default axis\n    X = Activation('relu')(X)\n    \n    ### START CODE HERE\n    ## Second component of main path (≈3 lines)\n    ## Set the padding = 'same'\n    X = Conv2D(filters = F2, kernel_size = f, strides = (1,1), padding = 'same', kernel_initializer = initializer(seed=0))(X)\n    X = BatchNormalization(axis = 3)(X, training = training) # Default axis\n    X = Activation('relu')(X)\n\n    ## Third component of main path (≈2 lines)\n    ## Set the padding = 'valid'\n    X = Conv2D(filters = F3, kernel_size = 1, strides = (1,1), padding = 'valid', kernel_initializer = initializer(seed=0))(X)\n    X = BatchNormalization(axis = 3)(X, training = training) # Default axis\n    \n    ## Final step: Add shortcut value to main path, and pass it through a RELU activation (≈2 lines)\n    X = Add()([X, X_shortcut])\n    X = Activation('relu')(X)\n    ### END CODE HERE\n\n    return X","metadata":{"nbgrader":{"grade":false,"grade_id":"cell-0017b68317ffa974","locked":false,"schema_version":3,"solution":true,"task":false},"execution":{"iopub.status.busy":"2023-05-31T04:00:57.518691Z","iopub.execute_input":"2023-05-31T04:00:57.519125Z","iopub.status.idle":"2023-05-31T04:00:57.547011Z","shell.execute_reply.started":"2023-05-31T04:00:57.519075Z","shell.execute_reply":"2023-05-31T04:00:57.542622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a name='3-2'></a>\n### 3.2 - The Convolutional Block\n\nThe ResNet \"convolutional block\" is the second block type. You can use this type of block when the input and output dimensions don't match up. The difference with the identity block is that there is a CONV2D layer in the shortcut path: \n\n<img src=\"https://github.com/GAURAV2567/Kaggle/blob/main/images/convblock_kiank.png?raw=true\" style=\"width:650px;height:150px;\">\n<caption><center> <u> <font color='purple'> <b>Figure 4</b> </u><font color='purple'>  : <b>Convolutional block</b> </center></caption>\n\n* The CONV2D layer in the shortcut path is used to resize the input $x$ to a different dimension, so that the dimensions match up in the final addition needed to add the shortcut value back to the main path. (This plays a similar role as the matrix $W_s$ discussed in lecture.) \n* For example, to reduce the activation dimensions's height and width by a factor of 2, you can use a 1x1 convolution with a stride of 2. \n* The CONV2D layer on the shortcut path does not use any non-linear activation function. Its main role is to just apply a (learned) linear function that reduces the dimension of the input, so that the dimensions match up for the later addition step. \n* As for the previous exercise, the additional `initializer` argument is required for grading purposes, and it has been set by default to [glorot_uniform](https://www.tensorflow.org/api_docs/python/tf/keras/initializers/GlorotUniform)\n\nThe details of the convolutional block are as follows. \n\nFirst component of main path:\n- The first CONV2D has $F_1$ filters of shape (1,1) and a stride of (s,s). Its padding is \"valid\". Use 0 as the `glorot_uniform` seed `kernel_initializer = initializer(seed=0)`.\n- The first BatchNorm is normalizing the 'channels' axis.\n- Then apply the ReLU activation function. This has no hyperparameters. \n\nSecond component of main path:\n- The second CONV2D has $F_2$ filters of shape (f,f) and a stride of (1,1). Its padding is \"same\".  Use 0 as the `glorot_uniform` seed `kernel_initializer = initializer(seed=0)`.\n- The second BatchNorm is normalizing the 'channels' axis.\n- Then apply the ReLU activation function. This has no hyperparameters. \n\nThird component of main path:\n- The third CONV2D has $F_3$ filters of shape (1,1) and a stride of (1,1). Its padding is \"valid\".  Use 0 as the `glorot_uniform` seed `kernel_initializer = initializer(seed=0)`.\n- The third BatchNorm is normalizing the 'channels' axis. Note that there is no ReLU activation function in this component. \n\nShortcut path:\n- The CONV2D has $F_3$ filters of shape (1,1) and a stride of (s,s). Its padding is \"valid\".  Use 0 as the `glorot_uniform` seed `kernel_initializer = initializer(seed=0)`.\n- The BatchNorm is normalizing the 'channels' axis. \n\nFinal step: \n- The shortcut and the main path values are added together.\n- Then apply the ReLU activation function. This has no hyperparameters. \n \n<a name='ex-2'></a>    \n### Exercise 2 - convolutional_block\n    \nImplement the convolutional block. The first component of the main path is already implemented; then it's your turn to implement the rest! As before, always use 0 as the seed for the random initialization, to ensure consistency with the grader.\n- [Conv2D](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D)\n- [BatchNormalization](https://www.tensorflow.org/api_docs/python/tf/keras/layers/BatchNormalization) (axis: Integer, the axis that should be normalized (typically the features axis)) `BatchNormalization(axis = 3)(X, training = training)`. If training is set to False, its weights are not updated with the new examples. I.e when the model is used in prediction mode.\n- For the activation, use:  `Activation('relu')(X)`\n- [Add](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Add)\n    \nWe have added the initializer argument to our functions. This parameter receives an initializer function like the ones included in the package [tensorflow.keras.initializers](https://www.tensorflow.org/api_docs/python/tf/keras/initializers) or any other custom initializer. By default it will be set to [glorot_uniform](https://www.tensorflow.org/versions/r2.3/api_docs/python/tf/keras/initializers/GlorotUniform)\n\nRemember that these functions accept a `seed` argument that can be any value you want, but that in this notebook must set to 0 for **grading purposes**.","metadata":{}},{"cell_type":"code","source":"# UNQ_C2\n# GRADED FUNCTION: convolutional_block\n\ndef convolutional_block(X, f, filters, s = 2, training=True, initializer=glorot_uniform):\n    \"\"\"\n    Implementation of the convolutional block as defined in Figure 4\n    \n    Arguments:\n    X -- input tensor of shape (m, n_H_prev, n_W_prev, n_C_prev)\n    f -- integer, specifying the shape of the middle CONV's window for the main path\n    filters -- python list of integers, defining the number of filters in the CONV layers of the main path\n    s -- Integer, specifying the stride to be used\n    training -- True: Behave in training mode\n                False: Behave in inference mode\n    initializer -- to set up the initial weights of a layer. Equals to Glorot uniform initializer, \n                   also called Xavier uniform initializer.\n    \n    Returns:\n    X -- output of the convolutional block, tensor of shape (m, n_H, n_W, n_C)\n    \"\"\"\n    \n    # Retrieve Filters\n    F1, F2, F3 = filters\n    \n    # Save the input value\n    X_shortcut = X\n\n\n    ##### MAIN PATH #####\n    \n    # First component of main path glorot_uniform(seed=0)\n    X = Conv2D(filters = F1, kernel_size = 1, strides = (s, s), padding='valid', kernel_initializer = initializer(seed=0))(X)\n    X = BatchNormalization(axis = 3)(X, training=training)\n    X = Activation('relu')(X)\n\n    ### START CODE HERE\n    \n    ## Second component of main path (≈3 lines)\n    X = Conv2D(filters = F2, kernel_size = f, strides = (1, 1), padding='same', kernel_initializer = initializer(seed=0))(X)\n    X = BatchNormalization(axis = 3)(X, training=training)\n    X = Activation('relu')(X)\n\n    ## Third component of main path (≈2 lines)\n    X = Conv2D(filters = F3, kernel_size = 1, strides = (1, 1), padding='valid', kernel_initializer = initializer(seed=0))(X)\n    X = BatchNormalization(axis = 3)(X, training=training)\n    \n    ##### SHORTCUT PATH ##### (≈2 lines)\n    X_shortcut = Conv2D(filters = F3, kernel_size = 1, strides = (s, s), padding='valid', kernel_initializer = initializer(seed=0))(X_shortcut)\n    X_shortcut = BatchNormalization(axis = 3)(X_shortcut, training=training)\n    \n    ### END CODE HERE\n\n    # Final step: Add shortcut value to main path (Use this order [X, X_shortcut]), and pass it through a RELU activation\n    X = Add()([X, X_shortcut])\n    X = Activation('relu')(X)\n    \n    return X","metadata":{"nbgrader":{"grade":false,"grade_id":"cell-df47af4847e5335f","locked":false,"schema_version":3,"solution":true,"task":false},"execution":{"iopub.status.busy":"2023-05-31T04:00:58.277472Z","iopub.execute_input":"2023-05-31T04:00:58.278585Z","iopub.status.idle":"2023-05-31T04:00:58.291056Z","shell.execute_reply.started":"2023-05-31T04:00:58.278540Z","shell.execute_reply":"2023-05-31T04:00:58.290113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a name='4'></a>  \n## 4 - Building Your First ResNet Model (50 layers)\n\nYou now have the necessary blocks to build a very deep ResNet. The following figure describes in detail the architecture of this neural network. \"ID BLOCK\" in the diagram stands for \"Identity block,\" and \"ID BLOCK x3\" means you should stack 3 identity blocks together.\n\n<img src=\"https://github.com/GAURAV2567/Kaggle/blob/main/images/resnet_kiank.png?raw=true\" style=\"width:850px;height:150px;\">\n<caption><center> <u> <font color='purple'> <b>Figure 5</b> </u><font color='purple'>  : <b>ResNet-50 model</b> </center></caption>\n\nThe details of this ResNet-50 model are:\n- Zero-padding pads the input with a pad of (3,3)\n- Stage 1:\n    - The 2D Convolution has 64 filters of shape (7,7) and uses a stride of (2,2). \n    - BatchNorm is applied to the 'channels' axis of the input.\n    - ReLU activation is applied.\n    - MaxPooling uses a (3,3) window and a (2,2) stride.\n- Stage 2:\n    - The convolutional block uses three sets of filters of size [64,64,256], \"f\" is 3, and \"s\" is 1.\n    - The 2 identity blocks use three sets of filters of size [64,64,256], and \"f\" is 3.\n- Stage 3:\n    - The convolutional block uses three sets of filters of size [128,128,512], \"f\" is 3 and \"s\" is 2.\n    - The 3 identity blocks use three sets of filters of size [128,128,512] and \"f\" is 3.\n- Stage 4:\n    - The convolutional block uses three sets of filters of size [256, 256, 1024], \"f\" is 3 and \"s\" is 2.\n    - The 5 identity blocks use three sets of filters of size [256, 256, 1024] and \"f\" is 3.\n- Stage 5:\n    - The convolutional block uses three sets of filters of size [512, 512, 2048], \"f\" is 3 and \"s\" is 2.\n    - The 2 identity blocks use three sets of filters of size [512, 512, 2048] and \"f\" is 3.\n- The 2D Average Pooling uses a window of shape (2,2).\n- The 'flatten' layer doesn't have any hyperparameters.\n- The Fully Connected (Dense) layer reduces its input to the number of classes using a softmax activation.\n\n    \n<a name='ex-3'></a>      \n### Exercise 3 - ResNet50 \n    \nImplement the ResNet with 50 layers described in the figure above. We have implemented Stages 1 and 2. Please implement the rest. (The syntax for implementing Stages 3-5 should be quite similar to that of Stage 2) Make sure you follow the naming convention in the text above. \n\nYou'll need to use this function: \n- Average pooling [see reference](https://www.tensorflow.org/api_docs/python/tf/keras/layers/AveragePooling2D)\n\nHere are some other functions we used in the code below:\n- Conv2D: [See reference](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Conv2D)\n- BatchNorm: [See reference](https://www.tensorflow.org/api_docs/python/tf/keras/layers/BatchNormalization) (axis: Integer, the axis that should be normalized (typically the features axis))\n- Zero padding: [See reference](https://www.tensorflow.org/api_docs/python/tf/keras/layers/ZeroPadding2D)\n- Max pooling: [See reference](https://www.tensorflow.org/api_docs/python/tf/keras/layers/MaxPool2D)\n- Fully connected layer: [See reference](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Dense)\n- Addition: [See reference](https://www.tensorflow.org/api_docs/python/tf/keras/layers/Add)","metadata":{}},{"cell_type":"code","source":"# UNQ_C3\n# GRADED FUNCTION: ResNet50\n\ndef ResNet50(input_shape = (64, 64, 3), classes = 6):\n    \"\"\"\n    Stage-wise implementation of the architecture of the popular ResNet50:\n    CONV2D -> BATCHNORM -> RELU -> MAXPOOL -> CONVBLOCK -> IDBLOCK*2 -> CONVBLOCK -> IDBLOCK*3\n    -> CONVBLOCK -> IDBLOCK*5 -> CONVBLOCK -> IDBLOCK*2 -> AVGPOOL -> FLATTEN -> DENSE \n\n    Arguments:\n    input_shape -- shape of the images of the dataset\n    classes -- integer, number of classes\n\n    Returns:\n    model -- a Model() instance in Keras\n    \"\"\"\n    \n    # Define the input as a tensor with shape input_shape\n    X_input = Input(input_shape)\n\n    \n    # Zero-Padding\n    X = ZeroPadding2D((3, 3))(X_input)\n    \n    # Stage 1\n    X = Conv2D(64, (7, 7), strides = (2, 2), kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3)(X)\n    X = Activation('relu')(X)\n    X = MaxPooling2D((3, 3), strides=(2, 2))(X)\n\n    # Stage 2\n    X = convolutional_block(X, f = 3, filters = [64, 64, 256], s = 1)\n    X = identity_block(X, 3, [64, 64, 256])\n    X = identity_block(X, 3, [64, 64, 256])\n\n    ### START CODE HERE\n    \n    ## Stage 3 (≈4 lines)\n    X = convolutional_block(X, f = 3, filters = [128, 128, 512], s = 2)\n    X = identity_block(X, 3, [128, 128, 512])\n    X = identity_block(X, 3, [128, 128, 512])\n    X = identity_block(X, 3, [128, 128, 512])\n    \n    ## Stage 4 (≈6 lines)\n    X = convolutional_block(X, f = 3, filters = [256, 256, 1024], s = 2)\n    X = identity_block(X, 3, [256, 256, 1024])\n    X = identity_block(X, 3, [256, 256, 1024])\n    X = identity_block(X, 3, [256, 256, 1024])\n    X = identity_block(X, 3, [256, 256, 1024])\n    X = identity_block(X, 3, [256, 256, 1024])\n\n    ## Stage 5 (≈3 lines)\n    X = convolutional_block(X, f = 3, filters = [512, 512, 2048], s = 2)\n    X = identity_block(X, 3, [512, 512, 2048])\n    X = identity_block(X, 3, [512, 512, 2048])\n\n    ## AVGPOOL (≈1 line). Use \"X = AveragePooling2D(...)(X)\"\n    X = AveragePooling2D((2,2))(X)\n    \n    ### END CODE HERE\n\n    # output layer\n    X = Flatten()(X)\n    X = Dense(classes, activation='softmax', kernel_initializer = glorot_uniform(seed=0))(X)\n    \n    \n    # Create model\n    model = Model(inputs = X_input, outputs = X)\n\n    return model","metadata":{"nbgrader":{"grade":false,"grade_id":"cell-10dc95a4cf6275b9","locked":false,"schema_version":3,"solution":true,"task":false},"execution":{"iopub.status.busy":"2023-05-31T04:00:58.909371Z","iopub.execute_input":"2023-05-31T04:00:58.909740Z","iopub.status.idle":"2023-05-31T04:00:58.925173Z","shell.execute_reply.started":"2023-05-31T04:00:58.909710Z","shell.execute_reply":"2023-05-31T04:00:58.924300Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Run the following code to build the model's graph. If your implementation is incorrect, you'll know it by checking your accuracy when running `model.fit(...)` below.","metadata":{}},{"cell_type":"code","source":"model = ResNet50(input_shape = (64,64, 3), classes = 5)\nprint(model.summary())","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:00.142766Z","iopub.execute_input":"2023-05-31T04:01:00.143131Z","iopub.status.idle":"2023-05-31T04:01:05.745153Z","shell.execute_reply.started":"2023-05-31T04:01:00.143101Z","shell.execute_reply":"2023-05-31T04:01:05.744348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:05.746740Z","iopub.execute_input":"2023-05-31T04:01:05.747386Z","iopub.status.idle":"2023-05-31T04:01:05.797835Z","shell.execute_reply.started":"2023-05-31T04:01:05.747349Z","shell.execute_reply":"2023-05-31T04:01:05.797116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.preprocessing import image_dataset_from_directory\nfrom tensorflow.keras.layers.experimental.preprocessing import RandomFlip, RandomRotation\nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:05.798859Z","iopub.execute_input":"2023-05-31T04:01:05.799219Z","iopub.status.idle":"2023-05-31T04:01:05.805497Z","shell.execute_reply.started":"2023-05-31T04:01:05.799185Z","shell.execute_reply":"2023-05-31T04:01:05.804646Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a name='4.1'></a> \n## Loading the Dataset","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 32\nIMG_SIZE = (64,64)\ndirectory = \"/kaggle/input/plots-train/plots/\"\ntrain_dataset = image_dataset_from_directory(directory,\n                                             shuffle=True,\n                                             batch_size=BATCH_SIZE,\n                                             image_size=IMG_SIZE,\n                                             validation_split=0.2,\n                                             subset='training',\n                                             seed=42)\nvalidation_dataset = image_dataset_from_directory(directory,\n                                             shuffle=True,\n                                             batch_size=BATCH_SIZE,\n                                             image_size=IMG_SIZE,\n                                             validation_split=0.2,\n                                             subset='validation',\n                                             seed=42)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:05.807630Z","iopub.execute_input":"2023-05-31T04:01:05.809433Z","iopub.status.idle":"2023-05-31T04:01:50.008529Z","shell.execute_reply.started":"2023-05-31T04:01:05.809400Z","shell.execute_reply":"2023-05-31T04:01:50.007618Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_names = train_dataset.class_names\n\nplt.figure(figsize=(10, 10))\nfor images, labels in train_dataset.take(1):\n    for i in range(9):\n        ax = plt.subplot(3, 3, i + 1)\n        plt.imshow(images[i].numpy().astype(\"uint8\"))\n        plt.title(class_names[labels[i]])\n        plt.axis(\"off\")","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:50.009965Z","iopub.execute_input":"2023-05-31T04:01:50.010312Z","iopub.status.idle":"2023-05-31T04:01:51.574289Z","shell.execute_reply.started":"2023-05-31T04:01:50.010280Z","shell.execute_reply":"2023-05-31T04:01:51.573317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Skipping Augmentation for now\n###### You can try augmentation techniques to improve accuracy as per the course","metadata":{}},{"cell_type":"code","source":"from sklearn.preprocessing import OneHotEncoder","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:51.576863Z","iopub.execute_input":"2023-05-31T04:01:51.577986Z","iopub.status.idle":"2023-05-31T04:01:51.873266Z","shell.execute_reply.started":"2023-05-31T04:01:51.577954Z","shell.execute_reply":"2023-05-31T04:01:51.872351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Convert labels to one-hot encoded matrices\ndef one_hot_encoding(image, label):\n    label = tf.one_hot(label, depth=5)\n    return image, label","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:51.874804Z","iopub.execute_input":"2023-05-31T04:01:51.875161Z","iopub.status.idle":"2023-05-31T04:01:51.880163Z","shell.execute_reply.started":"2023-05-31T04:01:51.875128Z","shell.execute_reply":"2023-05-31T04:01:51.879058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Normalize image vectors\ndef normalize_images(image_batch, label_batch):\n    return image_batch / 255., label_batch","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:51.881732Z","iopub.execute_input":"2023-05-31T04:01:51.882053Z","iopub.status.idle":"2023-05-31T04:01:51.891422Z","shell.execute_reply.started":"2023-05-31T04:01:51.882023Z","shell.execute_reply":"2023-05-31T04:01:51.890518Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = train_dataset.map(normalize_images)\ntrain_dataset = train_dataset.map(one_hot_encoding)\nvalidation_dataset = validation_dataset.map(normalize_images)\nvalidation_dataset = validation_dataset.map(one_hot_encoding)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:51.892656Z","iopub.execute_input":"2023-05-31T04:01:51.893132Z","iopub.status.idle":"2023-05-31T04:01:51.999131Z","shell.execute_reply.started":"2023-05-31T04:01:51.893101Z","shell.execute_reply":"2023-05-31T04:01:51.997945Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Run the following cell to train your model on 10 epochs with a batch size of 32. On a GPU, it should take less than 2 minutes. ","metadata":{}},{"cell_type":"markdown","source":"## Setting the GPU\n#skip this if you are running locally without GPU","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nprint(\"Num GPUs Available: \", len(tf.config.list_physical_devices('GPU')))","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:52.000546Z","iopub.execute_input":"2023-05-31T04:01:52.000917Z","iopub.status.idle":"2023-05-31T04:01:52.007480Z","shell.execute_reply.started":"2023-05-31T04:01:52.000885Z","shell.execute_reply":"2023-05-31T04:01:52.006347Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nprint(tf.config.list_physical_devices('GPU'))","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:01:52.011028Z","iopub.execute_input":"2023-05-31T04:01:52.011766Z","iopub.status.idle":"2023-05-31T04:01:52.023634Z","shell.execute_reply.started":"2023-05-31T04:01:52.011735Z","shell.execute_reply":"2023-05-31T04:01:52.022231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"strategy = tf.distribute.MirroredStrategy()\nwith strategy.scope():\n    history = model.fit(train_dataset, validation_data=validation_dataset, epochs = 5)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2023-05-31T04:01:52.037738Z","iopub.execute_input":"2023-05-31T04:01:52.038563Z","iopub.status.idle":"2023-05-31T04:14:38.590971Z","shell.execute_reply.started":"2023-05-31T04:01:52.038531Z","shell.execute_reply":"2023-05-31T04:14:38.589927Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"acc = [0.] + history.history['accuracy']\nval_acc = [0.] + history.history['val_accuracy']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nplt.figure(figsize=(8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(acc, label='Training Accuracy')\nplt.plot(val_acc, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.ylabel('Accuracy')\nplt.ylim([min(plt.ylim()),1])\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(2, 1, 2)\nplt.plot(loss, label='Training Loss')\nplt.plot(val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.ylabel('Cross Entropy')\nplt.ylim([0,1.0])\nplt.title('Training and Validation Loss')\nplt.xlabel('epoch')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:24:57.018420Z","iopub.execute_input":"2023-05-31T04:24:57.018812Z","iopub.status.idle":"2023-05-31T04:24:57.539056Z","shell.execute_reply.started":"2023-05-31T04:24:57.018781Z","shell.execute_reply":"2023-05-31T04:24:57.538171Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's see how this model (trained on only two epochs) performs on the test set.","metadata":{}},{"cell_type":"code","source":"preds = model.evaluate(validation_dataset)\nprint (\"Loss = \" + str(preds[0]))\nprint (\"Test Accuracy = \" + str(preds[1]))","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2023-05-31T04:25:06.573539Z","iopub.execute_input":"2023-05-31T04:25:06.573926Z","iopub.status.idle":"2023-05-31T04:25:26.860271Z","shell.execute_reply.started":"2023-05-31T04:25:06.573897Z","shell.execute_reply":"2023-05-31T04:25:26.859374Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a name='5'></a>  \n# 5. Fine-tuning","metadata":{}},{"cell_type":"code","source":"#Lowering Learning rate for better convergence\nbase_learning_rate = 0.001","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:25:26.862297Z","iopub.execute_input":"2023-05-31T04:25:26.863166Z","iopub.status.idle":"2023-05-31T04:25:26.867802Z","shell.execute_reply.started":"2023-05-31T04:25:26.863128Z","shell.execute_reply":"2023-05-31T04:25:26.866781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optimizer = tf.keras.optimizers.Adam(learning_rate=0.1*base_learning_rate)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:25:26.869271Z","iopub.execute_input":"2023-05-31T04:25:26.870231Z","iopub.status.idle":"2023-05-31T04:25:26.882452Z","shell.execute_reply.started":"2023-05-31T04:25:26.870194Z","shell.execute_reply":"2023-05-31T04:25:26.881575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:25:26.885469Z","iopub.execute_input":"2023-05-31T04:25:26.886491Z","iopub.status.idle":"2023-05-31T04:25:26.904867Z","shell.execute_reply.started":"2023-05-31T04:25:26.886457Z","shell.execute_reply":"2023-05-31T04:25:26.903741Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"initial_epochs = 5","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:25:26.908519Z","iopub.execute_input":"2023-05-31T04:25:26.908766Z","iopub.status.idle":"2023-05-31T04:25:26.915036Z","shell.execute_reply.started":"2023-05-31T04:25:26.908743Z","shell.execute_reply":"2023-05-31T04:25:26.913794Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fine_tune_epochs = 5\ntotal_epochs =  initial_epochs + fine_tune_epochs\n\nhistory_fine = model.fit(train_dataset,\n                         epochs=total_epochs,\n                         initial_epoch=history.epoch[-1],\n                         validation_data=validation_dataset)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:25:26.916737Z","iopub.execute_input":"2023-05-31T04:25:26.917126Z","iopub.status.idle":"2023-05-31T04:37:20.563787Z","shell.execute_reply.started":"2023-05-31T04:25:26.917092Z","shell.execute_reply":"2023-05-31T04:37:20.562647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"acc += history_fine.history['accuracy']\nval_acc += history_fine.history['val_accuracy']\n\nloss += history_fine.history['loss']\nval_loss += history_fine.history['val_loss']","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:37:20.565363Z","iopub.execute_input":"2023-05-31T04:37:20.565821Z","iopub.status.idle":"2023-05-31T04:37:20.571505Z","shell.execute_reply.started":"2023-05-31T04:37:20.565787Z","shell.execute_reply":"2023-05-31T04:37:20.570547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(acc, label='Training Accuracy')\nplt.plot(val_acc, label='Validation Accuracy')\nplt.ylim([0, 1])\nplt.plot([initial_epochs-1,initial_epochs-1],\n          plt.ylim(), label='Start Fine Tuning')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(2, 1, 2)\nplt.plot(loss, label='Training Loss')\nplt.plot(val_loss, label='Validation Loss')\nplt.ylim([0, 1.0])\nplt.plot([initial_epochs-1,initial_epochs-1],\n         plt.ylim(), label='Start Fine Tuning')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.xlabel('epoch')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:37:20.572922Z","iopub.execute_input":"2023-05-31T04:37:20.573883Z","iopub.status.idle":"2023-05-31T04:37:21.084020Z","shell.execute_reply.started":"2023-05-31T04:37:20.573850Z","shell.execute_reply":"2023-05-31T04:37:21.083146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Using Learning rate decay\ninitial_learning_rate = optimizer.learning_rate.numpy()\nlr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(\n    initial_learning_rate,\n    decay_steps=5000,\n    decay_rate=0.1,\n    staircase=True)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:37:21.085540Z","iopub.execute_input":"2023-05-31T04:37:21.085925Z","iopub.status.idle":"2023-05-31T04:37:21.092149Z","shell.execute_reply.started":"2023-05-31T04:37:21.085891Z","shell.execute_reply":"2023-05-31T04:37:21.091154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:37:21.096356Z","iopub.execute_input":"2023-05-31T04:37:21.096665Z","iopub.status.idle":"2023-05-31T04:37:21.131129Z","shell.execute_reply.started":"2023-05-31T04:37:21.096639Z","shell.execute_reply":"2023-05-31T04:37:21.130257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer=optimizer, loss='categorical_crossentropy', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:37:21.132307Z","iopub.execute_input":"2023-05-31T04:37:21.132636Z","iopub.status.idle":"2023-05-31T04:37:21.151498Z","shell.execute_reply.started":"2023-05-31T04:37:21.132602Z","shell.execute_reply":"2023-05-31T04:37:21.150497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fine_tune_epochs2 = 5\ntotal_epochs =  initial_epochs + fine_tune_epochs + fine_tune_epochs2\n\nhistory_fine = model.fit(train_dataset,\n                         epochs=total_epochs,\n                         initial_epoch=history_fine.epoch[-1],\n                         validation_data=validation_dataset)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:37:21.152695Z","iopub.execute_input":"2023-05-31T04:37:21.153100Z","iopub.status.idle":"2023-05-31T04:49:09.504939Z","shell.execute_reply.started":"2023-05-31T04:37:21.153057Z","shell.execute_reply":"2023-05-31T04:49:09.503746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"acc += history_fine.history['accuracy']\nval_acc += history_fine.history['val_accuracy']\n\nloss += history_fine.history['loss']\nval_loss += history_fine.history['val_loss']","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:49:09.508406Z","iopub.execute_input":"2023-05-31T04:49:09.508723Z","iopub.status.idle":"2023-05-31T04:49:09.516964Z","shell.execute_reply.started":"2023-05-31T04:49:09.508696Z","shell.execute_reply":"2023-05-31T04:49:09.516032Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(acc, label='Training Accuracy')\nplt.plot(val_acc, label='Validation Accuracy')\nplt.ylim([0, 1])\nplt.plot([initial_epochs-1,initial_epochs-1],\n          plt.ylim(), label='Start Fine Tuning')\nplt.plot([(initial_epochs + fine_tune_epochs)-1,(initial_epochs + fine_tune_epochs)-1],\n         plt.ylim(), label='Start Fine Tuning2')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(2, 1, 2)\nplt.plot(loss, label='Training Loss')\nplt.plot(val_loss, label='Validation Loss')\nplt.ylim([0, 1.0])\nplt.plot([initial_epochs-1,initial_epochs-1],\n         plt.ylim(), label='Start Fine Tuning')\nplt.plot([(initial_epochs + fine_tune_epochs)-1,(initial_epochs + fine_tune_epochs)-1],\n         plt.ylim(), label='Start Fine Tuning2')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.xlabel('epoch')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:51:10.140761Z","iopub.execute_input":"2023-05-31T04:51:10.141118Z","iopub.status.idle":"2023-05-31T04:51:10.695086Z","shell.execute_reply.started":"2023-05-31T04:51:10.141088Z","shell.execute_reply":"2023-05-31T04:51:10.694145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds = model.evaluate(validation_dataset)\nprint (\"Loss = \" + str(preds[0]))\nprint (\"Test Accuracy = \" + str(preds[1]))","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:49:10.041409Z","iopub.execute_input":"2023-05-31T04:49:10.042309Z","iopub.status.idle":"2023-05-31T04:49:30.553559Z","shell.execute_reply.started":"2023-05-31T04:49:10.042274Z","shell.execute_reply":"2023-05-31T04:49:30.552617Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Stopping as no further improvement is identified in Validation set","metadata":{}},{"cell_type":"code","source":"model_path = 'save_model/'\nmodel.save(model_path)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:49:30.556077Z","iopub.execute_input":"2023-05-31T04:49:30.556951Z","iopub.status.idle":"2023-05-31T04:49:59.597789Z","shell.execute_reply.started":"2023-05-31T04:49:30.556913Z","shell.execute_reply":"2023-05-31T04:49:59.596722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"weights_path = 'save_weight/'\nmodel.save_weights(weights_path)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:49:59.603514Z","iopub.execute_input":"2023-05-31T04:49:59.603825Z","iopub.status.idle":"2023-05-31T04:50:00.847850Z","shell.execute_reply.started":"2023-05-31T04:49:59.603799Z","shell.execute_reply":"2023-05-31T04:50:00.846908Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_architecture_path = '/kaggle/working/model_architecture.json'\nmodel_json = model.to_json()\nwith open(model_architecture_path, 'w') as json_file:\n    json_file.write(model_json)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:50:00.849320Z","iopub.execute_input":"2023-05-31T04:50:00.849649Z","iopub.status.idle":"2023-05-31T04:50:00.906160Z","shell.execute_reply.started":"2023-05-31T04:50:00.849613Z","shell.execute_reply":"2023-05-31T04:50:00.905351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_weights_path = '/kaggle/working/model_weights.h5'\nmodel.save_weights(model_weights_path)","metadata":{"execution":{"iopub.status.busy":"2023-05-31T04:50:00.907403Z","iopub.execute_input":"2023-05-31T04:50:00.907919Z","iopub.status.idle":"2023-05-31T04:50:01.299712Z","shell.execute_reply.started":"2023-05-31T04:50:00.907885Z","shell.execute_reply":"2023-05-31T04:50:01.298744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<font color = 'blue'>\n    \n**You can improve more by experimenting with the different Loss funcitons, Optimizers and Hyperparameter tuning**","metadata":{}},{"cell_type":"markdown","source":"**Congratulations** on finishing this assignment! You've now implemented a state-of-the-art image classification system! Woo hoo! \n\nResNet50 is a powerful model for image classification when it's trained for an adequate number of iterations. Hopefully, from this point, you can use what you've learned and apply it to your own classification problem to perform state-of-the-art accuracy.","metadata":{}},{"cell_type":"markdown","source":"<font color = 'blue'>\n\n**What you should remember**:\n\n- Very deep \"plain\" networks don't work in practice because vanishing gradients make them hard to train.  \n- Skip connections help address the Vanishing Gradient problem. They also make it easy for a ResNet block to learn an identity function. \n- There are two main types of blocks: The **identity block** and the **convolutional block**. \n- Very deep Residual Networks are built by stacking these blocks together.","metadata":{}},{"cell_type":"markdown","source":"<a name='6'></a>  \n## 6 - Bibliography\n\nThis notebook presents the ResNet algorithm from He et al. (2015). The implementation here also took significant inspiration and follows the structure given in the GitHub repository of Francois Chollet: \n\n- Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun - [Deep Residual Learning for Image Recognition (2015)](https://arxiv.org/abs/1512.03385)\n- Francois Chollet's GitHub repository: https://github.com/fchollet/deep-learning-models/blob/master/resnet50.py\n","metadata":{}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}