跳到主要内容

数据截至 (上游 commit c187ef3271d5)

看得更细 — 框、像素,和一次只改图不改网络的训练

这一章讲三件事。第一件:同一张图,答案可以问得越来越细。 上一章问的是「这张图是什么」,这一章依次问「每个东西在哪」和「每个像素属于谁」。

第二件:越细的答案,要越贵的标注,也要新的标尺。 「框得差不多对」不是是非题, 得有一条能算出数来的线;而这条线又催生出一个能汇总整个数据集的分数。

第三件,是全书最反直觉的一节:训练不一定在调权重。 把网络整个冻死、让第 01 章那个「往哪边挪」的信号去改输入图像本身 —— 这就是风格迁移。它证明了一件事:那个循环里被挪动的东西,可以不是网络。

在全书链条里的位置: 三个零件里,这一章换的还是「数据摆成什么形状」和 「输出层配哪个损失」—— 只不过标签从「整张图一个数」变成了一堆框、一整张掩码, 最后干脆变成输入图自己。

这一章也是全书自相矛盾最集中的一段。 我们逐条核过,四处都给了行号,你可以自己去看。

1. 顶层全景:同一批航拍羊,从「有羊」到「每只羊在哪」

这一章的主走查是一批无人机拍的航拍照片,画面里散着一群羊, 要模型把每一只羊各框出来1。链条是这样的:

3609 张训练图(每张里好多只羊,每只都有一个人工画好的框)

├─① 把框的写法从一种格式换成另一种 ──→ 一行一个框的文本文件

├─② 按框架要的目录结构摆好 ──────────→ images/ 和 labels/ 各三份

├─③ 加载一个别人训好的检测模型 ──────→ 接着往下训 10 轮

├─④ 拿一张没见过的图去问 ────────────→ 它先吐出一大堆候选框

├─⑤ 砍掉「我不太确信」的 ────────────→ 剩下少数几个

├─⑥ 把叠在同一只羊上的合成一个 ──────→ 每只羊剩一个框

└─⑦ 用「交并比」判命中,汇总成一个分数 → 这次训得好不好

图说:①② 是数据准备,③ 是训练,④⑤⑥ 是模型每次推理都要走的三步,⑦ 是评估。 这一章另外还有两条独立的走查 —— 洪水区域分割和风格迁移, 它们用的是完全不同的数据,读到第 7、8 节时请当心别和这条混起来。

2. 三种「看懂」,和它们各自的价钱

上一章开头那张图给了三级答案,这一章要把后两级做出来2:

问法答案长什么样一张图要标什么
图像分类(上一章)一个标签在文件夹里放对位置就行
目标检测一堆矩形框,每个框带一个类别人工把每个东西各框一遍
语义分割一张和原图一样大的图,每个像素一个类别人工把每一块区域涂出来

那些矩形框有个正式名字:边界框3

代价这一列才是这一章真正的成本线。 书讲分割时把标注过程描述得很直白: 你得在一个标注工具里,像「按数字填色」那样把属于某一类的区域一块块涂出来 —— 又费时间,又没什么智力含量,但不做就没有训练数据4。 这类「人工给数据配上答案」的活,行话叫数据标注

书里为此推荐了一个免费工具(Label Studio),但明说本章跳过这一步, 直接挑了一个已经配好掩码的数据集5

要标多少张? 书给的是一串影响因素,不是一个数字6:图片要清晰、框要画准 (标错会误导模型、还会拖长训练);素材要多样(不同角度、不同大小、不同光照, 甚至互相遮挡一部分也有用);要区分的类别越多、类别之间越像,就要越多数据。 它给的底线是:每个类别至少几百张标注良好的图片。

但这条底线有一个大幅折扣的前提,而它值得单独记一笔: 书说做目标检测几乎总是应该用一个别人已经训好的网络, 因为它已经「看过」几百万张图,现在只需要学会认出你要的那几种东西。

用了这一招,每类几十张到 100 张就可能够了7。 几百张 vs 几十张,差一个数量级 —— 这件事为什么成立、怎么做,第 12 章整章讲。

3. 检测怎么做到:只看一遍

先看现象,再看做法。 最直觉的办法是:拿上一章那个分类器, 在图上一格一格地滑,每停一处问一次「这里有没有羊」。问题是图上位置太多、 框的大小又有无数种,这样试一遍慢得没法用

书把真实做法分成两条路线8:

路线怎么做取舍
两阶段先挑出「这里可能有东西」的若干块区域,再对每块做分类准,但慢
单阶段定位和分类在同一趟里一起出来 —— 检测常用在实时场景

单阶段里最有名的一个,名字本身就是它的做法:你只看一遍(YOLO)9。 它的流程是三步。

第一步:把图切成网格,每一格负责报「中心落在我这一格里」的东西。 一格报出若干个框,外加每个框的一个数10

第二步:那个数叫置信度 —— 「我有多确信这个框里真有东西」。 设一条门槛,低于门槛的框直接扔掉11

第三步:同一个东西往往被好几个相邻的格子各报了一遍,框互相压着。 这时用一个叫非极大值抑制的算法收尾:留下置信度最高的那个框, 把和它重叠、可能指同一个东西的其余框全部抹掉。 每个物体最后只剩最可靠的那一个框12

这三步里,第三步依赖一个还没定义的东西:「重叠」到底怎么量? 下一节就是它。

4. 框「差不多对」怎么量:交并比与 mAP

先看现象: 预测框和人工画的框几乎不可能严丝合缝地重合。 那么「这算不算框对了」就不是是非题,得有一条能算出数来的线。

书给的量法叫交并比(IoU),定义只有一句: 两个框重叠部分的面积,除以两个框合起来盖住的总面积13。 取值在 0 到 1 之间:

IoU = 0.1 IoU = 0.5 IoU = 0.9
两框只擦了个边 大致对上了 几乎完全重合

图说:书用这三档给读者建立量感 —— 0.5 就是「差不多对了」的那一档。

书自己就是这么读它的:重合得很少时值很小;重合得相当好时大约是 0.5; 几乎完美时接近 114

有了这条线,「命中」才有定义:先定一个门槛,IoU 超过门槛才算命中。 最常用的门槛是 0.5,按这个门槛把整个数据集上的精确率汇总成一个数, 就是你在检测这一行到处会见到的 mAP5015

