{"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":"# Week 1: Using CNN's with the Cats vs Dogs Dataset\n\nWelcome to the 1st assignment of the course! This week, you will be using the famous `Cats vs Dogs` dataset to train a model that can classify images of dogs from images of cats. For this, you will create your own Convolutional Neural Network in Tensorflow and leverage Keras' image preprocessing utilities.\n\nYou will also create some helper functions to move the images around the filesystem so if you are not familiar with the `os` module be sure to take a look a the [docs](https://docs.python.org/3/library/os.html).\n\nLet's get started!","metadata":{"id":"fc59dbb8"}},{"cell_type":"markdown","source":"_**NOTE:** To prevent errors from the autograder, pleave avoid editing or deleting non-graded cells in this notebook . Please only put your solutions in between the `### START CODE HERE` and `### END CODE HERE` code comments, and refrain from adding any new cells._","metadata":{"id":"84dcabb6"}},{"cell_type":"code","source":"# grader-required-cell\n\nimport os\nimport zipfile\nimport random\nimport shutil\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom shutil import copyfile\nimport matplotlib.pyplot as plt","metadata":{"id":"b0179aa5","tags":["graded"],"execution":{"iopub.status.busy":"2023-07-19T19:17:32.985946Z","iopub.execute_input":"2023-07-19T19:17:32.986282Z","iopub.status.idle":"2023-07-19T19:17:42.704960Z","shell.execute_reply.started":"2023-07-19T19:17:32.986254Z","shell.execute_reply":"2023-07-19T19:17:42.704194Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Download the dataset from its original source by running the cell below.\n\nNote that the `zip` file that contains the images is unzipped under the `/tmp` directory.","metadata":{"id":"ffcd9e7e"}},{"cell_type":"code","source":"# If the URL doesn't work, visit https://www.microsoft.com/en-us/download/confirmation.aspx?id=54765\n# And right click on the 'Download Manually' link to get a new URL to the dataset\n\n# Note: This is a very large dataset and will take some time to download\n\n!wget --no-check-certificate \\\n    \"https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_5340.zip\" \\\n    -O \"/tmp/cats-and-dogs.zip\"\n\nlocal_zip = '/tmp/cats-and-dogs.zip'\nzip_ref   = zipfile.ZipFile(local_zip, 'r')\nzip_ref.extractall('/tmp')\nzip_ref.close()","metadata":{"id":"c881d8ff","lines_to_next_cell":2,"tags":[],"outputId":"fcef0718-bf8a-4c01-f376-3c569bbba523","execution":{"iopub.status.busy":"2023-07-19T19:17:42.706270Z","iopub.execute_input":"2023-07-19T19:17:42.707691Z","iopub.status.idle":"2023-07-19T19:17:55.082844Z","shell.execute_reply.started":"2023-07-19T19:17:42.707634Z","shell.execute_reply":"2023-07-19T19:17:55.081676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now the images are stored within the `/tmp/PetImages` directory. There is a subdirectory for each class, so one for dogs and one for cats.","metadata":{"id":"e3094745"}},{"cell_type":"code","source":"# grader-required-cell\n\nsource_path = '/tmp/PetImages'\n\nsource_path_dogs = os.path.join(source_path, 'Dog')\nsource_path_cats = os.path.join(source_path, 'Cat')\n\n# Deletes all non-image files (there are two .db files bundled into the dataset)\n!find /tmp/PetImages/ -type f ! -name \"*.jpg\" -exec rm {} +\n\n# os.listdir returns a list containing all files under the given path\nprint(f\"There are {len(os.listdir(source_path_dogs))} images of dogs.\")\nprint(f\"There are {len(os.listdir(source_path_cats))} images of cats.\")","metadata":{"id":"bc3a9fa5","tags":["graded"],"outputId":"f40d2d50-c4c6-40c9-b4e7-7d299c57f3b0","execution":{"iopub.status.busy":"2023-07-19T19:17:55.084810Z","iopub.execute_input":"2023-07-19T19:17:55.085679Z","iopub.status.idle":"2023-07-19T19:17:55.444540Z","shell.execute_reply.started":"2023-07-19T19:17:55.085629Z","shell.execute_reply":"2023-07-19T19:17:55.443190Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Expected Output:**\n\n```\nThere are 12500 images of dogs.\nThere are 12500 images of cats.\n```","metadata":{"id":"f98b9905"}},{"cell_type":"markdown","source":"You will need a directory for cats-v-dogs, and subdirectories for training\nand validation. These in turn will need subdirectories for 'cats' and 'dogs'. To accomplish this, complete the `create_train_val_dirs` below:","metadata":{"id":"7e7e2d79"}},{"cell_type":"code","source":"# grader-required-cell\n\n# Define root directory\nroot_dir = '/tmp/cats-v-dogs'\n\n# Empty directory to prevent FileExistsError is the function is run several times\nif os.path.exists(root_dir):\n  shutil.rmtree(root_dir)\n\n# GRADED FUNCTION: create_train_val_dirs\ndef create_train_val_dirs(root_path):\n  \"\"\"\n  Creates directories for the train and test sets\n\n  Args:\n    root_path (string) - the base directory path to create subdirectories from\n\n  Returns:\n    None\n  \"\"\"\n  ### START CODE HERE\n\n  # HINT:\n  # Use os.makedirs to create your directories with intermediate subdirectories\n  # Don't hardcode the paths. Use os.path.join to append the new directories to the root_path parameter\n\n  train_dir = os.path.join(root_path, 'training')\n  val_dir = os.path.join(root_path, 'validation')\n  cat_train_dir = os.path.join(train_dir, 'cats')\n  dog_train_dir = os.path.join(train_dir, 'dogs')\n\n  cat_val_dir = os.path.join(val_dir, 'cats')\n  dog_val_dir = os.path.join(val_dir, 'dogs')\n\n  os.makedirs(train_dir, exist_ok=True)\n  os.makedirs(val_dir, exist_ok=True)\n  os.makedirs(dog_train_dir)\n  os.makedirs(cat_train_dir)\n  os.makedirs(cat_val_dir)\n  os.makedirs(dog_val_dir)\n\n  ### END CODE HERE\n\n\ntry:\n  create_train_val_dirs(root_path=root_dir)\nexcept FileExistsError:\n  print(\"You should not be seeing this since the upper directory is removed beforehand\")","metadata":{"cellView":"code","id":"52ef5808","tags":["graded"],"execution":{"iopub.status.busy":"2023-07-19T19:17:55.447624Z","iopub.execute_input":"2023-07-19T19:17:55.448579Z","iopub.status.idle":"2023-07-19T19:17:55.820423Z","shell.execute_reply.started":"2023-07-19T19:17:55.448540Z","shell.execute_reply":"2023-07-19T19:17:55.819228Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# grader-required-cell\n\n# Test your create_train_val_dirs function\n\nfor rootdir, dirs, files in os.walk(root_dir):\n    for subdir in dirs:\n        print(os.path.join(rootdir, subdir))","metadata":{"id":"5c43b630","tags":["graded"],"outputId":"c0f9eefa-d79c-4e96-8aa9-864077064428","execution":{"iopub.status.busy":"2023-07-19T19:17:55.821897Z","iopub.execute_input":"2023-07-19T19:17:55.822481Z","iopub.status.idle":"2023-07-19T19:17:55.848067Z","shell.execute_reply.started":"2023-07-19T19:17:55.822452Z","shell.execute_reply":"2023-07-19T19:17:55.846781Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"CNN**Expected Output (directory order might vary):**\n\n``` txt\n/tmp/cats-v-dogs/training\n/tmp/cats-v-dogs/validation\n/tmp/cats-v-dogs/training/cats\n/tmp/cats-v-dogs/training/dogs\n/tmp/cats-v-dogs/validation/cats\n/tmp/cats-v-dogs/validation/dogs\n\n```","metadata":{"id":"e2009a58"}},{"cell_type":"markdown","source":"Code the `split_data` function which takes in the following arguments:\n- SOURCE_DIR: directory containing the files\n\n- TRAINING_DIR: directory that a portion of the files will be copied to (will be used for training)\n- VALIDATION_DIR: directory that a portion of the files will be copied to (will be used for validation)\n- SPLIT_SIZE: determines the portion of images used for training.\n\nThe files should be randomized, so that the training set is a random sample of the files, and the validation set is made up of the remaining files.\n\nFor example, if `SOURCE_DIR` is `PetImages/Cat`, and `SPLIT_SIZE` is .9 then 90% of the images in `PetImages/Cat` will be copied to the `TRAINING_DIR` directory\nand 10% of the images will be copied to the `VALIDATION_DIR` directory.\n\nAll images should be checked before the copy, so if they have a zero file length, they will be omitted from the copying process. If this is the case then your function should print out a message such as `\"filename is zero length, so ignoring.\"`. **You should perform this check before the split so that only non-zero images are considered when doing the actual split.**\n\n\nHints:\n\n- `os.listdir(DIRECTORY)` returns a list with the contents of that directory.\n\n- `os.path.getsize(PATH)` returns the size of the file\n\n- `copyfile(source, destination)` copies a file from source to destination\n\n- `random.sample(list, len(list))` shuffles a list","metadata":{"id":"3f296af6"}},{"cell_type":"code","source":"# grader-required-cell\n\n# GRADED FUNCTION: split_data\ndef split_data(SOURCE_DIR, TRAINING_DIR, VALIDATION_DIR, SPLIT_SIZE):\n  \"\"\"\n  Splits the data into train and test sets\n\n  Args:\n    SOURCE_DIR (string): directory path containing the images\n    TRAINING_DIR (string): directory path to be used for training\n    VALIDATION_DIR (string): directory path to be used for validation\n    SPLIT_SIZE (float): proportion of the dataset to be used for training\n\n  Returns:\n    None\n  \"\"\"\n  images = os.listdir(SOURCE_DIR)\n  images = [i for i in images if os.path.isfile(os.path.join(SOURCE_DIR, i)) and os.path.getsize(os.path.join(SOURCE_DIR, i)) > 0]\n  random.sample(images, len(images))\n  sample_size = int(len(images) * SPLIT_SIZE) # pick = 90 / 100 * total\n  train_imgs = images[:sample_size]\n  val_imgs = images[sample_size:]\n  for i in train_imgs:\n    copyfile(os.path.join(SOURCE_DIR, i), os.path.join(TRAINING_DIR, i))\n  for i in val_imgs:\n    copyfile(os.path.join(SOURCE_DIR, i), os.path.join(VALIDATION_DIR, i))\n\n\n","metadata":{"cellView":"code","id":"51d821b1","tags":["graded"],"execution":{"iopub.status.busy":"2023-07-19T19:17:55.849792Z","iopub.execute_input":"2023-07-19T19:17:55.850411Z","iopub.status.idle":"2023-07-19T19:17:55.870222Z","shell.execute_reply.started":"2023-07-19T19:17:55.850380Z","shell.execute_reply":"2023-07-19T19:17:55.869011Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.listdir('/tmp/PetImages/Cat')[:5]","metadata":{"id":"Q8wyyFcecwHn","outputId":"ad8791e6-e306-4fdc-d895-33bf4a18418d","execution":{"iopub.status.busy":"2023-07-19T19:17:55.871710Z","iopub.execute_input":"2023-07-19T19:17:55.872159Z","iopub.status.idle":"2023-07-19T19:17:55.900255Z","shell.execute_reply.started":"2023-07-19T19:17:55.872124Z","shell.execute_reply":"2023-07-19T19:17:55.898957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# grader-required-cell\n\n# Test your split_data function\n\n# Define paths\nCAT_SOURCE_DIR = \"/tmp/PetImages/Cat/\"\nDOG_SOURCE_DIR = \"/tmp/PetImages/Dog/\"\n\nTRAINING_DIR = \"/tmp/cats-v-dogs/training/\"\nVALIDATION_DIR = \"/tmp/cats-v-dogs/validation/\"\n\nTRAINING_CATS_DIR = os.path.join(TRAINING_DIR, \"cats/\")\nVALIDATION_CATS_DIR = os.path.join(VALIDATION_DIR, \"cats/\")\n\nTRAINING_DOGS_DIR = os.path.join(TRAINING_DIR, \"dogs/\")\nVALIDATION_DOGS_DIR = os.path.join(VALIDATION_DIR, \"dogs/\")\n\n# Empty directories in case you run this cell multiple times\nif len(os.listdir(TRAINING_CATS_DIR)) > 0:\n  for file in os.scandir(TRAINING_CATS_DIR):\n    os.remove(file.path)\nif len(os.listdir(TRAINING_DOGS_DIR)) > 0:\n  for file in os.scandir(TRAINING_DOGS_DIR):\n    os.remove(file.path)\nif len(os.listdir(VALIDATION_CATS_DIR)) > 0:\n  for file in os.scandir(VALIDATION_CATS_DIR):\n    os.remove(file.path)\nif len(os.listdir(VALIDATION_DOGS_DIR)) > 0:\n  for file in os.scandir(VALIDATION_DOGS_DIR):\n    os.remove(file.path)\n\n# Define proportion of images used for training\nsplit_size = .9\n\n# Run the function\n# NOTE: Messages about zero length images should be printed out\nsplit_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, VALIDATION_CATS_DIR, split_size)\nsplit_data(DOG_SOURCE_DIR, TRAINING_DOGS_DIR, VALIDATION_DOGS_DIR, split_size)\n\n# Check that the number of images matches the expected output\n\n# Your function should perform copies rather than moving images so original directories should contain unchanged images\nprint(f\"\\n\\nOriginal cat's directory has {len(os.listdir(CAT_SOURCE_DIR))} images\")\nprint(f\"Original dog's directory has {len(os.listdir(DOG_SOURCE_DIR))} images\\n\")\n\n# Training and validation splits\nprint(f\"There are {len(os.listdir(TRAINING_CATS_DIR))} images of cats for training\")\nprint(f\"There are {len(os.listdir(TRAINING_DOGS_DIR))} images of dogs for training\")\nprint(f\"There are {len(os.listdir(VALIDATION_CATS_DIR))} images of cats for validation\")\nprint(f\"There are {len(os.listdir(VALIDATION_DOGS_DIR))} images of dogs for validation\")","metadata":{"id":"e5a316b6","tags":["graded"],"outputId":"795f92a3-d35f-4138-fb82-e4b459ebb740","execution":{"iopub.status.busy":"2023-07-19T19:17:55.901493Z","iopub.execute_input":"2023-07-19T19:17:55.902652Z","iopub.status.idle":"2023-07-19T19:17:59.111812Z","shell.execute_reply.started":"2023-07-19T19:17:55.902612Z","shell.execute_reply":"2023-07-19T19:17:59.110934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Expected Output:**\n\n```\n666.jpg is zero length, so ignoring.\n11702.jpg is zero length, so ignoring.\n\n\nOriginal cat's directory has 12500 images\nOriginal dog's directory has 12500 images\n\nThere are 11249 images of cats for training\nThere are 11249 images of dogs for training\nThere are 1250 images of cats for validation\nThere are 1250 images of dogs for validation\n```","metadata":{"id":"866801c2"}},{"cell_type":"markdown","source":"Now that you have successfully organized the data in a way that can be easily fed to Keras' `ImageDataGenerator`, it is time for you to code the generators that will yield batches of images, both for training and validation. For this, complete the `train_val_generators` function below.\n\nSomething important to note is that the images in this dataset come in a variety of resolutions. Luckily, the `flow_from_directory` method allows you to standarize this by defining a tuple called `target_size` that will be used to convert each image to this target resolution. **For this exercise, use a `target_size` of (150, 150)**.\n\n**Hint:**\n\nDon't use data augmentation by setting extra parameters when you instantiate the `ImageDataGenerator` class. This will make the training of your model to take longer to reach the necessary accuracy threshold to pass this assignment and this topic will be covered in the next week.","metadata":{"id":"0848b4d7"}},{"cell_type":"code","source":"# grader-required-cell\n\n# GRADED FUNCTION: train_val_generators\ndef train_val_generators(TRAINING_DIR, VALIDATION_DIR):\n  \"\"\"\n  Creates the training and validation data generators\n\n  Args:\n    TRAINING_DIR (string): directory path containing the training images\n    VALIDATION_DIR (string): directory path containing the testing/validation images\n\n  Returns:\n    train_generator, validation_generator - tuple containing the generators\n  \"\"\"\n  ### START CODE HERE\n\n  # Instantiate the ImageDataGenerator class (don't forget to set the rescale argument)\n  train_datagen = ImageDataGenerator(rescale=(1/255))\n\n  # Pass in the appropriate arguments to the flow_from_directory method\n  train_generator = train_datagen.flow_from_directory(directory=TRAINING_DIR,\n                                                      batch_size=20,\n                                                      class_mode='binary',\n                                                      target_size=(150, 150))\n\n  # Instantiate the ImageDataGenerator class (don't forget to set the rescale argument)\n  validation_datagen = ImageDataGenerator(rescale=(1/255))\n\n  # Pass in the appropriate arguments to the flow_from_directory method\n  validation_generator = validation_datagen.flow_from_directory(directory=VALIDATION_DIR,\n                                                                batch_size=20,\n                                                                class_mode='binary',\n                                                                target_size=(150, 150))\n  ### END CODE HERE\n  return train_generator, validation_generator","metadata":{"cellView":"code","id":"072bb609","tags":["graded"],"execution":{"iopub.status.busy":"2023-07-19T19:17:59.112942Z","iopub.execute_input":"2023-07-19T19:17:59.113202Z","iopub.status.idle":"2023-07-19T19:17:59.119828Z","shell.execute_reply.started":"2023-07-19T19:17:59.113179Z","shell.execute_reply":"2023-07-19T19:17:59.118824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# grader-required-cell\n\n# Test your generators\ntrain_generator, validation_generator = train_val_generators(TRAINING_DIR, VALIDATION_DIR)","metadata":{"id":"642806f1","tags":["graded"],"outputId":"a505446d-b5e0-4a37-db85-2ba6b2fab374","execution":{"iopub.status.busy":"2023-07-19T19:17:59.122906Z","iopub.execute_input":"2023-07-19T19:17:59.123194Z","iopub.status.idle":"2023-07-19T19:17:59.992558Z","shell.execute_reply.started":"2023-07-19T19:17:59.123169Z","shell.execute_reply":"2023-07-19T19:17:59.991588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Expected Output:**\n\n```\nFound 22498 images belonging to 2 classes.\nFound 2500 images belonging to 2 classes.\n```\n","metadata":{"id":"734f5056"}},{"cell_type":"markdown","source":"One last step before training is to define the architecture of the model that will be trained.\n\nComplete the `create_model` function below which should return a Keras' `Sequential` model.\n\nAside from defining the architecture of the model, you should also compile it so make sure to use a `loss` function that is compatible with the `class_mode` you defined in the previous exercise, which should also be compatible with the output of your network. You can tell if they aren't compatible if you get an error during training.\n\n**Note that you should use at least 3 convolution layers to achieve the desired performance.**","metadata":{"id":"89098bc7"}},{"cell_type":"code","source":"# grader-required-cell\n\n# GRADED FUNCTION: create_model\ndef create_model():\n  # DEFINE A KERAS MODEL TO CLASSIFY CATS V DOGS\n  # USE AT LEAST 3 CONVOLUTION LAYERS\n\n  ### START CODE HERE\n\n  model = tf.keras.models.Sequential([\n      tf.keras.layers.Conv2D(filters=32, kernel_size=(3,3), activation='relu', input_shape=(150, 150, 3)),\n      tf.keras.layers.MaxPool2D(pool_size=(2,2)),\n      tf.keras.layers.Conv2D(filters=16, kernel_size=(3,3), activation='relu'),\n      tf.keras.layers.MaxPool2D(pool_size=(2,2)),\n      tf.keras.layers.Conv2D(filters=16, kernel_size=(3,3), activation='relu'),\n      tf.keras.layers.MaxPool2D(pool_size=(2,2)),\n      tf.keras.layers.Flatten(),\n      tf.keras.layers.Dense(units=256, activation='relu'),\n      tf.keras.layers.Dense(units=1, activation='sigmoid')\n  ])\n\n\n  model.compile(optimizer='rmsprop',\n                loss='binary_crossentropy',\n                metrics=['accuracy'])\n\n  ### END CODE HERE\n\n  return model","metadata":{"cellView":"code","id":"6f375c5d","lines_to_next_cell":2,"tags":["graded"],"execution":{"iopub.status.busy":"2023-07-19T19:17:59.993432Z","iopub.execute_input":"2023-07-19T19:17:59.993673Z","iopub.status.idle":"2023-07-19T19:18:00.001190Z","shell.execute_reply.started":"2023-07-19T19:17:59.993652Z","shell.execute_reply":"2023-07-19T19:17:59.999932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now it is time to train your model!\n\n**Note:** You can ignore the `UserWarning: Possibly corrupt EXIF data.` warnings.","metadata":{"id":"991de70d"}},{"cell_type":"code","source":"# Get the untrained model\nmodel = create_model()\n\n# Train the model\n# Note that this may take some time.\nhistory = model.fit(train_generator,\n                    epochs=15,\n                    verbose=1,\n                    validation_data=validation_generator)","metadata":{"id":"fedfe6d0","tags":[],"outputId":"b345bdf9-de43-4990-bc0a-c50097f1f987","execution":{"iopub.status.busy":"2023-07-19T19:18:00.002790Z","iopub.execute_input":"2023-07-19T19:18:00.003266Z","iopub.status.idle":"2023-07-19T20:20:45.725471Z","shell.execute_reply.started":"2023-07-19T19:18:00.003235Z","shell.execute_reply":"2023-07-19T20:20:45.724215Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Once training has finished, you can run the following cell to check the training and validation accuracy achieved at the end of each epoch.\n\n**To pass this assignment, your model should achieve a training accuracy of at least 95% and a validation accuracy of at least 80%**. If your model didn't achieve these thresholds, try training again with a different model architecture and remember to use at least 3 convolutional layers.","metadata":{"id":"9a08d2ee"}},{"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, 'r', \"Training Accuracy\")\nplt.plot(epochs, val_acc, 'b', \"Validation Accuracy\")\nplt.title('Training and validation accuracy')\nplt.show()\nprint(\"\")\n\n#------------------------------------------------\n# Plot training and validation loss per epoch\n#------------------------------------------------\nplt.plot(epochs, loss, 'r', \"Training Loss\")\nplt.plot(epochs, val_loss, 'b', \"Validation Loss\")\nplt.show()","metadata":{"id":"70658d4d","tags":[],"outputId":"afb9be03-2d47-4e7d-9975-11b4bcbd015c","execution":{"iopub.status.busy":"2023-07-19T20:20:45.727672Z","iopub.execute_input":"2023-07-19T20:20:45.728314Z","iopub.status.idle":"2023-07-19T20:20:46.045646Z","shell.execute_reply.started":"2023-07-19T20:20:45.728287Z","shell.execute_reply":"2023-07-19T20:20:46.044859Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"You will probably encounter that the model is overfitting, which means that it is doing a great job at classifying the images in the training set but struggles with new data. This is perfectly fine and you will learn how to mitigate this issue in the upcoming week.\n\nBefore downloading this notebook and closing the assignment, be sure to also download the `history.pkl` file which contains the information of the training history of your model. You can download this file by running the cell below:","metadata":{"id":"de6fc5c1"}}]}