Files
COE379L_Project2/Project 2.ipynb

1310 lines
119 KiB
Plaintext
Raw Permalink Normal View History

2025-11-14 15:53:55 -06:00
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"id": "a6a514c3",
"metadata": {},
"outputs": [],
"source": [
"from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D, AveragePooling2D\n",
"from tensorflow.keras.optimizers import Adam\n",
"from tensorflow.keras import Sequential\n",
"import tensorflow as tf\n",
"import numpy as np\n",
"from PIL import Image"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "9dd43bb5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TensorFlow is configured to use the following GPUs:\n",
"PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')\n"
]
}
],
"source": [
"gpus = tf.config.list_physical_devices('GPU')\n",
"if gpus:\n",
" print(\"TensorFlow is configured to use the following GPUs:\")\n",
" for gpu in gpus:\n",
" print(gpu)\n",
"else:\n",
" print(\"TensorFlow is not configured to use any GPUs.\")\n",
"\n",
"# want to speed up training lol - maybe I can try VGG16\n",
"# This was done on my desktop with a 3060Ti"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "acde946d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"(128, 128, 3)\n"
]
}
],
"source": [
"print(np.asarray(Image.open('Data/damage/-93.795_30.03779.jpeg')).shape)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "d97582d5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 21322 files belonging to 2 classes.\n",
"Dataset created. Each batch shape: (batch_size, 128, 128, 3)\n"
]
}
],
"source": [
"# AI Generated, See [1]\n",
"from tensorflow.keras.preprocessing import image_dataset_from_directory\n",
"\n",
"# Load color JPEG images from directory structure:\n",
"# Data/\n",
"# ├── damage/\n",
"# └── no_damage/\n",
"\n",
"dataset = image_dataset_from_directory(\n",
" 'Data',\n",
" image_size=(128, 128),\n",
" batch_size=32,\n",
" label_mode='binary',\n",
" color_mode='rgb', # load as color for now.\n",
" shuffle=True,\n",
" seed=1\n",
")\n",
"\n",
"# Normalize pixel values to [0, 1] range for better training\n",
"normalization_layer = tf.keras.layers.Rescaling(1./255)\n",
"dataset = dataset.map(lambda x, y: (normalization_layer(x), y))\n",
"\n",
"# Optimize performance\n",
"dataset = dataset.prefetch(tf.data.AUTOTUNE)\n",
"\n",
"print(f\"Dataset created. Each batch shape: (batch_size, 128, 128, 3)\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "a54e1514",
"metadata": {},
"outputs": [],
"source": [
"size = tf.data.experimental.cardinality(dataset).numpy()\n",
"train_size = int(0.7*size)\n",
"eval_size = int(0.15*size)\n",
"test_size = size - train_size - eval_size ## used examples and documentation on tensorflow datasets to figure out how to split the tf dataset.\n",
"\n",
"train_set = dataset.take(train_size)\n",
"eval_set = dataset.skip(train_size).take(eval_size)\n",
"test_set = dataset.skip(train_size + eval_size).take(test_size)\n",
"\n",
"INPUT_SHAPE = (128, 128, 3)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "78ad8a27",
"metadata": {},
"outputs": [],
"source": [
"model = Sequential()\n",
"\n",
"model.add(Flatten(input_shape=INPUT_SHAPE))\n",
"model.add(Dense(8192, activation='relu', input_shape=(128*128*3,)))\n",
"model.add(Dense(512, activation='relu'))\n",
"model.add(Dense(1, activation='sigmoid')) # google search yielded that sigmoid is best for binary classification\n",
"# I also know we did as many outputs as classes for multi-class classification, but this made sense for binary classification.\n",
"# our decision function will be whether output > 0.5."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "2ac2b6d9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" flatten (Flatten) (None, 49152) 0 \n",
" \n",
" dense (Dense) (None, 8192) 402661376 \n",
" \n",
" dense_1 (Dense) (None, 512) 4194816 \n",
" \n",
" dense_2 (Dense) (None, 1) 513 \n",
" \n",
"=================================================================\n",
"Total params: 406,856,705\n",
"Trainable params: 406,856,705\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.compile(optimizer=Adam(learning_rate=0.001), # tweaked learning rate for optimal validation accuracy...\n",
" loss='binary_crossentropy', # This is used for binary classification\n",
" metrics=['accuracy'])\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "32ebf84f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/10\n",
"466/466 - 28s - loss: 2.1829 - accuracy: 0.6406 - val_loss: 0.6086 - val_accuracy: 0.6656 - 28s/epoch - 61ms/step\n",
"Epoch 2/10\n",
"466/466 - 28s - loss: 0.6037 - accuracy: 0.6912 - val_loss: 0.6005 - val_accuracy: 0.6850 - 28s/epoch - 60ms/step\n",
"Epoch 3/10\n",
"466/466 - 28s - loss: 0.5818 - accuracy: 0.7039 - val_loss: 0.6081 - val_accuracy: 0.6947 - 28s/epoch - 59ms/step\n",
"Epoch 4/10\n",
"466/466 - 28s - loss: 0.5727 - accuracy: 0.7214 - val_loss: 0.6248 - val_accuracy: 0.6925 - 28s/epoch - 60ms/step\n",
"Epoch 5/10\n",
"466/466 - 29s - loss: 0.5704 - accuracy: 0.7217 - val_loss: 0.5795 - val_accuracy: 0.7122 - 29s/epoch - 62ms/step\n",
"Epoch 6/10\n",
"466/466 - 28s - loss: 0.5612 - accuracy: 0.7334 - val_loss: 0.5546 - val_accuracy: 0.7344 - 28s/epoch - 61ms/step\n",
"Epoch 7/10\n",
"466/466 - 29s - loss: 0.5804 - accuracy: 0.7141 - val_loss: 0.5565 - val_accuracy: 0.7303 - 29s/epoch - 62ms/step\n",
"Epoch 8/10\n",
"466/466 - 29s - loss: 0.5577 - accuracy: 0.7288 - val_loss: 0.5608 - val_accuracy: 0.7366 - 29s/epoch - 61ms/step\n",
"Epoch 9/10\n",
"466/466 - 28s - loss: 0.5715 - accuracy: 0.7185 - val_loss: 0.6075 - val_accuracy: 0.6925 - 28s/epoch - 61ms/step\n",
"Epoch 10/10\n",
"466/466 - 28s - loss: 0.5649 - accuracy: 0.7266 - val_loss: 0.5778 - val_accuracy: 0.6997 - 28s/epoch - 60ms/step\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2ae33a8f820>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(train_set, validation_data=eval_set, epochs=10, batch_size=32, verbose=2)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "70bd7f55",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Evaluating model on the test set...\n",
"101/101 [==============================] - 2s 9ms/step - loss: 0.5653 - accuracy: 0.7137\n",
"Test Loss: 0.5652936697006226\n",
"Test Accuracy: 0.7137071490287781\n"
]
}
],
"source": [
"print(\"Evaluating model on the test set...\")\n",
"loss, accuracy = model.evaluate(test_set)\n",
"\n",
"print(f\"Test Loss: {loss}\")\n",
"print(f\"Test Accuracy: {accuracy}\")"
]
},
{
"cell_type": "markdown",
"id": "7ec85434",
"metadata": {},
"source": [
"## Review\n",
"We got 71.3% accuracy with the ANN on damage classification. Not abysmal, but not even 3/4 accurate."
]
},
{
"cell_type": "markdown",
"id": "c40cb450",
"metadata": {},
"source": [
"## LeNet-5 Architecture"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "a4762a81",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"405"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Generated by AI - see [2]\n",
"import gc\n",
"\n",
"del model # Delete the model object\n",
"tf.keras.backend.clear_session() # Clear the Keras backend session\n",
"gc.collect() # Force garbage collection"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "accbb768",
"metadata": {},
"outputs": [],
"source": [
"# from readthedocs for COE379L\n",
"\n",
"model = Sequential()\n",
"\n",
"# Layer 1: Convolutional layer with 6 filters of size 5x5, followed by average pooling\n",
"model.add(Conv2D(6, kernel_size=(5, 5), activation='relu', input_shape=INPUT_SHAPE))\n",
"model.add(AveragePooling2D(pool_size=(2, 2)))\n",
"\n",
"# Layer 2: Convolutional layer with 16 filters of size 5x5, followed by average pooling\n",
"model.add(Conv2D(16, kernel_size=(5, 5), activation='relu'))\n",
"model.add(AveragePooling2D(pool_size=(2, 2)))\n",
"\n",
"# Flatten the feature maps to feed into fully connected layers\n",
"model.add(Flatten())\n",
"\n",
"# Layer 3: Fully connected layer with 120 neurons\n",
"model.add(Dense(120, activation='relu'))\n",
"\n",
"# Layer 4: Fully connected layer with 84 neurons\n",
"model.add(Dense(84, activation='relu'))\n",
"\n",
"# Output layer: Fully connected layer with num_classes neurons (e.g., 10 for MNIST)\n",
"model.add(Dense(1, activation='sigmoid')) # Using sigmoid for binary classification"
]
},
{
"cell_type": "code",
"execution_count": 26,
"id": "38709719",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" conv2d (Conv2D) (None, 124, 124, 6) 456 \n",
" \n",
" average_pooling2d (AverageP (None, 62, 62, 6) 0 \n",
" ooling2D) \n",
" \n",
" conv2d_1 (Conv2D) (None, 58, 58, 16) 2416 \n",
" \n",
" average_pooling2d_1 (Averag (None, 29, 29, 16) 0 \n",
" ePooling2D) \n",
" \n",
" flatten (Flatten) (None, 13456) 0 \n",
" \n",
" dense (Dense) (None, 120) 1614840 \n",
" \n",
" dense_1 (Dense) (None, 84) 10164 \n",
" \n",
" dense_2 (Dense) (None, 1) 85 \n",
" \n",
"=================================================================\n",
"Total params: 1,627,961\n",
"Trainable params: 1,627,961\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.compile(optimizer='adam',\n",
" loss='binary_crossentropy',\n",
" metrics=['accuracy'])\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 27,
"id": "53076eba",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/20\n",
"466/466 - 6s - loss: 0.4877 - accuracy: 0.7623 - val_loss: 0.2477 - val_accuracy: 0.9000 - 6s/epoch - 14ms/step\n",
"Epoch 2/20\n",
"466/466 - 6s - loss: 0.2384 - accuracy: 0.9068 - val_loss: 0.1885 - val_accuracy: 0.9209 - 6s/epoch - 13ms/step\n",
"Epoch 3/20\n",
"466/466 - 6s - loss: 0.2021 - accuracy: 0.9221 - val_loss: 0.1943 - val_accuracy: 0.9219 - 6s/epoch - 13ms/step\n",
"Epoch 4/20\n",
"466/466 - 6s - loss: 0.1619 - accuracy: 0.9372 - val_loss: 0.1546 - val_accuracy: 0.9350 - 6s/epoch - 12ms/step\n",
"Epoch 5/20\n",
"466/466 - 6s - loss: 0.1365 - accuracy: 0.9464 - val_loss: 0.1441 - val_accuracy: 0.9431 - 6s/epoch - 13ms/step\n",
"Epoch 6/20\n",
"466/466 - 6s - loss: 0.1371 - accuracy: 0.9474 - val_loss: 0.1876 - val_accuracy: 0.9294 - 6s/epoch - 13ms/step\n",
"Epoch 7/20\n",
"466/466 - 6s - loss: 0.0859 - accuracy: 0.9692 - val_loss: 0.1660 - val_accuracy: 0.9347 - 6s/epoch - 12ms/step\n",
"Epoch 8/20\n",
"466/466 - 6s - loss: 0.0740 - accuracy: 0.9740 - val_loss: 0.1469 - val_accuracy: 0.9462 - 6s/epoch - 12ms/step\n",
"Epoch 9/20\n",
"466/466 - 6s - loss: 0.0514 - accuracy: 0.9815 - val_loss: 0.1547 - val_accuracy: 0.9512 - 6s/epoch - 12ms/step\n",
"Epoch 10/20\n",
"466/466 - 6s - loss: 0.0392 - accuracy: 0.9873 - val_loss: 0.2277 - val_accuracy: 0.9456 - 6s/epoch - 12ms/step\n",
"Epoch 11/20\n",
"466/466 - 6s - loss: 0.0459 - accuracy: 0.9851 - val_loss: 0.1725 - val_accuracy: 0.9503 - 6s/epoch - 12ms/step\n",
"Epoch 12/20\n",
"466/466 - 6s - loss: 0.0418 - accuracy: 0.9871 - val_loss: 0.2082 - val_accuracy: 0.9484 - 6s/epoch - 12ms/step\n",
"Epoch 13/20\n",
"466/466 - 6s - loss: 0.0217 - accuracy: 0.9930 - val_loss: 0.2124 - val_accuracy: 0.9478 - 6s/epoch - 12ms/step\n",
"Epoch 14/20\n",
"466/466 - 6s - loss: 0.0189 - accuracy: 0.9943 - val_loss: 0.2859 - val_accuracy: 0.9331 - 6s/epoch - 12ms/step\n",
"Epoch 15/20\n",
"466/466 - 6s - loss: 0.0556 - accuracy: 0.9832 - val_loss: 0.2833 - val_accuracy: 0.9284 - 6s/epoch - 12ms/step\n",
"Epoch 16/20\n",
"466/466 - 6s - loss: 0.0247 - accuracy: 0.9924 - val_loss: 0.2470 - val_accuracy: 0.9444 - 6s/epoch - 12ms/step\n",
"Epoch 17/20\n",
"466/466 - 6s - loss: 0.0107 - accuracy: 0.9968 - val_loss: 0.2742 - val_accuracy: 0.9391 - 6s/epoch - 12ms/step\n",
"Epoch 18/20\n",
"466/466 - 6s - loss: 0.0177 - accuracy: 0.9945 - val_loss: 0.2596 - val_accuracy: 0.9469 - 6s/epoch - 13ms/step\n",
"Epoch 19/20\n",
"466/466 - 6s - loss: 0.0020 - accuracy: 0.9997 - val_loss: 0.4816 - val_accuracy: 0.9244 - 6s/epoch - 12ms/step\n",
"Epoch 20/20\n",
"466/466 - 6s - loss: 0.0302 - accuracy: 0.9905 - val_loss: 0.2815 - val_accuracy: 0.9412 - 6s/epoch - 13ms/step\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2ae35e4aa40>"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(train_set, validation_data=eval_set, epochs=20, batch_size=32, verbose=2)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "6226ee23",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Evaluating model on the test set...\n",
"101/101 [==============================] - 2s 7ms/step - loss: 0.2875 - accuracy: 0.9402\n",
"Test Loss: 0.2874923050403595\n",
"Test Accuracy: 0.9401868581771851\n"
]
}
],
"source": [
"print(\"Evaluating model on the test set...\")\n",
"loss, accuracy = model.evaluate(test_set)\n",
"\n",
"print(f\"Test Loss: {loss}\")\n",
"print(f\"Test Accuracy: {accuracy}\")"
]
},
{
"cell_type": "markdown",
"id": "4cf4e747",
"metadata": {},
"source": [
"## Review\n",
"The LeNet-5 model, with only specification of input size and modification of output layer to fit our classification needs, achieved 94% accuracy, stunningly better than a pure ANN."
]
},
{
"attachments": {
"image.png": {
"image/png": "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
}
},
"cell_type": "markdown",
"id": "8b8dc5cd",
"metadata": {},
"source": [
"## Alternate-LeNet-5\n",
"\n",
"Using the following implementation as outlined in the linked research paper.\n",
"\n",
"https://arxiv.org/pdf/1807.01688\n",
"\n",
"![image.png](attachment:image.png)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b227ae15",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1620"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"del model # Delete the model object\n",
"tf.keras.backend.clear_session() # Clear the Keras backend session\n",
"gc.collect() # Force garbage collection"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "176909e0",
"metadata": {},
"outputs": [],
"source": [
"# reconstructed from Quoc Dung Cao, Youngjun Choe research paper linked above\n",
"\n",
"model = Sequential()\n",
"\n",
"model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=INPUT_SHAPE))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"\n",
"model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"\n",
"model.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"\n",
"model.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"\n",
"model.add(Flatten())\n",
"model.add(Dropout(0.5))\n",
"\n",
"model.add(Dense(512, activation='relu'))\n",
"\n",
"model.add(Dense(1, activation='sigmoid'))"
]
},
{
"cell_type": "code",
"execution_count": 34,
"id": "fd7abac9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" conv2d (Conv2D) (None, 126, 126, 32) 896 \n",
" \n",
" max_pooling2d (MaxPooling2D (None, 63, 63, 32) 0 \n",
" ) \n",
" \n",
" conv2d_1 (Conv2D) (None, 61, 61, 64) 18496 \n",
" \n",
" max_pooling2d_1 (MaxPooling (None, 30, 30, 64) 0 \n",
" 2D) \n",
" \n",
" conv2d_2 (Conv2D) (None, 28, 28, 128) 73856 \n",
" \n",
" max_pooling2d_2 (MaxPooling (None, 14, 14, 128) 0 \n",
" 2D) \n",
" \n",
" conv2d_3 (Conv2D) (None, 12, 12, 128) 147584 \n",
" \n",
" max_pooling2d_3 (MaxPooling (None, 6, 6, 128) 0 \n",
" 2D) \n",
" \n",
" flatten (Flatten) (None, 4608) 0 \n",
" \n",
" dropout (Dropout) (None, 4608) 0 \n",
" \n",
" dense (Dense) (None, 512) 2359808 \n",
" \n",
" dense_1 (Dense) (None, 1) 513 \n",
" \n",
"=================================================================\n",
"Total params: 2,601,153\n",
"Trainable params: 2,601,153\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.compile(optimizer='adam',\n",
" loss='binary_crossentropy',\n",
" metrics=['accuracy'])\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "355ac8e2",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/20\n",
"466/466 - 9s - loss: 0.3474 - accuracy: 0.8470 - val_loss: 0.1996 - val_accuracy: 0.9191 - 9s/epoch - 18ms/step\n",
"Epoch 2/20\n",
"466/466 - 7s - loss: 0.1778 - accuracy: 0.9319 - val_loss: 0.1495 - val_accuracy: 0.9412 - 7s/epoch - 15ms/step\n",
"Epoch 3/20\n",
"466/466 - 7s - loss: 0.1538 - accuracy: 0.9411 - val_loss: 0.1291 - val_accuracy: 0.9497 - 7s/epoch - 16ms/step\n",
"Epoch 4/20\n",
"466/466 - 7s - loss: 0.1199 - accuracy: 0.9545 - val_loss: 0.0982 - val_accuracy: 0.9638 - 7s/epoch - 16ms/step\n",
"Epoch 5/20\n",
"466/466 - 7s - loss: 0.1168 - accuracy: 0.9561 - val_loss: 0.1072 - val_accuracy: 0.9616 - 7s/epoch - 16ms/step\n",
"Epoch 6/20\n",
"466/466 - 7s - loss: 0.0910 - accuracy: 0.9667 - val_loss: 0.1278 - val_accuracy: 0.9534 - 7s/epoch - 16ms/step\n",
"Epoch 7/20\n",
"466/466 - 7s - loss: 0.0847 - accuracy: 0.9678 - val_loss: 0.1191 - val_accuracy: 0.9512 - 7s/epoch - 15ms/step\n",
"Epoch 8/20\n",
"466/466 - 7s - loss: 0.0771 - accuracy: 0.9710 - val_loss: 0.1312 - val_accuracy: 0.9559 - 7s/epoch - 15ms/step\n",
"Epoch 9/20\n",
"466/466 - 7s - loss: 0.0696 - accuracy: 0.9742 - val_loss: 0.0831 - val_accuracy: 0.9691 - 7s/epoch - 16ms/step\n",
"Epoch 10/20\n",
"466/466 - 7s - loss: 0.0664 - accuracy: 0.9762 - val_loss: 0.0856 - val_accuracy: 0.9688 - 7s/epoch - 15ms/step\n",
"Epoch 11/20\n",
"466/466 - 7s - loss: 0.0617 - accuracy: 0.9777 - val_loss: 0.0782 - val_accuracy: 0.9766 - 7s/epoch - 15ms/step\n",
"Epoch 12/20\n",
"466/466 - 7s - loss: 0.0541 - accuracy: 0.9807 - val_loss: 0.0725 - val_accuracy: 0.9744 - 7s/epoch - 15ms/step\n",
"Epoch 13/20\n",
"466/466 - 7s - loss: 0.0546 - accuracy: 0.9804 - val_loss: 0.0857 - val_accuracy: 0.9678 - 7s/epoch - 16ms/step\n",
"Epoch 14/20\n",
"466/466 - 7s - loss: 0.0441 - accuracy: 0.9849 - val_loss: 0.0788 - val_accuracy: 0.9750 - 7s/epoch - 15ms/step\n",
"Epoch 15/20\n",
"466/466 - 7s - loss: 0.0406 - accuracy: 0.9859 - val_loss: 0.0534 - val_accuracy: 0.9822 - 7s/epoch - 16ms/step\n",
"Epoch 16/20\n",
"466/466 - 7s - loss: 0.0351 - accuracy: 0.9873 - val_loss: 0.1637 - val_accuracy: 0.9506 - 7s/epoch - 15ms/step\n",
"Epoch 17/20\n",
"466/466 - 7s - loss: 0.0301 - accuracy: 0.9895 - val_loss: 0.0535 - val_accuracy: 0.9831 - 7s/epoch - 15ms/step\n",
"Epoch 18/20\n",
"466/466 - 7s - loss: 0.0356 - accuracy: 0.9859 - val_loss: 0.0538 - val_accuracy: 0.9812 - 7s/epoch - 15ms/step\n",
"Epoch 19/20\n",
"466/466 - 7s - loss: 0.0295 - accuracy: 0.9891 - val_loss: 0.0696 - val_accuracy: 0.9756 - 7s/epoch - 16ms/step\n",
"Epoch 20/20\n",
"466/466 - 7s - loss: 0.0236 - accuracy: 0.9916 - val_loss: 0.0556 - val_accuracy: 0.9800 - 7s/epoch - 15ms/step\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2aec3e9f070>"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(train_set, validation_data=eval_set, epochs=20, batch_size=32, verbose=2)"
]
},
{
"cell_type": "code",
"execution_count": 36,
"id": "9aeaaa8a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Evaluating model on the test set...\n",
"101/101 [==============================] - 2s 8ms/step - loss: 0.0690 - accuracy: 0.9723\n",
"Test Loss: 0.06901176273822784\n",
"Test Accuracy: 0.972274124622345\n"
]
}
],
"source": [
"print(\"Evaluating model on the test set...\")\n",
"loss, accuracy = model.evaluate(test_set)\n",
"\n",
"print(f\"Test Loss: {loss}\")\n",
"print(f\"Test Accuracy: {accuracy}\")"
]
},
{
"cell_type": "markdown",
"id": "3179517e",
"metadata": {},
"source": [
"## Review\n",
"Nice! We're getting significantly higher than even the regular LeNet5 implementation! 97.2% test accuracy.\n",
"\n",
"Let's try an alternate implementation I saw in the research paper using full dropout"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "ce2681ff",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1496"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"del model # Delete the model object\n",
"tf.keras.backend.clear_session() # Clear the Keras backend session\n",
"gc.collect() # Force garbage collection"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "31d60ea7",
"metadata": {},
"outputs": [],
"source": [
"# reconstructed from Quoc Dung Cao, Youngjun Choe research paper linked above\n",
"\n",
"model = Sequential()\n",
"\n",
"model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=INPUT_SHAPE))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"model.add(Dropout(0.25))\n",
"\n",
"model.add(Conv2D(64, kernel_size=(3, 3), activation='relu'))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"model.add(Dropout(0.25))\n",
"\n",
"model.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"model.add(Dropout(0.25))\n",
"\n",
"model.add(Conv2D(128, kernel_size=(3, 3), activation='relu'))\n",
"model.add(MaxPooling2D(pool_size=(2, 2)))\n",
"model.add(Dropout(0.25))\n",
"\n",
"model.add(Flatten())\n",
"model.add(Dropout(0.5))\n",
"\n",
"model.add(Dense(512, activation='relu'))\n",
"\n",
"model.add(Dense(1, activation='sigmoid'))"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "abd7055a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" conv2d (Conv2D) (None, 126, 126, 32) 896 \n",
" \n",
" max_pooling2d (MaxPooling2D (None, 63, 63, 32) 0 \n",
" ) \n",
" \n",
" dropout (Dropout) (None, 63, 63, 32) 0 \n",
" \n",
" conv2d_1 (Conv2D) (None, 61, 61, 64) 18496 \n",
" \n",
" max_pooling2d_1 (MaxPooling (None, 30, 30, 64) 0 \n",
" 2D) \n",
" \n",
" dropout_1 (Dropout) (None, 30, 30, 64) 0 \n",
" \n",
" conv2d_2 (Conv2D) (None, 28, 28, 128) 73856 \n",
" \n",
" max_pooling2d_2 (MaxPooling (None, 14, 14, 128) 0 \n",
" 2D) \n",
" \n",
" dropout_2 (Dropout) (None, 14, 14, 128) 0 \n",
" \n",
" conv2d_3 (Conv2D) (None, 12, 12, 128) 147584 \n",
" \n",
" max_pooling2d_3 (MaxPooling (None, 6, 6, 128) 0 \n",
" 2D) \n",
" \n",
" dropout_3 (Dropout) (None, 6, 6, 128) 0 \n",
" \n",
" flatten (Flatten) (None, 4608) 0 \n",
" \n",
" dropout_4 (Dropout) (None, 4608) 0 \n",
" \n",
" dense (Dense) (None, 512) 2359808 \n",
" \n",
" dense_1 (Dense) (None, 1) 513 \n",
" \n",
"=================================================================\n",
"Total params: 2,601,153\n",
"Trainable params: 2,601,153\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.compile(optimizer='adam',\n",
" loss='binary_crossentropy',\n",
" metrics=['accuracy'])\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "7805e967",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/20\n",
"466/466 - 14s - loss: 0.4298 - accuracy: 0.8050 - val_loss: 0.2053 - val_accuracy: 0.9262 - 14s/epoch - 30ms/step\n",
"Epoch 2/20\n",
"466/466 - 8s - loss: 0.1968 - accuracy: 0.9272 - val_loss: 0.1491 - val_accuracy: 0.9384 - 8s/epoch - 16ms/step\n",
"Epoch 3/20\n",
"466/466 - 8s - loss: 0.1473 - accuracy: 0.9448 - val_loss: 0.1412 - val_accuracy: 0.9525 - 8s/epoch - 17ms/step\n",
"Epoch 4/20\n",
"466/466 - 8s - loss: 0.1342 - accuracy: 0.9486 - val_loss: 0.1384 - val_accuracy: 0.9541 - 8s/epoch - 16ms/step\n",
"Epoch 5/20\n",
"466/466 - 8s - loss: 0.1177 - accuracy: 0.9553 - val_loss: 0.1087 - val_accuracy: 0.9613 - 8s/epoch - 16ms/step\n",
"Epoch 6/20\n",
"466/466 - 8s - loss: 0.1134 - accuracy: 0.9586 - val_loss: 0.1008 - val_accuracy: 0.9641 - 8s/epoch - 16ms/step\n",
"Epoch 7/20\n",
"466/466 - 8s - loss: 0.1112 - accuracy: 0.9592 - val_loss: 0.1058 - val_accuracy: 0.9597 - 8s/epoch - 16ms/step\n",
"Epoch 8/20\n",
"466/466 - 8s - loss: 0.0979 - accuracy: 0.9626 - val_loss: 0.0776 - val_accuracy: 0.9716 - 8s/epoch - 16ms/step\n",
"Epoch 9/20\n",
"466/466 - 8s - loss: 0.0925 - accuracy: 0.9642 - val_loss: 0.0819 - val_accuracy: 0.9709 - 8s/epoch - 17ms/step\n",
"Epoch 10/20\n",
"466/466 - 8s - loss: 0.0810 - accuracy: 0.9702 - val_loss: 0.1525 - val_accuracy: 0.9419 - 8s/epoch - 17ms/step\n",
"Epoch 11/20\n",
"466/466 - 8s - loss: 0.0794 - accuracy: 0.9709 - val_loss: 0.1138 - val_accuracy: 0.9594 - 8s/epoch - 16ms/step\n",
"Epoch 12/20\n",
"466/466 - 8s - loss: 0.0744 - accuracy: 0.9723 - val_loss: 0.0609 - val_accuracy: 0.9775 - 8s/epoch - 16ms/step\n",
"Epoch 13/20\n",
"466/466 - 8s - loss: 0.0764 - accuracy: 0.9717 - val_loss: 0.0733 - val_accuracy: 0.9709 - 8s/epoch - 16ms/step\n",
"Epoch 14/20\n",
"466/466 - 8s - loss: 0.0719 - accuracy: 0.9759 - val_loss: 0.0857 - val_accuracy: 0.9675 - 8s/epoch - 17ms/step\n",
"Epoch 15/20\n",
"466/466 - 8s - loss: 0.0691 - accuracy: 0.9738 - val_loss: 0.0607 - val_accuracy: 0.9756 - 8s/epoch - 16ms/step\n",
"Epoch 16/20\n",
"466/466 - 8s - loss: 0.0656 - accuracy: 0.9765 - val_loss: 0.0777 - val_accuracy: 0.9712 - 8s/epoch - 17ms/step\n",
"Epoch 17/20\n",
"466/466 - 8s - loss: 0.0576 - accuracy: 0.9796 - val_loss: 0.0735 - val_accuracy: 0.9712 - 8s/epoch - 16ms/step\n",
"Epoch 18/20\n",
"466/466 - 8s - loss: 0.0647 - accuracy: 0.9773 - val_loss: 0.0829 - val_accuracy: 0.9675 - 8s/epoch - 16ms/step\n",
"Epoch 19/20\n",
"466/466 - 8s - loss: 0.0504 - accuracy: 0.9817 - val_loss: 0.0828 - val_accuracy: 0.9706 - 8s/epoch - 17ms/step\n",
"Epoch 20/20\n",
"466/466 - 8s - loss: 0.0518 - accuracy: 0.9813 - val_loss: 0.0587 - val_accuracy: 0.9800 - 8s/epoch - 16ms/step\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x17b5a67d660>"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(train_set, validation_data=eval_set, epochs=20, batch_size=32, verbose=2)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "6796fddd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Evaluating model on the test set...\n",
"101/101 [==============================] - 3s 13ms/step - loss: 0.0634 - accuracy: 0.9785\n",
"Test Loss: 0.06337141245603561\n",
"Test Accuracy: 0.9785046577453613\n"
]
}
],
"source": [
"print(\"Evaluating model on the test set...\")\n",
"loss, accuracy = model.evaluate(test_set)\n",
"\n",
"print(f\"Test Loss: {loss}\")\n",
"print(f\"Test Accuracy: {accuracy}\")"
]
},
{
"cell_type": "markdown",
"id": "062ebc4c",
"metadata": {},
"source": [
"## Review\n",
"Full dropout slightly improved test performance to 97.85% accuracy, showing its possible value in combating overfitting. Let's go ahead and persist this model."
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "6299d82f",
"metadata": {},
"outputs": [],
"source": [
"model.save('LeNetFullDropout.keras')"
]
},
{
"cell_type": "markdown",
"id": "b5ab2a55",
"metadata": {},
"source": [
"Let's finish off with some VGG16!"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "c8e1d164",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"76"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"del model # Delete the model object\n",
"tf.keras.backend.clear_session() # Clear the Keras backend session\n",
"gc.collect() # Force garbage collection"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "ed65b102",
"metadata": {},
"outputs": [],
"source": [
"from keras.applications.vgg16 import VGG16\n",
"\n",
"# Following aided significantly by AI - see [3]\n",
"vgg_base = VGG16(weights='imagenet', include_top=False, input_shape=INPUT_SHAPE)\n",
"\n",
"vgg_base.trainable = False # Freeze the base model\n",
"\n",
"# 3. Create a new model with custom top layers\n",
"model = Sequential()\n",
"model.add(vgg_base)\n",
"model.add(Flatten())\n",
"model.add(Dense(256, activation='relu'))\n",
"model.add(Dropout(0.5)) # Regularization to prevent overfitting\n",
"model.add(Dense(1, activation='sigmoid')) # Single neuron with sigmoid for binary classification\n",
"\n",
"# 4. Compile the model\n",
"model.compile(\n",
" optimizer=Adam(learning_rate=0.0001), # Lower learning rate often better for transfer learning\n",
" loss='binary_crossentropy',\n",
" metrics=['accuracy']\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 44,
"id": "f4139d04",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/10\n",
"466/466 - 18s - loss: 0.2548 - accuracy: 0.8989 - val_loss: 0.2039 - val_accuracy: 0.9203 - 18s/epoch - 38ms/step\n",
"Epoch 2/10\n",
"466/466 - 17s - loss: 0.1924 - accuracy: 0.9262 - val_loss: 0.1783 - val_accuracy: 0.9303 - 17s/epoch - 36ms/step\n",
"Epoch 3/10\n",
"466/466 - 17s - loss: 0.1704 - accuracy: 0.9334 - val_loss: 0.1660 - val_accuracy: 0.9331 - 17s/epoch - 37ms/step\n",
"Epoch 4/10\n",
"466/466 - 17s - loss: 0.1551 - accuracy: 0.9415 - val_loss: 0.1590 - val_accuracy: 0.9322 - 17s/epoch - 37ms/step\n",
"Epoch 5/10\n",
"466/466 - 17s - loss: 0.1433 - accuracy: 0.9443 - val_loss: 0.1562 - val_accuracy: 0.9337 - 17s/epoch - 37ms/step\n",
"Epoch 6/10\n",
"466/466 - 17s - loss: 0.1334 - accuracy: 0.9472 - val_loss: 0.1530 - val_accuracy: 0.9362 - 17s/epoch - 37ms/step\n",
"Epoch 7/10\n",
"466/466 - 17s - loss: 0.1246 - accuracy: 0.9521 - val_loss: 0.1503 - val_accuracy: 0.9394 - 17s/epoch - 37ms/step\n",
"Epoch 8/10\n",
"466/466 - 17s - loss: 0.1169 - accuracy: 0.9560 - val_loss: 0.1522 - val_accuracy: 0.9366 - 17s/epoch - 36ms/step\n",
"Epoch 9/10\n",
"466/466 - 17s - loss: 0.1093 - accuracy: 0.9576 - val_loss: 0.1462 - val_accuracy: 0.9406 - 17s/epoch - 37ms/step\n",
"Epoch 10/10\n",
"466/466 - 17s - loss: 0.1023 - accuracy: 0.9604 - val_loss: 0.1395 - val_accuracy: 0.9434 - 17s/epoch - 37ms/step\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2afcb341c60>"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(train_set, validation_data=eval_set, epochs=10, batch_size=32, verbose=2)"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "f92a2256",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Evaluating model on the test set...\n",
"101/101 [==============================] - 4s 30ms/step - loss: 0.1548 - accuracy: 0.9361\n",
"Test Loss: 0.15479429066181183\n",
"Test Accuracy: 0.9361370205879211\n"
]
}
],
"source": [
"print(\"Evaluating model on the test set...\")\n",
"loss, accuracy = model.evaluate(test_set)\n",
"\n",
"print(f\"Test Loss: {loss}\")\n",
"print(f\"Test Accuracy: {accuracy}\")"
]
},
{
"cell_type": "markdown",
"id": "d7305533",
"metadata": {},
"source": [
"## Review\n",
"\n",
"This method has a lower accuracy than our LeNet tests, but let's try and unfreeze the base model..."
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "d461abbd",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" vgg16 (Functional) (None, 4, 4, 512) 14714688 \n",
" \n",
" flatten (Flatten) (None, 8192) 0 \n",
" \n",
" dense (Dense) (None, 256) 2097408 \n",
" \n",
" dropout (Dropout) (None, 256) 0 \n",
" \n",
" dense_1 (Dense) (None, 1) 257 \n",
" \n",
"=================================================================\n",
"Total params: 16,812,353\n",
"Trainable params: 16,812,353\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"del model # Delete the model object\n",
"tf.keras.backend.clear_session() # Clear the Keras backend session\n",
"gc.collect() # Force garbage collection\n",
"\n",
"vgg_base.trainable = True # Unfreeze the base model for fine-tuning\n",
"\n",
"# 3. Create a new model with custom top layers\n",
"model = Sequential()\n",
"model.add(vgg_base)\n",
"model.add(Flatten())\n",
"model.add(Dense(256, activation='relu'))\n",
"model.add(Dropout(0.5)) # Regularization to prevent overfitting\n",
"model.add(Dense(1, activation='sigmoid')) # Single neuron with sigmoid for binary classification\n",
"\n",
"# 4. Compile the model\n",
"model.compile(\n",
" optimizer=Adam(learning_rate=0.0001), # Lower learning rate often better for transfer learning\n",
" loss='binary_crossentropy',\n",
" metrics=['accuracy']\n",
")\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 22,
"id": "af72dc1a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/10\n",
"466/466 - 51s - loss: 0.1921 - accuracy: 0.9238 - val_loss: 0.1273 - val_accuracy: 0.9484 - 51s/epoch - 109ms/step\n",
"Epoch 2/10\n",
"466/466 - 50s - loss: 0.0786 - accuracy: 0.9714 - val_loss: 0.0519 - val_accuracy: 0.9825 - 50s/epoch - 108ms/step\n",
"Epoch 3/10\n",
"466/466 - 50s - loss: 0.0598 - accuracy: 0.9796 - val_loss: 0.0656 - val_accuracy: 0.9803 - 50s/epoch - 108ms/step\n",
"Epoch 4/10\n",
"466/466 - 51s - loss: 0.0620 - accuracy: 0.9784 - val_loss: 0.0473 - val_accuracy: 0.9800 - 51s/epoch - 108ms/step\n",
"Epoch 5/10\n",
"466/466 - 50s - loss: 0.0372 - accuracy: 0.9872 - val_loss: 0.0446 - val_accuracy: 0.9819 - 50s/epoch - 108ms/step\n",
"Epoch 6/10\n",
"466/466 - 51s - loss: 0.0247 - accuracy: 0.9913 - val_loss: 0.0336 - val_accuracy: 0.9897 - 51s/epoch - 109ms/step\n",
"Epoch 7/10\n",
"466/466 - 51s - loss: 0.0312 - accuracy: 0.9900 - val_loss: 0.0508 - val_accuracy: 0.9812 - 51s/epoch - 108ms/step\n",
"Epoch 8/10\n",
"466/466 - 50s - loss: 0.0180 - accuracy: 0.9940 - val_loss: 0.0522 - val_accuracy: 0.9809 - 50s/epoch - 108ms/step\n",
"Epoch 9/10\n",
"466/466 - 50s - loss: 0.0188 - accuracy: 0.9945 - val_loss: 0.0562 - val_accuracy: 0.9878 - 50s/epoch - 108ms/step\n",
"Epoch 10/10\n",
"466/466 - 51s - loss: 0.0128 - accuracy: 0.9954 - val_loss: 0.0542 - val_accuracy: 0.9794 - 51s/epoch - 109ms/step\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x17b58ac46a0>"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(train_set, validation_data=eval_set, epochs=10, batch_size=32, verbose=2)"
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "f89f658b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Evaluating model on the test set...\n",
"101/101 [==============================] - 4s 28ms/step - loss: 0.0486 - accuracy: 0.9826\n",
"Test Loss: 0.0486268512904644\n",
"Test Accuracy: 0.9825544953346252\n"
]
}
],
"source": [
"print(\"Evaluating model on the test set...\")\n",
"loss, accuracy = model.evaluate(test_set)\n",
"\n",
"print(f\"Test Loss: {loss}\")\n",
"print(f\"Test Accuracy: {accuracy}\")"
]
},
{
"cell_type": "markdown",
"id": "405fe9da",
"metadata": {},
"source": [
"## Review\n",
"This is our highest accuracy yet, achieving 98.25% accuracy on the test set!\n",
"\n",
"However, considering possible tradeoffs of the different algorithms, this begs the question of whether it is worth the 0.4% accuracy improvement for the massive increase in model weight and cost for inference.\n",
"\n",
"Let's try persisting the VGG16 and testing if the inference server runs on the VM..."
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "976db635",
"metadata": {},
"outputs": [],
"source": [
"## save model\n",
"model.save('vgg16Variant.keras')"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "b93da195",
"metadata": {},
"outputs": [],
"source": [
"model = tf.keras.models.load_model('vgg16Variant.keras')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d9cdccd5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"WARNING:tensorflow:6 out of the last 6 calls to <function Model.make_predict_function.<locals>.predict_function at 0x000001DA8DE7AF80> triggered tf.function retracing. Tracing is expensive and the excessive number of tracings could be due to (1) creating @tf.function repeatedly in a loop, (2) passing tensors with different shapes, (3) passing Python objects instead of tensors. For (1), please define your @tf.function outside of the loop. For (2), @tf.function has reduce_retracing=True option that can avoid unnecessary retracing. For (3), please refer to https://www.tensorflow.org/guide/function#controlling_retracing and https://www.tensorflow.org/api_docs/python/tf/function for more details.\n",
"1/1 [==============================] - 0s 104ms/step\n",
"Prediction: [[0.01878772]]\n",
"The model predicts: damage\n"
]
}
],
"source": [
"test = Image.open('Data/damage/-97.001016_28.446817.jpeg')\n",
"test = np.asarray(test).reshape((1, 128, 128, 3)) / 255.0\n",
"prediction = model.predict(test)\n",
"\n",
"if prediction[0][0] <= 0.5:\n",
" word = \"damage\"\n",
"else:\n",
" word = \"no_damage\"\n",
"\n",
"print(f\"Prediction: {prediction}\")\n",
"print(word)"
]
},
{
"cell_type": "markdown",
"id": "b7a01b80",
"metadata": {},
"source": [
"With this test, we've concluded parts 1 & 2 of the project. The packaging of this VGG16 inference server is available in the directory titled part3"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "tf (3.10.11)",
"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.10.11"
}
},
"nbformat": 4,
"nbformat_minor": 5
}