Pi5AI Lab 01: Handwritten Digit Recognition
Introduction
In this lab, students will build and deploy a machine-learning pipeline to recognize handwritten digits (0–9). Starting on a Windows workstation using Docker and Jupyter Notebook, you will:
- Prepare a Docker-based development environment with Python and TensorFlow 2.
- Train a Convolutional Neural Network (CNN) on the MNIST dataset and evaluate its performance.
- Implement real-time digit recognition using a webcam.
- Convert and deploy the trained model to a Raspberry Pi 5 with a Hailo-8/8L AI module for edge inference.
- Load and classify static images from disk to verify model accuracy.
By completing this lab, you will gain hands-on experience with containerized development, model training, and evaluation, real-time inference on both desktop and embedded hardware, and image-based inference workflows.
Environment Setup
- Install Docker Desktop (Windows 10/11)
- Download and install the latest Docker Desktop. Enable WSL 2 support.
- Under Settings > General, tick Use the WSL 2 based engine.
- Project Setup
First, create the following folder structure on your computer:<AI_Project_Folder>/ |-- AI_Lab/ | `-- Lab01_HandwrittenDigitRecognition/ | |-- docker/ | |-- notebooks/ | |-- src/ | `-- saved_model/
- Create the Dockerfile
This file defines the environment for this project.
File: <AI_Project_Folder>\AI_Lab\Lab01_HandwrittenDigitRecognition\docker\Dockerfile# Use the official TensorFlow image as a base FROM tensorflow/tensorflow:2.13.0 # Install OpenCV fuinctions to display and process images RUN apt-get update && apt-get install -y \ libgl1-mesa-glx \ libglib2.0-0 \ libsm6 \ libxrender1 \ libxext6 \ && rm -rf /var/lib/apt/lists/* # Set the working directory inside the container WORKDIR /app # Install required Python packages RUN pip install --no-cache-dir jupyterlab opencv-python matplotlib # Expose the Jupyter Notebook port and a port for a web app if needed EXPOSE 8888 6006 # Command to run Jupyter Lab CMD ["jupyter", "lab", "--ip=0.0.0.0", "--port=8888", "--no-browser", "--allow-root", "--NotebookApp.token=''"]
- Build and Run the Docker Container
Open a terminal (Command Prompt or PowerShell) and run the following commands:
After the container starts, you will see Jupyter Notebook's startup messages in the command prompt or PowerShell, including a URL to access Jupyter Notebook. Typically, this URL will be http://127.0.0.1:8888/lab. Copy this URL and open it in your web browser.# Navigate to your project directory cd \<AI_Project_Folder>\AI_Lab\Lab01_HandwrittenDigitRecognition # Build the Docker image docker build -t ai-lab-windows -f docker/Dockerfile . # Run the Docker container docker run -p 8888:8888 -v "${pwd}:/app" --name ai-lab-instance ai-lab-windows
PART I: AI Model Training (Jupyter Notebook)
In the Jupyter Notebook environment, we will use TensorFlow 2 to train a handwritten digit recognition model. We will use the MNIST dataset, a standard dataset containing images of handwritten digits from 0-9. After training, the model will be saved as handwritten_digit_model.h5.
In the Jupyter Notebook interface, create a new Python 3 Notebook and paste the following code. This code will load the MNIST dataset, normalize the images, build a simple Convolutional Neural Network (CNN) model, and then train and save the model.
# Load functions
import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten, MaxPooling2D
import matplotlib.pyplot as plt
# Load the MNIST dataset
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# 重塑資料以符合模型需求
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
x_test = x_test.reshape(x_test.shape[0], 28, 28, 1)
# Normalize the images to a range of 0 to 1
x_train = x_train.astype('float32') / 255
x_test = x_test.astype('float32') / 255
# Build the model
model = Sequential([
Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=(28, 28, 1)),
MaxPooling2D(pool_size=(2, 2)),
Flatten(),
Dense(128, activation='relu'),
Dense(10, activation='softmax')
])
# 在第四個儲存格:編譯模型
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
# 在第五個儲存格:訓練模型
model.fit(x_train, y_train, epochs=5, validation_data=(x_test, y_test))
# 在第六個儲存格:儲存訓練好的模型
model.save('/app/saved_model/digit_recognition_model.h5')
print("模型已成功儲存!")