AI-深度学习

从零搭建视觉模型 14:验证、测试与错误分析

展开合集目录
  1. 从零搭建视觉模型 01:图片进入模型后发生了什么
  2. 从零搭建视觉模型 02:Python 起步,写给 C/C++ 开发者
  3. 从零搭建视觉模型 03:从像素到张量的基础概念
  4. 从零搭建视觉模型 04:图片如何变成张量
  5. 从零搭建视觉模型 05:MLP 入门,从手算到图片输入
  6. 从零搭建视觉模型 06:亲手搭建一个小型 CNN
  7. 从零搭建视觉模型 07:模型怎样预测类别:分数、概率与决策
  8. 从零搭建视觉模型 08:让模型开始学习,损失、梯度与训练循环
  9. 从零搭建视觉模型 09:数据集、标签与数据划分
  10. 从零搭建视觉模型 10:损失函数与优化器:怎样把错误变成更新
  11. 从零搭建视觉模型 11:批次、训练轮次与学习率
  12. 从零搭建视觉模型 12:训练第一个真实图片分类器
  13. 从零搭建视觉模型 13:过拟合、数据增强与正则化
  14. 从零搭建视觉模型 14:验证、测试与错误分析
  15. 从零搭建视觉模型 15:保存模型、恢复训练与独立推理
  16. 从零搭建视觉模型 · 综合实践:实现 MLP,从损失计算、训练到 ONNX 推理
  17. 从零搭建视觉模型 16:ResNet 与残差连接
  18. 从零搭建视觉模型 17:预训练、迁移学习与微调
  19. 从零搭建视觉模型 18:轻量模型与计算成本
  20. 从零搭建视觉模型 19:目标检测与 YOLO:从类别到目标框
  21. 从零搭建视觉模型 20:图像分割与 U-Net:给每个像素一个判断
  22. 从零搭建视觉模型 21:注意力与视觉 Transformer
  23. 从零搭建视觉模型 22:从训练模型到 ONNX
  24. 从零搭建视觉模型 23:量化与精度对比
  25. 从零搭建视觉模型 24:从摄像头输入到部署验收
  26. 从零搭建视觉模型 25:发展历史、主流分类与当前格局
从零搭建视觉模型 14:验证、测试与错误分析的封面

学习初稿 · 第 14 课。 本篇已开放网页阅读,用于先建立完整认识。文中手算值和示意记录不代表真实训练成绩;真实数据训练、预训练权重和板端测试以本篇具体说明为准,本篇已附代码练习,实际验证范围见文末与包内记录。

一个准确率数字隐藏了什么

假设某数据中 95% 都是汽车,程序永远回答汽车就能达到 95% 准确率,却完全不会识别飞机。指标必须结合类别分布与任务代价解释。

本课把汽车视为正类、飞机视为负类。正负只是一种统计约定,不表示好坏。换了正类,精确率和召回率的含义也跟着变,因此报告时必须写清楚。

从四种结果建立混淆矩阵

真实与预测 预测汽车 预测飞机
真实汽车 TP:正确找出汽车 FN:漏掉汽车
真实飞机 FP:误报汽车 TN:正确排除汽车

准确率为 (TP+TN)/总数,精确率为 TP/(TP+FP),召回率为 TP/(TP+FN)。精确率问“报出来的有多少是真的”,召回率问“真实存在的找出了多少”。

下面是一组固定标签的独立手算检查:

truth = [1, 1, 1, 1, 0, 0]
pred =  [1, 1, 0, 0, 1, 0]
tp = sum(y == 1 and p == 1 for y, p in zip(truth, pred))
fp = sum(y == 0 and p == 1 for y, p in zip(truth, pred))
fn = sum(y == 1 and p == 0 for y, p in zip(truth, pred))
tn = sum(y == 0 and p == 0 for y, p in zip(truth, pred))
print(tp, fp, fn, tn)
print('precision:', tp / (tp + fp))
print('recall:', tp / (tp + fn))
assert (tp, fp, fn, tn) == (2, 1, 2, 1)

本例精确率为 2/3、召回率为 1/2、准确率为 1/2。如果分母为零,指标并没有天然合理的数值,应注明采用未定义、零值或工具规定的处理方式。

阈值会改变错误的分布

