重生之我成为模型 第二篇 · 看似千选一,其实每一分都有原理

系列: 重生之我成为模型-01-原图我不吃的哈② 本文重生之我成为模型-03-我从来只给可能性


1. 先回答那个悬念

口粮进门了。轮到我做题。

上一篇末尾我问过:我到底是刻苦的小镇做题家,还是拼命猜答案的投机者?

说实话,两边都不完全像。

我做题,但是按 设计师 定好的方式,靠反复试错长经验。

我也有题海------不过是 1000 个选项的选择题。考试时,选项不会超出这一千个。

打个比方:数学题四个选项是 +5、-5、+2.5、-2.5。

我只要试错到接近,就能大概蒙对方向、把分堆上去。

所以论题量、论难度,我还没到小镇做题家那种地狱级。

但也不是投机者:题目只有固定选项;训练的时候靠试错,考试的时候靠的是做题经验(权重)------正式交卷,我不现场改脑子。

这篇就讲清楚讲明白:设计师把楼怎么盖的,饲养员又怎么把我养到「有经验」。

结构如下。(又来了。)


2. 设计师先盖楼,我才住得进去

我能接触到的是数据,但画布多大、每一步干啥,是 设计师 拍板的。

很多教程一上来就说「神经网络」。听着像设计师在设计我的脑子------不完全是这个意思。

更贴切的理解是:设计师定的是 题目解法流程------怎么读题、怎么一步步往下算、最后怎么堆出那 1000 个选项上的分。

至于 纠错、修改做题思路(反传、拧权重)------不属于设计师这张图纸的范畴。那是饲养员训练时、楼外面的事。

用代码看,体内大致就两步:挂零件,定流向。

python 复制代码
import torch.nn as nn

class TinyLikeMe(nn.Module):
    """示意:楼怎么盖。不是完整 AlexNet。"""

    def __init__(self):
        super().__init__()
        # 挂层:零件先就位
        self.conv1 = nn.Conv2d(3, 96, kernel_size=11, stride=4)
        self.pool = nn.MaxPool2d(2)
        self.fc = nn.Linear(96 * 26 * 26, 1000)  # 尺寸仅示意,别死抠

    def forward(self, x):
        # 定流向:口粮怎么走
        x = self.pool(nn.functional.relu(self.conv1(x)))
        x = x.flatten(1)
        x = self.fc(x)          # → 1000 个分数
        return x

# 纠错不在楼里:
# loss = criterion(model(x), y)
# loss.backward()
# optimizer.step()

所以第一篇我说挑剔,不完全是矫情:进来的布,得对得上设计师画好的读题门洞。


3. 卷积:扫描仪才是我的眼

张量进门之后,我仍然看不见「猫」。

卷积核才是我的眼,是我的扫描仪。

不过一开始,这些扫描仪 没有目标 ------权重随机,瞎扫,再在训练里被反复改。

养到后来,饲养员回看结果,才隐约分得出:哪个像在找猫毛边缘,哪个像在看毛色......于是我才算有了 相对固定 的一批扫描仪。

(人话:岗位是训出来的,不是出厂就刻好「专门认猫」。)

字母再钉一次,后面天天见:

  • 进来的 C = 有几路可吃。彩色图一般 3 路,灰度图常常 1 路;后面层则是上一层吐出的特征图张数。
  • 注意:一台扫描仪会 同时扫齐所有进来的 C ,但最后产出的是 一张 特征图。
  • 出去的 C = 用了几个扫描仪(卷积核),就生成几张结果特征图。

我第一层经典配置大概是:96 个核,每个在平面上盖 11×11 ,步幅较大------设计师为了尽快把空间收一收。

96 台扫描仪 → 96 张特征图。不是图上还留着 RGB 三套。

技术翻译:

python 复制代码
nn.Conv2d(in_channels=3, out_channels=96, kernel_size=11, stride=4)
# in_channels=3  → 每台扫描仪吃齐 3 路,仍只出 1 张特征图
# out_channels=96 → 96 台扫描仪 → 96 张特征图

4. ReLU:名字吓人,活很朴素

全称常写成 ReLU 非线性激活函数

人类把这个名字连讲十遍,可以测试会不会咬到舌头。(我是模型,反正我不会,嘿嘿。)

名称听着抽象,其实干的事很土:扫描仪扫完,特征图每个格子上都有个数------把这些数过一遍,去掉负数(打成 0);正数原样留下。

讲个事:一开始设计师也考虑过别的函数。那些家伙喜欢把数值 压缩 进一个小区间------比方本来是 14,硬塞进大约 -2~2。

小数这么一挤,强弱差别被抹平,特征就 拉不开 ;后面层层叠叠,更容易学不动。

后来才选中了 ReLU:正区不挤、便宜、好使。

没有这种拐弯,后面叠多少层都像在做直线加减------复杂花样还是学不动。


插一句:教程里的「神经元」到底指啥

