文件最后提交记录最后更新时间
18 天前
18 天前
18 天前
18 天前
18 天前
18 天前
README.md

CNN 模型训练

训练数字识别 CNN 和二分类 CNN,输出到 models/

脚本 用途 输出文件
train.py 数字分类 CNN 训练 models/sudoku_cnn.pth + models/sudoku_cnn.pt (TorchScript)
train_binary.py 二分类 CNN 训练 models/cell_binary.pth + models/cell_binary.pt (TorchScript)
extract_gt_samples.py 从反馈数据提取数字样本 training/gt_samples.npy, training/gt_labels.npy

完整闭环流程

┌─────────────────────────────────────────────────────────┐
│  1. C++ Web 服务 (--enable-feedback)                     │
│     用户上传图片 → AI 识别 → 用户手动校正                 │
│     → POST /feedback/ 保存 (data/feedback/)              │
├─────────────────────────────────────────────────────────┤
│  2. 提取训练样本                                          │
│     cd training && python3 extract_gt_samples.py         │
│     → gt_samples.npy + gt_labels.npy                     │
├─────────────────────────────────────────────────────────┤
│  3. 训练模型                                              │
│     python3 train.py          # 数字分类 CNN              │
│     python3 train_binary.py   # 二分类 CNN                │
│     → models/sudoku_cnn.pt + models/cell_binary.pt       │
├─────────────────────────────────────────────────────────┤
│  4. 部署新模型                                            │
│     替换 models/ 目录下的 .pt 文件                        │
│     重启 C++ 服务即可生效                                  │
└─────────────────────────────────────────────────────────┘

模型架构

两个 CNN 模型定义均为自包含(train.py 和 train_binary.py 中各有一份),不依赖外部 Python 包。

SudokuDigitCNN(数字分类,约 4 万参数)

输入 1×28×28
  → Conv(1→16,3×3) → BN → ReLU → MaxPool(2)   # 14×14×16
  → Conv(16→32,3×3) → BN → ReLU → MaxPool(2)   # 7×7×32
  → Conv(32→64,3×3) → BN → ReLU → MaxPool(2)   # 3×3×64
  → Flatten → Linear(576→64) → ReLU → Dropout(0.3) → Linear(64→9)

CellBinaryCNN(二分类,约 6.5K 参数)

输入 1×40×40
  → Conv(1→8,3×3) → BN → ReLU → MaxPool(2)     # 20×20×8
  → Conv(8→16,3×3) → BN → ReLU → MaxPool(2)    # 10×10×16
  → Conv(16→32,3×3) → BN → ReLU → AdaptiveAvgPool2d(1)  # 1×1×32
  → Flatten → Linear(32→16) → ReLU → Dropout(0.25) → Linear(16→2)

数字分类三阶段训练策略

Phase 1: MNIST 预训练(5 epochs, LR=0.001)
  ├── 数据:MNIST 数字 1-9,约 60K 样本
  └── 目的:学习数字笔画基本特征

Phase 2: 自定义样本微调(30 epochs, LR=0.0003)
  ├── 数据:training/samples.npy + label.npy(手动标注)
  └── 目的:适应本项目的数独字体和预处理方式

Phase 3: GT 校正数据精调(15 epochs, LR=0.0001)
  ├── 数据:从 feedback 中提取的真实数字样本(含增强)
  └── 目的:修复特定误分类,提升泛化能力

依赖

脚本 外部依赖
train.py PyTorch, torchvision, OpenCV, NumPy(模型定义自包含)
train_binary.py PyTorch, OpenCV, NumPy + 原项目的 sudoku.correction(透视校正)
extract_gt_samples.py OpenCV, NumPy + 原项目的 sudoku.correction + sudoku.extraction

extract_gt_samples.pytrain_binary.py 需要从原始 Python 项目加载图像处理函数。

设置环境变量指向原项目路径:

export SUDOKU_PY_PATH=/home/ma-user/code/sudoku-py

运行训练

cd training

# 第 1 步:从反馈数据提取样本(需先收集 feedback)
python3 extract_gt_samples.py

# 第 2 步:训练数字分类 CNN
python3 train.py                     # 完整三阶段
python3 train.py --skip-phase3       # 跳过 GT 微调

# 第 3 步:训练二分类 CNN
python3 train_binary.py

# 第 4 步:部署
# 训练完成后 models/ 下的 .pt 文件会自动更新
# 重启 C++ 服务即可生效

自定义训练数据

添加新样本(手动标注)

如果模型对某些图片识别效果不好,可以加入新的训练样本:

import numpy as np

samples = np.load("training/samples.npy")  # (N, 400) 20×20 展平
labels = np.load("training/label.npy")      # (N,) 标签 1-9

# 追加新样本
new_sample = your_20x20_image.reshape(1, 400)
new_label = np.array([5])
samples = np.vstack([samples, new_sample])
labels = np.concatenate([labels, new_label])

np.save("training/samples.npy", samples)
np.save("training/label.npy", labels)

然后重新运行 python3 train.py

超参数调优

所有可调参数集中在训练脚本顶部:

# train.py
BATCH_SIZE = 64
EPOCHS_PRETRAIN = 5
EPOCHS_FINETUNE = 30
EPOCHS_GT_FINETUNE = 15
LR_PRETRAIN = 0.001
LR_FINETUNE = 0.0003
LR_GT_FINETUNE = 0.0001
  • 验证准确率不涨:降低 LR
  • 欠拟合:增加 EPOCHS
  • 过拟合:增大 Dropout(0.3 → 0.5)