Using the CIFAR10 dataset built in to the tensorflow library
Note: The accuracy of this model is poor, but I wanted to practice. I could have used Data Augmentation (ImageDataGenerator) to increase diversity of the training data, increased the number of epochs, as well as several other adjustments.
import numpy as np
from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, BatchNormalization
from tensorflow.keras.models import Sequential
from tensorflow.keras import datasets
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import random
import warnings
warnings.filterwarnings('ignore')
(training_images, training_labels), (test_images, test_labels) = datasets.cifar10.load_data()
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
random_indices = np.random.choice(training_images.shape[0], 20, replace=False)
for i, index in enumerate(random_indices):
plt.subplot(4, 5, i + 1)
plt.imshow(training_images[index])
plt.title(class_names[training_labels[index][0]])
plt.axis('off')
plt.tight_layout()
plt.show()
training_images = training_images/255
model = Sequential([
Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)),
Conv2D(32, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
BatchNormalization(),
Dropout(0.25),
Conv2D(64, (3, 3), activation='relu'),
Conv2D(64, (3, 3), activation='relu'),
MaxPooling2D((2, 2)),
BatchNormalization(),
Dropout(0.25),
Conv2D(128, (3, 3), activation='relu'),
Conv2D(128, (3, 3), activation='relu'),
BatchNormalization(),
Flatten(),
Dense(512, activation='relu'),
Dropout(0.5),
Dense(256, activation='relu'),
Dropout(0.5),
Dense(10, activation='softmax')
])
model.summary()
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ conv2d (Conv2D) │ (None, 30, 30, 32) │ 896 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_1 (Conv2D) │ (None, 28, 28, 32) │ 9,248 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d (MaxPooling2D) │ (None, 14, 14, 32) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ batch_normalization │ (None, 14, 14, 32) │ 128 │ │ (BatchNormalization) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout (Dropout) │ (None, 14, 14, 32) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_2 (Conv2D) │ (None, 12, 12, 64) │ 18,496 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_3 (Conv2D) │ (None, 10, 10, 64) │ 36,928 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_1 (MaxPooling2D) │ (None, 5, 5, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ batch_normalization_1 │ (None, 5, 5, 64) │ 256 │ │ (BatchNormalization) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_1 (Dropout) │ (None, 5, 5, 64) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_4 (Conv2D) │ (None, 3, 3, 128) │ 73,856 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_5 (Conv2D) │ (None, 1, 1, 128) │ 147,584 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ batch_normalization_2 │ (None, 1, 1, 128) │ 512 │ │ (BatchNormalization) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ flatten (Flatten) │ (None, 128) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense (Dense) │ (None, 512) │ 66,048 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_2 (Dropout) │ (None, 512) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 256) │ 131,328 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_3 (Dropout) │ (None, 256) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_2 (Dense) │ (None, 10) │ 2,570 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 487,850 (1.86 MB)
Trainable params: 487,402 (1.86 MB)
Non-trainable params: 448 (1.75 KB)
model.compile(optimizer = 'adam', loss ='sparse_categorical_crossentropy', metrics =['accuracy'])
model.fit(training_images, training_labels, batch_size = 512, epochs=5)
Epoch 1/5 98/98 ━━━━━━━━━━━━━━━━━━━━ 26s 252ms/step - accuracy: 0.2329 - loss: 2.1257 Epoch 2/5 98/98 ━━━━━━━━━━━━━━━━━━━━ 25s 254ms/step - accuracy: 0.4825 - loss: 1.4211 Epoch 3/5 98/98 ━━━━━━━━━━━━━━━━━━━━ 25s 253ms/step - accuracy: 0.5750 - loss: 1.1918 Epoch 4/5 98/98 ━━━━━━━━━━━━━━━━━━━━ 25s 256ms/step - accuracy: 0.6311 - loss: 1.0451 Epoch 5/5 98/98 ━━━━━━━━━━━━━━━━━━━━ 25s 259ms/step - accuracy: 0.6769 - loss: 0.9315
<keras.src.callbacks.history.History at 0x30955a8d0>
Note: This poor accuracy (compared to the training data) suggests heavy overfitting.
model.evaluate(test_images, test_labels)
313/313 ━━━━━━━━━━━━━━━━━━━━ 3s 10ms/step - accuracy: 0.3016 - loss: 65.2209
[64.67840576171875, 0.2994999885559082]
random_indices = random.sample(range(test_images.shape[0]), 16)
predictions = model.predict(training_images[random_indices])
for i in range(16):
plt.subplot(4,4,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(training_images[random_indices[i]], cmap=plt.cm.binary)
predicted_label = np.argmax(predictions[i])
true_label = training_labels[random_indices[i]]
if predicted_label == true_label:
color = 'green'
else:
color = 'red'
plt.xlabel("{} ({})".format(class_names[predicted_label], class_names[true_label[0]]), color=color)
plt.tight_layout()
plt.show()
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 55ms/step
predicted_classes = model.predict(test_images)
313/313 ━━━━━━━━━━━━━━━━━━━━ 4s 11ms/step
predicted_classes = predicted_classes.argmax(1)
from sklearn.metrics import confusion_matrix
import seaborn as sns
cm = confusion_matrix(predicted_classes, test_labels)
plt.figure(figsize=(10, 10))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=[str(i) for i in range(10)],
yticklabels=[str(i) for i in range(10)])
plt.xlabel('Predicted Labels')
plt.ylabel('True Labels')
plt.show()