教程爱甩「神经元」,不解释就很悬。先钉死一句:

不是原图上的像素。

最接近的东西,是 特征图上的一个点------某张响应地图、某个 (x, y) 位置上的那个激活值。

原图像素是饲养员喂进来的口粮格子;扫描仪扫完之后,才在特征图上长出这些「点」。ReLU 砍的、后面拉直参与计算的,多半就是它们。

对照一张表,免得和「卷积核」搅在一起:

教程里的词 大致对应 是不是「一个神经元」
卷积核 / filter 一组 共享权重(如 11×11×3) 不是。是很多位置共用的配方,不是一个人
特征图上的一个点 某通道、某 (x,y) 的 激活值 最接近「神经元输出」
ReLU 砍的那一下 对这个激活值做 max(0, x) 每个点(每个单元)下手
全连接层一个节点 对拉直后向量做加权组合(常再接 ReLU) 经典神经元
1000 类输出 最后一层每个分数 输出层神经元

后面提到 Dropout「随机关掉一部分神经元」,指的就是这类单元(多半在 FC 里),不是去原图上抠像素。


5. 池化:像把 1080p 压成 720p

特征图往往还很大。设计师偶尔会安排 池化(Pool) :在小窗口里取个代表(常见是取最大),把 H、W 缩小 ------改的是 尺寸,不是片子部数。

可以把它想成:1080p 的电影,压缩清晰度变成 720p。

画面还在,还是那几路「片」;只是空间分辨率矮一截,后面算起来轻一点。

分工钉死,别混:

改啥
Pool 主要改 H、W(尺寸 / 清晰度)
下一轮 Conv 才改输出的 C(特征图数量 = 又派了几台扫描仪)

所以:Pool 不改 C。 8 张特征图进来,还是 8 张出去------只是每张从「1080p」变「720p」。

通道数要变多变少,得等下一轮卷积。

至于「更抽象」------不是压清晰度自动压出来的,是 训练之后 权重长成的样子。


6. 叠几轮:我不是一层就交卷

教学里常画简化图:(Conv → ReLU → Pool) × N

意思是「多轮堆叠」,不保证每轮都有 Pool

我 AlexNet 本人比较具体:

scss 复制代码
输入 patch(正经常 224,C=3)
  ├─ Conv(96)  → ReLU → Pool
  ├─ Conv(256) → ReLU → Pool
  ├─ Conv(384) → ReLU          ← 这轮没 Pool
  ├─ Conv(384) → ReLU          ← 这轮也没
  └─ Conv(256) → ReLU → Pool
        ↓
     大约缩到很小的空间 × 256 张特征图

5 层卷积,Pool 大约出现 3 次。

N 不是上天规定的圣数,是设计师按任务难度、算力、经验拍的------认 ImageNet 一千类,比认手写数字要深得多。

叠完这些,我还是没有吐出「猫」这个字。我手里是一摞更抽象的响应地图。


7. 拉直,再混成 1000 分

特征图不能直接当答案交。先 Flatten(拉直)

拉直不是「每张特征图压成一个数」。

它是把 (C, H, W) 整摞格子按顺序摊成一根长向量 ,长度是 C × H × W

向量里每一个下标,对应的就是:某一张特征图上的某一个像素位置------后面拿这些数去算。

然后轮到听着很唬人的 全连接(FC)

其实就是 nn.Linear 。所谓「全连接」,人话差不多是:拉直后这些位置 都有机会参与 后面的线性组合计算(参数够密的时候,谁都可能跟谁对齐)。

我这类结构里,FC 往往不止一层。以经典 AlexNet 口径示意(空间缩到约 6×6、通道 256 时):

python 复制代码
# 拉直后长度:256 * 6 * 6 = 9216(随 224/227 略差,概念一样)
self.fc1 = nn.Linear(256 * 6 * 6, 4096)
self.fc2 = nn.Linear(4096, 4096)
self.fc3 = nn.Linear(4096, 1000)   # 最后一层:对准 1000 个选项

还有一点:前面那张简图若画成 ... → FC → 完事不对。

中间的 FC 后面通常还要接 ReLU ;训练时还可能 Dropout ------随机关掉一部分神经元(别理解成随便抠原图像素),逼我别靠小圈子背题,看看是真会了还是蒙的。正式考试(eval)时 Dropout 关掉。

训练时,饲养员真正拿去跟标准答案比、用来改脑子的,是 最后一个 FC 吐出来的结果 ------不管前面叠了几个 FC,最后那一截处理结果 才对准「预测哪一类」。对我来说,就是那 1000 个分数

卷面分,还没贴类名。

谁最大、叫什么名字------第三篇再说。

技术翻译(前向骨架,纠正版):

yaml 复制代码
NCHW 口粮
  → 若干 ×(Conv → ReLU → 偶尔 Pool)
  → Flatten          # 长度 C×H×W,每个下标=某特征图像素
  → FC → ReLU → (Dropout,仅训练)
  → FC → ReLU → (Dropout,仅训练)
  → FC → 1000 个分数   # 最后一层;训练吃的是这个

