Professional Documents
Culture Documents
Setup
This imports the required libraries.
import tensorflow as tf
from tensorflow.keras import layers, optimizers, metrics, Sequential,
utils
import os
import json
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
METRICS = [
lambda : tf.keras.metrics.TruePositives(name='tp'),
lambda : tf.keras.metrics.FalsePositives(name='fp'),
lambda : tf.keras.metrics.TrueNegatives(name='tn'),
lambda : tf.keras.metrics.FalseNegatives(name='fn'),
lambda : tf.keras.metrics.BinaryAccuracy(name='accuracy'),
lambda : tf.keras.metrics.Precision(name='precision'),
lambda : tf.keras.metrics.Recall(name='recall'),
lambda : tf.keras.metrics.AUC(name='auc'),
]
def fresh_metrics():
return [metric() for metric in METRICS]
The dataset contains several classes of image. For this notebook, we'll use just two then
convert them to a tensor of strings.
# Where to find the test data
base_dir = '/datasets/intel-multiclass/'
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')
Some Tensorflow functions for use in defining the datasets we'll use.
• A predicate that determines if a given image is in one of our desired classes.
• A function that finds the class number from a label (in the image file's directory
name)
• A function that loads an image, given a path.
def desired_class(image_path):
label_text = tf.strings.split(image_path, os.path.sep)[-2]
return tf.math.reduce_any(label_text == desired_labels_tensor)
def lookup_class_label(label_text):
return class_numbers[label_text.numpy().decode('utf-8')]
def load_image(image_path):
# read the image from disk, decode it, resize it, and scale the
# pixels intensities to the range [0, 1]
image = tf.io.read_file(image_path)
image = tf.io.decode_jpeg(image, channels=3)
image = tf.image.resize(image, IMAGE_RESCALE)
image /= 255.0
# grab the label and encode it
label_text = tf.strings.split(image_path, os.path.sep)[-2]
label = tf.py_function(lookup_class_label, inp=[label_text],
Tout=tf.int32)
label = tf.ensure_shape(label, [])
These are all the image filenames we will use. Note the use of the filter to retain only the
two classes we're interested in.
train_dataset_files = tf.data.Dataset.list_files(
os.path.join(train_dir, '*', '*.jpg'),
shuffle=True).filter(desired_class)
train_data = train_dataset_files.map(load_image,
num_parallel_calls=tf.data.AUTOTUNE)
train_data = train_data.cache()
train_data = train_data.shuffle(20000)
train_data = train_data.batch(BATCH_SIZE)
train_data = train_data.prefetch(tf.data.AUTOTUNE)
validation_dataset_files = tf.data.Dataset.list_files(
os.path.join(validation_dir, '*', '*.jpg'),
shuffle=True).filter(desired_class)
validation_data = validation_dataset_files.map(load_image,
num_parallel_calls=tf.data.AUTOTUNE)
validation_data = validation_data.cache()
validation_data = validation_data.batch(BATCH_SIZE)
validation_data = validation_data.prefetch(tf.data.AUTOTUNE)
test_dataset_files = tf.data.Dataset.list_files(
os.path.join(test_dir, '*', '*.jpg'),
shuffle=True
).filter(desired_class)
test_data = test_dataset_files.map(load_image,
num_parallel_calls=tf.data.AUTOTUNE)
test_data = test_data.cache()
test_data = test_data.batch(BATCH_SIZE)
test_data = test_data.prefetch(tf.data.AUTOTUNE)
A check that we have what we're expecting: a dataset of batches of 150×150×3 images,
each paired with an integer label.
train_data
sample_imgs.shape, sample_labels.shape
A batch of 64 images (each 150×150 pixels, 3 colour channels) and a batch of 64 labels.
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.imshow(sample_imgs[i])
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.title(class_names[sample_labels[i]])
plt.show()
Jittered labels
The labels of the validation set, jittered. These may be useful for charts similar to those in
the Foundations notebooks.
test_labels = np.array(list(test_data.unbatch().map(lambda x, y:
y).as_numpy_iterator()))
test_labels.shape
(1353,)
(1353,)
Define and train a sample model
We now create and train a simple model using these datasets.
You should use this example as a basis for the models of your own that you create in this
question.
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=IMAGE_SIZE),
tf.keras.layers.Dense(1024, activation='sigmoid'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
Note that we're using binary cross entropy as the loss function (as there are two classes).
Categorical cross-entropy is used when there are multiple classes, one-hot encoded.
opt = tf.keras.optimizers.SGD()
model.compile(optimizer=opt,
loss='binary_crossentropy',
metrics=['accuracy'])
history = model.fit(train_data,
validation_data=validation_data,
epochs=5)
Epoch 1/5
58/58 [==============================] - 2s 25ms/step - loss: 0.8806 -
accuracy: 0.5477 - val_loss: 0.6577 - val_accuracy: 0.5667
Epoch 2/5
58/58 [==============================] - 1s 14ms/step - loss: 0.6805 -
accuracy: 0.5796 - val_loss: 0.6932 - val_accuracy: 0.5556
Epoch 3/5
58/58 [==============================] - 1s 14ms/step - loss: 0.6518 -
accuracy: 0.6223 - val_loss: 0.6419 - val_accuracy: 0.6528
Epoch 4/5
58/58 [==============================] - 1s 14ms/step - loss: 0.6300 -
accuracy: 0.6361 - val_loss: 0.6766 - val_accuracy: 0.5611
Epoch 5/5
58/58 [==============================] - 1s 14ms/step - loss: 0.6191 -
accuracy: 0.6602 - val_loss: 0.6225 - val_accuracy: 0.6639
model = tf.keras.models.load_model('q1_sample.h5')
with open('q1_sample_history.json') as f:
sample_history = json.load(f)
epochs = range(len(acc))
plt.figure()
plt.show()
Update the metrics used on the model and evaluate them on the validation data.
model.compile(metrics=fresh_metrics())
model.evaluate(validation_data, return_dict=True)
{'loss': 0.0,
'tp': 136.0,
'fp': 72.0,
'tn': 103.0,
'fn': 49.0,
'accuracy': 0.6638888716697693,
'precision': 0.6538461446762085,
'recall': 0.7351351380348206,
'auc': 0.7169111967086792}
You are now able to work on the tasks in this TMA question.
(a) (5 marks)
Referring to the sample model above:
• show how many trainable parameters it has
• show the shape of inputs to the model
• describe in words the shape of the inputs.
Give your answer below
Insert additional code and markdown cells as needed.
1a.)
• The input layer consists of 150 ×150 ×3=67 , 500 inputs.
• The second layer has 1 , 024 inputs, so there must be 67 , 500 ×1 , 024 weights,
resulting in 69 , 120 ,000 parameters so far.
• Each input in the second layer also has a bias, resulting in
69 , 120 ,000+ 1, 024=69 , 121 ,024 parameters so far.
• The third layer only has 1 output, which results in 1 , 024 weights and 1 bias, so the
total number of trainable parameters are 69 , 121, 024 +1 ,024 +1=69 , 122 ,049 .
The shape of the input is:
model.layers[0].input.shape
This is a 150 x 150 pixel image with 3 color channels. It can be represented by an array of
150 arrays, each of which has 150 arrays too, which contain 3 pixel values, each for red,
green and blue:
# [
# [[r1_1, g1_1, b1_1], ..., [r1_150, g1_150, b1_150]]
# ...
# [[r150_1, g150_1, b150_1], ..., [r_150_150, g_150_150,
b150_150]]
# ]
opt = tf.keras.optimizers.SGD(learning_rate=0.001)
model2.compile(
optimizer=opt,
loss='binary_crossentropy',
metrics=['accuracy']
)
history = model2.fit(
train_data,
validation_data=validation_data,
epochs=40
)
Epoch 1/40
58/58 [==============================] - 1s 17ms/step - loss: 0.6661 -
accuracy: 0.5994 - val_loss: 0.6241 - val_accuracy: 0.6139
Epoch 2/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5883 -
accuracy: 0.6913 - val_loss: 0.7870 - val_accuracy: 0.5417
Epoch 3/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5891 -
accuracy: 0.6959 - val_loss: 0.5806 - val_accuracy: 0.7111
Epoch 4/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5569 -
accuracy: 0.7264 - val_loss: 0.5696 - val_accuracy: 0.7083
Epoch 5/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5475 -
accuracy: 0.7267 - val_loss: 0.5653 - val_accuracy: 0.6972
Epoch 6/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5368 -
accuracy: 0.7372 - val_loss: 0.5521 - val_accuracy: 0.7250
Epoch 7/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5190 -
accuracy: 0.7580 - val_loss: 0.5488 - val_accuracy: 0.7222
Epoch 8/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5162 -
accuracy: 0.7586 - val_loss: 0.5722 - val_accuracy: 0.7333
Epoch 9/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5054 -
accuracy: 0.7678 - val_loss: 0.5411 - val_accuracy: 0.7500
Epoch 10/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5030 -
accuracy: 0.7686 - val_loss: 0.6288 - val_accuracy: 0.6194
Epoch 11/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4885 -
accuracy: 0.7870 - val_loss: 0.5286 - val_accuracy: 0.7444
Epoch 12/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4790 -
accuracy: 0.7910 - val_loss: 0.5218 - val_accuracy: 0.7528
Epoch 13/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4798 -
accuracy: 0.7862 - val_loss: 0.5209 - val_accuracy: 0.7444
Epoch 14/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4616 -
accuracy: 0.8081 - val_loss: 0.5493 - val_accuracy: 0.7694
Epoch 15/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4646 -
accuracy: 0.7989 - val_loss: 0.5086 - val_accuracy: 0.7806
Epoch 16/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4518 -
accuracy: 0.8054 - val_loss: 0.5053 - val_accuracy: 0.7750
Epoch 17/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4527 -
accuracy: 0.8035 - val_loss: 0.5029 - val_accuracy: 0.7750
Epoch 18/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4476 -
accuracy: 0.8129 - val_loss: 0.4999 - val_accuracy: 0.7667
Epoch 19/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4307 -
accuracy: 0.8221 - val_loss: 0.5047 - val_accuracy: 0.7417
Epoch 20/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4290 -
accuracy: 0.8227 - val_loss: 0.5169 - val_accuracy: 0.7833
Epoch 21/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4401 -
accuracy: 0.8191 - val_loss: 0.5783 - val_accuracy: 0.6750
Epoch 22/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4221 -
accuracy: 0.8327 - val_loss: 0.5015 - val_accuracy: 0.7528
Epoch 23/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4093 -
accuracy: 0.8413 - val_loss: 0.5170 - val_accuracy: 0.7750
Epoch 24/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4116 -
accuracy: 0.8375 - val_loss: 0.4852 - val_accuracy: 0.7889
Epoch 25/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4036 -
accuracy: 0.8467 - val_loss: 0.5073 - val_accuracy: 0.7306
Epoch 26/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3975 -
accuracy: 0.8500 - val_loss: 0.4848 - val_accuracy: 0.7722
Epoch 27/40
58/58 [==============================] - 1s 15ms/step - loss: 0.3879 -
accuracy: 0.8597 - val_loss: 0.5052 - val_accuracy: 0.7333
Epoch 28/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3920 -
accuracy: 0.8494 - val_loss: 0.5078 - val_accuracy: 0.7222
Epoch 29/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3951 -
accuracy: 0.8451 - val_loss: 0.4806 - val_accuracy: 0.7861
Epoch 30/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3743 -
accuracy: 0.8548 - val_loss: 0.4808 - val_accuracy: 0.7694
Epoch 31/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3818 -
accuracy: 0.8529 - val_loss: 0.4751 - val_accuracy: 0.8028
Epoch 32/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3686 -
accuracy: 0.8627 - val_loss: 0.4825 - val_accuracy: 0.7917
Epoch 33/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3702 -
accuracy: 0.8646 - val_loss: 0.4765 - val_accuracy: 0.7639
Epoch 34/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3675 -
accuracy: 0.8602 - val_loss: 0.4814 - val_accuracy: 0.7694
Epoch 35/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3509 -
accuracy: 0.8765 - val_loss: 0.4929 - val_accuracy: 0.7528
Epoch 36/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3498 -
accuracy: 0.8737 - val_loss: 0.5218 - val_accuracy: 0.7139
Epoch 37/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3547 -
accuracy: 0.8675 - val_loss: 0.5959 - val_accuracy: 0.6639
Epoch 38/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3654 -
accuracy: 0.8570 - val_loss: 0.4716 - val_accuracy: 0.7972
Epoch 39/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3580 -
accuracy: 0.8621 - val_loss: 0.4680 - val_accuracy: 0.7806
Epoch 40/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3583 -
accuracy: 0.8600 - val_loss: 0.4612 - val_accuracy: 0.7944
(c) (5 marks)
Comment on the plots of loss and accuracy, for both training and validation data, during the
training of this model. Do you think this model would benefit from additional training?
acc = history.history["accuracy"]
val_acc = history.history['val_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(len(acc))
plt.figure()
plt.show()
Give your answer below
Insert additional code and markdown cells as needed.
print("Epoch 1 Training Accuracy: ", str(history.history['accuracy']
[0] * 100) + '%')
print("Epoch 5 Training Accuracy: ", str(history.history['accuracy']
[4] * 100) + '%')
print("Epoch 40 Training Accuracy: ", str(history.history['accuracy']
[39] * 100) + '%')
Some epochs saw a worse training accuracy compared to the previous epoch, but overall,
the training accuracy gradually improved as the epochs increased, reaching 88% in the
final epoch. It is worth mentioning that the rate at which the training accuracy improved
slowed down significantly after 5 epochs — the training accuracy improved by ~13%
between the first and fifth epoch, but took a further 35 epochs to improve by another
~13%:
Although the validation accuracy gradually increased over the 40 epochs, it was much more
volatile. For example:
print("Epoch 37 Validation Accuracy: ",
str(history.history['val_accuracy'][36] * 100) + '%')
print("Epoch 38 Validation Accuracy: ",
str(history.history['val_accuracy'][37] * 100) + '%')
Epoch 37 Validation Accuracy: 66.38888716697693%
Epoch 38 Validation Accuracy: 79.72221970558167%
The validation accuracy between the 37th and 38th epoch decreased by ~13%. Like the
training accuracy, the validation accuracy also saw diminishing returns as the epochs
increased, settling between 75% - 80% from the 10th epoch.
The training loss decreased at a relatively stable pace, reducing from ~65% to ~35% over
the 40 epochs. The validation loss however suffered from diminishing returns, settling
between ~45% to ~50% from the 15th epoch.
To conclude, the training accuracy is already very good, and despite the training loss is
35%, it would most likely decrease significantly if the model is trained further. However,
the validation accuracy and loss have flattened and do not show any signs of improvement.
Therefore, training the model further would just lead to the training loss/accuracy
increasing to perfect-like values and the validation loss/accuracy remaining constant.
There is not much benefit of training the model further, as the validation performance, and
therefore, real-world performance too, may not increase by much (if at all). Training the
model further also increases the risk of over-fitting.
Evaluate the model, using these metrics, on all three of the train, validation, and test
datasets.
Use that model to generate predicted classes for all elements in the test dataset. Plot a
scatter chart of the predicted results with the actual results (defined above as either
test_labels or jittered_labels.)
train_metric
{'loss': 0.0,
'tp': 1666.0,
'fp': 131.0,
'tn': 1665.0,
'fn': 237.0,
'accuracy': 0.9005136489868164,
'precision': 0.9271007180213928,
'recall': 0.8754597902297974,
'auc': 0.9654821753501892}
validation_metric
{'loss': 0.0,
'tp': 141.0,
'fp': 30.0,
'tn': 145.0,
'fn': 44.0,
'accuracy': 0.7944444417953491,
'precision': 0.8245614171028137,
'recall': 0.7621621489524841,
'auc': 0.8669652938842773}
test_metric
{'loss': 0.0,
'tp': 549.0,
'fp': 92.0,
'tn': 565.0,
'fn': 147.0,
'accuracy': 0.823355495929718,
'precision': 0.8564742803573608,
'recall': 0.7887930870056152,
'auc': 0.8947311043739319}
The accuracy, precision, and recall values are the lowest in the validation set and highest in
the training set, with the testing set falling in between, but leaning more closely to the
validation set.
The fact that the accuracy, precision, and recall values in the training set are higher than
the values in the testing/validation set is to be expected. This is because the model is tuned
to optimise the training data. Some over-fitting is inevitably present.
model2_input = np.array(list(test_data.unbatch().map(lambda x, y:
x).as_numpy_iterator()))
expected_output = np.array(list(test_data.unbatch().map(lambda x, y:
y).as_numpy_iterator()))
model2_predictions = model2.predict(model2_input)[:, 0]
plt.figure(figsize=(10, 10))
misclassifications = 0
for i in range(25):
plt.subplot(5, 5, i + 1)
plt.imshow(model2_input[i])
plt.xticks([])
plt.yticks([])
plt.grid(False)
if model2_predictions[i] < 0.5 and expected_output[i] >= 0.5:
print(f"Misclassification at row {(i // 5) + 1}, column {(i %
5) + 1} - expecting {class_names[1]}.")
misclassifications += 1
elif model2_predictions[i] >= 0.5 and expected_output[i] < 0.5:
print(f"Misclassification at row {(i // 5) + 1}, column {(i %
5) + 1} - expecting {class_names[0]}.")
misclassifications += 1
plt.title(class_names[1 if model2_predictions[i] >= 0.5 else 0])
print(f"{(misclassifications/25) * 100}% of data points were
misclassified.")
plt.show()
<matplotlib.legend.Legend at 0x7f81987d5370>
print(f"False Negatives: {test_metric['fn']}")
print(f"False Positives: {test_metric['fp']}")
As can be seen from the graph above, there are more points in the lower right quadrant
(false negatives) compared to the top left quadrant (false positives).
• points in the scatter chart are clustered at the more extreme values for each class, with few
with predicted values near 0.5. This indicates that the model can classify well.
• for the test data, precision, accuracy and recall are all high and similar, indicating that there
(e) (5 marks) isn’t a systematic bias in the results and that both classes are classified correctly.
• for the training data, the values of all metrics are extremely high, indicating that the model
has learnt most features of the training data.
Referring to the evaluations in part (d), explain why it is important to have separate
datasets for training and testing ML models. What would be the implications if the same
dataset was used for both roles? When should testing data be used? What is the advantage
of having a separate validation dataset?
opt = tf.keras.optimizers.SGD(learning_rate=0.001)
modelS.compile(
optimizer=opt,
loss='binary_crossentropy',
metrics=['accuracy']
)
historyS = modelS.fit(
train_data,
validation_data=validation_data,
epochs=40
)
acc = historyS.history["accuracy"]
val_acc = historyS.history['val_accuracy']
loss = historyS.history['loss']
val_loss = historyS.history['val_loss']
epochs = range(len(acc))
plt.figure()
plt.show()
modelS.compile(metrics=fresh_metrics())
train_metric = modelS.evaluate(train_data, return_dict=True)
validation_metric = modelS.evaluate(validation_data, return_dict=True)
test_metric = modelS.evaluate(test_data, return_dict=True)
Epoch 1/40
58/58 [==============================] - 1s 10ms/step - loss: 0.6722 -
accuracy: 0.6018 - val_loss: 0.6674 - val_accuracy: 0.6306
Epoch 2/40
58/58 [==============================] - 0s 8ms/step - loss: 0.6510 -
accuracy: 0.6418 - val_loss: 0.6903 - val_accuracy: 0.5444
Epoch 3/40
58/58 [==============================] - 0s 8ms/step - loss: 0.6348 -
accuracy: 0.6559 - val_loss: 0.6398 - val_accuracy: 0.6417
Epoch 4/40
58/58 [==============================] - 0s 8ms/step - loss: 0.6189 -
accuracy: 0.6726 - val_loss: 0.6460 - val_accuracy: 0.5889
Epoch 5/40
58/58 [==============================] - 0s 8ms/step - loss: 0.6053 -
accuracy: 0.6899 - val_loss: 0.6245 - val_accuracy: 0.6250
Epoch 6/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5957 -
accuracy: 0.6907 - val_loss: 0.6135 - val_accuracy: 0.6583
Epoch 7/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5852 -
accuracy: 0.7086 - val_loss: 0.6105 - val_accuracy: 0.6667
Epoch 8/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5757 -
accuracy: 0.7142 - val_loss: 0.6021 - val_accuracy: 0.6667
Epoch 9/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5710 -
accuracy: 0.7105 - val_loss: 0.6086 - val_accuracy: 0.6500
Epoch 10/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5587 -
accuracy: 0.7248 - val_loss: 0.5897 - val_accuracy: 0.6944
Epoch 11/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5543 -
accuracy: 0.7305 - val_loss: 0.5893 - val_accuracy: 0.6778
Epoch 12/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5461 -
accuracy: 0.7364 - val_loss: 0.5794 - val_accuracy: 0.6972
Epoch 13/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5413 -
accuracy: 0.7324 - val_loss: 0.5853 - val_accuracy: 0.6667
Epoch 14/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5344 -
accuracy: 0.7364 - val_loss: 0.5725 - val_accuracy: 0.7056
Epoch 15/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5250 -
accuracy: 0.7502 - val_loss: 0.5803 - val_accuracy: 0.6833
Epoch 16/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5254 -
accuracy: 0.7540 - val_loss: 0.5679 - val_accuracy: 0.7056
Epoch 17/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5165 -
accuracy: 0.7632 - val_loss: 0.5689 - val_accuracy: 0.6861
Epoch 18/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5128 -
accuracy: 0.7591 - val_loss: 0.5605 - val_accuracy: 0.7083
Epoch 19/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5103 -
accuracy: 0.7583 - val_loss: 0.5625 - val_accuracy: 0.7056
Epoch 20/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5049 -
accuracy: 0.7597 - val_loss: 0.5684 - val_accuracy: 0.7139
Epoch 21/40
58/58 [==============================] - 0s 8ms/step - loss: 0.5019 -
accuracy: 0.7705 - val_loss: 0.5815 - val_accuracy: 0.6917
Epoch 22/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4986 -
accuracy: 0.7637 - val_loss: 0.5663 - val_accuracy: 0.6778
Epoch 23/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4942 -
accuracy: 0.7710 - val_loss: 0.5566 - val_accuracy: 0.7056
Epoch 24/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4878 -
accuracy: 0.7848 - val_loss: 0.5551 - val_accuracy: 0.7056
Epoch 25/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4868 -
accuracy: 0.7799 - val_loss: 0.5471 - val_accuracy: 0.7167
Epoch 26/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4809 -
accuracy: 0.7805 - val_loss: 0.5468 - val_accuracy: 0.7111
Epoch 27/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4796 -
accuracy: 0.7837 - val_loss: 0.5588 - val_accuracy: 0.7222
Epoch 28/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4743 -
accuracy: 0.7821 - val_loss: 0.5473 - val_accuracy: 0.7194
Epoch 29/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4781 -
accuracy: 0.7818 - val_loss: 0.5427 - val_accuracy: 0.7167
Epoch 30/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4646 -
accuracy: 0.7975 - val_loss: 0.5401 - val_accuracy: 0.7194
Epoch 31/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4650 -
accuracy: 0.7924 - val_loss: 0.5351 - val_accuracy: 0.7306
Epoch 32/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4595 -
accuracy: 0.8070 - val_loss: 0.5419 - val_accuracy: 0.7333
Epoch 33/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4548 -
accuracy: 0.8043 - val_loss: 0.5391 - val_accuracy: 0.7139
Epoch 34/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4551 -
accuracy: 0.8029 - val_loss: 0.5464 - val_accuracy: 0.7194
Epoch 35/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4486 -
accuracy: 0.8072 - val_loss: 0.5309 - val_accuracy: 0.7167
Epoch 36/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4467 -
accuracy: 0.8045 - val_loss: 0.5312 - val_accuracy: 0.7222
Epoch 37/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4424 -
accuracy: 0.8094 - val_loss: 0.5359 - val_accuracy: 0.7250
Epoch 38/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4385 -
accuracy: 0.8151 - val_loss: 0.5268 - val_accuracy: 0.7194
Epoch 39/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4401 -
accuracy: 0.8135 - val_loss: 0.5379 - val_accuracy: 0.7333
Epoch 40/40
58/58 [==============================] - 0s 8ms/step - loss: 0.4334 -
accuracy: 0.8143 - val_loss: 0.5538 - val_accuracy: 0.7000
58/58 [==============================] - 1s 8ms/step - loss:
0.0000e+00 - tp: 1752.0000 - fp: 588.0000 - tn: 1208.0000 - fn:
151.0000 - accuracy: 0.8002 - precision: 0.7487 - recall: 0.9207 -
auc: 0.9003
6/6 [==============================] - 0s 10ms/step - loss: 0.0000e+00
- tp: 160.0000 - fp: 83.0000 - tn: 92.0000 - fn: 25.0000 - accuracy:
0.7000 - precision: 0.6584 - recall: 0.8649 - auc: 0.8135
22/22 [==============================] - 0s 8ms/step - loss:
0.0000e+00 - tp: 616.0000 - fp: 292.0000 - tn: 365.0000 - fn: 80.0000
- accuracy: 0.7251 - precision: 0.6784 - recall: 0.8851 - auc: 0.8408
The number of neurons in both middle layers was changed to 32. This significantly reduced
the training time, from ~1 second per step to ~8 ms per step. This is attributed to there
being exponentially fewer weights and biases to update upon every learning iteration.
Surprisingly, reducing the number of neurons only reduced the test-set accuracy slightly
(77% compared to ~81% seen in 1(d)).
A possible explanation for why good accuracy is retained when reducing the number of
neurons significantly could be the fact that there are fewer features distinguishing an
image of a sea and an image of a building, compared to something more complex like an
image of a cat or a dog. An image of a sea generally has more bluer colors and has less
granular detail (smoothness of water compared to a building facade with many windows).
Therefore, as images of seas and buildings could theoretically be more linearly separable,
good results still may be achieved with fewer neurons.
The compromise in accuracy may be worth the gain in computation time for some non-
critical applications.
modelL = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=IMAGE_SIZE),
tf.keras.layers.Dense(1024, activation='relu'),
tf.keras.layers.Dense(256, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
opt = tf.keras.optimizers.SGD(learning_rate=0.03)
modelL.compile(
optimizer=opt,
loss='binary_crossentropy',
metrics=['accuracy']
)
historyL = modelL.fit(
train_data,
validation_data=validation_data,
epochs=40
)
acc = historyL.history["accuracy"]
val_acc = historyL.history['val_accuracy']
loss = historyL.history['loss']
val_loss = historyL.history['val_loss']
epochs = range(len(acc))
plt.figure()
plt.show()
modelS.compile(metrics=fresh_metrics())
train_metric = modelS.evaluate(train_data, return_dict=True)
validation_metric = modelS.evaluate(validation_data, return_dict=True)
test_metric = modelS.evaluate(test_data, return_dict=True)
Epoch 1/40
58/58 [==============================] - 1s 16ms/step - loss: 1.2910 -
accuracy: 0.5407 - val_loss: 0.6742 - val_accuracy: 0.5306
Epoch 2/40
58/58 [==============================] - 1s 14ms/step - loss: 0.6697 -
accuracy: 0.5783 - val_loss: 0.6830 - val_accuracy: 0.5361
Epoch 3/40
58/58 [==============================] - 1s 14ms/step - loss: 0.6594 -
accuracy: 0.5983 - val_loss: 0.6521 - val_accuracy: 0.5917
Epoch 4/40
58/58 [==============================] - 1s 14ms/step - loss: 0.6441 -
accuracy: 0.6150 - val_loss: 0.6331 - val_accuracy: 0.6167
Epoch 5/40
58/58 [==============================] - 1s 14ms/step - loss: 0.6634 -
accuracy: 0.6010 - val_loss: 0.6518 - val_accuracy: 0.6083
Epoch 6/40
58/58 [==============================] - 1s 14ms/step - loss: 0.6326 -
accuracy: 0.6459 - val_loss: 0.6161 - val_accuracy: 0.6806
Epoch 7/40
58/58 [==============================] - 1s 14ms/step - loss: 0.6072 -
accuracy: 0.6718 - val_loss: 0.6524 - val_accuracy: 0.5972
Epoch 8/40
58/58 [==============================] - 1s 14ms/step - loss: 0.6009 -
accuracy: 0.6734 - val_loss: 0.6196 - val_accuracy: 0.6167
Epoch 9/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5946 -
accuracy: 0.6799 - val_loss: 0.6670 - val_accuracy: 0.6222
Epoch 10/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5633 -
accuracy: 0.7045 - val_loss: 0.5932 - val_accuracy: 0.6528
Epoch 11/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5585 -
accuracy: 0.7094 - val_loss: 0.6176 - val_accuracy: 0.6500
Epoch 12/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5401 -
accuracy: 0.7313 - val_loss: 0.5841 - val_accuracy: 0.6722
Epoch 13/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5368 -
accuracy: 0.7242 - val_loss: 0.5855 - val_accuracy: 0.6833
Epoch 14/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5351 -
accuracy: 0.7326 - val_loss: 0.5699 - val_accuracy: 0.7028
Epoch 15/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5292 -
accuracy: 0.7399 - val_loss: 0.5937 - val_accuracy: 0.7222
Epoch 16/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5097 -
accuracy: 0.7494 - val_loss: 0.5774 - val_accuracy: 0.7028
Epoch 17/40
58/58 [==============================] - 1s 14ms/step - loss: 0.5106 -
accuracy: 0.7410 - val_loss: 0.7333 - val_accuracy: 0.5944
Epoch 18/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4934 -
accuracy: 0.7591 - val_loss: 0.6937 - val_accuracy: 0.6611
Epoch 19/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4866 -
accuracy: 0.7648 - val_loss: 0.6245 - val_accuracy: 0.6889
Epoch 20/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4896 -
accuracy: 0.7610 - val_loss: 0.7110 - val_accuracy: 0.6472
Epoch 21/40
58/58 [==============================] - 1s 15ms/step - loss: 0.4754 -
accuracy: 0.7753 - val_loss: 0.5777 - val_accuracy: 0.7028
Epoch 22/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4450 -
accuracy: 0.7978 - val_loss: 0.5889 - val_accuracy: 0.7083
Epoch 23/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4402 -
accuracy: 0.7940 - val_loss: 0.6355 - val_accuracy: 0.6611
Epoch 24/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4657 -
accuracy: 0.7791 - val_loss: 0.5875 - val_accuracy: 0.7306
Epoch 25/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4589 -
accuracy: 0.7853 - val_loss: 0.5737 - val_accuracy: 0.6944
Epoch 26/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4413 -
accuracy: 0.7924 - val_loss: 0.5628 - val_accuracy: 0.7306
Epoch 27/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4338 -
accuracy: 0.7983 - val_loss: 0.5584 - val_accuracy: 0.7250
Epoch 28/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4484 -
accuracy: 0.7940 - val_loss: 0.7197 - val_accuracy: 0.6583
Epoch 29/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4451 -
accuracy: 0.7929 - val_loss: 0.5591 - val_accuracy: 0.7278
Epoch 30/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4229 -
accuracy: 0.8102 - val_loss: 0.7303 - val_accuracy: 0.6000
Epoch 31/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4278 -
accuracy: 0.8010 - val_loss: 0.6060 - val_accuracy: 0.7139
Epoch 32/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4228 -
accuracy: 0.8156 - val_loss: 0.5679 - val_accuracy: 0.7278
Epoch 33/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3744 -
accuracy: 0.8378 - val_loss: 0.6726 - val_accuracy: 0.7139
Epoch 34/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4053 -
accuracy: 0.8275 - val_loss: 0.5585 - val_accuracy: 0.7389
Epoch 35/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4169 -
accuracy: 0.8064 - val_loss: 0.5464 - val_accuracy: 0.7222
Epoch 36/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4946 -
accuracy: 0.7716 - val_loss: 0.5534 - val_accuracy: 0.7056
Epoch 37/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4370 -
accuracy: 0.7945 - val_loss: 0.5461 - val_accuracy: 0.7167
Epoch 38/40
58/58 [==============================] - 1s 14ms/step - loss: 0.4342 -
accuracy: 0.8097 - val_loss: 0.5664 - val_accuracy: 0.7250
Epoch 39/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3885 -
accuracy: 0.8216 - val_loss: 0.5505 - val_accuracy: 0.7500
Epoch 40/40
58/58 [==============================] - 1s 14ms/step - loss: 0.3784 -
accuracy: 0.8245 - val_loss: 0.5495 - val_accuracy: 0.7417
58/58 [==============================] - 1s 8ms/step - loss:
0.0000e+00 - tp: 1752.0000 - fp: 588.0000 - tn: 1208.0000 - fn:
151.0000 - accuracy: 0.8002 - precision: 0.7487 - recall: 0.9207 -
auc: 0.9003
6/6 [==============================] - 0s 10ms/step - loss: 0.0000e+00
- tp: 160.0000 - fp: 83.0000 - tn: 92.0000 - fn: 25.0000 - accuracy:
0.7000 - precision: 0.6584 - recall: 0.8649 - auc: 0.8135
22/22 [==============================] - 0s 8ms/step - loss:
0.0000e+00 - tp: 616.0000 - fp: 292.0000 - tn: 365.0000 - fn: 80.0000
- accuracy: 0.7251 - precision: 0.6784 - recall: 0.8851 - auc: 0.8408
The learning rate was changed from 0.001 to 0.03. This led to a decrease in accuracy and
more volatile jumps in training loss and accuracy.
A key motivation behind increasing the learning rate by such a high margin was to discover
if the results from 1(d) were constrained by the Stochastic Gradient Descent algorithm
getting stuck in a local minimum.
A higher learning rate allows the algorithm to be less concerned about deeply honing into
anything that appears to lead to a minimum, and more freely explore the nearby space,
which could potentially lead to a lower minimum. This is why the training loss and
accuracy is more volatile than previously.
However, since worse results for accuracy and precision were achieved on the testing set
compared to previously, it appears that the learning rate is perhaps too high. It could be
interesting to experiment with a learning rate lower than 0.001 to see whether better
accuracy can be achieved. This would require more epochs though, which would increase
computation time.
I am expecting comments on training and validation data sets and any evidence of over fitting.
I am also expecting comments on accuracy, precision and recall scores as well.