{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Aleksandra Jonas, Aleksandra Gronowska, Iwona Christop\n", "# Zadanie 9-10 - VGG16 + ResNet on train_test_sw " ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Przygotowanie danych" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "from IPython.display import Image, display" ] }, { "cell_type": "code", "execution_count": 16, "id": "2fe63b50", "metadata": {}, "outputs": [], "source": [ "import sys\n", "import subprocess\n", "import pkg_resources\n", "import numpy as np\n", "\n", "required = { 'scikit-image'}\n", "installed = {pkg.key for pkg in pkg_resources.working_set}\n", "missing = required - installed\n", "# VGG16 requires images to be of dim = (224, 224, 3)\n", "newSize = (224,224)\n", "\n", "if missing: \n", " python = sys.executable\n", " subprocess.check_call([python, '-m', 'pip', 'install', *missing], stdout=subprocess.DEVNULL)\n", "\n", "def load_train_data(input_dir):\n", " import numpy as np\n", " import pandas as pd\n", " import os\n", " from skimage.io import imread\n", " import cv2 as cv\n", " from pathlib import Path\n", " import random\n", " from shutil import copyfile, rmtree\n", " import json\n", "\n", " import seaborn as sns\n", " import matplotlib.pyplot as plt\n", "\n", " import matplotlib\n", " \n", " image_dir = Path(input_dir)\n", " categories_name = []\n", " for file in os.listdir(image_dir):\n", " d = os.path.join(image_dir, file)\n", " if os.path.isdir(d):\n", " categories_name.append(file)\n", "\n", " folders = [directory for directory in image_dir.iterdir() if directory.is_dir()]\n", "\n", " train_img = []\n", " categories_count=[]\n", " labels=[]\n", " for i, direc in enumerate(folders):\n", " count = 0\n", " for obj in direc.iterdir():\n", " if os.path.isfile(obj) and os.path.basename(os.path.normpath(obj)) != 'desktop.ini':\n", " labels.append(os.path.basename(os.path.normpath(direc)))\n", " count += 1\n", " img = imread(obj)#zwraca ndarry postaci xSize x ySize x colorDepth\n", " img = img[:, :, :3]\n", " img = cv.resize(img, newSize, interpolation=cv.INTER_AREA)# zwraca ndarray\n", " img = img / 255 #normalizacja\n", " train_img.append(img)\n", " categories_count.append(count)\n", " X={}\n", " X[\"values\"] = np.array(train_img)\n", " X[\"categories_name\"] = categories_name\n", " X[\"categories_count\"] = categories_count\n", " X[\"labels\"]=labels\n", " return X\n", "\n", "def load_test_data(input_dir):\n", " import numpy as np\n", " import pandas as pd\n", " import os\n", " from skimage.io import imread\n", " import cv2 as cv\n", " from pathlib import Path\n", " import random\n", " from shutil import copyfile, rmtree\n", " import json\n", "\n", " import seaborn as sns\n", " import matplotlib.pyplot as plt\n", "\n", " import matplotlib\n", "\n", " image_path = Path(input_dir)\n", "\n", " labels_path = image_path.parents[0] / 'test_labels.json'\n", "\n", " jsonString = labels_path.read_text()\n", " objects = json.loads(jsonString)\n", "\n", " categories_name = []\n", " categories_count=[]\n", " count = 0\n", " c = objects[0]['value']\n", " for e in objects:\n", " if e['value'] != c:\n", " categories_count.append(count)\n", " c = e['value']\n", " count = 1\n", " else:\n", " count += 1\n", " if not e['value'] in categories_name:\n", " categories_name.append(e['value'])\n", "\n", " categories_count.append(count)\n", " \n", " test_img = []\n", "\n", " labels=[]\n", " for e in objects:\n", " p = image_path / e['filename']\n", " img = imread(p)#zwraca ndarry postaci xSize x ySize x colorDepth\n", " img = img[:, :, :3]\n", " img = cv.resize(img, newSize, interpolation=cv.INTER_AREA)# zwraca ndarray\n", " img = img / 255#normalizacja\n", " test_img.append(img)\n", " labels.append(e['value'])\n", "\n", " X={}\n", " X[\"values\"] = np.array(test_img)\n", " X[\"categories_name\"] = categories_name\n", " X[\"categories_count\"] = categories_count\n", " X[\"labels\"]=labels\n", " return X" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "def create_tf_ds(X_train, y_train_enc, X_validate, y_validate_enc, X_test, y_test_enc):\n", " import tensorflow as tf\n", " \n", " train_ds = tf.data.Dataset.from_tensor_slices((X_train, y_train_enc))\n", " validation_ds = tf.data.Dataset.from_tensor_slices((X_validate, y_validate_enc))\n", " test_ds = tf.data.Dataset.from_tensor_slices((X_test, y_test_enc))\n", "\n", " train_ds_size = tf.data.experimental.cardinality(train_ds).numpy()\n", " test_ds_size = tf.data.experimental.cardinality(test_ds).numpy()\n", " validation_ds_size = tf.data.experimental.cardinality(validation_ds).numpy()\n", "\n", " print(\"Training data size:\", train_ds_size)\n", " print(\"Test data size:\", test_ds_size)\n", " print(\"Validation data size:\", validation_ds_size)\n", "\n", " train_ds = (train_ds\n", " .shuffle(buffer_size=train_ds_size)\n", " .batch(batch_size=32, drop_remainder=True))\n", " test_ds = (test_ds\n", " .shuffle(buffer_size=train_ds_size)\n", " .batch(batch_size=32, drop_remainder=True))\n", " validation_ds = (validation_ds\n", " .shuffle(buffer_size=train_ds_size)\n", " .batch(batch_size=32, drop_remainder=True))\n", " \n", " return train_ds, test_ds, validation_ds" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "def get_run_logdir(root_logdir):\n", " import os\n", " import time\n", "\n", " run_id = time.strftime(\"run_%Y_%m_%d-%H_%M_%S\")\n", " return os.path.join(root_logdir, run_id)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "def diagram_setup(model_name):\n", " from tensorflow import keras\n", " import os\n", " \n", " root_logdir = os.path.join(os.curdir, f\"logs\\\\fit\\\\{model_name}\\\\\")\n", " \n", " run_logdir = get_run_logdir(root_logdir)\n", " tensorboard_cb = keras.callbacks.TensorBoard(run_logdir)" ] }, { "cell_type": "code", "execution_count": 20, "id": "cc941c5a", "metadata": {}, "outputs": [], "source": [ "# Data load\n", "data_train = load_train_data(\"./train_test_sw/train_sw\")\n", "values_train = data_train['values']\n", "labels_train = data_train['labels']\n", "\n", "data_test = load_test_data(\"./train_test_sw/test_sw\")\n", "X_test = data_test['values']\n", "y_test = data_test['labels']" ] }, { "cell_type": "code", "execution_count": 21, "id": "25040ac9", "metadata": {}, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split\n", "X_train, X_validate, y_train, y_validate = train_test_split(values_train, labels_train, test_size=0.2, random_state=42)" ] }, { "cell_type": "code", "execution_count": 22, "id": "a1fe47e6", "metadata": {}, "outputs": [], "source": [ "from sklearn.preprocessing import LabelEncoder\n", "class_le = LabelEncoder()\n", "y_train_enc = class_le.fit_transform(y_train)\n", "y_validate_enc = class_le.fit_transform(y_validate)\n", "y_test_enc = class_le.fit_transform(y_test)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Training data size: 820\n", "Test data size: 259\n", "Validation data size: 206\n" ] } ], "source": [ "train_ds, test_ds, validation_ds = create_tf_ds(X_train, y_train_enc, X_validate, y_validate_enc, X_test, y_test_enc)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## VGG16" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [], "source": [ "diagram_setup('vgg_sw')" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [], "source": [ "import keras,os\n", "from keras.models import Sequential\n", "from keras.layers import Dense, Conv2D, MaxPool2D , Flatten\n", "from keras.preprocessing.image import ImageDataGenerator\n", "import numpy as np\n", "\n", "model = keras.models.Sequential([\n", " keras.layers.Conv2D(filters=64, kernel_size=(3,3), activation='relu', input_shape=(224,224,3), padding=\"same\"),\n", " keras.layers.Conv2D(filters=64, kernel_size=(3,3), activation='relu', input_shape=(224,224,3), padding=\"same\"),\n", " keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2)),\n", " keras.layers.Conv2D(filters=128, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Conv2D(filters=128, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2)),\n", " keras.layers.Conv2D(filters=256, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Conv2D(filters=256, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Conv2D(filters=256, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2)),\n", " keras.layers.Conv2D(filters=512, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Conv2D(filters=512, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Conv2D(filters=512, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.MaxPool2D(pool_size=(2,2), strides=(2,2)),\n", " keras.layers.Conv2D(filters=512, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Conv2D(filters=512, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Conv2D(filters=512, kernel_size=(3,3), padding=\"same\", activation=\"relu\"),\n", " keras.layers.Flatten(),\n", " keras.layers.Dense(units = 4096, activation='relu'),\n", " keras.layers.Dense(units = 4096, activation='relu'),\n", " keras.layers.Dense(units = 5, activation='softmax')\n", "])" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/jonas/Library/Python/3.9/lib/python/site-packages/keras/optimizers/optimizer_v2/adam.py:117: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.\n", " super().__init__(name, **kwargs)\n" ] } ], "source": [ "from keras.optimizers import Adam\n", "opt = Adam(lr=0.001)\n", "model.compile(optimizer=opt, loss=keras.losses.sparse_categorical_crossentropy, metrics=['accuracy'])" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"sequential_1\"\n", "_________________________________________________________________\n", " Layer (type) Output Shape Param # \n", "=================================================================\n", " conv2d_13 (Conv2D) (None, 224, 224, 64) 1792 \n", " \n", " conv2d_14 (Conv2D) (None, 224, 224, 64) 36928 \n", " \n", " max_pooling2d_4 (MaxPooling (None, 112, 112, 64) 0 \n", " 2D) \n", " \n", " conv2d_15 (Conv2D) (None, 112, 112, 128) 73856 \n", " \n", " conv2d_16 (Conv2D) (None, 112, 112, 128) 147584 \n", " \n", " max_pooling2d_5 (MaxPooling (None, 56, 56, 128) 0 \n", " 2D) \n", " \n", " conv2d_17 (Conv2D) (None, 56, 56, 256) 295168 \n", " \n", " conv2d_18 (Conv2D) (None, 56, 56, 256) 590080 \n", " \n", " conv2d_19 (Conv2D) (None, 56, 56, 256) 590080 \n", " \n", " max_pooling2d_6 (MaxPooling (None, 28, 28, 256) 0 \n", " 2D) \n", " \n", " conv2d_20 (Conv2D) (None, 28, 28, 512) 1180160 \n", " \n", " conv2d_21 (Conv2D) (None, 28, 28, 512) 2359808 \n", " \n", " conv2d_22 (Conv2D) (None, 28, 28, 512) 2359808 \n", " \n", " max_pooling2d_7 (MaxPooling (None, 14, 14, 512) 0 \n", " 2D) \n", " \n", " conv2d_23 (Conv2D) (None, 14, 14, 512) 2359808 \n", " \n", " conv2d_24 (Conv2D) (None, 14, 14, 512) 2359808 \n", " \n", " conv2d_25 (Conv2D) (None, 14, 14, 512) 2359808 \n", " \n", " flatten_1 (Flatten) (None, 100352) 0 \n", " \n", " dense_3 (Dense) (None, 4096) 411045888 \n", " \n", " dense_4 (Dense) (None, 4096) 16781312 \n", " \n", " dense_5 (Dense) (None, 5) 20485 \n", " \n", "=================================================================\n", "Total params: 442,562,373\n", "Trainable params: 442,562,373\n", "Non-trainable params: 0\n", "_________________________________________________________________\n" ] } ], "source": [ "model.summary()" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "WARNING:tensorflow:`period` argument is deprecated. Please use `save_freq` to specify the frequency in number of batches seen.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/6b/j4d60ym516x2s6wymzj707rh0000gn/T/ipykernel_9339/4100383455.py:4: UserWarning: `Model.fit_generator` is deprecated and will be removed in a future version. Please use `Model.fit`, which supports generators.\n", " hist_vgg = model.fit_generator(steps_per_epoch=len(train_ds), generator=train_ds, validation_data= validation_ds, validation_steps=len(validation_ds), epochs=1, callbacks=[checkpoint,early])\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "25/25 [==============================] - ETA: 0s - loss: 1.6126 - accuracy: 0.1663 \n", "Epoch 1: val_accuracy improved from -inf to 0.18750, saving model to vgg16_1.h5\n", "25/25 [==============================] - 515s 21s/step - loss: 1.6126 - accuracy: 0.1663 - val_loss: 1.6102 - val_accuracy: 0.1875\n" ] } ], "source": [ "from keras.callbacks import ModelCheckpoint, EarlyStopping\n", "checkpoint = ModelCheckpoint(\"vgg16_1.h5\", monitor='val_accuracy', verbose=1, save_best_only=True, save_weights_only=False, mode='auto', period=1)\n", "early = EarlyStopping(monitor='val_accuracy', min_delta=0, patience=20, verbose=1, mode='auto')\n", "hist_vgg = model.fit_generator(steps_per_epoch=len(train_ds), generator=train_ds, validation_data= validation_ds, validation_steps=len(validation_ds), epochs=1, callbacks=[checkpoint,early])" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABN30lEQVR4nO3deXxMZ98/8M+ZRCb7JpFFQ4QgJSIV0lBFpY0gFbXGkoSgailSLXnsXdBaGmrpzU1ye4pYiupNpRE7qbVRKvYQSxJCsyKRzPX7w888RoKETCZzfN6v17xqrnOdc77ndNr5uM515khCCAEiIiIimVDougAiIiKiysRwQ0RERLLCcENERESywnBDREREssJwQ0RERLLCcENERESywnBDREREssJwQ0RERLLCcENERESywnBDRJVGkiRMnz69wutduXIFkiQhNja20msiotcPww2RzMTGxkKSJEiShAMHDpRaLoSAi4sLJElC165ddVAhEZF2MdwQyZSxsTHWrFlTqn3v3r24fv06lEqlDqoiItI+hhsimercuTM2bNiA4uJijfY1a9agRYsWcHR01FFlr4+CggJdl0D0WmK4IZKpkJAQ3LlzBwkJCeq2oqIibNy4Ef369StznYKCAnz22WdwcXGBUqlEo0aNMHfuXAghNPoVFhZi3LhxsLe3h4WFBT788ENcv369zG3euHEDgwcPhoODA5RKJZo0aYKVK1e+1DHdvXsX48ePh6enJ8zNzWFpaYnAwECcPHmyVN8HDx5g+vTpaNiwIYyNjeHk5ISPPvoIly5dUvdRqVRYsGABPD09YWxsDHt7e3Tq1AnHjh0D8Py5QE/PL5o+fTokScKZM2fQr18/2NjY4J133gEA/PXXXwgPD4ebmxuMjY3h6OiIwYMH486dO2Wer4iICDg7O0OpVKJevXr45JNPUFRUhMuXL0OSJHz//fel1jt06BAkScLatWsrelqJZMdQ1wUQkXa4urrCz88Pa9euRWBgIADgt99+Q05ODvr27YuFCxdq9BdC4MMPP8Tu3bsRERGB5s2bIz4+Hp9//jlu3Lih8YU6ZMgQ/PTTT+jXrx9at26NXbt2oUuXLqVqyMzMxNtvvw1JkjBq1CjY29vjt99+Q0REBHJzczF27NgKHdPly5exZcsW9OrVC/Xq1UNmZib+9a9/oV27djhz5gycnZ0BACUlJejatSsSExPRt29fjBkzBnl5eUhISMDp06dRv359AEBERARiY2MRGBiIIUOGoLi4GPv378cff/wBHx+fCtX2WK9eveDu7o6ZM2eqQ2FCQgIuX76MQYMGwdHREX///TeWLVuGv//+G3/88QckSQIA3Lx5E61atUJ2djaGDRuGxo0b48aNG9i4cSPu3bsHNzc3tGnTBqtXr8a4ceM09rt69WpYWFigW7duL1U3kawIIpKVmJgYAUAcPXpULFq0SFhYWIh79+4JIYTo1auX6NChgxBCiLp164ouXbqo19uyZYsAIL7++muN7fXs2VNIkiQuXrwohBAiOTlZABAjRozQ6NevXz8BQEybNk3dFhERIZycnERWVpZG3759+worKyt1XampqQKAiImJee6xPXjwQJSUlGi0paamCqVSKb788kt128qVKwUAMX/+/FLbUKlUQgghdu3aJQCITz/99Jl9nlfX08c6bdo0AUCEhISU6vv4OJ+0du1aAUDs27dP3RYaGioUCoU4evToM2v617/+JQCIlJQU9bKioiJhZ2cnwsLCSq1H9DriZSkiGevduzfu37+P//73v8jLy8N///vfZ16S2r59OwwMDPDpp59qtH/22WcQQuC3335T9wNQqt/TozBCCPz8888ICgqCEAJZWVnqV0BAAHJycnDixIkKHY9SqYRC8eh/WyUlJbhz5w7Mzc3RqFEjjW39/PPPsLOzw+jRo0tt4/Eoyc8//wxJkjBt2rRn9nkZw4cPL9VmYmKi/vODBw+QlZWFt99+GwDUdatUKmzZsgVBQUFljho9rql3794wNjbG6tWr1cvi4+ORlZWFAQMGvHTdRHLCcEMkY/b29vD398eaNWuwadMmlJSUoGfPnmX2vXr1KpydnWFhYaHR7uHhoV7++J8KhUJ9aeexRo0aaby/ffs2srOzsWzZMtjb22u8Bg0aBAC4detWhY5HpVLh+++/h7u7O5RKJezs7GBvb4+//voLOTk56n6XLl1Co0aNYGj47Cvvly5dgrOzM2xtbStUw4vUq1evVNvdu3cxZswYODg4wMTEBPb29up+j+u+ffs2cnNz0bRp0+du39raGkFBQRp3wq1evRq1a9fGe++9V4lHQqS/OOeGSOb69euHoUOHIiMjA4GBgbC2tq6S/apUKgDAgAEDEBYWVmafZs2aVWibM2fOxJQpUzB4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Vq0C8OhSVFhYGBYsWABfX19kZGQAAExMTGBlZaWTYyAiIqLqRaeXpY4dOwZvb294e3sDACIjI+Ht7a2+rTs9PR1paWnq/suWLUNxcTFGjhwJJycn9WvMmDE6qZ+IiIiqn2rzOzdVhb9zQ0REpH9em9+5ISIiInoaww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyQrDDREREckKww0RERHJCsMNERERyYpOw82+ffsQFBQEZ2dnSJKELVu2vHCdPXv24K233oJSqUSDBg0QGxur9TqJiIhIf+g03BQUFMDLywuLFy8uV//U1FR06dIFHTp0QHJyMsaOHYshQ4YgPj5ey5USERGRvjDU5c4DAwMRGBhY7v4//vgj6tWrh3nz5gEAPDw8cODAAXz//fcICAjQVplERESkR/Rqzk1SUhL8/f012gICApCUlPTMdQoLC5Gbm6vxIiIiIvnSq3CTkZEBBwcHjTYHBwfk5ubi/v37Za4za9YsWFlZqV8uLi5VUSoRERHpiF6Fm5cRFRWFnJwc9evatWu6LomIiIi0SKdzbirK0dERmZmZGm2ZmZmwtLSEiYlJmesolUoolcqqKI+IiIiqAb0aufHz80NiYqJGW0JCAvz8/HRUEREREVU3Og03+fn5SE5ORnJyMoBHt3onJycjLS0NwKNLSqGhoer+w4cPx+XLl/HFF1/g7NmzWLJkCdavX49x48bponwiIiKqhnQabo4dOwZvb294e3sDACIjI+Ht7Y2pU6cCANLT09VBBwDq1auHbdu2ISEhAV5eXpg3bx7+/e9/8zZwIiIiUpOEEELXRVSl3NxcWFlZIScnB5aWlrouh4iIiMqhIt/fejXnhoiIiOhFGG6IiIhIVl4q3BQXF2Pnzp3417/+hby8PADAzZs3kZ+fX6nFEREREVVUhX/n5urVq+jUqRPS0tJQWFiI999/HxYWFvj2229RWFiIH3/8URt1EhEREZVLhUduxowZAx8fH/zzzz8aP5zXvXv3Ur9BQ0RERFTVKjxys3//fhw6dAhGRkYa7a6urrhx40alFUZERET0Mio8cqNSqVBSUlKq/fr167CwsKiUooiIiIheVoXDzQcffIDo6Gj1e0mSkJ+fj2nTpqFz586VWRsRERFRhVX4R/yuX7+OgIAACCFw4cIF+Pj44MKFC7Czs8O+fftQq1YtbdVaKfgjfkRERPqnIt/fL/ULxcXFxYiLi8Nff/2F/Px8vPXWW+jfv/8zn8xdnTDcEBER6Z+KfH9XeEIxABgaGmLAgAEvVRwRERGRNlU43Kxateq5y598ijcRERFRVavwZSkbGxuN9w8fPsS9e/dgZGQEU1NT3L17t1ILrGy8LEVERKR/tPrgzH/++UfjlZ+fj3PnzuGdd97B2rVrX7poIiIiospQKQ/OdHd3x+zZszFmzJjK2BwRERHRS6u0p4IbGhri5s2blbU5IiIiopdS4QnFW7du1XgvhEB6ejoWLVqENm3aVFphRERERC+jwuEmODhY470kSbC3t8d7772HefPmVVZdRERERC+lwuFGpVJpow4iIiKiSlFpc26IiIiIqoNyjdxERkaWe4Pz589/6WKIiIiIXlW5ws2ff/5Zro1JkvRKxRARERG9qnKFm927d2u7DiIiIqJKwTk3REREJCsv9VTwY8eOYf369UhLS0NRUZHGsk2bNlVKYUREREQvo8IjN3FxcWjdujVSUlKwefNmPHz4EH///Td27doFKysrbdRIREREVG4VDjczZ87E999/j19//RVGRkZYsGABzp49i969e6NOnTraqJGIiIio3Cocbi5duoQuXboAAIyMjFBQUABJkjBu3DgsW7as0gskIiIiqogKhxsbGxvk5eUBAGrXro3Tp08DALKzs3Hv3r3KrY6IiIiogsodbh6HmHfffRcJCQkAgF69emHMmDEYOnQoQkJC0LFjR+1USURERFRO5b5bqlmzZmjZsiWCg4PRq1cvAMCkSZNQo0YNHDp0CD169MDkyZO1VigRERFReUhCCFGejvv370dMTAw2btwIlUqFHj16YMiQIWjbtq22a6xUubm5sLKyQk5ODiwtLXVdDhEREZVDRb6/y31Zqm3btli5ciXS09Pxww8/4MqVK2jXrh0a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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "plt.plot(hist_vgg.history[\"accuracy\"])\n", "plt.plot(hist_vgg.history['val_accuracy'])\n", "plt.plot(hist_vgg.history['loss'])\n", "plt.plot(hist_vgg.history['val_loss'])\n", "plt.title(\"Model accuracy\")\n", "plt.ylabel(\"Value\")\n", "plt.xlabel(\"Epoch\")\n", "plt.legend([\"Accuracy\",\"Validation Accuracy\",\"Loss\",\"Validation Loss\"])\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8/8 [==============================] - 32s 4s/step - loss: 1.6094 - accuracy: 0.1992\n" ] }, { "data": { "text/plain": [ "[1.609419822692871, 0.19921875]" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.evaluate(test_ds)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## ResNet50" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/resnet/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5\n", "94765736/94765736 [==============================] - 5s 0us/step\n" ] } ], "source": [ "from keras.layers import Input, Lambda, Dense, Flatten\n", "from keras.models import Model\n", "from keras.applications import ResNet50\n", "from keras.preprocessing import image\n", "from keras.preprocessing.image import ImageDataGenerator\n", "from keras.models import Sequential\n", "import numpy as np\n", "from glob import glob\n", "import matplotlib.pyplot as plt\n", "\n", "# re-size all the images to this\n", "IMAGE_SIZE = [224, 224]\n", "\n", "# add preprocessing layer to the front of resnet\n", "resnet = ResNet50(input_shape=IMAGE_SIZE + [3], weights='imagenet', include_top=False)\n", "\n", "# don't train existing weights\n", "for layer in resnet.layers:\n", " layer.trainable = False\n", " \n", " # useful for getting number of classes\n", "classes = 5\n", " \n", "\n", "# our layers - you can add more if you want\n", "x = Flatten()(resnet.output)\n", "# x = Dense(1000, activation='relu')(x)\n", "prediction = Dense(5, activation='softmax')(x)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Model: \"model\"\n", "__________________________________________________________________________________________________\n", " Layer (type) Output Shape Param # Connected to \n", "==================================================================================================\n", " input_1 (InputLayer) [(None, 224, 224, 3 0 [] \n", " )] \n", " \n", " conv1_pad (ZeroPadding2D) (None, 230, 230, 3) 0 ['input_1[0][0]'] \n", " \n", " conv1_conv (Conv2D) (None, 112, 112, 64 9472 ['conv1_pad[0][0]'] \n", " ) \n", " \n", " conv1_bn (BatchNormalization) (None, 112, 112, 64 256 ['conv1_conv[0][0]'] \n", " ) \n", " \n", " conv1_relu (Activation) (None, 112, 112, 64 0 ['conv1_bn[0][0]'] \n", " ) \n", " \n", " pool1_pad (ZeroPadding2D) (None, 114, 114, 64 0 ['conv1_relu[0][0]'] \n", " ) \n", " \n", " pool1_pool (MaxPooling2D) (None, 56, 56, 64) 0 ['pool1_pad[0][0]'] \n", " \n", " conv2_block1_1_conv (Conv2D) (None, 56, 56, 64) 4160 ['pool1_pool[0][0]'] \n", " \n", " conv2_block1_1_bn (BatchNormal (None, 56, 56, 64) 256 ['conv2_block1_1_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block1_1_relu (Activatio (None, 56, 56, 64) 0 ['conv2_block1_1_bn[0][0]'] \n", " n) \n", " \n", " conv2_block1_2_conv (Conv2D) (None, 56, 56, 64) 36928 ['conv2_block1_1_relu[0][0]'] \n", " \n", " conv2_block1_2_bn (BatchNormal (None, 56, 56, 64) 256 ['conv2_block1_2_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block1_2_relu (Activatio (None, 56, 56, 64) 0 ['conv2_block1_2_bn[0][0]'] \n", " n) \n", " \n", " conv2_block1_0_conv (Conv2D) (None, 56, 56, 256) 16640 ['pool1_pool[0][0]'] \n", " \n", " conv2_block1_3_conv (Conv2D) (None, 56, 56, 256) 16640 ['conv2_block1_2_relu[0][0]'] \n", " \n", " conv2_block1_0_bn (BatchNormal (None, 56, 56, 256) 1024 ['conv2_block1_0_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block1_3_bn (BatchNormal (None, 56, 56, 256) 1024 ['conv2_block1_3_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block1_add (Add) (None, 56, 56, 256) 0 ['conv2_block1_0_bn[0][0]', \n", " 'conv2_block1_3_bn[0][0]'] \n", " \n", " conv2_block1_out (Activation) (None, 56, 56, 256) 0 ['conv2_block1_add[0][0]'] \n", " \n", " conv2_block2_1_conv (Conv2D) (None, 56, 56, 64) 16448 ['conv2_block1_out[0][0]'] \n", " \n", " conv2_block2_1_bn (BatchNormal (None, 56, 56, 64) 256 ['conv2_block2_1_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block2_1_relu (Activatio (None, 56, 56, 64) 0 ['conv2_block2_1_bn[0][0]'] \n", " n) \n", " \n", " conv2_block2_2_conv (Conv2D) (None, 56, 56, 64) 36928 ['conv2_block2_1_relu[0][0]'] \n", " \n", " conv2_block2_2_bn (BatchNormal (None, 56, 56, 64) 256 ['conv2_block2_2_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block2_2_relu (Activatio (None, 56, 56, 64) 0 ['conv2_block2_2_bn[0][0]'] \n", " n) \n", " \n", " conv2_block2_3_conv (Conv2D) (None, 56, 56, 256) 16640 ['conv2_block2_2_relu[0][0]'] \n", " \n", " conv2_block2_3_bn (BatchNormal (None, 56, 56, 256) 1024 ['conv2_block2_3_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block2_add (Add) (None, 56, 56, 256) 0 ['conv2_block1_out[0][0]', \n", " 'conv2_block2_3_bn[0][0]'] \n", " \n", " conv2_block2_out (Activation) (None, 56, 56, 256) 0 ['conv2_block2_add[0][0]'] \n", " \n", " conv2_block3_1_conv (Conv2D) (None, 56, 56, 64) 16448 ['conv2_block2_out[0][0]'] \n", " \n", " conv2_block3_1_bn (BatchNormal (None, 56, 56, 64) 256 ['conv2_block3_1_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block3_1_relu (Activatio (None, 56, 56, 64) 0 ['conv2_block3_1_bn[0][0]'] \n", " n) \n", " \n", " conv2_block3_2_conv (Conv2D) (None, 56, 56, 64) 36928 ['conv2_block3_1_relu[0][0]'] \n", " \n", " conv2_block3_2_bn (BatchNormal (None, 56, 56, 64) 256 ['conv2_block3_2_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block3_2_relu (Activatio (None, 56, 56, 64) 0 ['conv2_block3_2_bn[0][0]'] \n", " n) \n", " \n", " conv2_block3_3_conv (Conv2D) (None, 56, 56, 256) 16640 ['conv2_block3_2_relu[0][0]'] \n", " \n", " conv2_block3_3_bn (BatchNormal (None, 56, 56, 256) 1024 ['conv2_block3_3_conv[0][0]'] \n", " ization) \n", " \n", " conv2_block3_add (Add) (None, 56, 56, 256) 0 ['conv2_block2_out[0][0]', \n", " 'conv2_block3_3_bn[0][0]'] \n", " \n", " conv2_block3_out (Activation) (None, 56, 56, 256) 0 ['conv2_block3_add[0][0]'] \n", " \n", " conv3_block1_1_conv (Conv2D) (None, 28, 28, 128) 32896 ['conv2_block3_out[0][0]'] \n", " \n", " conv3_block1_1_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block1_1_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block1_1_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block1_1_bn[0][0]'] \n", " n) \n", " \n", " conv3_block1_2_conv (Conv2D) (None, 28, 28, 128) 147584 ['conv3_block1_1_relu[0][0]'] \n", " \n", " conv3_block1_2_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block1_2_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block1_2_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block1_2_bn[0][0]'] \n", " n) \n", " \n", " conv3_block1_0_conv (Conv2D) (None, 28, 28, 512) 131584 ['conv2_block3_out[0][0]'] \n", " \n", " conv3_block1_3_conv (Conv2D) (None, 28, 28, 512) 66048 ['conv3_block1_2_relu[0][0]'] \n", " \n", " conv3_block1_0_bn (BatchNormal (None, 28, 28, 512) 2048 ['conv3_block1_0_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block1_3_bn (BatchNormal (None, 28, 28, 512) 2048 ['conv3_block1_3_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block1_add (Add) (None, 28, 28, 512) 0 ['conv3_block1_0_bn[0][0]', \n", " 'conv3_block1_3_bn[0][0]'] \n", " \n", " conv3_block1_out (Activation) (None, 28, 28, 512) 0 ['conv3_block1_add[0][0]'] \n", " \n", " conv3_block2_1_conv (Conv2D) (None, 28, 28, 128) 65664 ['conv3_block1_out[0][0]'] \n", " \n", " conv3_block2_1_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block2_1_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block2_1_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block2_1_bn[0][0]'] \n", " n) \n", " \n", " conv3_block2_2_conv (Conv2D) (None, 28, 28, 128) 147584 ['conv3_block2_1_relu[0][0]'] \n", " \n", " conv3_block2_2_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block2_2_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block2_2_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block2_2_bn[0][0]'] \n", " n) \n", " \n", " conv3_block2_3_conv (Conv2D) (None, 28, 28, 512) 66048 ['conv3_block2_2_relu[0][0]'] \n", " \n", " conv3_block2_3_bn (BatchNormal (None, 28, 28, 512) 2048 ['conv3_block2_3_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block2_add (Add) (None, 28, 28, 512) 0 ['conv3_block1_out[0][0]', \n", " 'conv3_block2_3_bn[0][0]'] \n", " \n", " conv3_block2_out (Activation) (None, 28, 28, 512) 0 ['conv3_block2_add[0][0]'] \n", " \n", " conv3_block3_1_conv (Conv2D) (None, 28, 28, 128) 65664 ['conv3_block2_out[0][0]'] \n", " \n", " conv3_block3_1_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block3_1_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block3_1_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block3_1_bn[0][0]'] \n", " n) \n", " \n", " conv3_block3_2_conv (Conv2D) (None, 28, 28, 128) 147584 ['conv3_block3_1_relu[0][0]'] \n", " \n", " conv3_block3_2_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block3_2_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block3_2_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block3_2_bn[0][0]'] \n", " n) \n", " \n", " conv3_block3_3_conv (Conv2D) (None, 28, 28, 512) 66048 ['conv3_block3_2_relu[0][0]'] \n", " \n", " conv3_block3_3_bn (BatchNormal (None, 28, 28, 512) 2048 ['conv3_block3_3_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block3_add (Add) (None, 28, 28, 512) 0 ['conv3_block2_out[0][0]', \n", " 'conv3_block3_3_bn[0][0]'] \n", " \n", " conv3_block3_out (Activation) (None, 28, 28, 512) 0 ['conv3_block3_add[0][0]'] \n", " \n", " conv3_block4_1_conv (Conv2D) (None, 28, 28, 128) 65664 ['conv3_block3_out[0][0]'] \n", " \n", " conv3_block4_1_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block4_1_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block4_1_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block4_1_bn[0][0]'] \n", " n) \n", " \n", " conv3_block4_2_conv (Conv2D) (None, 28, 28, 128) 147584 ['conv3_block4_1_relu[0][0]'] \n", " \n", " conv3_block4_2_bn (BatchNormal (None, 28, 28, 128) 512 ['conv3_block4_2_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block4_2_relu (Activatio (None, 28, 28, 128) 0 ['conv3_block4_2_bn[0][0]'] \n", " n) \n", " \n", " conv3_block4_3_conv (Conv2D) (None, 28, 28, 512) 66048 ['conv3_block4_2_relu[0][0]'] \n", " \n", " conv3_block4_3_bn (BatchNormal (None, 28, 28, 512) 2048 ['conv3_block4_3_conv[0][0]'] \n", " ization) \n", " \n", " conv3_block4_add (Add) (None, 28, 28, 512) 0 ['conv3_block3_out[0][0]', \n", " 'conv3_block4_3_bn[0][0]'] \n", " \n", " conv3_block4_out (Activation) (None, 28, 28, 512) 0 ['conv3_block4_add[0][0]'] \n", " \n", " conv4_block1_1_conv (Conv2D) (None, 14, 14, 256) 131328 ['conv3_block4_out[0][0]'] \n", " \n", " conv4_block1_1_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block1_1_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block1_1_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block1_1_bn[0][0]'] \n", " n) \n", " \n", " conv4_block1_2_conv (Conv2D) (None, 14, 14, 256) 590080 ['conv4_block1_1_relu[0][0]'] \n", " \n", " conv4_block1_2_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block1_2_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block1_2_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block1_2_bn[0][0]'] \n", " n) \n", " \n", " conv4_block1_0_conv (Conv2D) (None, 14, 14, 1024 525312 ['conv3_block4_out[0][0]'] \n", " ) \n", " \n", " conv4_block1_3_conv (Conv2D) (None, 14, 14, 1024 263168 ['conv4_block1_2_relu[0][0]'] \n", " ) \n", " \n", " conv4_block1_0_bn (BatchNormal (None, 14, 14, 1024 4096 ['conv4_block1_0_conv[0][0]'] \n", " ization) ) \n", " \n", " conv4_block1_3_bn (BatchNormal (None, 14, 14, 1024 4096 ['conv4_block1_3_conv[0][0]'] \n", " ization) ) \n", " \n", " conv4_block1_add (Add) (None, 14, 14, 1024 0 ['conv4_block1_0_bn[0][0]', \n", " ) 'conv4_block1_3_bn[0][0]'] \n", " \n", " conv4_block1_out (Activation) (None, 14, 14, 1024 0 ['conv4_block1_add[0][0]'] \n", " ) \n", " \n", " conv4_block2_1_conv (Conv2D) (None, 14, 14, 256) 262400 ['conv4_block1_out[0][0]'] \n", " \n", " conv4_block2_1_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block2_1_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block2_1_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block2_1_bn[0][0]'] \n", " n) \n", " \n", " conv4_block2_2_conv (Conv2D) (None, 14, 14, 256) 590080 ['conv4_block2_1_relu[0][0]'] \n", " \n", " conv4_block2_2_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block2_2_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block2_2_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block2_2_bn[0][0]'] \n", " n) \n", " \n", " conv4_block2_3_conv (Conv2D) (None, 14, 14, 1024 263168 ['conv4_block2_2_relu[0][0]'] \n", " ) \n", " \n", " conv4_block2_3_bn (BatchNormal (None, 14, 14, 1024 4096 ['conv4_block2_3_conv[0][0]'] \n", " ization) ) \n", " \n", " conv4_block2_add (Add) (None, 14, 14, 1024 0 ['conv4_block1_out[0][0]', \n", " ) 'conv4_block2_3_bn[0][0]'] \n", " \n", " conv4_block2_out (Activation) (None, 14, 14, 1024 0 ['conv4_block2_add[0][0]'] \n", " ) \n", " \n", " conv4_block3_1_conv (Conv2D) (None, 14, 14, 256) 262400 ['conv4_block2_out[0][0]'] \n", " \n", " conv4_block3_1_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block3_1_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block3_1_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block3_1_bn[0][0]'] \n", " n) \n", " \n", " conv4_block3_2_conv (Conv2D) (None, 14, 14, 256) 590080 ['conv4_block3_1_relu[0][0]'] \n", " \n", " conv4_block3_2_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block3_2_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block3_2_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block3_2_bn[0][0]'] \n", " n) \n", " \n", " conv4_block3_3_conv (Conv2D) (None, 14, 14, 1024 263168 ['conv4_block3_2_relu[0][0]'] \n", " ) \n", " \n", " conv4_block3_3_bn (BatchNormal (None, 14, 14, 1024 4096 ['conv4_block3_3_conv[0][0]'] \n", " ization) ) \n", " \n", " conv4_block3_add (Add) (None, 14, 14, 1024 0 ['conv4_block2_out[0][0]', \n", " ) 'conv4_block3_3_bn[0][0]'] \n", " \n", " conv4_block3_out (Activation) (None, 14, 14, 1024 0 ['conv4_block3_add[0][0]'] \n", " ) \n", " \n", " conv4_block4_1_conv (Conv2D) (None, 14, 14, 256) 262400 ['conv4_block3_out[0][0]'] \n", " \n", " conv4_block4_1_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block4_1_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block4_1_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block4_1_bn[0][0]'] \n", " n) \n", " \n", " conv4_block4_2_conv (Conv2D) (None, 14, 14, 256) 590080 ['conv4_block4_1_relu[0][0]'] \n", " \n", " conv4_block4_2_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block4_2_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block4_2_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block4_2_bn[0][0]'] \n", " n) \n", " \n", " conv4_block4_3_conv (Conv2D) (None, 14, 14, 1024 263168 ['conv4_block4_2_relu[0][0]'] \n", " ) \n", " \n", " conv4_block4_3_bn (BatchNormal (None, 14, 14, 1024 4096 ['conv4_block4_3_conv[0][0]'] \n", " ization) ) \n", " \n", " conv4_block4_add (Add) (None, 14, 14, 1024 0 ['conv4_block3_out[0][0]', \n", " ) 'conv4_block4_3_bn[0][0]'] \n", " \n", " conv4_block4_out (Activation) (None, 14, 14, 1024 0 ['conv4_block4_add[0][0]'] \n", " ) \n", " \n", " conv4_block5_1_conv (Conv2D) (None, 14, 14, 256) 262400 ['conv4_block4_out[0][0]'] \n", " \n", " conv4_block5_1_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block5_1_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block5_1_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block5_1_bn[0][0]'] \n", " n) \n", " \n", " conv4_block5_2_conv (Conv2D) (None, 14, 14, 256) 590080 ['conv4_block5_1_relu[0][0]'] \n", " \n", " conv4_block5_2_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block5_2_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block5_2_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block5_2_bn[0][0]'] \n", " n) \n", " \n", " conv4_block5_3_conv (Conv2D) (None, 14, 14, 1024 263168 ['conv4_block5_2_relu[0][0]'] \n", " ) \n", " \n", " conv4_block5_3_bn (BatchNormal (None, 14, 14, 1024 4096 ['conv4_block5_3_conv[0][0]'] \n", " ization) ) \n", " \n", " conv4_block5_add (Add) (None, 14, 14, 1024 0 ['conv4_block4_out[0][0]', \n", " ) 'conv4_block5_3_bn[0][0]'] \n", " \n", " conv4_block5_out (Activation) (None, 14, 14, 1024 0 ['conv4_block5_add[0][0]'] \n", " ) \n", " \n", " conv4_block6_1_conv (Conv2D) (None, 14, 14, 256) 262400 ['conv4_block5_out[0][0]'] \n", " \n", " conv4_block6_1_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block6_1_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block6_1_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block6_1_bn[0][0]'] \n", " n) \n", " \n", " conv4_block6_2_conv (Conv2D) (None, 14, 14, 256) 590080 ['conv4_block6_1_relu[0][0]'] \n", " \n", " conv4_block6_2_bn (BatchNormal (None, 14, 14, 256) 1024 ['conv4_block6_2_conv[0][0]'] \n", " ization) \n", " \n", " conv4_block6_2_relu (Activatio (None, 14, 14, 256) 0 ['conv4_block6_2_bn[0][0]'] \n", " n) \n", " \n", " conv4_block6_3_conv (Conv2D) (None, 14, 14, 1024 263168 ['conv4_block6_2_relu[0][0]'] \n", " ) \n", " \n", " conv4_block6_3_bn (BatchNormal (None, 14, 14, 1024 4096 ['conv4_block6_3_conv[0][0]'] \n", " ization) ) \n", " \n", " conv4_block6_add (Add) (None, 14, 14, 1024 0 ['conv4_block5_out[0][0]', \n", " ) 'conv4_block6_3_bn[0][0]'] \n", " \n", " conv4_block6_out (Activation) (None, 14, 14, 1024 0 ['conv4_block6_add[0][0]'] \n", " ) \n", " \n", " conv5_block1_1_conv (Conv2D) (None, 7, 7, 512) 524800 ['conv4_block6_out[0][0]'] \n", " \n", " conv5_block1_1_bn (BatchNormal (None, 7, 7, 512) 2048 ['conv5_block1_1_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block1_1_relu (Activatio (None, 7, 7, 512) 0 ['conv5_block1_1_bn[0][0]'] \n", " n) \n", " \n", " conv5_block1_2_conv (Conv2D) (None, 7, 7, 512) 2359808 ['conv5_block1_1_relu[0][0]'] \n", " \n", " conv5_block1_2_bn (BatchNormal (None, 7, 7, 512) 2048 ['conv5_block1_2_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block1_2_relu (Activatio (None, 7, 7, 512) 0 ['conv5_block1_2_bn[0][0]'] \n", " n) \n", " \n", " conv5_block1_0_conv (Conv2D) (None, 7, 7, 2048) 2099200 ['conv4_block6_out[0][0]'] \n", " \n", " conv5_block1_3_conv (Conv2D) (None, 7, 7, 2048) 1050624 ['conv5_block1_2_relu[0][0]'] \n", " \n", " conv5_block1_0_bn (BatchNormal (None, 7, 7, 2048) 8192 ['conv5_block1_0_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block1_3_bn (BatchNormal (None, 7, 7, 2048) 8192 ['conv5_block1_3_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block1_add (Add) (None, 7, 7, 2048) 0 ['conv5_block1_0_bn[0][0]', \n", " 'conv5_block1_3_bn[0][0]'] \n", " \n", " conv5_block1_out (Activation) (None, 7, 7, 2048) 0 ['conv5_block1_add[0][0]'] \n", " \n", " conv5_block2_1_conv (Conv2D) (None, 7, 7, 512) 1049088 ['conv5_block1_out[0][0]'] \n", " \n", " conv5_block2_1_bn (BatchNormal (None, 7, 7, 512) 2048 ['conv5_block2_1_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block2_1_relu (Activatio (None, 7, 7, 512) 0 ['conv5_block2_1_bn[0][0]'] \n", " n) \n", " \n", " conv5_block2_2_conv (Conv2D) (None, 7, 7, 512) 2359808 ['conv5_block2_1_relu[0][0]'] \n", " \n", " conv5_block2_2_bn (BatchNormal (None, 7, 7, 512) 2048 ['conv5_block2_2_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block2_2_relu (Activatio (None, 7, 7, 512) 0 ['conv5_block2_2_bn[0][0]'] \n", " n) \n", " \n", " conv5_block2_3_conv (Conv2D) (None, 7, 7, 2048) 1050624 ['conv5_block2_2_relu[0][0]'] \n", " \n", " conv5_block2_3_bn (BatchNormal (None, 7, 7, 2048) 8192 ['conv5_block2_3_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block2_add (Add) (None, 7, 7, 2048) 0 ['conv5_block1_out[0][0]', \n", " 'conv5_block2_3_bn[0][0]'] \n", " \n", " conv5_block2_out (Activation) (None, 7, 7, 2048) 0 ['conv5_block2_add[0][0]'] \n", " \n", " conv5_block3_1_conv (Conv2D) (None, 7, 7, 512) 1049088 ['conv5_block2_out[0][0]'] \n", " \n", " conv5_block3_1_bn (BatchNormal (None, 7, 7, 512) 2048 ['conv5_block3_1_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block3_1_relu (Activatio (None, 7, 7, 512) 0 ['conv5_block3_1_bn[0][0]'] \n", " n) \n", " \n", " conv5_block3_2_conv (Conv2D) (None, 7, 7, 512) 2359808 ['conv5_block3_1_relu[0][0]'] \n", " \n", " conv5_block3_2_bn (BatchNormal (None, 7, 7, 512) 2048 ['conv5_block3_2_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block3_2_relu (Activatio (None, 7, 7, 512) 0 ['conv5_block3_2_bn[0][0]'] \n", " n) \n", " \n", " conv5_block3_3_conv (Conv2D) (None, 7, 7, 2048) 1050624 ['conv5_block3_2_relu[0][0]'] \n", " \n", " conv5_block3_3_bn (BatchNormal (None, 7, 7, 2048) 8192 ['conv5_block3_3_conv[0][0]'] \n", " ization) \n", " \n", " conv5_block3_add (Add) (None, 7, 7, 2048) 0 ['conv5_block2_out[0][0]', \n", " 'conv5_block3_3_bn[0][0]'] \n", " \n", " conv5_block3_out (Activation) (None, 7, 7, 2048) 0 ['conv5_block3_add[0][0]'] \n", " \n", " flatten_2 (Flatten) (None, 100352) 0 ['conv5_block3_out[0][0]'] \n", " \n", " dense_6 (Dense) (None, 5) 501765 ['flatten_2[0][0]'] \n", " \n", "==================================================================================================\n", "Total params: 24,089,477\n", "Trainable params: 501,765\n", "Non-trainable params: 23,587,712\n", "__________________________________________________________________________________________________\n" ] } ], "source": [ "# create a model object\n", "model = Model(inputs=resnet.input, outputs=prediction)\n", "\n", "# view the structure of the model\n", "model.summary()" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/var/folders/6b/j4d60ym516x2s6wymzj707rh0000gn/T/ipykernel_9339/2291254579.py:10: UserWarning: `Model.fit_generator` is deprecated and will be removed in a future version. Please use `Model.fit`, which supports generators.\n", " r = model.fit_generator(\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "25/25 [==============================] - 54s 2s/step - loss: 7.2784 - accuracy: 0.2350 - val_loss: 2.7387 - val_accuracy: 0.2240\n" ] } ], "source": [ "# tell the model what cost and optimization method to use\n", "model.compile(\n", " loss='sparse_categorical_crossentropy',\n", " optimizer='adam',\n", " metrics=['accuracy']\n", ")\n", "\n", "#train_ds_vgg_sw, test_ds_vgg_sw, validation_ds_vgg_sw\n", "# fit the model\n", "r = model.fit_generator(\n", " train_ds,\n", " validation_data=validation_ds,\n", " epochs=1,\n", " steps_per_epoch=len(train_ds),\n", " validation_steps=len(validation_ds)\n", ")" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAHHCAYAAACRAnNyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABGwklEQVR4nO3deXxN597///dOsDMnQkjSpqaaqjHUVHVaVE5JUdTUFDEEHdCietRNi/YUPTpoq3W3vUmOc4qipe1pNUVNNQ8nSg1FU/OsEjEkJNfvDz/7a0uQkGSt8Ho+HuvBvta11vqsJey3a11rb4cxxggAAMCGPKwuAAAA4FoIKgAAwLYIKgAAwLYIKgAAwLYIKgAAwLYIKgAAwLYIKgAAwLYIKgAAwLYIKgAAwLYIKgBy5HA4NHr06Dxv98cff8jhcCghISHfawJw5yGoADaWkJAgh8Mhh8Ohn3/+Odt6Y4wiIiLkcDjUunVrCyoEgIJFUAGKAC8vL02fPj1b+9KlS7V//345nU4LqgKAgkdQAYqAxx9/XLNnz9bFixfd2qdPn666desqNDTUosruHGfOnLG6BOCORFABioCYmBidOHFCCxYscLVlZGRozpw5evrpp3Pc5syZM3rppZcUEREhp9OpqlWr6u2339bVX5ienp6uwYMHKyQkRP7+/nriiSe0f//+HPd54MAB9e7dW2XLlpXT6VSNGjU0derUmzqnkydPaujQoYqMjJSfn58CAgIUHR2tTZs2Zet7/vx5jR49WlWqVJGXl5fCwsL05JNPavfu3a4+WVlZev/99xUZGSkvLy+FhISoZcuWWr9+vaTrz525ej7O6NGj5XA4tHXrVj399NMqWbKk/vKXv0iSfvnlF/Xs2VMVK1aUl5eXQkND1bt3b504cSLH6xUXF6fw8HA5nU5VqFBBzz33nDIyMvT777/L4XDovffey7bdypUr5XA4NGPGjLxeVuC2U8zqAgDcWPny5dWoUSPNmDFD0dHRkqT58+crJSVFTz31lD744AO3/sYYPfHEE1q8eLHi4uJUu3ZtJSYm6uWXX9aBAwfc3hz79Omjf//733r66af10EMP6aefflKrVq2y1XDkyBE9+OCDcjgcGjBggEJCQjR//nzFxcUpNTVVgwYNytM5/f7775o3b546deqkChUq6MiRI/rkk0/UpEkTbd26VeHh4ZKkzMxMtW7dWosWLdJTTz2lF198UadPn9aCBQu0ZcsWVapUSZIUFxenhIQERUdHq0+fPrp48aKWL1+u1atXq169enmq7bJOnTqpcuXKGjt2rCvgLViwQL///rt69eql0NBQ/frrr/r000/166+/avXq1XI4HJKkgwcPqkGDBjp16pT69eunatWq6cCBA5ozZ47Onj2rihUrqnHjxvr88881ePBgt+N+/vnn8vf3V9u2bW+qbuC2YgDYVnx8vJFk1q1bZyZNmmT8/f3N2bNnjTHGdOrUyTRr1swYY0y5cuVMq1atXNvNmzfPSDJ///vf3fbXsWNH43A4zK5du4wxxiQlJRlJ5vnnn3fr9/TTTxtJZtSoUa62uLg4ExYWZo4fP+7W96mnnjKBgYGuupKTk40kEx8ff91zO3/+vMnMzHRrS05ONk6n07z++uuutqlTpxpJ5t133822j6ysLGOMMT/99JORZF544YVr9rleXVef66hRo4wkExMTk63v5fO80owZM4wks2zZMldbbGys8fDwMOvWrbtmTZ988omRZLZt2+Zal5GRYUqXLm169OiRbTvgTsStH6CI6Ny5s86dO6f//Oc/On36tP7zn/9c87bP999/L09PT73wwgtu7S+99JKMMZo/f76rn6Rs/a4eHTHG6Msvv1SbNm1kjNHx48ddS4sWLZSSkqKNGzfm6XycTqc8PC79E5SZmakTJ07Iz89PVatWddvXl19+qdKlS2vgwIHZ9nF59OLLL7+Uw+HQqFGjrtnnZjz77LPZ2ry9vV2/P3/+vI4fP64HH3xQklx1Z2Vlad68eWrTpk2OozmXa+rcubO8vLz0+eefu9YlJibq+PHj6tat203XDdxOCCpAERESEqKoqChNnz5dX331lTIzM9WxY8cc++7Zs0fh4eHy9/d3a69evbpr/eVfPTw8XLdPLqtatarb62PHjunUqVP69NNPFRIS4rb06tVLknT06NE8nU9WVpbee+89Va5cWU6nU6VLl1ZISIh++eUXpaSkuPrt3r1bVatWVbFi175TvXv3boWHhys4ODhPNdxIhQoVsrWdPHlSL774osqWLStvb2+FhIS4+l2u+9ixY0pNTdX9999/3f0HBQWpTZs2bk90ff7557rrrrv06KOP5uOZAEUXc1SAIuTpp59W3759dfjwYUVHRysoKKhQjpuVlSVJ6tatm3r06JFjn5o1a+Zpn2PHjtWrr76q3r1764033lBwcLA8PDw0aNAg1/Hy07VGVjIzM6+5zZWjJ5d17txZK1eu1Msvv6zatWvLz89PWVlZatmy5U3VHRsbq9mzZ2vlypWKjIzUN998o+eff9412gTc6QgqQBHSvn17PfPMM1q9erW++OKLa/YrV66cFi5cqNOnT7uNqmzfvt21/vKvWVlZrlGLy3bs2OG2v8tPBGVmZioqKipfzmXOnDlq1qyZpkyZ4tZ+6tQplS5d2vW6UqVKWrNmjS5cuKDixYvnuK9KlSopMTFRJ0+evOaoSsmSJV37v9Ll0aXc+PPPP7Vo0SKNGTNGr732mqt9586dbv1CQkIUEBCgLVu23HCfLVu2VEhIiD7//HM1bNhQZ8+eVffu3XNdE3C7I7IDRYifn58mT56s0aNHq02bNtfs9/jjjyszM1OTJk1ya3/vvffkcDhcTw5d/vXqp4YmTpzo9trT01MdOnTQl19+meOb77Fjx/J8Lp6entkelZ49e7YOHDjg1tahQwcdP34827lIcm3foUMHGWM0ZsyYa/YJCAhQ6dKltWzZMrf1H3/8cZ5qvnKfl119vTw8PNSuXTt9++23rsejc6pJkooVK6aYmBjNmjVLCQkJioyMzPPoFHA7Y0QFKGKudevlSm3atFGzZs00YsQI/fHHH6pVq5Z+/PFHff311xo0aJBrTkrt2rUVExOjjz/+WCkpKXrooYe0aNEi7dq1K9s+x48fr8WLF6thw4bq27ev7rvvPp08eVIbN27UwoULdfLkyTydR+vWrfX666+rV69eeuihh7R582Z9/vnnqlixolu/2NhYTZs2TUOGDNHatWv18MMP68yZM1q4cKGef/55tW3bVs2aNVP37t31wQcfaOfOna7bMMuXL1ezZs00YMAASZcexR4/frz69OmjevXqadmyZfrtt99yXXNAQIAeeeQR/eMf/9CFCxd011136ccff1RycnK2vmPHjtWPP/6oJk2aqF+/fqpevboOHTqk2bNn6+eff3a7bRcbG6sPPvhAixcv1ltvvZWn6wjc9ix73gjADV35ePL1XP14sjHGnD592gwePNiEh4eb4sWLm8qVK5sJEya4Ho297Ny5c+aFF14wpUqVMr6+vqZNmzZm37592R7ZNcaYI0eOmP79+5uIiAhTvHhxExoaapo3b24+/fRTV5+8PJ780ksvmbCwMOPt7W0aN25sVq1aZZo0aWKaNGni1vfs2bNmxIgRpkKFCq7jduzY0ezevdvV5+LFi2bChAmmWrVqpkSJEiYkJMRER0ebDRs2uO0nLi7OBAYGGn9/f9O5c2dz9OjRaz6efOzYsWx179+/37Rv394EBQWZwMBA06lTJ3Pw4MEcr9eePXtMbGysCQkJMU6n01SsWNH079/fpKenZ9tvjRo1jIeHh9m/f/91rxtwp3EYc9UYJgCg0NWpU0fBwcFatGiR1aUAtsIcFQCw2Pr165WUlKTY2FirSwFshxEVALDIli1btGHDBr3zzjs6fvy4fv/9d3l5eVldFmArjKgAgEXmzJmjXr166cKFC5oxYwYhBcgBIyoAAMC2GFEBAAC2RVABAAC2VaQ/8C0rK0sHDx6Uv7//LX1DKgAAKDzGGJ0+fVrh4eE3/F6rIh1UDh48qIiICKvLAAAAN2Hfvn26++67r9unSAeVy1+2tm/fPgUEBFhcDQAAyI3U1FRFRES4fWnqtRTpoHL5dk9AQABBBQCAIiY30zaYTAsAAGyLoAIAAGyLoAIAAGyrSM9RAYCiLDMzUxcuXLC6DCDfFS9eXJ6envmyL4IKABQyY4wOHz6sU6dOWV0KUGCCgoIUGhp6y59zRlABgEJ2OaSUKVNGPj4+fGAlbivGGJ09e1ZHjx6VJIWFhd3S/ggqAFCIMjMzXSGlVKlSVpcDFAhvb29J0tGjR1WmTJlbug3EZFoAKESX56T4+PhYXAlQsC7/jN/qPCyCCgBYgNs9uN3l1884QQUAANgWQQUAANgWQQUAkCerVq2Sp6enWrVqZXUpuAMQVAAAeTJlyhQNHDhQy5Yt08GDBy2rIyMjw7Jjo/AQVAAAuZaWlqYvvvhCzz33nFq1aqWEhAS39d9++63q168vLy8vlS5dWu3bt3etS09P17BhwxQRESGn06l7771XU6ZMkSQlJCQoKCjIbV/z5s1zm5A5evRo1a5dW//3f/+nChUqyMvLS5L0ww8/6C9/+YuCgoJUqlQptW7dWrt373bb1/79+xUTE6Pg4GD5+vqqXr16WrNmjf744w95eHho/fr1bv0nTpyocuXKKSsr61YvGW4Rn6MCABYzxujchUxLju1d3DNPT2fMmjVL1apVU9WqVdWtWzcNGjRIw4cPl8Ph0Hfffaf27dtrxIgRmjZtmjIyMvT999+7to2NjdWqVav0wQcfqFatWkpOTtbx48fzVO+uXbv05Zdf6quvvnJ9NseZM2c0ZMgQ1axZU2lpaXrttdfUvn17JSUlycPDQ2lpaWrSpInuuusuffPNNwoNDdXGjRuVlZWl8uXLKyoqSvHx8apXr57rOPHx8erZs6c8PPj/vNUIKgBgsXMXMnXfa4mWHHvr6y3kUyL3bwVTpkxRt27dJEktW7ZUSkqKli5dqqZNm+rNN9/UU089pTFjxrj616pVS5L022+/adasWVqwYIGioqIkSRUrVsxzvRkZGZo2bZpCQkJcbR06dHDrM3XqVIWEhGjr1q26//77NX36dB07dkzr1q1TcHCwJOnee+919e/Tp4+effZZvfvuu3I6ndq4caM2b96sr7/+Os/1If8RFQEAubJjxw6tXbtWMTExkqRixYqpS5curts3SUlJat68eY7bJiUlydPTU02aNLmlGsqVK+cWUiRp586diomJUcWKFRUQEKDy5ctLkvbu3es6dp06dVwh5Wrt2rWTp6en5s6dK+nSbahmzZq59gNrMaICABbzLu6pra+3sOzYuTVlyhRdvHhR4eHhrjZjjJxOpyZNmuT62PQcj3OddZLk4eEhY4xbW06faOrr65utrU2bNipXrpw+++wzhYeHKysrS/fff79rsu2Njl2iRAnFxsYqPj5eTz75pKZPn67333//utug8BBUAMBiDocjT7dfrHDx4kVNmzZN77zzjh577DG3de3atdOMGTNUs2ZNLVq0SL169cq2fWRkpLKysrR06VLXrZ8rhYSE6PTp0zpz5owrjCQlJd2wrhMnTmjHjh367LPP9PDDD0uSfv75Z7c+NWvW1P/93//p5MmT1xxV6dOnj+6//359/PHHunjxop588skbHhuFw95/MwAAtvCf//xHf/75p+Li4hQYGOi2rkOHDpoyZYomTJig5s2bq1KlSnrqqad08eJFff/99xo2bJjKly+vHj16qHfv3q7JtHv27NHRo0fVuXNnNWzYUD4+Pvqf//kfvfDCC1qzZk22J4pyUrJkSZUqVUqffvqpwsLCtHfvXr3yyitufWJiYjR27Fi1a9dO48aNU1hYmP773/8qPDxcjRo1kiRVr15dDz74oIYNG6bevXvfcBQGhYc5KgCAG5oyZYqioqKyhRTpUlBZv369goOD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JG3atElPP/202+hQ+fLl1aNHD/Xu3Vvz5s1TcnKylixZolmzZrn6eHp6qmfPnho+fLgqV66c4625/EZQAQDkSVxcnP7880+1aNHCbT7JyJEj9cADD6hFixZq2rSpQkND1a5du1zv18PDQ3PnztW5c+fUoEED9enTR2+++aZbnyeeeEKDBw/WgAEDVLt2ba1cuVKvvvqqW58OHTqoZcuWatasmUJCQnJ8RNrHx0eJiYk6efKk6tevr44dO6p58+aaNGlS3i7GFS5PzM1pfknz5s3l7e2tf//73ypVqpR++uknpaWlqUmTJqpbt64+++wz122mHj16aOLEifr4449Vo0YNtW7dWjt37nTta+rUqbp48aLq1q2rQYMG6e9//3uu6nv33XdVsmRJPfTQQ2rTpo1atGihBx54wK3P5MmT1bFjRz3//POqVq2a+vbt6zbqJF3688/IyFCvXr3yeoluisNceaOriElNTVVgYKBSUlIUEBBgdTkAcEPnz59XcnKyKlSoIC8vL6vLAfJs+fLlat68ufbt23fd0afr/azn5f2bybQAAOCG0tPTdezYMY0ePVqdOnW66VtkecWtHwAAcEMzZsxQuXLldOrUKf3jH/8otOMSVAAAwA317NlTmZmZ2rBhg+66665COy5BBQAA2BZBBQAA2BZBBQAA2BZBBQAA2BZBBQAA2BZBBQAA2BZBBQAA2BZBBQCQKz179szTd/cA+YGgAgAAbIugAgC4ZUuXLlWDBg3kdDoVFhamV155RRcvXnStnzNnjiIjI+Xt7a1SpUopKirK9a28S5YsUYMGDeTr66ugoCA1btxYe/bssepUYDN8KSEAWMwYo3MXz1lybO9i3nI4HLe0jwMHDujxxx9Xz549NW3aNG3fvl19+/aVl5eXRo8erUOHDikmJkb/+Mc/1L59e50+fVrLly+XMUYXL15Uu3bt1LdvX82YMUMZGRlau3btLdeE2wdBBQAsdu7iOTWc3tCSY695eo18ivvc0j4+/vhjRUREaNKkSXI4HKpWrZoOHjyoYcOG6bXXXtOhQ4d08eJFPfnkkypXrpwkKTIyUpJ08uRJpaSkqHXr1qpUqZIkqXr16rd2UritcOsHAHBLtm3bpkaNGrmNgjRu3FhpaWnav3+/atWqpebNmysyMlKdOnXSZ599pj///FOSFBwcrJ49e6pFixZq06aN3n//fR06dMiqU4ENMaICABbzLuatNU+vsezYBc3T01MLFizQypUr9eOPP+rDDz/UiBEjtGbNGlWoUEHx8fF64YUX9MMPP+iLL77QyJEjtWDBAj344IMFXhvsj6ACABZzOBy3fPvFStWrV9eXX34pY4xrVGXFihXy9/fX3XffLenSOTZu3FiNGzfWa6+9pnLlymnu3LkaMmSIJKlOnTqqU6eOhg8frkaNGmn69OkEFUgiqAAA8iAlJUVJSUlubf369dPEiRM1cOBADRgwQDt27NCoUaM0ZMgQeXh4aM2aNVq0aJEee+wxlSlTRmvWrNGxY8dUvXp1JScn69NPP9UTTzyh8PBw7dixQzt37lRsbKw1JwjbIagAAHJtyZIlqlOnjltbXFycvv/+e7388suqVauWgoODFRcXp5EjR0qSAgICtGzZMk2cOFGpqakqV66c3nnnHUVHR+vIkSPavn27/vnPf+rEiRMKCwtT//799cwzz1hxerAhhzHGWF3EzUpNTVVgYKBSUlIUEBBgdTkAcEPnz59XcnKyKlSoIC8vL6vLAQrM9X7W8/L+zVM/AADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtggqAADAtiwPKgcOHFC3bt1UqlQpeXt7KzIyUuvXr7e6LAAAYAOWfjLtn3/+qcaNG6tZs2aaP3++QkJCtHPnTpUsWdLKsgAAgE1YOqLy1ltvKSIiQvHx8WrQoIEqVKigxx57TJUqVbKyLABAAWnatKkGDRrkel2+fHlNnDjxuts4HA7Nmzfvlo+dX/tB4bI0qHzzzTeqV6+eOnXqpDJlyqhOnTr67LPPrtk/PT1dqampbgsAoOC1adNGLVu2zHHd8uXL5XA49Msvv+R5v+vWrVO/fv1utTw3o0ePVu3atbO1Hzp0SNHR0fl6rKslJCQoKCioQI9xp7E0qPz++++aPHmyKleurMTERD333HN64YUX9M9//jPH/uPGjVNgYKBriYiIKOSKAeDOFBcXpwULFmj//v3Z1sXHx6tevXqqWbNmnvcbEhIiHx+f/CjxhkJDQ+V0OgvlWMg/lgaVrKwsPfDAAxo7dqzq1Kmjfv36qW/fvvrf//3fHPsPHz5cKSkprmXfvn2FXDEA3Jlat26tkJAQJSQkuLWnpaVp9uzZiouL04kTJxQTE6O77rpLPj4+ioyM1IwZM66736tv/ezcuVOPPPKIvLy8dN9992nBggXZthk2bJiqVKkiHx8fVaxYUa+++qouXLgg6dKIxpgxY7Rp0yY5HA45HA5XzVff+tm8ebMeffRReXt7q1SpUurXr5/S0tJc63v27Kl27drp7bffVlhYmEqVKqX+/fu7jnUz9u7dq7Zt28rPz08BAQHq3Lmzjhw54lq/adMmNWvWTP7+/goICFDdunVdD5js2bNHbdq0UcmSJeXr66saNWro+++/v+laigpLJ9OGhYXpvvvuc2urXr26vvzyyxz7O51O0jCA244xRubcOUuO7fD2lsPhuGG/YsWKKTY2VgkJCRoxYoRrm9mzZyszM1MxMTFKS0tT3bp1NWzYMAUEBOi7775T9+7dValSJTVo0OCGx8jKytKTTz6psmXLas2aNUpJSXGbz3KZv7+/EhISFB4ers2bN6tv377y9/fX3/72N3Xp0kVbtmzRDz/8oIULF0qSAgMDs+3jzJkzatGihRo1aqR169bp6NGj6tOnjwYMGOAWxhYvXqywsDAtXrxYu3btUpcuXVS7dm317dv3hueT0/ldDilLly7VxYsX1b9/f3Xp0kVLliyRJHXt2lV16tTR5MmT5enpqaSkJBUvXlyS1L9/f2VkZGjZsmXy9fXV1q1b5efnl+c6ihpLg0rjxo21Y8cOt7bffvtN5cqVs6giACh85tw57XigriXHrrpxgxy5vPXSu3dvTZgwQUuXLlXTpk0lXbrt06FDB9ct+aFDh7r6Dxw4UImJiZo1a1augsrChQu1fft2JSYmKjw8XJI0duzYbPNKRo4c6fp9+fLlNXToUM2cOVN/+9vf5O3tLT8/PxUrVkyhoaHXPNb06dN1/vx5TZs2Tb6+vpKkSZMmqU2bNnrrrbdUtmxZSVLJkiU1adIkeXp6qlq1amrVqpUWLVp0U0Fl0aJF2rx5s5KTk11TF6ZNm6YaNWpo3bp1ql+/vvbu3auXX35Z1apVkyRVrlzZtf3evXvVoUMHRUZGSpIqVqyY5xqKIktv/QwePFirV6/W2LFjtWvXLk2fPl2ffvqp+vfvb2VZAIAcVKtWTQ899JCmTp0qSdq1a5eWL1+uuLg4SVJmZqbeeOMNRUZGKjg4WH5+fkpMTNTevXtztf9t27YpIiLCFVIkqVGjRtn6ffHFF2rcuLFCQ0Pl5+enkSNH5voYVx6rVq1arpAiXfrPc1ZWltt/oGvUqCFPT0/X67CwMB09ejRPx7rymBEREW7zK++77z4FBQVp27ZtkqQhQ4aoT58+ioqK0vjx47V7925X3xdeeEF///vf1bhxY40aNeqmJi8XRZaOqNSvX19z587V8OHD9frrr6tChQqaOHGiunbtamVZAFCoHN7eqrpxg2XHzou4uDgNHDhQH330keLj41WpUiU1adJEkjRhwgS9//77mjhxoiIjI+Xr66tBgwYpIyMj3+pdtWqVunbtqjFjxqhFixYKDAzUzJkz9c477+TbMa50+bbLZQ6HQ1lZWQVyLOnSE0tPP/20vvvuO82fP1+jRo3SzJkz1b59e/Xp00ctWrTQd999px9//FHjxo3TO++8o4EDBxZYPXZgaVCRLk3Qat26tdVlAIBlHA5Hrm+/WK1z58568cUXNX36dE2bNk3PPfeca77KihUr1LZtW3Xr1k3SpTkZv/32W7a5iNdSvXp17du3T4cOHVJYWJgkafXq1W59Vq5cqXLlymnEiBGutj179rj1KVGihDIzM294rISEBJ05c8Y1qrJixQp5eHioatWquao3ry6f3759+1yjKlu3btWpU6fcrlGVKlVUpUoVDR48WDExMYqPj1f79u0lSREREXr22Wf17LPPavjw4frss89u+6Bi+UfoAwCKDj8/P3Xp0kXDhw/XoUOH1LNnT9e6ypUra8GCBVq5cqW2bdumZ555xu2JlhuJiopSlSpV1KNHD23atEnLly93CySXj7F3717NnDlTu3fv1gcffKC5c+e69SlfvrySk5OVlJSk48ePKz09PduxunbtKi8vL/Xo0UNbtmzR4sWLNXDgQHXv3t01P+VmZWZmKikpyW3Ztm2boqKiFBkZqa5du2rjxo1au3atYmNj1aRJE9WrV0/nzp3TgAEDtGTJEu3Zs0crVqzQunXrVL16dUnSoEGDlJiYqOTkZG3cuFGLFy92rbudEVQAAHkSFxenP//8Uy1atHCbTzJy5Eg98MADatGihZo2barQ0FC1a9cu1/v18PDQ3Llzde7cOTVo0EB9+vTRm2++6dbniSee0ODBgzVgwADVrl1bK1eu1KuvvurWp0OHDmrZsqWaNWumkJCQHB+R9vHxUWJiok6ePKn69eurY8eOat68uSZNmpS3i5GDtLQ01alTx21p06aNHA6Hvv76a5UsWVKPPPKIoqKiVLFiRX3xxReSJE9PT504cUKxsbGqUqWKOnfurOjoaI0ZM0bSpQDUv39/Va9eXS1btlSVKlX08ccf33K9ducwxhiri7hZqampCgwMVEpKigICAqwuBwBu6Pz580pOTlaFChXk5eVldTlAgbnez3pe3r8ZUQEAALZFUAEAALZFUAEAALZFUAEAALZFUAEACxTh5xiAXMmvn3GCCgAUosufdHr27FmLKwEK1uWf8as/3TevLP9kWgC4k3h6eiooKMj1fTE+Pj65+vZioKgwxujs2bM6evSogoKC3L4r6WYQVACgkF3+Vt+b/XI7oCgICgq67jdY5xZBBQAKmcPhUFhYmMqUKaMLFy5YXQ6Q74oXL37LIymXEVQAwCKenp759o85cLtiMi0AALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtggoAALAtS4PK6NGj5XA43JZq1apZWRIAALCRYlYXUKNGDS1cuND1ulgxy0sCAAA2YXkqKFasmEJDQ60uAwAA2JDlc1R27typ8PBwVaxYUV27dtXevXuv2Tc9PV2pqaluCwAAuH1ZGlQaNmyohIQE/fDDD5o8ebKSk5P18MMP6/Tp0zn2HzdunAIDA11LREREIVcMAAAKk8MYY6wu4rJTp06pXLlyevfddxUXF5dtfXp6utLT012vU1NTFRERoZSUFAUEBBRmqQAA4CalpqYqMDAwV+/fls9RuVJQUJCqVKmiXbt25bje6XTK6XQWclUAAMAqls9RuVJaWpp2796tsLAwq0sBAAA2YGlQGTp0qJYuXao//vhDK1euVPv27eXp6amYmBgrywIAADZh6a2f/fv3KyYmRidOnFBISIj+8pe/aPXq1QoJCbGyLAAAYBOWBpWZM2daeXgAAGBztpqjAgAAcCWCCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAAsC2CCgAA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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# loss\n", "plt.plot(r.history[\"accuracy\"])\n", "plt.plot(r.history['val_accuracy'])\n", "plt.plot(r.history['loss'])\n", "plt.plot(r.history['val_loss'])\n", "plt.title(\"Model accuracy\")\n", "plt.ylabel(\"Value\")\n", "plt.xlabel(\"Epoch\")\n", "plt.legend([\"Accuracy\",\"Validation Accuracy\",\"Loss\",\"Validation Loss\"])\n", "plt.show()\n", "\n", "model.save('resnet_1.h5')" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8/8 [==============================] - 12s 1s/step - loss: 2.9013 - accuracy: 0.2031\n" ] }, { "data": { "text/plain": [ "[2.901285171508789, 0.203125]" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model.evaluate(test_ds)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.6" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" } } }, "nbformat": 4, "nbformat_minor": 2 }