二分类按汽车概率超过阈值报警时,降低阈值通常会接收更多样本,可能减少漏报、增加误报。这个方向不是对任意一小批数据都保证严格变化,但能帮助理解取舍。

阈值应使用验证集和业务代价确定,随后冻结,再在测试集上测试。不能先在测试集尝试几十个阈值,再把最好的结果当作独立验证。

多类别也要看每类指标。宏平均给各类别同等权重,按样本量加权的平均则更受大类影响。比较两个报告前先核对类别集合、平均方式和样本来源。

先看错误图,再改模型

为错误样本保存文件 ID、真实标签、预测标签、分数和来源组;按小目标、遮挡、逆光、背景相似、标签错误等条件归类。几张高分错误图往往能暴露 RGB 顺序、裁剪和标签映射问题。

如果错误主要发生在某个拍摄来源,先检查分布变化;如果模型总是混淆两类的细节,检查分辨率和标注定义;如果所有类别突然反转,先检查类别表。直接换更深网络可能把错误隐藏得更难定位。

错误分析需要避免反复利用测试集做开发。开发阶段用训练与验证错误建立假设,最终测试用于检验已冻结方案;若已经依据测试错误做了修改,需要新的独立评估来源或明确承认测试被用于开发。

测试报告应能回答的四个问题

用了哪些样本,采用哪份模型和预处理,按什么决策规则计算,结果在哪些条件下失效。还应记录样本数,避免把 10 张测试图上的 100% 与几千张独立图片的成绩相提并论。

相关样本数量很多也不等于独立证据很多。一段视频的 10000 个相邻帧不能简单当作 10000 次独立试验;泛化范围取决于来源覆盖和相关性。

本草稿的固定数组可以验证指标计算,但没有真实模型测试成绩。发布前应导出验证错误清单,在配置冻结后执行独立测试,并保存可追溯报告。

练习

  1. TP=8、FP=2、FN=4,精确率与召回率分别是多少?
  2. 只对模型最有把握的一半样本计算准确率,报告还缺什么?
  3. 为什么“测试集不反向传播”仍不保证测试独立?
参考答案

精确率 0.8,召回率 8/12。还缺接收率、拒绝样本分布及全量表现,否则只说明筛选后子集。若用测试成绩选择超参数、轮数或阈值,测试已经参与开发决策,即使未计算梯度也会造成选择偏差。

下一课把选好的模型保存下来,并验证重新加载后是否产生同样输出。

综合实践

想把这些知识接成一套可运行的代码,可以进入实现 MLP:从损失计算、训练到 ONNX 推理。实践包含自生成数据、训练与验证、模型保存、独立推理、ONNX 导出和数值对照;遇到问题可按实践中的索引返回对应理论章节。

配套代码练习

实验:混淆矩阵与阈值比较

查看完整代码:main.py
"""混淆矩阵与阈值比较。运行方式与练习见 README.md。"""
labels = [0,0,0,1,1,1]
scores = [0.1,0.4,0.8,0.3,0.7,0.9]  # 第 1 类分数,构造样本
for threshold in [0.5,0.75]:
    matrix = [[0,0],[0,0]]
    for truth,score in zip(labels,scores): matrix[truth][int(score>=threshold)] += 1
    tn,fp = matrix[0]; fn,tp = matrix[1]
    precision = tp/(tp+fp) if tp+fp else None
    recall = tp/(tp+fn) if tp+fn else None
    print('threshold:',threshold,'matrix:',matrix,'precision:',precision,'recall:',recall)
    assert sum(map(sum,matrix)) == len(labels)
    if threshold == 0.5: assert matrix == [[2,1],[1,2]]
下载代码

在项目根目录执行;下载包解压后,在解压目录执行 python3 main.py。

cd 'content/posts/AI-深度学习/从零搭建视觉模型/14-验证测试与错误分析/code' && python3 main.py

本篇已附独立实验包,在代码卡片中查看源码、下载或复制运行命令。解压后执行 python3 main.py;依赖安装见包内 README.md。

观察目标: 0.5 时精确率与召回率都为 2/3;0.75 时分别为 1/2 和 1/3。

动手修改: 加入 100 个容易识别的负样本,比较准确率和正类召回率;说明为什么只看准确率会误导。

所有输入均在本篇代码中构造;运行范围和验证记录见包内 verification.md。


完整阅读目录 · 上一篇 · 下一篇