还有一个更严格的版本 mAP50-95:把门槛从 0.5 到 0.95、每隔 0.05 算一遍再取平均。 它逼模型不只是「框到了」,还得框得准 —— 书说它给出的画面更稳健16

顺便把一个到处都会撞见的统称定下来:mAP50、精确率、召回率这些 「专门算出来给模型打分」的数,有个统称就叫指标

训练过程里另外还有三条曲线要看,它们把「哪里没学好」拆开了17:

曲线它在量什么
box loss框的位置和大小画得准不准
cls loss框里那个东西的类别判得对不对
dfl loss一种较新的损失,专门用来把框的位置定得更准

判断(我们的,不是书里的):书在这里列了一个不存在的格子。 它把上一章那张四格表原样搬过来讲检测,列出了真阳、真阴、假阳、假阴四项18可目标检测根本没有真阴 —— 真阴的意思是「这里没有东西,模型也说没有」, 而一张图上「没有框的地方」有无穷多个位置,你没法把它们数出来。 这恰恰就是检测必须用 mAP 而不能用准确率的原因:准确率的分母里有真阴, 而这个分母在检测里不存在。书列了这一格,后面再也没用过它。 如果错,会错在: 如果把图硬性切成有限个网格、并把「这一格没有物体」当成一次真阴, 那么真阴是可数的 —— 但那样一来,真阴会淹没其余三格,任何模型的准确率都接近 100%, 这个数照样没有意义。判据是:书自己后面报的全是精确率、召回率和 mAP,一次都没报准确率。

5. 同一个框有三种写法,换错一种全盘皆错

这一节讲的是一个纯工程陷阱,但它坑掉的人比上面所有机制加起来都多。

一个矩形框要用四个数描述。问题在于:哪四个数,业界有三套互不兼容的约定, 分别由三个不同的团队定下来,各自跟着一套数据格式19:

写法那四个数是什么标注文件长什么样
Pascal VOC左上角、右下角两个点的坐标XML,一张图一个文件
COCO左上角坐标 + 宽 + 高JSON(一种给程序读的文本格式,一层层嵌套着「名字:值」),所有标注挤在一个文件里
YOLO中心点坐标 + 宽 + 高,而且四个数都除以图的宽高,变成 0 到 1一张图一个文本文件,一行一个框

为什么这件事致命: 同样的四个数 (100, 80, 40, 30), 按 COCO 读是「左上角在 (100,80),框宽 40 高 30」, 按 YOLO 读是「中心在 (100,80)」—— 两个框差了半个框的距离,而且程序不会报错。 模型照着错位的标注训一遍,损失也会下降,只是学出来的东西是错的。

所以数据格式和算法对不上时,必须显式换算 —— 这正是主走查第 ① 步在做的事20

6. 主走查:3609 张航拍羊,从换格式走到一张标好框的图

下面凡是标了「书里的数」的都来自原书;标了「演示用」的是我们为讲清一步编的。

第 ① 步,换格式。 数据是 HuggingFace 上的航拍羊群数据集, 训练 3609 张、验证 350 张、测试 17421。 书把每个框的四个数除以图的宽和高,归到 0 到 1,再按「一行一个框」写进文本文件, 每行前面加一个 0 表示类别编号22

第 ② 步,摆目录。 框架要求图片和标注分开放,各自再分训练/验证/测试: images/trainlabels/trainimages/val …… 一共六个目录23。 再写一个配置文件告诉它:数据在哪、要认几类(nc: 1)、这一类叫什么(names: ['sheep'])24

第 ③ 步,加载现成模型接着训。 一行 YOLO('yolov8n.pt') 就把一个别人训好的模型拉下来; 然后 model.train(epochs=10, imgsz=320, batch=16):训 10 轮、图统一缩到 320、每批 16 张25注意这里没有第 01 章那种手写循环 —— 整个训练被这个框架收走了。

顺带一说:这一段代码里还有一行设置环境变量(在程序外面挂一个「名字=值」的开关, 程序一启动就去读它)的语句,把训练记录写到本地一个文件夹。

它挂的那个工具叫 MLflow,是用来把每次训练的参数和成绩存档的 —— 书在这里直接用了它,而它是什么要到原书第 12 章才讲,中间隔了八章26。 你现在只需要知道这一行不影响训练结果;这套工具第 14 章会专门讲。

第 ④ 步,推理:先吐出一大堆候选框。 训完之后加载成绩最好的那份权重, 拿测试集里的一张图去问27。模型按第 3 节那三步走。

假设图里有一只羊站在偏左上的位置,它周围三个格子各报了一个框 (以下这组数是为演示编的,不是书里的真实数值):

候选框 A:置信度 0.91 候选框 B:置信度 0.78 候选框 C:置信度 0.34

第 ⑤ 步,按置信度砍。 门槛设 0.5,C 直接出局,剩 A 和 B。

第 ⑥ 步,去重。 A 和 B 压在同一只羊上,算一下它们的交并比: 假设重叠面积占两框合起来的 82%,也就是 IoU = 0.82,远高于「算同一个东西」的门槛。 于是留下置信度最高的 A,抹掉 B —— 这只羊最后只剩一个框(这三个数同样是演示用的)。

第 ⑦ 步,评估。 把上面这套动作在验证集的每张图上跑一遍, 逐个框和人工框比交并比、按 0.5 的门槛判命中,汇总成 mAP50;再按 0.5 到 0.95 汇总成 mAP50-95。 书报的是训练曲线的走向:三条损失一路下降,而精确率、召回率、mAP 一路上升, 说明模型确实在学会认羊和定位28

第 ⑧ 步,看结果。 把预测框叠回原图,书的评语是羊被识别得相当好29

判断(我们的,不是书里的):第 ① 步的格式,正文和代码对不上。 正文说这份数据是 COCO 格式(左上角 + 宽高),必须换成 YOLO 格式30; 可两处代码都是按「中心点 + 宽高」在算的 —— 画框那一段的注释白纸黑字写着 「从 [x_center, y_center, width, height] 转成 [x_min, y_min, x_max, y_max]」, 而且减的是宽高的一半;写标注文件那一段也直接把四个数命名成 x_center, y_center, width, height31两者只有一个能对。 如果正文对(数据真是 COCO),那么写出去的每个标注都整体偏了半个框; 如果代码对(数据本来就是中心格式),那么正文那句「它们是 COCO 格式」是错的。 旁证偏向后者: 画框那段代码给三个坐标各加了一个 +10 的偏移量, 这种硬凑的数通常是「怎么画都对不齐」时留下的痕迹。 如果错,会错在: 如果那个数据集的框确实是左上角格式、而代码里的变量名只是起错了名字, 那么正文对、代码错,结论要反过来 —— 但无论哪一种,这两处不一致是确定的。 判据:打开数据集看一个框的四个数,和图里羊的实际位置比一下。

