{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":30733,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"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\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","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-06-05T13:16:00.983974Z","iopub.execute_input":"2024-06-05T13:16:00.984936Z","iopub.status.idle":"2024-06-05T13:16:01.351433Z","shell.execute_reply.started":"2024-06-05T13:16:00.984892Z","shell.execute_reply":"2024-06-05T13:16:01.350438Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import keras\nkeras.__version__","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:16:04.175209Z","iopub.execute_input":"2024-06-05T13:16:04.176061Z","iopub.status.idle":"2024-06-05T13:16:07.403235Z","shell.execute_reply.started":"2024-06-05T13:16:04.176027Z","shell.execute_reply":"2024-06-05T13:16:07.402225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.applications import VGG16\n\nconv_base = VGG16(weights='imagenet',\n                  include_top=False,\n                  input_shape=(150, 150, 3))","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:16:26.550636Z","iopub.execute_input":"2024-06-05T13:16:26.551275Z","iopub.status.idle":"2024-06-05T13:16:26.793667Z","shell.execute_reply.started":"2024-06-05T13:16:26.551241Z","shell.execute_reply":"2024-06-05T13:16:26.792662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"conv_base.summary()","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:16:29.265449Z","iopub.execute_input":"2024-06-05T13:16:29.265823Z","iopub.status.idle":"2024-06-05T13:16:29.300292Z","shell.execute_reply.started":"2024-06-05T13:16:29.265794Z","shell.execute_reply":"2024-06-05T13:16:29.299263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras.models import Model\nfrom keras.layers import Dense, GlobalAveragePooling2D,Dropout","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:16:37.024359Z","iopub.execute_input":"2024-06-05T13:16:37.024731Z","iopub.status.idle":"2024-06-05T13:16:37.031324Z","shell.execute_reply.started":"2024-06-05T13:16:37.024701Z","shell.execute_reply":"2024-06-05T13:16:37.030380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"x = conv_base.output\nx = GlobalAveragePooling2D()(x)\n# let's add a fully-connected layer\nx=Dropout(0.25)(x)\nx = Dense(1024, activation='relu')(x)\nx=Dropout(0.25)(x)\n# and a logistic layer -- let's say we have 200 classes\npredictions = Dense(1, activation='sigmoid')(x)\n\n# this is the model we will train\nmodel = Model(inputs=conv_base.input, outputs=predictions)","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:16:58.420577Z","iopub.execute_input":"2024-06-05T13:16:58.421411Z","iopub.status.idle":"2024-06-05T13:16:58.457205Z","shell.execute_reply.started":"2024-06-05T13:16:58.421381Z","shell.execute_reply":"2024-06-05T13:16:58.456514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:17:03.792558Z","iopub.execute_input":"2024-06-05T13:17:03.792900Z","iopub.status.idle":"2024-06-05T13:17:03.831566Z","shell.execute_reply.started":"2024-06-05T13:17:03.792875Z","shell.execute_reply":"2024-06-05T13:17:03.830719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport matplotlib.pyplot as plt\nimport shutil\nfrom sklearn.model_selection import train_test_split","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:17:11.584159Z","iopub.execute_input":"2024-06-05T13:17:11.584521Z","iopub.status.idle":"2024-06-05T13:17:11.931599Z","shell.execute_reply.started":"2024-06-05T13:17:11.584492Z","shell.execute_reply":"2024-06-05T13:17:11.930805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import zipfile\nimport os\n\n# Define paths to the zip files\ntrain_zip_path = '/kaggle/input/dogs-vs-cats/train.zip'\ntest_zip_path = '/kaggle/input/dogs-vs-cats/test1.zip'\n\n# Define directories to extract the data\ntrain_extract_dir = '/kaggle/working/train'\ntest_extract_dir = '/kaggle/working/test'\n\n# Create directories if they don't exist\nos.makedirs(train_extract_dir, exist_ok=True)\nos.makedirs(test_extract_dir, exist_ok=True)\n\n# Unzip train data\nwith zipfile.ZipFile(train_zip_path, 'r') as zip_ref:\n    zip_ref.extractall(train_extract_dir)\n\n# Unzip test data\nwith zipfile.ZipFile(test_zip_path, 'r') as zip_ref:\n    zip_ref.extractall(test_extract_dir)\n\n# List extracted files\nprint(\"Train data extracted to:\", os.listdir(train_extract_dir))\nprint(\"Test data extracted to:\", os.listdir(test_extract_dir))","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:17:35.592321Z","iopub.execute_input":"2024-06-05T13:17:35.592708Z","iopub.status.idle":"2024-06-05T13:17:46.354221Z","shell.execute_reply.started":"2024-06-05T13:17:35.592679Z","shell.execute_reply":"2024-06-05T13:17:46.353083Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport numpy as np\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nbase_dir = base_dir = '/kaggle/working/cats_and_dogs_small'\n\ntrain_dir = os.path.join(base_dir, 'train')\nvalidation_dir = os.path.join(base_dir, 'validation')\ntest_dir = os.path.join(base_dir, 'validation')\n\ndatagen = ImageDataGenerator(rescale=1./255)\nbatch_size = 20\n\ndef extract_features(directory, sample_count):\n    features = np.zeros(shape=(sample_count, 4, 4, 512))\n    labels = np.zeros(shape=(sample_count))\n    generator = datagen.flow_from_directory(\n        directory,\n        target_size=(150, 150),\n        batch_size=batch_size,\n        class_mode='binary')\n    i = 0\n    for inputs_batch, labels_batch in generator:\n        features_batch = conv_base.predict(inputs_batch)\n        features[i * batch_size : (i + 1) * batch_size] = features_batch\n        labels[i * batch_size : (i + 1) * batch_size] = labels_batch\n        i += 1\n        if i * batch_size >= sample_count:\n            # Note that since generators yield data indefinitely in a loop,\n            # we must `break` after every image has been seen once.\n            break\n    return features, labels\n\ntrain_features, train_labels = extract_features(train_dir, 2000)\nvalidation_features, validation_labels = extract_features(validation_dir, 1000)\ntest_features, test_labels = extract_features(test_dir, 1000)","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:18:16.941686Z","iopub.execute_input":"2024-06-05T13:18:16.942097Z","iopub.status.idle":"2024-06-05T13:18:56.432791Z","shell.execute_reply.started":"2024-06-05T13:18:16.942065Z","shell.execute_reply":"2024-06-05T13:18:56.431827Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ls /kaggle/working/cats_and_dogs_small","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:20:01.564208Z","iopub.execute_input":"2024-06-05T13:20:01.564623Z","iopub.status.idle":"2024-06-05T13:20:02.551058Z","shell.execute_reply.started":"2024-06-05T13:20:01.564591Z","shell.execute_reply":"2024-06-05T13:20:02.549817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\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","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:20:49.864780Z","iopub.execute_input":"2024-06-05T13:20:49.865248Z","iopub.status.idle":"2024-06-05T13:20:49.871367Z","shell.execute_reply.started":"2024-06-05T13:20:49.865195Z","shell.execute_reply":"2024-06-05T13:20:49.870476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_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\n# Note that the validation data should not be augmented!\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\ntrain_generator = train_datagen.flow_from_directory(\n        # This is the target directory\n        train_dir,\n        # All images will be resized to 150x150\n        target_size=(150, 150),\n        batch_size=20,\n        # Since we use binary_crossentropy loss, we need binary labels\n        class_mode='binary')\n\nvalidation_generator = test_datagen.flow_from_directory(\n        validation_dir,\n        target_size=(150, 150),\n        batch_size=20,\n        class_mode='binary')\n","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:20:52.936046Z","iopub.execute_input":"2024-06-05T13:20:52.936871Z","iopub.status.idle":"2024-06-05T13:20:53.590063Z","shell.execute_reply.started":"2024-06-05T13:20:52.936840Z","shell.execute_reply":"2024-06-05T13:20:53.589138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from keras import optimizers\nmodel.compile(loss='binary_crossentropy',\n              optimizer=tf.keras.optimizers.RMSprop(learning_rate=2e-5),\n              metrics=['acc'])","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:21:08.422614Z","iopub.execute_input":"2024-06-05T13:21:08.422951Z","iopub.status.idle":"2024-06-05T13:21:08.440040Z","shell.execute_reply.started":"2024-06-05T13:21:08.422925Z","shell.execute_reply":"2024-06-05T13:21:08.438979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n    train_generator,\n    steps_per_epoch=100,\n    epochs=30,\n    validation_data=validation_generator,\n    validation_steps=30\n)","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:33:31.786774Z","iopub.execute_input":"2024-06-05T13:33:31.787173Z","iopub.status.idle":"2024-06-05T13:41:50.855667Z","shell.execute_reply.started":"2024-06-05T13:33:31.787138Z","shell.execute_reply":"2024-06-05T13:41:50.854687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's plot our results again:","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\nimport os\nimport tensorflow as tf","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:42:34.002814Z","iopub.execute_input":"2024-06-05T13:42:34.003233Z","iopub.status.idle":"2024-06-05T13:42:34.008089Z","shell.execute_reply.started":"2024-06-05T13:42:34.003201Z","shell.execute_reply":"2024-06-05T13:42:34.007051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(len(acc))\n\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'b', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'b', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:43:54.864638Z","iopub.execute_input":"2024-06-05T13:43:54.865020Z","iopub.status.idle":"2024-06-05T13:43:55.438449Z","shell.execute_reply.started":"2024-06-05T13:43:54.864974Z","shell.execute_reply":"2024-06-05T13:43:55.437544Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Fine-tuning\n","metadata":{}},{"cell_type":"code","source":"conv_base.summary()","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:45:03.428188Z","iopub.execute_input":"2024-06-05T13:45:03.428980Z","iopub.status.idle":"2024-06-05T13:45:03.462749Z","shell.execute_reply.started":"2024-06-05T13:45:03.428947Z","shell.execute_reply":"2024-06-05T13:45:03.461787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"conv_base.trainable = True\n\nset_trainable = False\nfor layer in conv_base.layers:\n    if layer.name == 'block5_conv1':\n        set_trainable = True\n    if set_trainable:\n        layer.trainable = True\n    else:\n        layer.trainable = False","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:45:27.289423Z","iopub.execute_input":"2024-06-05T13:45:27.289795Z","iopub.status.idle":"2024-06-05T13:45:27.295886Z","shell.execute_reply.started":"2024-06-05T13:45:27.289766Z","shell.execute_reply":"2024-06-05T13:45:27.294857Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss='binary_crossentropy',\n              optimizer=tf.keras.optimizers.RMSprop(learning_rate=2e-5),\n              metrics=['acc'])","metadata":{"execution":{"iopub.status.busy":"2024-06-05T13:47:07.372843Z","iopub.execute_input":"2024-06-05T13:47:07.373749Z","iopub.status.idle":"2024-06-05T13:47:07.383372Z","shell.execute_reply.started":"2024-06-05T13:47:07.373715Z","shell.execute_reply":"2024-06-05T13:47:07.382491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n      train_generator,\n      steps_per_epoch=100,\n      epochs=100,\n      validation_data=validation_generator,\n      validation_steps=30)","metadata":{"execution":{"iopub.status.busy":"2024-06-05T14:14:12.642037Z","iopub.execute_input":"2024-06-05T14:14:12.642806Z","iopub.status.idle":"2024-06-05T14:37:01.919544Z","shell.execute_reply.started":"2024-06-05T14:14:12.642770Z","shell.execute_reply":"2024-06-05T14:37:01.918725Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's plot our results using the same plotting code as before:","metadata":{}},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(len(acc))\n\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'b', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'b', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-05T14:37:39.655383Z","iopub.execute_input":"2024-06-05T14:37:39.656242Z","iopub.status.idle":"2024-06-05T14:37:40.086947Z","shell.execute_reply.started":"2024-06-05T14:37:39.656205Z","shell.execute_reply":"2024-06-05T14:37:40.085973Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"These curves look very noisy. To make them more readable, we can smooth them by replacing every loss and accuracy with exponential moving averages of these quantities. Here's a trivial utility function to do this:","metadata":{}},{"cell_type":"code","source":"def smooth_curve(points, factor=0.8):\n  smoothed_points = []\n  for point in points:\n    if smoothed_points:\n      previous = smoothed_points[-1]\n      smoothed_points.append(previous * factor + point * (1 - factor))\n    else:\n      smoothed_points.append(point)\n  return smoothed_points\n\nplt.plot(epochs,\n         smooth_curve(acc), 'bo', label='Smoothed training acc')\nplt.plot(epochs,\n         smooth_curve(val_acc), 'b', label='Smoothed validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(epochs,\n         smooth_curve(loss), 'bo', label='Smoothed training loss')\nplt.plot(epochs,\n         smooth_curve(val_loss), 'b', label='Smoothed validation loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-06-05T14:38:17.320517Z","iopub.execute_input":"2024-06-05T14:38:17.320904Z","iopub.status.idle":"2024-06-05T14:38:17.889659Z","shell.execute_reply.started":"2024-06-05T14:38:17.320873Z","shell.execute_reply":"2024-06-05T14:38:17.888706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can now finally evaluate this model on the test data:","metadata":{}},{"cell_type":"code","source":"test_generator = test_datagen.flow_from_directory(\n        test_dir,\n        target_size=(150, 150),\n        batch_size=20,\n        class_mode='binary')\n\ntest_loss, test_acc = model.evaluate(test_generator, steps=50)\nprint('test acc:', test_acc)","metadata":{"execution":{"iopub.status.busy":"2024-06-05T14:40:01.911113Z","iopub.execute_input":"2024-06-05T14:40:01.911477Z","iopub.status.idle":"2024-06-05T14:40:05.090273Z","shell.execute_reply.started":"2024-06-05T14:40:01.911450Z","shell.execute_reply":"2024-06-05T14:40:05.089296Z"},"trusted":true},"execution_count":null,"outputs":[]}]}