想练习图像分类,可以从 scikit-learn 内置手写数字数据开始:每张图只有 8×8 个灰度像素,展平成 64 个数值后,用 SVC 在 CPU 上训练并预测 0–9。这个练习不需要下载预训练大模型;数据随 scikit-learn 提供,但首次安装 Python 包仍需要可用的包下载源。
以下代码已在 Windows、Python 3.11.15、scikit-learn 1.9.1、NumPy 2.4.6、Matplotlib 3.11.2 的 CPU 环境运行。测试集 450 张图中有 5 张误分。数字只代表本例固定划分的运行结果,不能用于推断手机照片、扫描件或其他图片上的识别能力。

先看清 digits 输入格式
官方 load_digits 文档列出 1,797 个样本、10 个类别、64 个特征,像素值为 0–16。digits.images保留 8×8 二维图,digits.data是展平后的特征;它们与 digits.target共享样本顺序。
| 对象 | 本例形状 | 用途 |
|---|---|---|
| digits.images | 1797×8×8 | 查看图像 |
| digits.data | 1797×64 | SVC 模型输入 |
| digits.target | 1797 | 0–9 的真实类别 |
只按样本下标进行训练/测试划分,可以让像素、标签和原图索引保持一致。本例使用分层随机划分,随机种子为 42,测试比例为 25%,保证类别比例大致一致。若自己的图片来自同一个人或同一张原图的裁剪,应用人物、原图等组别来划分,避免近乎相同的图落到两侧。
先建环境。以下命令固定为本文运行版本;macOS/Linux 激活命令为 source .venv/bin/activate。
python -m venv .venv
.venv\Scripts\activate
python -m pip install scikit-learn==1.9.1 numpy==2.4.6 matplotlib==3.11.2
训练、评测并导出误分图
把完整代码保存为 digits_demo.py,执行 python digits_demo.py。代码使用径向基核 SVC,固定 C=10、gamma=0.001。SVC 官方文档说明 C 是正则化参数,gamma 用于核函数;这些配置是本例设置,并非对所有图像都适用的最佳参数。
from pathlib import Path
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from sklearn.datasets import load_digits
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
digits = load_digits()
indices = np.arange(len(digits.target))
train_idx, test_idx = train_test_split(
indices, test_size=0.25, random_state=42, stratify=digits.target)
X_train, X_test = digits.data[train_idx], digits.data[test_idx]
y_train, y_test = digits.target[train_idx], digits.target[test_idx]
assert X_train.shape[1] == 64
assert digits.images.shape[1:] == (8, 8)
assert digits.data.min() == 0 and digits.data.max() == 16
model = SVC(kernel='rbf', gamma=0.001, C=10)
model.fit(X_train, y_train)
pred = model.predict(X_test)
cm = confusion_matrix(y_test, pred, labels=np.arange(10))
wrong = np.flatnonzero(pred != y_test)
assert cm.shape == (10, 10) and int(cm.sum()) == len(y_test)
assert accuracy_score(y_test, pred) == np.mean(pred == y_test)
print('images_shape:', digits.images.shape)
print('train_test_rows:', len(train_idx), len(test_idx))
print('accuracy:', round(float(accuracy_score(y_test, pred)), 6))
print('first_five_truth:', y_test[:5].tolist())
print('first_five_prediction:', pred[:5].tolist())
print('misclassified_rows:', len(wrong))
print('confusion_matrix:')
print(cm)
fig, axes = plt.subplots(2, 4, figsize=(9, 5))
for ax, position in zip(axes.flat, list(wrong[:8]) + [None] * 8):
ax.axis('off')
if position is not None:
ax.imshow(X_test[position].reshape(8, 8), cmap='gray', vmin=0, vmax=16)
ax.set_title(f'true={y_test[position]}, pred={pred[position]}')
fig.tight_layout()
fig.savefig('digits_errors.png', dpi=160)
plt.close(fig)
assert Path('digits_errors.png').is_file()
print('saved: digits_errors.png')
核对准确率、类别错误和图片
以下是本例实际输出。混淆矩阵行是真实类别,列是预测类别,类别顺序固定为 0–9。
images_shape: (1797, 8, 8)
train_test_rows: 1347 450
accuracy: 0.988889
first_five_truth: [1, 0, 9, 1, 5]
first_five_prediction: [1, 0, 9, 1, 5]
misclassified_rows: 5
confusion_matrix:
[[45 0 0 0 0 0 0 0 0 0]
[ 0 46 0 0 0 0 0 0 0 0]
[ 0 0 44 0 0 0 0 0 0 0]
[ 0 0 0 46 0 0 0 0 0 0]
[ 0 0 0 0 45 0 0 0 0 0]
[ 0 0 0 0 0 45 0 0 0 1]
[ 0 0 0 0 0 0 44 0 1 0]
[ 0 0 0 0 0 0 0 45 0 0]
[ 0 2 0 0 0 0 0 0 41 0]
[ 0 0 0 0 0 0 0 1 0 44]]
saved: digits_errors.png
训练 1,347 张、测试 450 张;准确率 0.988889 对应 445/450,误分 5 张。矩阵所有单元格求和为 450,非对角线求和为 5,二者与逐图比较一致。前五个预测与真值一致只是五个样本的检查,完整结果仍应看全部测试图。
打开当前目录下的 digits_errors.png,可以看到 true=8/pred=1、true=6/pred=8、true=9/pred=7、true=5/pred=9 等错例;本次两张真实 8 被预测为 1。图像色阶固定为 0–16,避免每张图自动拉伸后造成亮度误解。代码最多显示前八个误分,其余子图留空,不代表又有新的预测样本。
如果结果和这里不同,先打印 Python 和 scikit-learn 版本,确认随机种子、分层划分、C、gamma 和数据没有改变。只要输入检查、预测长度、混淆矩阵与逐图比较一致,数值变化本身并不一定是代码故障。不要改看测试集后挑出的参数再宣称这是独立评测。
自己的手写图片为什么不能直接输入
本模型只接受每张图 64 维、与 digits 训练分布相近的数值特征。普通 JPG/PNG 的 RGB 颜色、尺寸、背景、数字位置和 0–255 色阶都可能不同;仅把图片压成 8×8 并展平,不能保证识别可靠。
- 先确定一张图是否只包含一个数字,文字行和多位数要先做分割。
- 记录灰度化、前景/背景方向、裁剪、居中、缩放和像素范围的统一规则。训练与预测必须使用同一套转换。
- 用自己的有标签样本重新训练或验证,并单独保留不同书写人、设备和采集批次的测试图。
- 同时报告逐类错例和总体指标,尤其关注容易混淆的数字,不用当前 445/450 的结果作自有图片准确率承诺。
如果输入变成 784 维(例如 28×28),SVC 会发现特征数不匹配。要么按新数据重新建立模型,要么明确转换到已验证的输入协议;随便截取前 64 个数会破坏空间对应关系。这个教程完成的是小型灰度数字分类训练与错例检查,没有验证通用物体分类、文字 OCR 或生产识别系统。
Ai菜鸟网。发布者:AI小管家,转载请注明出处:https://www.alyyhw.com/30599.html