7. 另起一条走查:细到每个像素

这一节和主走查用的不是同一份数据,请当心。

问题变了。 分类的答案是一个数,检测的答案是四个数; 分割的答案是一整张图 —— 和原图一样大,只不过每个位置存的不是颜色,是类别编号32。 一张 128×128 的图,答案就是 16384 个数。

做法是把网络掰成两段,合起来长得像一个 U,所以这种架构常被叫作 U-Net33。 两段各管一件事。

前半段叫编码器:一路缩小,和上一章那条「一边缩尺寸一边涨通道」的路子一样, 它负责回答「图里有什么」—— 但位置信息在缩小的过程中被磨掉了

后半段叫解码器:一路放大回原来的尺寸,负责回答「在哪儿」, 把抽象特征翻译回逐像素的判断34

输入图 ──→ [编码器:越缩越小] ──→ 瓶颈 ──→ [解码器:越放越大] ──→ 逐像素的类别图
这是什么 在哪儿

图说:U 形的两条腿就是这一缩一放。但书没画那个 U 上最关键的一样东西 —— 见下面的补充。

补充(不在书里,依据我们的 ai-book-reference 书架): U 形结构真正的关键不是「缩了再放」,而是把编码器每一级的特征直接横向抄送给解码器对应的那一级。 理由很硬:瓶颈是故意压细的,细节在那里必然丢失;而分割恰恰需要像素级的精确边界。 所以「是什么」走瓶颈,「在哪里」走这条捷径。这一层没有,U 就只是两条腿、没有横杠35

这一次的数据: 290 张洪水区域照片,每张配一张人工涂好的掩码,只分两类:淹了、没淹36。 切成 232 张训练 / 58 张验证 —— 听着少得可怜, 但书当场提醒了一句很值钱的话:每张图有 128 × 128 = 16384 个目标值, 所以监督信号的总量并不小37

走一遍:

一张洪水照片
→ 缩到 128×128、转成张量 图:[8, 3, 128, 128] (一批 8 张、彩色 3 通道)
→ 掩码同样缩到 128×128、去掉通道 掩码:[8, 128, 128]
→ 掩码里大于 0.5 的记 1、其余记 0 这一步把灰度掩码变成 0/1 两类
→ 送进一个别人训好的分割模型,接着训 10 轮
→ 预测出来的每个像素给一个数,大于 0 记 1
→ 三张图并排:原图 | 人工掩码 | 模型掩码

图说:书的评语是模型给出的掩码已经和人工掩码相当接近38这里的形状变化就是这一节的全部要点:输入是三通道的彩色图,答案是一张单通道的类别图。

「拿别人训好的模型接着往下训」这件事有个名字,叫微调 —— 第 12 章整章讲它。

判断(我们的,不是书里的):这一节讲的是 U-Net,跑的却不是 U-Net。 代码加载的是 nvidia/mit-b0,而书自己在讲另一种网络结构时早就许诺过: 「我们不从零实现这套结构,而是在 §4.5 把这样一个模型微调到我们的数据上」39 —— §4.5 正是这一节。所以这一节实际跑的是那种「把图切成小块当序列读」的结构 (上一章第 8 节讲过入口),不是它刚讲完的编码器-解码器。 书没有把这两句接起来,读者会以为自己训的就是刚讲的那个 U-Net。 如果错,会错在: 如果 nvidia/mit-b0 其实是一个卷积编码器而不是那种结构, 这条判断就不成立。判据在书里而不在别处:上一章那句许诺明确写着「在 §4.5 微调这样一个模型」, 而 §4.5 只加载了这一个模型。

8. 另起第二条走查:把网络冻死,改的是图

这一节是全书最反直觉的一处,而且它是一根伏笔 —— 第 12 章会回来收。

先看现象: 给一张汉堡的照片配上《神奈川冲浪里》那幅浮世绘, 输出一张「同样的景、浮世绘的笔触」的新图40

然后是那个反转。 第 01 章那个循环里,固定的是数据、变的是权重。 风格迁移把这两样对调了:书自己的说法是,它不是传统意义上的模型训练, 因为没有任何模型权重被调整 —— 权重被冻结(锁死、不再更新), 被反复调整的是那个「目标」,也就是正在生成的那张图本身41

传统训练: 输入(固定) → 模型(权重在变) → 输出
风格迁移: 输入(在变!) → 模型(权重冻死) → 输出

图说:同一个循环,挪的东西换了。梯度这次流回的不是权重,是像素。

代码上就是一行: 把内容图复制一份,给它打开「这张图要算梯度」这个开关, 然后把这份图交给优化器 —— 优化器的调节对象从模型参数变成了这张图的像素42

用来打分的那台网络是 VGG19。 书说它是为一场大型图像分类竞赛做的, 一共 24 层,其中 16 层卷积 + 5 层池化 + 3 层全连接;池化层没有可训练的参数, 所以「带参数的层」只有 19 层,名字里那个 19 就是这么来的43。 它在整个过程里一个字都不改。

关键设计:内容和风格从网络的不同深度取。 这正好用上了上一章那条层级特征 —— 浅层认边缘纹理,深层认大块形状。所以内容从较深的一层取(它记的是「画面里有什么」), 风格从浅到深好几层一起取(它们记的是笔触和色块)44

那「风格」到底是什么?这一节最要紧的定义在这里。 书给的答案是:风格 = 哪些特征爱一起出现,以及出现得有多频繁 —— 把这件事算出来的那个东西叫 Gram 矩阵45

它怎么算(书给了四步)46:

① 取某一层的输出:C 个通道,每个通道是一张 H×W 的特征图
② 把每张特征图拉直,得到 C 行、H×W 列的一张表
③ 这张表乘上它自己的转置,得到一个 C×C 的方阵
—— 第 (i, j) 格 = 第 i 个通道和第 j 个通道逐位置相乘再求和(这叫点积)
这个数大,说明这两种特征常常同时出现在同一个位置
④ 除以 C×H×W 做一次缩放,免得不同大小的特征图算出来量级差太多

