import csv
import string
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator, array_to_img
Define some globals with the path to both files you just downloaded:
TRAINING_FILE = './sign_mnist_train.csv'
VALIDATION_FILE = './sign_mnist_test.csv'
Note: No actual images provided, instead we will have the data serialized as csv files.
Let's check:
with open(TRAINING_FILE) as training_file:
line = training_file.readline()
print(f"First line (header) looks like this:\n{line}")
line = training_file.readline()
print(f"Each subsequent line (data points) look like this:\n{line}")
Each file includes a header (the first line) and each subsequent data point is represented as a line that contains 785 values.
The first value is the label (the numeric representation of each letter) and the other 784 values are the value of each pixel of the image (original images have a resolution of 28x28, which sums up to 784 pixels)
with open(filename, newline='') as file:
# Remember that csv.reader can be iterated and returns one line in each iteration
csv_reader = csv.reader(file, delimiter=",")
for row in csv_reader:
labels = np.loadtxt(file, delimiter=',', usecols=(0))
with open(filename, newline='') as file:
csv_reader = csv.reader(file, delimiter=",")
for pixels in csv_reader:
images = np.loadtxt(file, delimiter=',', usecols=range(1,785))
images = np.reshape(images,(-1,28,28))
Let's check the data:
print(f"Training images has shape: {training_images.shape} and dtype: {training_images.dtype}")
print(f"Training labels has shape: {training_labels.shape} and dtype: {training_labels.dtype}")
print(f"Validation images has shape: {validation_images.shape} and dtype: {validation_images.dtype}")
print(f"Validation labels has shape: {validation_labels.shape} and dtype: {validation_labels.dtype}")
Now that we have converted the initial csv data into a format that is compatible with computer vision tasks, let's take a moment to actually see how the images of the dataset look like:
# Plot a sample of 10 images from the training set
def plot_categories(training_images, training_labels):
fig, axes = plt.subplots(1, 10, figsize=(16, 15))
axes = axes.flatten()
letters = list(string.ascii_lowercase)
for k in range(10):
img = training_images[k]
img = np.expand_dims(img, axis=-1)
img = array_to_img(img)
ax = axes[k]
ax.imshow(img, cmap="Greys_r")
ax.set_title(f"{letters[int(training_labels[k])]}")
ax.set_axis_off()
plt.tight_layout()
plt.show()
plot_categories(training_images, training_labels)
# In this section you will have to add another dimension to the data
# So, for example, if your array is (10000, 28, 28)
# We will need to make it (10000, 28, 28, 1)
training_images = np.expand_dims(training_images, axis = 3)
validation_images = np.expand_dims(validation_images, axis = 3)
# Instantiate the ImageDataGenerator class
train_datagen = ImageDataGenerator(rescale=1.0/255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
train_generator = train_datagen.flow(x=training_images,
y=training_labels,
batch_size=32)
validation_datagen = ImageDataGenerator( rescale = 1.0/255. )
validation_generator = validation_datagen.flow(x=validation_images,
y=validation_labels,
batch_size=32)
print(f"Images of training generator have shape: {train_generator.x.shape}")
print(f"Labels of training generator have shape: {train_generator.y.shape}")
print(f"Images of validation generator have shape: {validation_generator.x.shape}")
print(f"Labels of validation generator have shape: {validation_generator.y.shape}")
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(512, (3,3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
tf.keras.layers.Dropout(0.2),
# 512 neuron hidden layer
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dense(28, activation='softmax')
])
model.compile(optimizer = 'rmsprop',
loss = 'sparse_categorical_crossentropy',
metrics=['accuracy'])
history = model.fit(train_generator,
epochs=15,
validation_data=validation_generator)
Now take a look at our training history:
# Plot the chart for accuracy and loss on both training and validation
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.plot(epochs, acc, 'r', label='Training accuracy')
plt.plot(epochs, val_acc, 'b', label='Validation accuracy')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'r', label='Training Loss')
plt.plot(epochs, val_loss, 'b', label='Validation Loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()