手写数字识别之加载和使用模型
1 课程概览
本课讲解手写数字识别案例的最后一步——加载和使用保存的模型。详细讲解如何读取图片、将28×28像素转换为1×784、归一化处理、加载模型、预测数字。同时解决函数名以test开头触发pytest的问题,以及忽略sklearn警告的方法。
2 核心概念与定义
- joblib.load:加载保存的模型文件。
- imread:matplotlib中读取图片的函数。
- imshow:matplotlib中显示图片的函数。
- reshape(1, -1):将28×28转换为1行784列,-1表示自动计算列数。
- pytest:Python单元测试模块,函数名以test开头会触发该模块。
- warnings.filterwarnings:忽略警告信息。
3 算法与模型详解
3.1 使用模型流程
- 加载图片(imread)
- 绘制图片(imshow)
- 加载模型(joblib.load)
- 数据转换:
- 查看形状(28×28)
- reshape为1×784
- 归一化(除以255)
- 模型预测(predict)
- 打印预测结果
3.2 数据形状转换
| 转换前 | 转换后 | 代码 |
|---|---|---|
| (28, 28) | (1, 784) | reshape(1, 784) 或 reshape(1, -1) |
reshape(1, -1)说明:
- 1:转换为1行
- -1:自动计算列数(能转多少转多少)
- 效果等同于reshape(1, 784)
3.3 函数命名注意事项
| 函数名前缀 | 触发模块 | 说明 |
|---|---|---|
| test_ | pytest | 会触发单元测试模块,导致报错 |
| use_ 或其他 | 无 | 正常运行 |
⚠️函数名不能以test开头,否则会触发pytest模块。
3.4 忽略警告
import warnings
warnings.filterwarnings('ignore', module='sklearn.neighbors')
参数说明:
| 参数 | 说明 |
|---|---|
| 'ignore' | 忽略警告 |
| module | 指定忽略的模块 |
3.5 归一化的重要性
训练时:对数据进行了归一化(除以255) 预测时:必须对数据也进行归一化(除以255)
⚠️训练和预测的数据处理方式必须一致。
4 数学原理与推导
4.1 形状转换
$$\text{Data}{1 \times 784} = \text{reshape}(\text{Image}{28 \times 28})$$
4.2 归一化
$$X_{norm} = \frac{X}{255}$$
5 代码示例
import matplotlib.pyplot as plt
import joblib
import warnings
# 忽略sklearn.neighbors模块的警告
warnings.filterwarnings('ignore', module='sklearn.neighbors')
def use_model():
# 1. 加载图片
X = plt.imread('./data/demo.png')
# 2. 绘制图片
plt.imshow(X, cmap='gray')
plt.axis('off') # 关闭坐标轴
plt.show()
# 3. 加载模型
estimator = joblib.load('./model/手写数字识别.pkl')
# 4. 数据转换
# 4.1 查看形状(28×28)
print("原始形状:", X.shape) # (28, 28)
# 4.2 reshape为1×784
X = X.reshape(1, 784)
# 或 X = X.reshape(1, -1) # -1表示自动计算列数
print("转换后形状:", X.shape) # (1, 784)
# 4.3 归一化(除以255)
X = X / 255
# 5. 模型预测
y_predict = estimator.predict(X)
# 6. 打印预测结果
print("预测值为:", y_predict)
if __name__ == '__main__':
use_model()
输出示例:
原始形状: (28, 28)
转换后形状: (1, 784)
预测值为: [2]
6 重难点与易错提醒
- ❗重点:函数名不能以test开头,否则会触发pytest模块报错。
- ❗重点:预测前必须将28×28 reshape为1×784。
- ❗重点:预测前必须进行归一化(除以255),与训练时一致。
- ❗重点:reshape(1, -1)等价于reshape(1, 784),-1表示自动计算。
- ⚠️易错:函数名以test开头导致pytest报错。
- ⚠️易错:忘记归一化,导致预测结果错误。
- ⚠️易错:忘记reshape,形状不匹配导致predict报错。
- 💡深入理解:训练和预测的数据处理方式必须完全一致。
7 课堂问答精选
Q: 为什么函数名不能以test开头?
A: 在Python中,如果函数名以test开头,运行时会触发pytest模块(Python专门的单元测试模块)。pytest会尝试以测试方式运行该函数,导致复杂函数报错。解决方法是将函数名改为use_model或其他不以test开头的名称。
Q: reshape(1, -1)和reshape(1, 784)有什么区别?
A:
- reshape(1, 784):明确指定转换为1行784列。
- reshape(1, -1):指定1行,-1表示自动计算列数(能转多少转多少)。 两者效果相同,实际开发中常用reshape(1, -1),因为不需要知道具体列数。
Q: 为什么预测时也要进行归一化?
A: 因为训练模型时对数据进行了归一化(除以255),预测时必须保持一致的数据处理方式。如果不归一化,像素值范围是0~255,与训练时的0~1不匹配,会导致预测结果错误。
8 本课小结
- 使用模型流程:加载图片→绘制图片→加载模型→reshape转换→归一化→预测。
- 函数名不能以test开头,否则触发pytest报错。
- reshape(1, -1)等价于reshape(1, 784),-1表示自动计算列数。
- 预测前必须归一化(除以255),与训练时保持一致。
- warnings.filterwarnings('ignore', module='sklearn.neighbors')忽略警告。
9 延伸思考与实践
- 实践:使用自己手写的数字图片进行预测。
- 思考:为什么训练和预测的数据处理方式必须一致?
- 总结:KNN算法的完整流程(数据加载→预处理→训练→保存→加载→预测)。