1310 lines
119 KiB
Plaintext
1310 lines
119 KiB
Plaintext
{
|
|
"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",
|
|
""
|
|
]
|
|
},
|
|
{
|
|
"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
|
|
}
|