图说:第 ③ 步是全部的机制。 注意它把「在画面哪个位置」整个丢掉了 —— 矩阵里只剩「谁和谁一起出现」,不剩「出现在哪」。 这正是我们想要的:风格是不该带位置的。

这一次的走查:

内容图:一张汉堡的照片 风格图:《神奈川冲浪里》
→ 两张都缩到 224×224、按 VGG 的均值方差缩放 形状 [1, 3, 224, 224]
→ 把 VGG19 全部权重冻死
→ 生成图 = 内容图的一份复制,挂上「要算梯度」
→ 每一轮:
内容差 = 生成图在深层的特征 与 内容图在同一层的特征 之差
风格差 = 生成图在五个层的 Gram 矩阵 与 风格图的 Gram 矩阵 之差
(五层的权重从浅到深是 1.0 / 0.8 / 0.6 / 0.4 / 0.2)
总差 = 风格差 × 2000000 + 内容差 × 1
→ 反向传播,优化器改的是生成图的像素,学习率 0.003
→ 转 500 轮,每 100 轮存一张图

图说:那个 200 万比 1 的悬殊配比不是笔误。 书解释得很清楚: 两种差值本身的量级差得极远,给风格差乘一个大系数,只是为了把它们拉到可比的量级上47。 书最后描述的效果是:随着训练推进,画面里的天空越来越多地被用来表现浮世绘里的浪48

9. 书里的立场与证据

书里给了证据的:

  • 交并比那三档(0.1 / 0.5 / 0.9) —— 配了图,直观且标准;
  • 检测训练确实在进步 —— 三条损失下降、三个指标上升,是真实跑出来的曲线;
  • 风格迁移的效果 —— 有分阶段保存的图为证。

作者的经验判断(书里没给证据):

  • 「每类至少几百张,用了预训练几十张也够」 —— 经验法则,书自己用的措辞是 「没有固定的数字」;
  • 「两阶段更准、单阶段更快」 —— 这是行业通识,书没给对比实验;
  • 五个风格层的权重 1.0 / 0.8 / 0.6 / 0.4 / 0.2、以及 200 万这个系数 —— 都是拍下来的,书只解释了「为什么需要一个大系数」,没解释为什么是这个数。

书里没交代来历的: 这一章出现的三个机制 —— YOLO、U-Net、风格迁移 —— 全书没有引用任何一篇论文。我们补在了脚注里49

10. 边界与局限

这本书对的地方先说清: 这一章把「答案越问越细 → 标注越来越贵 → 标尺也得跟着换」 这条线索排得很清楚,而且每一级都真的跑通了一个例子。 标注格式那一节尤其实用 —— 那是新手最常栽的坑,很多教材根本不提。

但有四处照抄会踩坑,都给了行号:

  1. 检测的四格里列了不存在的真阴 —— 见第 4 节末的判断块;
  2. 框格式正文与代码对不上 —— 见第 6 节末的判断块;
  3. 讲了 U-Net 却跑了另一种结构 —— 见第 7 节末的判断块;
  4. 算 Gram 矩阵的那个函数忘了写返回语句。 函数体算完最后一步就结束了, 什么都没交回去 —— 照抄会拿到一个空值,后面全崩50同一节还有两处名字对不上: 正文定义的层字典叫 STYLE_LOSS_LAYERS, 函数里用的却是 LOSS_LAYERS;超参数那一行写的是小写的 vgg_mean, 预处理里用的却是大写的 VGG_MEAN。三处都是照抄跑不起来的那种错。

还有一处过时和一处版本落差:

  • 加载 VGG19 用的是 pretrained=True,这个参数从 torchvision 0.13(2022)起已经改成 weights=;
  • 书里画的那张检测架构图是 YOLO 第 1 代(448×448 输入、7×7×30 输出), 而代码跑的是 yolov8n.pt —— 第 8 代。中间隔了七代,书没提这件事。 架构图当「一阶段检测大概长什么样」看没问题,当「你正在跑的这个模型」看就错了。

这一章没覆盖的:

  • YOLO 内部怎么把「一个格子」变成「几个框加置信度」,书只给了三步流程,没给结构;
  • 实例分割(同类的两个东西也要分开)一个字没提,只讲了语义分割;
  • 标注工具只演示了界面,没讲怎么组织标注团队、怎么保证一致性;
  • 公式全是图片 —— 交并比、Gram 矩阵的算式在原文里一个字都没有, 上面那几处算式是我们按书的文字描述重写的。

11. 可带走的

主走查一行写完: 3609 张航拍羊 → 框从一种格式换算成「中心点 + 宽高 + 归一化」 → 摆成 images/labels 六个目录、配置里写 nc: 1 → 加载 yolov8n.pt 训 10 轮 → 推理时先出一堆候选框、按置信度砍、再按交并比去重 → mAP50 / mAP50-95 汇总。

  1. 答案越细,标注越贵:整图一个标签 → 每个东西一个框 → 每个像素一个类;
  2. 检测两条路线:两阶段准而慢,单阶段(YOLO)快;实时场景用后者;
  3. YOLO 三步:网格出框 → 按置信度砍 → 非极大值抑制去重;
  4. 交并比 = 交集面积 ÷ 并集面积;0.5 是「差不多对了」那一档;
  5. mAP50 是按 0.5 门槛汇总的分数,mAP50-95 更严格 —— 它逼你不只框到、还要框准;
  6. 检测没有真阴,所以不能用准确率,只能用 mAP;
  7. 框有三套写法(两角 / 左上加宽高 / 中心加宽高并归一化),换错一种程序不报错、模型学错;
  8. 分割 = 逐像素分类;编码器一路缩问「是什么」,解码器一路放问「在哪儿」;
  9. U 形结构真正的关键是编码器到解码器的横向抄送,书没画这一层;
  10. 232 张图不算少 —— 每张 128×128 = 16384 个目标值;
  11. 风格迁移把循环倒过来:权重冻死,梯度去改输入图的像素;
  12. 风格 = 哪些特征爱一起出现,用 Gram 矩阵算,它故意不含位置信息;
  13. 内容取深层、风格取多层;风格权重要乘 200 万,只是为了和内容差同量级。

12. 原文地图

