AI-深度学习

从零搭建视觉模型 01:图片进入模型后发生了什么

展开合集目录
  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:发展历史、主流分类与当前格局
从零搭建视觉模型 01:图片进入模型后发生了什么的封面

第 1 课:先认识输入、计算和输出。 本篇通过手算和示意性例子建立直观认识,不需要先写代码。文中的分数用于解释计算过程,不代表真实模型的训练成绩。

先看一个具体问题

假设我们想让程序判断一张图片里主要是汽车还是飞机。初学阶段先不考虑检测位置,也不考虑同时存在多个目标:输入一张图,输出这两个类别中的一个。这叫单标签图像分类。

人看到图片时会自然利用轮廓、部件和已有经验。计算机最初拿到的却只是文件里的数据。我们需要一条明确的处理链路,而不是一个写着“智能识别”的黑盒按钮。

图片文件 → 解码为像素 → 按约定整理数字 → 模型计算
                                            ↓
类别名称 ← 根据类别顺序解释 ← 每个类别的输出分数

本篇只要求理解这条链路。Python 语法、张量、卷积分别放到后面的课,不需要现在一次记住。

图片文件与模型输入不是同一个东西

JPEG 文件包含压缩编码。解码后得到的像素可以按行、列和颜色通道访问。模型一般处理已经整理好的数字数组,而不是直接对 JPEG 文件头做分类。

例如,一张宽 32、高 32 的 RGB 图片有 32 × 32 × 3 = 3072 个通道值。把它缩放、转换为浮点数或调换轴顺序,都是为了满足模型输入约定。这些操作不等于训练,也没有让图片自动变聪明。

训练时如果使用 RGB、固定尺寸和某种数值缩放,使用模型时也要一致。摄像头输出的是 BGR,如果仍按 RGB 解释,即使程序没有报错,也可能得到明显不同的结果。

模型可以先理解为结构加参数

结构规定数字经过哪些运算,参数规定这些运算中的可调数值。一个最小例子是 y = w × x + b:乘法和加法组成结构,w 与 b 是参数。

假设 x=2、w=3、b=1,输出就是 7。把 w 换成 4,输入没有变,输出变成 9。真实网络有许多参数和非线性运算,但“固定输入与参数,通过计算得到输出”的基本关系仍然存在。

参数不是人手工填写的“飞机规则表”。训练过程根据样本和目标调整参数,使模型在指定任务上减少误差。模型文件保存参数等信息,推理程序负责加载参数并按结构运行计算;只下载一个文件,还构不成一个完整的系统。

一次输出怎样变成类别

假设我们约定类别顺序是 [飞机, 汽车],模型给出两个分数 [1.2, 2.8]。第二个分数更大,程序便输出“汽车”。这只是一次示意计算,不是某个真实模型的预测记录。

若把类别表错误地改成 [汽车, 飞机],同一组分数就会被解释成“飞机”。所以模型正确不代表外围代码一定正确,类别顺序也是接口的一部分。

分数不一定落在 0~1 之间。后面会接触到 logits 和 Softmax;现在只需知道“输出原始分数”“转换分数”“选择类别”是可以分开的步骤。

训练与推理分别做什么

训练时提供图片和已知标签,比较预测与目标,计算误差,再更新参数。推理时使用已经确定的参数处理新输入,普通推理不会因为看了几张新图就自动学会新类别。

环节 是否需要目标标签 是否更新参数
训练 这里的监督分类训练需要 是
验证与测试 计算正确率时需要 否
实际推理 通常不知道正确答案 否

一个网络即使参数随机,也能产生分数;有输出不等于识别有效。训练集上的成绩好,也不保证陌生光照、背景和视角下仍然好,这就是后面学习数据划分与泛化的原因。

一个贯穿后续课程的任务

前几课用像素和横竖条纹建立计算基础。进入真实分类时,我们采用 CIFAR-10 中飞机和汽车的二分类子集,主要为了保持输入小、任务明确。小尺寸公开图片不能代替摄像头现场数据,这个实验也不是产品级模型。

整个系列逐步补齐输入、计算、学习、评估、保存和转换。检测、分割与 Transformer 在分类闭环之后再学习,最后回看历史总览。遇到新术语时先找它在链路中的位置,再学习具体实现。

自己解释一遍

  1. 参数随机的模型能输出分数吗?能否据此说它会识别?
  2. 模型输出不变,交换类别名称顺序会发生什么?
  3. 将像素除以 255 属于训练还是输入处理?
参考答案

能计算分数,但有效性要用有标注样本评估。交换名称会改变类别解释,可能把原本正确的结果解释成错误标签。对原本在 0~255 范围内的像素值,除以 255 会将其缩放到 0~1,属于输入处理中的归一化,不会更新模型参数。并非所有模型都统一采用这种处理方式,应遵循模型的输入约定。

下一课进入已有的《Python 起步》。本篇学完的标准是能用自己的话说清“图片经过什么、参数来自哪里、结果怎样解释”。

学习记录

2026-10-18:完成本篇阅读与三道练习。已经能够说明:随机参数可以产生分数,但不能据此认定模型具备识别能力;输出不变时,交换类别名称会改变结果解释;像素除以 255 属于输入归一化,不属于训练。

配套代码练习

实验:结构、参数与一次推理

查看完整代码:main.py
"""结构、参数与一次推理。运行方式与练习见 README.md。"""
classes = ['airplane', 'automobile']
# 构造的两个特征:天空比例、轮子响应;不是训练得到的视觉特征。
features = [0.8, 0.1]
weights = [[2.0, -1.0], [-1.0, 2.0]]
def predict(x, w):
    scores = [sum(a*b for a,b in zip(row,x)) for row in w]
    return scores, classes[max(range(len(scores)), key=scores.__getitem__)]
scores, name = predict(features, weights)
print('features:', features, 'scores:', scores, 'class:', name)
assert name == 'airplane'
changed = list(reversed(weights))
assert predict(features, changed)[1] == 'automobile'
print('同样的结构,更换参数后:', predict(features, changed))
下载代码

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

cd 'content/posts/AI-深度学习/从零搭建视觉模型/01-图片进入模型后发生了什么/code' && python3 main.py

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

观察目标: 原始参数预测 airplane;交换两行权重后预测 automobile。

动手修改: 只改变输入特征为 [0.1, 0.8],预测如何变化?再交换类别名称,解释参数和类别映射为什么都要保存。

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


完整阅读目录 · 下一篇