import numpy as np
import pandas as pd
import random
import tensorflow as tf
import matplotlib.pyplot as plt
from sklearn.metrics import accuracy_score
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Flatten, Conv2D, Dense,
MaxPooling2D
from tensorflow.keras.optimizers import SGD
from tensorflow.keras.utils import to_categorical
from tensorflow.keras.datasets import mnist
(X_train , y_train), (X_test, y_test) = mnist.load_data()
#there are 60000 images with height and width of 28X28
print(X_train.shape)
print(y_train.shape)
(60000, 28, 28)
(60000,)
#This range from 0 to 255 is common in grayscale images, where:
#0 represents black (no intensity).
#255 represents white (full intensity).
X_train[0].min(), X_train[0].max()
(0, 255)
#scales the pixel values of X_train and X_test to be in the range 0.0
to 1.0 instead of
#0 to 255.
X_train = (X_train - 0.0) / (255.0 - 0.0)
X_test = (X_test - 0.0) / (255.0 - 0.0)
X_train[0].min(), X_train[0].max()
(0.0, 1.0)
#image = input image of 28x28 metrics
#digit = label to that image
#plt = matplotlib for plotting
def plot_digit(image, digit, plt, i):
#subplot contains 4 rows and 5 cols
plt.subplot(4, 5, i + 1)
plt.imshow(image, cmap=plt.get_cmap('gray'))
plt.title(f"Digit: {digit}")
#plt.xticks([]) and plt.yticks([]): Remove the x- and y-axis ticks for
a cleaner appearance.
plt.xticks([])
plt.yticks([])
plt.figure(figsize=(16, 10))
for i in range(20):
plot_digit(X_train[i], y_train[i], plt, i)
plt.show()
#adding an extra dimension at the end of each image's shape to make it
3D.(28x28x1)
X_train = X_train.reshape((X_train.shape + (1,)))
X_test = X_test.reshape((X_test.shape + (1,)))
#print labels of first 20 images
y_train[0:20]
array([5, 0, 4, 1, 9, 2, 1, 3, 1, 4, 3, 5, 3, 6, 1, 7, 2, 8, 6, 9],
dtype=uint8)
#Defining Convolutional neural network
model = Sequential([
#A convolutional layer with 32 filters (or kernels), each of size
3x3.
Conv2D(32, (3, 3), activation="relu", input_shape=(28, 28, 1)),
MaxPooling2D((2, 2)),
#Flatten Converts the 2D feature maps from the previous layer into
a 1D vector.
#This is required to transition from the convolutional layers to
the fully connected layers.
Flatten(),
Dense(100, activation="relu"), #fully connected layer
Dense(10, activation="softmax")
])
#An optimizer is used update the weights and biases to minimize the
model's loss function
#The loss function measures how well the model's predictions align
with the actual labels.
#accuracy will be used to evaluate the model's performance during
training and testing.
optimizer = SGD(learning_rate=0.01, momentum=0.9)
model.compile(
optimizer=optimizer,
loss="sparse_categorical_crossentropy",
metrics=["accuracy"]
)
model.summary()
Model: "sequential_3"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳
━━━━━━━━━━━━━━━━━┓
┃ Layer (type) ┃ Output Shape ┃
Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇
━━━━━━━━━━━━━━━━━┩
│ conv2d_3 (Conv2D) │ (None, 26, 26, 32) │
320 │
├──────────────────────────────────────┼─────────────────────────────┼
─────────────────┤
│ max_pooling2d_3 (MaxPooling2D) │ (None, 13, 13, 32) │
0 │
├──────────────────────────────────────┼─────────────────────────────┼
─────────────────┤
│ flatten_3 (Flatten) │ (None, 5408) │
0 │
├──────────────────────────────────────┼─────────────────────────────┼
─────────────────┤
│ dense_6 (Dense) │ (None, 100) │
540,900 │
├──────────────────────────────────────┼─────────────────────────────┼
─────────────────┤
│ dense_7 (Dense) │ (None, 10) │
1,010 │
└──────────────────────────────────────┴─────────────────────────────┴
─────────────────┘
Total params: 542,230 (2.07 MB)
Trainable params: 542,230 (2.07 MB)
Non-trainable params: 0 (0.00 B)
#train the model
model.fit(X_train, y_train, epochs=10, batch_size=32)
#epochs: hows many times the training process will run through the
entire training dataset.
#batch_size defines the no. of samples that will propagated through
the network at one time.
Epoch 1/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 5ms/step - accuracy: 0.8633 - loss:
0.4561
Epoch 2/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9743 - loss:
0.0835
Epoch 3/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 5ms/step - accuracy: 0.9850 - loss:
0.0514
Epoch 4/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9881 - loss:
0.0369
Epoch 5/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9924 - loss:
0.0252
Epoch 6/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9945 - loss:
0.0194
Epoch 7/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9960 - loss:
0.0142
Epoch 8/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9976 - loss:
0.0096
Epoch 9/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9984 - loss:
0.0073
Epoch 10/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 10s 5ms/step - accuracy: 0.9985 - loss:
0.0058
<keras.src.callbacks.history.History at 0x1f6891b53d0>
# Evaluate the model on the test dataset
test_loss, test_accuracy = model.evaluate(X_test, y_test)
print(f'Test Loss: {test_loss:.4f}, Test Accuracy:
{test_accuracy:.4f}')
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - accuracy: 0.9868 - loss:
0.0485
Test Loss: 0.0391, Test Accuracy: 0.9886