主题原书章原文位置
检测的定位与边界框Chapter 4text/06-ch04-chapter-4.txt:1274(搜「we’ll go beyond that」) · text/06-ch04-chapter-4.txt:1276(搜「called bounding boxes」)
两阶段 vs 单阶段Chapter 4text/06-ch04-chapter-4.txt:1292(搜「two-stage and single-stage」) · text/06-ch04-chapter-4.txt:1297(搜「you only look once」)
YOLO 三步Chapter 4text/06-ch04-chapter-4.txt:1299(搜「places a grid over the image」) · text/06-ch04-chapter-4.txt:1316(搜「confidence value」) · text/06-ch04-chapter-4.txt:1320(搜「nonmax suppression」)
三种标注格式Chapter 4text/06-ch04-chapter-4.txt:1384(搜「University of Oxford」) · text/06-ch04-chapter-4.txt:1401(搜「upper left and lower right corners」)
要标多少数据、预训练的折扣Chapter 4text/06-ch04-chapter-4.txt:1452(搜「quality of the images」) · text/06-ch04-chapter-4.txt:1461(搜「almost always use a pretrained network」) · text/06-ch04-chapter-4.txt:1476(搜「few hundred well-annotated images」)
数据规模与格式换算Chapter 4text/06-ch04-chapter-4.txt:1445(搜「Number of images in train: 3609」) · text/06-ch04-chapter-4.txt:1410(搜「Convert boxes from」) · text/06-ch04-chapter-4.txt:1532(搜「Normalize bounding box coordinates」)
目录结构与配置文件Chapter 4text/06-ch04-chapter-4.txt:1477(搜「stored in the corresponding folders」) · text/06-ch04-chapter-4.txt:1554(搜「The nc parameter describes」)
加载与训练、MLflow 那一行Chapter 4text/06-ch04-chapter-4.txt:1598(搜「YOLO('yolov8n.pt')」) · text/06-ch04-chapter-4.txt:1617(搜「epochs=10, imgsz=320」) · text/06-ch04-chapter-4.txt:1601(搜「MLflow is generally used to manage」)
三条损失曲线Chapter 4text/06-ch04-chapter-4.txt:1636(搜「Box losses」) · text/06-ch04-chapter-4.txt:1642(搜「Distributed focal losses」)
勘误 检测的四格里有真阴Chapter 4text/06-ch04-chapter-4.txt:1663(搜「True negative」)
交并比与 mAPChapter 4text/06-ch04-chapter-4.txt:1691(搜「intersection over union」) · text/06-ch04-chapter-4.txt:1712(搜「the IoU value will be very」) · text/06-ch04-chapter-4.txt:1717(搜「mAP50」) · text/06-ch04-chapter-4.txt:1730(搜「mAP50-95」)
训练走向与推理Chapter 4text/06-ch04-chapter-4.txt:1735(搜「positive training curve」) · text/06-ch04-chapter-4.txt:1787(搜「superimposed on the image」)
分割:逐像素、U-Net、编码器解码器Chapter 4text/06-ch04-chapter-4.txt:1805(搜「predicted for each individual pixel」) · text/06-ch04-chapter-4.txt:1828(搜「U-Net because it has a U-shaped structure」) · text/06-ch04-chapter-4.txt:1835(搜「decoder part of the network」)
人工标注掩码的代价Chapter 4text/06-ch04-chapter-4.txt:1868(搜「manually annotate each of the source images」) · text/06-ch04-chapter-4.txt:1890(搜「painting by numbers」)
洪水数据、三份大小、16384 个目标值Chapter 4text/06-ch04-chapter-4.txt:1813(搜「290」) · text/06-ch04-chapter-4.txt:2041(搜「Training samples: 232」) · text/06-ch04-chapter-4.txt:2045(搜「16,384 target values」)
掩码二值化与形状Chapter 4text/06-ch04-chapter-4.txt:1997(搜「Convert to binary mask」) · text/06-ch04-chapter-4.txt:2056(搜「torch.Size([8, 3, 128, 128])」)
加载的分割模型与 ViT 那句许诺Chapter 4text/06-ch04-chapter-4.txt:2074(搜「nvidia/mit-b0」) · text/06-ch04-chapter-4.txt:2143(搜「adapt mask to have value 1」) · text/06-ch04-chapter-4.txt:221(搜「fine-tune」)
风格迁移:权重冻结、改的是目标Chapter 4text/06-ch04-chapter-4.txt:2192(搜「classic sense because no model weights」) · text/06-ch04-chapter-4.txt:2195(搜「weights are frozen and the target value」) · text/06-ch04-chapter-4.txt:2458(搜「generated_image = content_img.clone()」)
VGG19 的层数与两处取特征Chapter 4text/06-ch04-chapter-4.txt:2215(搜「16 convolutional layers」) · text/06-ch04-chapter-4.txt:2219(搜「higher the abstraction level」) · text/06-ch04-chapter-4.txt:2382(搜「STYLE_LOSS_LAYERS」)
Gram 矩阵的定义与四步Chapter 4text/06-ch04-chapter-4.txt:2415(搜「Gram matrix, which」) · text/06-ch04-chapter-4.txt:2425(搜「independent of the exact spatial arrangement」) · text/06-ch04-chapter-4.txt:2432(搜「posed matrices」)
两个权重的量级差与结果Chapter 4text/06-ch04-chapter-4.txt:2268(搜「very different orders of magnitude」) · text/06-ch04-chapter-4.txt:2277(搜「STYLE_WEIGHT = 2000000」) · text/06-ch04-chapter-4.txt:2505(搜「the sky more and more」)
勘误 Gram 函数没有返回、两处变量名对不上Chapter 4text/06-ch04-chapter-4.txt:2440(搜「def calc_gram_matrix」) · text/06-ch04-chapter-4.txt:2402(搜「if name in LOSS_LAYERS」) · text/06-ch04-chapter-4.txt:2278(搜「vgg_mean」)

