使用 PyTorch 建構手寫數字辨識模型

Author

Jim Pan

1 專案簡介

這是一個使用 PyTorch 深度學習框架建構的全連接神經網路(Fully Connected Neural Network, FCNN)專案,目標是辨識 MNIST 手寫數字圖片。這個經典任務可以有效展示我對模型架構、資料處理流程與訓練邏輯的掌握。


2 🛠 技術與流程概述

2.1 模型架構

本模型使用 torch.nn.Sequential 建構,網路結構如下:

model = nn.Sequential(
    nn.Flatten(),
    nn.Linear(784, 256),
    nn.ReLU(),
    nn.Linear(256, 512),
    nn.ReLU(),
    nn.Linear(512, 344),
    nn.ReLU(),
    nn.Linear(344, 10)
).to(device)
  • Flatten():將 28x28 圖片展平成 784 維向量
  • Linear 層:依序進行 784→256→512→344→10 維度變換
  • ReLU():啟用函數,提升非線性表現力
  • 輸出層不加 softmax,因為 CrossEntropyLoss() 內建 softmax 操作

2.2 模型架構圖(可視化)

graph TD
  A[Input: 784] --> B[Linear: 784 → 256]
  B --> C[ReLU]
  C --> D[Linear: 256 → 512]
  D --> E[ReLU]
  E --> F[Linear: 512 → 344]
  F --> G[ReLU]
  G --> H[Linear: 344 → 10]
  H --> I[CrossEntropyLoss (with Softmax)]

2.3 資料處理流程

使用 torchvision.datasets 匯入 MNIST 並轉換為 Tensor:

transform = transforms.Compose([
    transforms.ToTensor()
])

train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)

train_loader = DataLoader(dataset=train_dataset, batch_size=10000, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=1000, shuffle=False)

3 🔁 訓練流程說明(100 Epochs)

整個模型經過 100 次訓練迴圈(Epoch),每次迭代都包含訓練與測試兩階段。

3.1 損失與優化器設定:

lossfunction = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

3.2 訓練與測試主流程:

for i in range(100):
    model.train()
    for features, labels in train_loader:
        features, labels = features.to(device), labels.to(device)
        optimizer.zero_grad()
        predict = model(features.view(features.size(0), -1))
        loss = lossfunction(predict, labels)
        loss.backward()
        optimizer.step()

    model.eval()
    with torch.no_grad():
        for features, labels in test_loader:
            features, labels = features.to(device), labels.to(device)
            predict = model(features.view(features.size(0), -1))
            loss = lossfunction(predict, labels)

3.3 完整訓練日誌摘要(節錄結果)

Epoch [95/100], Train loss: 0.0715, Train acc: 0.9763
Epoch [95/100], Test loss: 0.0521, Test acc: 0.9805

Epoch [96/100], Train loss: 0.0690, Train acc: 0.9770
Epoch [96/100], Test loss: 0.0508, Test acc: 0.9810

Epoch [97/100], Train loss: 0.0672, Train acc: 0.9775
Epoch [97/100], Test loss: 0.0495, Test acc: 0.9812

Epoch [98/100], Train loss: 0.0661, Train acc: 0.9781
Epoch [98/100], Test loss: 0.0483, Test acc: 0.9816

Epoch [99/100], Train loss: 0.0650, Train acc: 0.9784
Epoch [99/100], Test loss: 0.0468, Test acc: 0.9819

Epoch [100/100], Train loss: 0.0647, Train acc: 0.9786
Epoch [100/100], Test loss: 0.0452, Test acc: 0.9820

4 📈 成果與準確率展示

模型經過 100 輪訓練後,在測試資料集上達到穩定準確率:

Epoch [100/100], Test loss: 0.0452, Test acc: 0.9820

並成功預測前 20 筆測試資料:

print("True Labels (first 20):", true_labels[:20])
print("Predicted Classes (first 20):", predicted_classes[:20])

5 📦 模型儲存與推論

5.1 儲存模型:

torch.save(model.state_dict(), './mymodel.pt')

5.2 載入模型並做預測:

params = torch.load('./mymodel.pt')
model.load_state_dict(params)
model.eval()

6 🧠 小結:核心學習收穫

  • 熟悉 MLP 架構與 PyTorch 設計流程
  • 掌握訓練、測試、儲存與推論完整流程
  • 體會學習率、迭代次數、ReLU 激活等超參數的影響
  • 熟悉 Apple Silicon 上的 MPS 設備加速

💡 雖然這段程式碼未公開在 GitHub,但我在本頁完整保留流程與成果,方便未來自己或他人參考與回顧。

Back to top