In [1]:
# Step 1: Import all the tools we need
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense, Dropout
from tensorflow.keras.utils import to_categorical
/Users/saroshbaig/Library/Python/3.9/lib/python/site-packages/urllib3/__init__.py:35: NotOpenSSLWarning: urllib3 v2 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'LibreSSL 2.8.3'. See: https://github.com/urllib3/urllib3/issues/3020
  warnings.warn(
In [2]:
# Step 2: Load the training and test data
train_data = pd.read_csv("sign_mnist_train.csv")
test_data = pd.read_csv("sign_mnist_test.csv")

# Step 3: Split the data into images (X) and labels (y)
X_train = train_data.drop("label", axis=1).values
y_train = train_data["label"].values

X_test = test_data.drop("label", axis=1).values
y_test = test_data["label"].values
In [3]:
# Step 4: Reshape the images
# Turn flat images into 28x28 pixels, with 1 color channel (grayscale)
X_train = X_train.reshape(-1, 28, 28, 1)
X_test = X_test.reshape(-1, 28, 28, 1)

# Step 5: Convert pixel values to smaller decimal numbers (0 to 1)
X_train = X_train.astype("float32") / 255
X_test = X_test.astype("float32") / 255

# Display the first 10 reshaped images
import matplotlib.pyplot as plt

plt.figure(figsize=(10, 5))
for i in range(10):
    image = X_train[i].reshape(28, 28)  # Remove channel dim for display
    plt.subplot(2, 5, i + 1)
    plt.imshow(image, cmap="gray")
    plt.title(f"Label: {y_train[i]}")
    plt.axis("off")
plt.tight_layout()
plt.show()
No description has been provided for this image
In [4]:
# Step 6: Turn the labels into one-hot encoded format
y_train_cat = to_categorical(y_train, num_classes=25)  # 25 classes (A-Y, no J or Z)
y_test_cat = to_categorical(y_test, num_classes=25)
In [5]:
# Step 7: Build the CNN model
model = Sequential([
    Input(shape=(28, 28, 1)),                  # Input layer (28x28 image, 1 channel)
    Conv2D(32, (3, 3), activation='relu'),     # First convolution layer
    MaxPooling2D(pool_size=(2, 2)),            # First max pooling layer

    Conv2D(64, (3, 3), activation='relu'),     # Second convolution layer
    MaxPooling2D(pool_size=(2, 2)),            # Second max pooling layer

    Flatten(),                                 # Flatten image to 1D list
    Dense(128, activation='relu'),             # Fully connected layer
    Dropout(0.3),                              # Dropout to prevent overfitting
    Dense(25, activation='softmax')            # Output layer (25 classes)
])
In [6]:
# Step 8: Compile the model
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

# Show the model structure
model.summary()
Model: "sequential"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape           ┃       Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ conv2d (Conv2D)                 │ (None, 26, 26, 32)     │           320 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 13, 13, 32)     │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ conv2d_1 (Conv2D)               │ (None, 11, 11, 64)     │        18,496 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 5, 5, 64)       │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ flatten (Flatten)               │ (None, 1600)           │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │       204,928 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense_1 (Dense)                 │ (None, 25)             │         3,225 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 226,969 (886.60 KB)
 Trainable params: 226,969 (886.60 KB)
 Non-trainable params: 0 (0.00 B)
In [7]:
# Step 9: Train the model
history = model.fit(
    X_train, y_train_cat,
    epochs=10,
    batch_size=64,
    validation_data=(X_test, y_test_cat),
    verbose=2
)
Epoch 1/10
429/429 - 5s - 13ms/step - accuracy: 0.5601 - loss: 1.4526 - val_accuracy: 0.8270 - val_loss: 0.5311
Epoch 2/10
429/429 - 5s - 11ms/step - accuracy: 0.9026 - loss: 0.3060 - val_accuracy: 0.8889 - val_loss: 0.3336
Epoch 3/10
429/429 - 5s - 11ms/step - accuracy: 0.9639 - loss: 0.1220 - val_accuracy: 0.9244 - val_loss: 0.2528
Epoch 4/10
429/429 - 5s - 11ms/step - accuracy: 0.9784 - loss: 0.0723 - val_accuracy: 0.9235 - val_loss: 0.2704
Epoch 5/10
429/429 - 5s - 11ms/step - accuracy: 0.9858 - loss: 0.0490 - val_accuracy: 0.9257 - val_loss: 0.2412
Epoch 6/10
429/429 - 5s - 11ms/step - accuracy: 0.9879 - loss: 0.0405 - val_accuracy: 0.9310 - val_loss: 0.2784
Epoch 7/10
429/429 - 5s - 11ms/step - accuracy: 0.9906 - loss: 0.0298 - val_accuracy: 0.9381 - val_loss: 0.2266
Epoch 8/10
429/429 - 5s - 11ms/step - accuracy: 0.9936 - loss: 0.0227 - val_accuracy: 0.9363 - val_loss: 0.2680
Epoch 9/10
429/429 - 5s - 12ms/step - accuracy: 0.9942 - loss: 0.0202 - val_accuracy: 0.9387 - val_loss: 0.2922
Epoch 10/10
429/429 - 5s - 13ms/step - accuracy: 0.9920 - loss: 0.0244 - val_accuracy: 0.9522 - val_loss: 0.2701
In [8]:
# Step 11: See the predictions on the first 10 images
predictions = model.predict(X_test)
predicted_labels = np.argmax(predictions, axis=1)

# Show the first 10 test images with predicted and actual labels
plt.figure(figsize=(12, 6))
for i in range(10):
    plt.subplot(2, 5, i + 1)
    plt.imshow(X_test[i].reshape(28, 28), cmap='gray')
    plt.title(f"Pred: {predicted_labels[i]}\nTrue: {y_test[i]}")
    plt.axis('off')
plt.tight_layout()
plt.show()
225/225 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step
No description has been provided for this image