Footnotes

  1. 出处:「Chapter 4 Computer Vision」第 1278-1281 段(text/06-ch04-chapter-4.txt:1280,搜「drone images showing sheep」)。原文:图 4.22 左边是测试图,右边是叠上预测框的同一张图。

  2. 出处:「Chapter 4」第 1273-1276 段(text/06-ch04-chapter-4.txt:1274,搜「we’ll go beyond that」)与第 1804-1808 段(text/06-ch04-chapter-4.txt:1805,搜「predicted for each individual pixel」)。原文:此前预测的是整张图级别的类别,目标检测把预测下放到图像区域;分割则把预测下放到每一个像素。

  3. 出处:「Chapter 4」第 1276 段(text/06-ch04-chapter-4.txt:1276,搜「called bounding boxes」)。原文:这些图像区域用矩形框表示,叫边界框;同一张图里可以有很多个框,属于同一类或不同类。

  4. 出处:「Chapter 4」第 1889-1892 段(text/06-ch04-chapter-4.txt:1890,搜「painting by numbers」)。原文:你必须像在图像编辑软件里那样,把所选类别的区域标出来 —— 这就像按数字填色,是一个非常耗时、智力上又没有挑战的过程,但为了得到好的训练数据,你不得不做。

  5. 出处:「Chapter 4」第 1874-1894 段(text/06-ch04-chapter-4.txt:1874,搜「One free service is Label Stu」)。原文:本书聚焦模型开发,因此跳过这一步,选了一个同时提供原图和对应掩码的数据集。

  6. 出处:「Chapter 4」第 1449-1476 段(text/06-ch04-chapter-4.txt:1452,搜「quality of the images」)与第 1476 段(text/06-ch04-chapter-4.txt:1476,搜「few hundred well-annotated images」)。原文的最后一句是:本质上没有一个固定的数字可追求,但每个目标类别至少应该有几百张标注良好的图片。

  7. 出处:「Chapter 4」第 1461-1464 段(text/06-ch04-chapter-4.txt:1461,搜「almost always use a pretrained network」)。原文:我们几乎总是应该为目标检测使用一个预训练网络 —— 它已经「见过」数百万张图,现在只需要学会检测那些特定物体;用了预训练,每类几十张到 100 张图就可能足够。

  8. 出处:「Chapter 4」第 1291-1296 段(text/06-ch04-chapter-4.txt:1292,搜「two-stage and single-stage」)。原文:早期研究者做的是两阶段模型 —— 先提议图中可能有物体的区域,再分析并分类这些区域,这种做法非常精确但也更慢;由于检测常用于实时应用,后来又发展出一步到位、预测更快的单阶段模型,定位和分类在一次运行中完成。

  9. 出处:「Chapter 4」第 1296-1298 段(text/06-ch04-chapter-4.txt:1297,搜「you only look once」)。补充(不在书里,依据我们的 ai-book-reference 书架):这套算法出自 Joseph Redmon 等人 2016 年的工作,它的快是靠结构性取舍换来的。 依据: book=shen-du-xue-xi-quan-shu §08-object-detection 事实=该章讲 YOLO 属于一阶段算法、引用发明人 Redmon 在 2016 年 CVPR 的对比(Faster R-CNN 算完一次车已开出 12 英尺、YOLO 只要 2 英尺),并明说「快是牺牲准确率所换来的」。

  10. 出处:「Chapter 4」第 1299-1302 段(text/06-ch04-chapter-4.txt:1299,搜「places a grid over the image」)。原文:YOLO 在图上铺一层网格,每一格负责预测那些中心落在该格内的物体;干这件事的是一个卷积网络,图 4.23 画出了它的结构。

  11. 出处:「Chapter 4」第 1316-1318 段(text/06-ch04-chapter-4.txt:1316,搜「confidence value」)。原文:结果会有很多互相重叠的框,每个框带一个「能在其中检测到对应物体」的置信度,置信度低于阈值的框被滤掉。

  12. 出处:「Chapter 4」第 1319-1322 段(text/06-ch04-chapter-4.txt:1320,搜「nonmax suppression」)。原文:同一个物体可能还剩下好几个略有差异的框,这时非极大值抑制登场 —— 它找出置信度最高的那个框,滤掉所有可能代表同一物体的重叠框,于是每个物体只剩下最好、最可靠的那一个预测。

  13. 出处:「Chapter 4」第 1689-1705 段(text/06-ch04-chapter-4.txt:1691,搜「intersection over union」)。原文:一般来说框不可能完美吻合,需要一个量化「只部分正确」的度量,它叫交并比;分子是交集(两个框共享的面积),分母是两个框合起来的总面积(并集)。原书的公式是图片,提取出来是空行。

  14. 出处:「Chapter 4」第 1712-1715 段(text/06-ch04-chapter-4.txt:1712,搜「the IoU value will be very」)。原文:预测与真实框只有很少重合时,交并比很小;吻合得相对好时大约是 0.5;几乎完美时接近 1。

  15. 出处:「Chapter 4」第 1715-1719 段(text/06-ch04-chapter-4.txt:1717,搜「mAP50」)。原文:交并比还被当成一些指标的过滤器,只有超过阈值的预测才被计入;mAP50 就是用 0.5 作为交并比阈值、在所有类别上求平均的平均精度。

  16. 出处:「Chapter 4」第 1730-1733 段(text/06-ch04-chapter-4.txt:1730,搜「mAP50-95」)。原文:这个指标比 mAP50 更全面,它在 0.5 到 0.95 之间以 0.05 为步长把各个阈值下的 mAP 求平均,给出一幅跨不同定位精度的稳健图景。

  17. 出处:「Chapter 4」第 1633-1644 段(text/06-ch04-chapter-4.txt:1636,搜「Box losses」)。原文三类:box loss 量框预测得准不准;cls loss 量框内物体的分类质量;dfl loss 是较新的一类专门用来提升定位精度的损失。

  18. 出处:「Chapter 4」第 1660-1668 段(text/06-ch04-chapter-4.txt:1663,搜「True negative」)。原文的第二项写着:「真阴 —— 那里没有船,也没有预测出船」。这一项在后面的精确率、召回率、mAP 里从未被用到。

  19. 出处:「Chapter 4」第 1375-1405 段的信息框(text/06-ch04-chapter-4.txt:1384,搜「University of Oxford」)。原文:Pascal VOC 由牛津大学提出,标注是 XML,一张图一个文件;COCO 由微软用 250 万张图训练,标注全部合在一个 JSON 文件里;YOLO 一张图一个标注文件,框逐行描述。三者的坐标约定见第 1401-1405 段(text/06-ch04-chapter-4.txt:1401,搜「upper left and lower right corners」):Pascal VOC 用左上和右下两个角,COCO 用左上角加水平垂直方向的延展,YOLO 的参考点在框的正中间、同样再给宽高。

  20. 出处:「Chapter 4」第 1407-1409 段(text/06-ch04-chapter-4.txt:1407,搜「doesn’t match the algorithm used」)。原文:如果所用数据的格式和所用算法不匹配,就必须做转换 —— 我们的例子正是这种情况。

  21. 出处:「Chapter 4」第 1440-1447 段(text/06-ch04-chapter-4.txt:1445,搜「Number of images in train: 3609」)。原文三个数:训练 3609、验证 350、测试 174。数据集是 HuggingFace 上的「Aerial Sheep Dataset」,鸟瞰视角、每只羊都带框。

  22. 出处:「Chapter 4」第 1526-1539 段(text/06-ch04-chapter-4.txt:1532,搜「Normalize bounding box coordinates」)。原文的写法:四个数分别除以图的宽或高,再按 0 x y w h 的格式一行一个框写进文本文件,开头那个 0 是类别编号。

  23. 出处:「Chapter 4」第 1477-1505 段(text/06-ch04-chapter-4.txt:1477,搜「stored in the corresponding folders」)。原文列出了 imageslabels 两棵目录树,各自再分训练、验证、测试。

  24. 出处:「Chapter 4」第 1550-1567 段(text/06-ch04-chapter-4.txt:1554,搜「The nc parameter describes」)。原文:配置文件里要写数据集根路径、训练/验证/测试图片目录、nc(要检测多少类)以及 names(各类的名字);这个例子里是 nc: 1names: ['sheep']

  25. 出处:「Chapter 4」第 1592-1598 段(text/06-ch04-chapter-4.txt:1598,搜「YOLO('yolov8n.pt')」)与第 1614-1618 段(text/06-ch04-chapter-4.txt:1617,搜「epochs=10, imgsz=320」)。原文:把准备好的配置文件传给 model.train,连同训练轮数、图像尺寸、批大小这些模型特定的参数。

  26. 出处:「Chapter 4」第 1600-1607 段(text/06-ch04-chapter-4.txt:1601,搜「MLflow is generally used to manage」)。原文:开始训练前需要先定义模型追踪,这里用 MLflow —— 它通常用来管理、追踪和部署机器学习实验,而 PyTorch 用来创建和训练模型;代码把 MLFLOW_TRACKING_URI 指到本地文件夹。这个工具的完整讲解在原书第 12 章 §12.2,也就是我们的第 14 章。

  27. 出处:「Chapter 4」第 1740-1785 段(text/06-ch04-chapter-4.txt:1750,搜「best.pt」)。原文:训练结果保存在 runs 文件夹里,加载其中的 best.pt;然后从测试集里挑一张图(代码取的是下标 1 那一张)交给模型。

  28. 出处:「Chapter 4」第 1735-1738 段(text/06-ch04-chapter-4.txt:1735,搜「positive training curve」)。原文:各轮之间损失函数持续下降,验证集上的精确率、召回率与 mAP 上升,说明模型正在成功学会识别并定位这些羊。

  29. 出处:「Chapter 4」第 1787-1798 段(text/06-ch04-chapter-4.txt:1787,搜「superimposed on the image」)。原文:把预测叠到图上,可以看到羊被识别得非常好。

  30. 出处:「Chapter 4」第 1372-1373 段(text/06-ch04-chapter-4.txt:1372,搜「they are in COCO format」)。原文:框可以有多种定义方式,这里它们是 COCO 格式,但我们必须把它们转成 YOLO 格式。

  31. 出处:「Chapter 4」第 1410-1416 段(text/06-ch04-chapter-4.txt:1410,搜「Convert boxes from」)与第 1530-1539 段(text/06-ch04-chapter-4.txt:1530,搜「x_center, y_center, width, height = bbox」)。前一处的注释和代码都按中心格式在算(减去宽高的一半),而且给三个坐标各加了一个 + 10 的偏移量;后一处直接把四个数命名成中心坐标与宽高。

  32. 出处:「Chapter 4」第 1822-1827 段(text/06-ch04-chapter-4.txt:1825,搜「the pixel size of the original image」)。原文:分割的预测和原图一样大 —— 如果图是 M×N 个像素,算法返回的维度是 (M, N, C),C 是模型要学会预测的类别数。

  33. 出处:「Chapter 4」第 1828-1830 段(text/06-ch04-chapter-4.txt:1828,搜「U-Net because it has a U-shaped structure」)。原文:大多数分割模型使用编码器-解码器架构;由于外形的缘故,这种架构常被称作 U-Net —— 一条用于捕捉上下文信息的下采样路径,接上一条用于精确定位与细节还原的上采样路径。

  34. 出处:「Chapter 4」第 1831-1839 段(text/06-ch04-chapter-4.txt:1835,搜「decoder part of the network」)。原文:编码器接收输入图并提取特征,同时降低图像的空间分辨率,学到边缘纹理这类抽象特征以及形状这类更复杂的特征;解码器接收编码器提取的特征,试图恢复原始空间分辨率,把抽象特征翻译回像素级精确的分割掩码。

  35. 补充(不在书里,依据我们的 ai-book-reference 书架):书只讲了「缩了再放」这两条腿,没提 U 形结构真正的关键 —— 编码路径到解码路径的横向跳连。依据: book=deep-learning-crash-course §07-u-net 事实=该章写明 U-Net 由 Ronneberger 等人 2015 年为生物医学图像分割提出,并讲清跳连的动机:瓶颈故意压细节,这对去噪是优点、对分割是致命伤,所以让「是什么」走瓶颈、「在哪里」走跳连这条捷径。

  36. 出处:「Chapter 4」第 1813-1815 段(text/06-ch04-chapter-4.txt:1813,搜「290」)。原文:数据集是「Flood Area Segmentation」,包含 290 张受洪水影响区域的图片,以及表示「没被淹」和「被淹」两类的分割掩码。

  37. 出处:「Chapter 4」第 2036-2045 段(text/06-ch04-chapter-4.txt:2041,搜「Training samples: 232」)与第 2045 段(text/06-ch04-chapter-4.txt:2045,搜「16,384 target values」)。原文:图片数量看起来相对少,但不要忘记每张图有 128 × 128 也就是 16384 个目标值。

  38. 出处:「Chapter 4」第 1993-1998 段(text/06-ch04-chapter-4.txt:1997,搜「Convert to binary mask」)、第 2050-2062 段(text/06-ch04-chapter-4.txt:2056,搜「torch.Size([8, 3, 128, 128])」)、第 2139-2144 段(text/06-ch04-chapter-4.txt:2143,搜「adapt mask to have value 1」)与第 2173-2174 段(text/06-ch04-chapter-4.txt:2173,搜「fairly good predictions」)。原文:掩码用灰度值表示类别,由于这里是两类问题,把大于 0.5 的都变成 1;预测出来的同样按「大于 0 记 1」二值化;最后三图并排显示,模型给出的预测已经和真实掩码相当接近。

  39. 出处:「Chapter 4」第 221-222 段(text/06-ch04-chapter-4.txt:221,搜「fine-tune」)与第 2071-2076 段(text/06-ch04-chapter-4.txt:2074,搜「nvidia/mit-b0」)。前一处是原书讲视觉 transformer 时写下的:我们不会从零实现这种网络架构,而是在 §4.5 把这样一个模型微调到我们的数据上;后一处就是 §4.5 里加载的那个检查点。

  40. 出处:「Chapter 4」第 2177-2182 段(text/06-ch04-chapter-4.txt:2178,搜「style of an artistic image is transferred」)与第 2304-2319 段(text/06-ch04-chapter-4.txt:2314,搜「The_Great_Wave_off_Kanagawa」)。原文用的两张图是一张汉堡的照片和葛饰北斋的《神奈川冲浪里》。

  41. 出处:「Chapter 4」第 2191-2195 段(text/06-ch04-chapter-4.txt:2192,搜「classic sense because no model weights」)与第 2195 段(text/06-ch04-chapter-4.txt:2195,搜「weights are frozen and the target value」)。原文:风格迁移不是传统意义上的模型训练,因为没有模型权重被调整;常规训练中输入和目标值是预先给定的、模型调的是自己的权重,而风格迁移里权重被冻结、目标值被持续调整。

  42. 出处:「Chapter 4」第 2456-2460 段(text/06-ch04-chapter-4.txt:2458,搜「generated_image = content_img.clone()」)与第 2284-2291 段(text/06-ch04-chapter-4.txt:2290,搜「param.requires_grad = False」)。原文:先把 VGG19 的全部参数设成不需要梯度、并切到评估模式;生成图由内容图复制而来并打开梯度,优化器接收的参数列表里只有这张图。

  43. 出处:「Chapter 4」第 2211-2218 段(text/06-ch04-chapter-4.txt:2215,搜「16 convolutional layers」)。原文:VGG19 最初是为 ImageNet 图像分类竞赛开发的;它有 19 层 —— 16 个卷积层、5 个池化层、3 个全连接层,合计其实是 24 层,但只有 19 层带可学习参数,因为池化层没有可训练参数。补充(不在书里,依据我们的 ai-book-reference 书架):这个模型族出自 2014 年 Simonyan 与 Zisserman 的工作。 依据: book=deep-learning-with-python-2e §08-convnets 事实=该章记 VGG16 是 2014 年 Simonyan 与 Zisserman 的模型、卷积基有近 1500 万参数。补充(不在书里,来自通用知识):VGG19 与 VGG16 出自同一篇论文,区别只是层数更多。

  44. 出处:「Chapter 4」第 2219-2222 段(text/06-ch04-chapter-4.txt:2219,搜「higher the abstraction level」)与第 2382-2388 段(text/06-ch04-chapter-4.txt:2382,搜「STYLE_LOSS_LAYERS」)。原文:网络开头的层负责识别像素、线条、边缘这类简单特征,越往深处特征的抽象层次越高、识别的是更大的部件或物体;我们利用这个性质,在网络的不同位置提取特征 —— 风格从多处取,内容从另一处取。代码里内容取的是 conv4_2,风格取的是 conv1_1conv5_1 五层。

  45. 出处:「Chapter 4」第 2412-2417 段(text/06-ch04-chapter-4.txt:2415,搜「Gram matrix, which」)。原文:内容的损失可以用经典办法算,但风格不行;每张图有自己的「观感」,艺术上体现为色彩模式、笔触、纹理,数学上可以用 Gram 矩阵来描述 —— 它确定哪些特征一起出现、出现得有多频繁,对算法来说这些就是相关的特征。

  46. 出处:「Chapter 4」第 2424-2438 段(text/06-ch04-chapter-4.txt:2425,搜「independent of the exact spatial arrangement」)与第 2431-2436 段(text/06-ch04-chapter-4.txt:2432,搜「posed matrices」)。原文四步:确定通道数 C 与横向纵向元素数 W、H;取出并变形各层的特征图;把张量与它的转置相乘得到一个方阵,矩阵里每一项都是两个特征向量的标量积,值高就说明这两种特征经常且强烈地一起出现;最后做归一化,因为各层特征图大小不同,不归一化损失会不稳定。原文还明说:Gram 矩阵与特征的确切空间排列无关。

  47. 出处:「Chapter 4」第 2264-2280 段(text/06-ch04-chapter-4.txt:2268,搜「very different orders of magnitude」)与第 2275-2280 段(text/06-ch04-chapter-4.txt:2277,搜「STYLE_WEIGHT = 2000000」)。原文:这里不需要批大小(只处理一张图),也不需要单独的学习率,只要定训练轮数;两种损失的量级差别很大,给风格损失乘一个大系数是为了把两者拉到可比的量级。轮数是 500,优化器 Adam 的学习率是 0.003(text/06-ch04-chapter-4.txt:2460,搜「lr=0.003」)。

  48. 出处:「Chapter 4」第 2502-2507 段(text/06-ch04-chapter-4.txt:2505,搜「the sky more and more」)。原文:图 4.42 展示了训练若干轮之后的进展,可以看到模型越来越多地把天空当作画面来表现风格图里的波浪。

  49. 见本页脚注 9(YOLO)、35(U-Net)、43(VGG19),以及下面这一条。补充(不在书里,依据我们的 ai-book-reference 书架):风格迁移这套两项损失的做法出自 2015 年 Gatys 等人的工作。 依据: book=deep-learning-with-python-2e §12-generative 事实=该章讲神经风格迁移是 2015 年 Gatys 等人提出的,内容损失取顶层激活、风格损失取多层格拉姆矩阵,并给它划了一条边界:它只是纹理迁移。

  50. 出处:「Chapter 4」第 2440-2448 段(text/06-ch04-chapter-4.txt:2440,搜「def calc_gram_matrix」)。原文的函数体算到 gram_matrix.div(...) 就结束了,没有 return。另两处名字不一致见第 2402 段(text/06-ch04-chapter-4.txt:2402,搜「if name in LOSS_LAYERS」,而定义在第 2382 段写的是 STYLE_LOSS_LAYERS)与第 2278 段(text/06-ch04-chapter-4.txt:2278,搜「vgg_mean」,而预处理里用的是 VGG_MEAN)。