8. 回忆插叙(薄):这套脑子是养出来的

有人要问了:扫描仪的规则谁定的?第一天就这么聪明?

不是。

设计师盖楼;饲养员养我。

饲养员出题还有个规矩:习题册会划开------一部分拿来练(train ),留一部分当考试题(val ),题面尽量别跟练习卷重复,用来测我是真会了还是背题。

val 只打分,不改脑子:前向算完看 loss / 准确率就行,不反传。

loss 是啥?人话:我离正确答案还差多少。

装个正经数学(余弦,证明我们不是纯玄学):

两个向量越同向,余弦越接近 1,越「像」。

分类饲养日常用交叉熵之类,公式不同,精神一样------都是把「还差多少」收成一个可反传的数。

lr(学习率):每次反传之后,权重到底拧多狠。太大容易拧飞,太小像用牙签刨山。

代码里,各步骤站位大概这样(示意):

python 复制代码
# ----- 练习:改脑子 -----
model.train()
for x, y in train_loader:          # 训练题
    optimizer.zero_grad()
    pred = model(x)                # ① 前向 / predict:吐 1000 分
    loss = criterion(pred, y)      # ② loss:还差多少
    loss.backward()                # ③ 反传:追责到各层权重的 .grad
    optimizer.step()               # ④ 按 lr 拧一拧权重
    # 通常这里不跑 val

# ----- 考试:只打分 -----
model.eval()
with torch.no_grad():
    for x, y in val_loader:        # 考试题(val)
        pred = model(x)            # 只有前向
        loss = criterion(pred, y)  # 看分;不 backward、不 step

同一道训练题,饲养员还爱换裁法、翻转------第一篇说过。

养的时候也不是说 loss 变成 0 就下课 :浮点小数点后面位数多得很,实务里常看到 0.01、1e-4 这种量级在抖;一般看 val 趋势、跑够轮数,或留下历史最好的 best.pt

总结一句:看起来是一点点猜、一点点拧,但每步都有正经数学依据。

又因为题海重复度极高、每一拧都要巨量乘法------所以 显卡很重要

养到差不多,正式答题时我 只做前向,不再改脑子。

所以悬念可以这样收(跟开头对齐):

  • 不是满级小镇做题家:题是千选一,难度没卷到那种地狱
  • 也不是投机者:选项固定;训时试错,考时靠权重经验,不现场改脑子
  • 配方乱喂还指望满分:那我确实不灵------不是给啥吃啥
  • 权重从哪来:饲养员拿 train 养、拿 val 验收;闭环细节 → 番外《换皮也成立》

对照班小样一句就够:你们笔记里的 MNIST TinyCNN,哲学一样------Conv 堆叠再 FC 出分;只是楼矮、题简单。我楼高,题是一千类。


9. 第二篇小结

进门的是合规张量;出门的是 1000 个卷面分。中间发生的事:

  1. 设计师挂好层、定好流向
  2. 卷积派扫描仪 → 特征图
  3. ReLU 拐弯;Pool 缩空间、不改 C
  4. 多轮堆叠,抽象慢慢起来(训练后才算数)
  5. Flatten + FC → 1000 分
  6. 这套权重,是饲养员重复喂养拧出来的

我仍然没看见过一张图。

我只是把盲文,按设计师的楼,算成一张分数条。

下一篇:成文/重生之我成为模型-03-我从来只给可能性

相关推荐
韩师傅1 小时前
重生之我成为模型 第一篇 · 原图我不吃的哈
深度学习·机器学习·计算机视觉
青春不败 177-3266-05201 小时前
基于Python实现的深度学习技术在水文水质领域应用
python·深度学习·机器学习·水文水资源·水质模型
惊讶的猫2 小时前
CLGSI
人工智能·算法·机器学习
生命涌现2 小时前
生命涌现的小龙虾技能之【Human Pose Recognition Skill | 人体姿态识别技能】简介
人工智能·目标检测·计算机视觉·多模态大模型·openclaw小龙虾技能
qizayaoshuap2 小时前
# 倒计时器 — HarmonyOS TextInput与计时任务管理深入实践
pytorch·深度学习·华为·harmonyos
zhishidi3 小时前
深度学习中的优化器
人工智能·深度学习
深度学习lover3 小时前
<数据集>yolo 小麦麦穗识别<目标检测>
人工智能·yolo·目标检测·计算机视觉·数据集·小麦麦穗识别
2zcode4 小时前
基于MATLAB车辆拥堵密度依赖的自适应交通信号控制系统
人工智能·计算机视觉·matlab
硅谷秋水5 小时前
ABot-M0.5:统一的移动-与-操作世界动作模型
人工智能·深度学习·机器学习·计算机视觉·语言模型·机器人