# CLS 02 · 从类别到区域与掩码 主线阅读与优先实验 同图四输出、共享计算、FCN、RoIAlign、信息碰撞与SAM接口 对应课堂(19 页) 可先阅读已有结果,再决定是否运行。重算时请核对各节记录的数据、参数、环境与日期。 **学习路径:** [一张图怎样变成一组框](/course/study/image-detection.html) · [像素、边界与对象身份](/course/study/pixels-instances.html)。两个入口引用同一份现有材料,不需要重复阅读或运行。 本册串起 [P25 的四种输出](/course/pages/l3-r2-p25.html) 到 [P48 的语言入口](/course/pages/l3-r2-p48.html):同一幅图,为什么要从类别走向框、像素和实例? 先读下面的同源场景,再沿共享特征、像素预测和区域对齐往下走。读完后应能解释两件事:两个同类杯子为什么仍需两个身份;改好采样位置为什么不能自动补回已被均值抹掉的信息。每个问题都有可单独引用的 [空间学习材料](/course/blocks/spatial-study-route.html)。 动手时先选一种深度:用 [LAB 03](https://deepnote.com/project/38755e4e-23f6-4f5f-8c68-8a2e4114b1c1/notebook/49a2c030eafa4e1db6fc4f1a08c3810a) 做坐标与表示短练习;想走完整学习过程,再在 [LAB 10:RGB→框](https://deepnote.com/project/38755e4e-23f6-4f5f-8c68-8a2e4114b1c1/notebook/a14237bfa9dd413d959ab4e458e11f42) 与 [LAB 11:RGB→mask](https://deepnote.com/project/38755e4e-23f6-4f5f-8c68-8a2e4114b1c1/notebook/9e268706471944e3a59e6f568f9ce9a3) 中选一本。框公式查 [CLS 07](https://deepnote.com/project/38755e4e-23f6-4f5f-8c68-8a2e4114b1c1/notebook/586e66e049764158a50747e69c219312),像素损失与实例区别查 [CLS 08](https://deepnote.com/project/38755e4e-23f6-4f5f-8c68-8a2e4114b1c1/notebook/2d81e2a1936043349eacb71c53c0defa),不必按编号全部运行。 [此段独立阅读](/course/notebook-blocks/d704ba6fc7e641f5b6d95572806fb361.html) ### 1. 同一场景,四种需要交付的答案 [此段独立阅读](/course/notebook-blocks/e057d39976ab4b019d5b6ded6289b6d4.html) **原始遮挡场景** ![原始遮挡场景](/course/knowledge-assets/bd786379d2b218a74dcc046d.jpg) **框:两个杯实例与一本书** ![框:两个杯实例与一本书](/course/knowledge-assets/0e0cbae0c22414b6dd0ae0e4.jpg) **语义像素:两只杯共享类别** ![语义像素:两只杯共享类别](/course/knowledge-assets/1b156cded6971deeabc529d0.jpg) **实例像素:两只杯分别编号** ![实例像素:两只杯分别编号](/course/knowledge-assets/b5f914ac916f45cc64a89ed7.jpg) 桌面多对象场景及教学框/掩码:同类杯子保留不同实例身份,局部遮挡让边界不总是完整可见。标注用于解释输出定义。 先不记模型名字。想象使用者依次改变要求: | 使用者要什么 | 输出中至少要有什么 | 它还没有回答什么 | | --- | --- | --- | | “画面里有什么?” | 杯子、书等类别 | 每个对象在哪里、有几个 | | “找出每一个杯子。” | 每个对象的类别与框坐标 | 框内哪些像素属于杯子 | | “把所有杯子像素选出来。” | 每个像素的类别 | 两个相接的杯子各是哪一个 | | “分别选中两个杯子。” | 像素归属和实例身份 | 遮挡背后的不可见形状仍需额外约定 | 这四行分别对应分类、检测、语义分割、实例分割。框给出一个矩形范围,不能表达把手中间的空洞;同一个“杯子”类别值,又不能单独区分两只杯子。 **先预测:** 如果只保留“杯子、书”两个词,后续能从这两个词恢复第二只杯子的坐标吗?新任务改变了输出,也改变了训练答案必须包含的信息。 [此段独立阅读](/course/notebook-blocks/dadca1922cc149af84b5a598bf7ef9f4.html) ### 2. 从候选区域开始:哪些计算在重复? [此段独立阅读](/course/notebook-blocks/539971d2bdc14788bac3c5dd86c6ee79.html) R-CNN 把可能含有对象的区域提出来,将每个区域变成网络可以处理的输入,再抽取特征、分类与修正框。预训练来自有监督图像分类,然后用检测数据适配。[R-CNN](https://arxiv.org/abs/1311.2524) 用手沿图中的杯子画三个重叠候选框。它们包含了许多相同像素;如果每个候选都单独跑一遍卷积,就重复计算了共有的杯身和桌面。框越多,重复越明显。 这一步的关键不是“发现了更多模型”,而是发现计算可以复用:**能否先对整张图计算一次,再从共享特征图上读取每个区域?** 框的位置仍必须传给区域读取环节,整图共享并不等于所有对象混成一个向量。 [此段独立阅读](/course/notebook-blocks/baa2d848a3684e9fa7adcc551b6b653f.html) ### 共享整图卷积:固定输出形状,保留区域身份 SPP-net 和 Fast R-CNN 将大量卷积计算移到整图共享阶段。对不同大小候选,区域池化再得到固定形状的区域特征,使后续分类/框回归可以共用参数。[SPP-net](https://arxiv.org/abs/1406.4729) · [Fast R-CNN](https://arxiv.org/abs/1504.08083) 沿同一张图追踪: - 原图经过主干,得到仍有空间位置的共享特征图 F。 - 框坐标从原图坐标系映射到 F 的坐标系。 - 区域读取把各框内特征整理成固定形状。 - 每个区域分别输出类别与修正后的坐标。 杯一、杯二的区域身份没有因计算共享而消失。需要进一步追问的是:区域最初从哪里来,能否也学习? [此段独立阅读](/course/notebook-blocks/54fc84db76d5470fa0ca91903c73280d.html) ### Faster R-CNN:让候选也由特征提出 Faster R-CNN 的区域建议网络(RPN)在共享特征图上预测候选是否像对象,并调整候选框的位置。它把“值得进一步查看的区域”也变成可训练输出,再交给后续区域分类与框回归。[Faster R-CNN](https://arxiv.org/abs/1506.01497) 三步的变化可以这样读:逐区域重复抽特征 → 整图特征共享 → 在共享特征上学习提出候选。检测监督包含对象类别与框;已有分类权重提供起点,新的输出仍需学习。 **到此停一下:** 如果所有框都准确了,我们是否已经知道每一个杯子把手的像素边界?下面从另一个问题出发,不把 FCN 排成 Faster R-CNN 的下一版。 [此段独立阅读](/course/notebook-blocks/d4372ab8df884c7e9001495510cf38ac.html) ### 3. FCN:直接问每个位置属于哪一类 [此段独立阅读](/course/notebook-blocks/7a7522255a9a4acc87acfbf8ab9d33aa.html) FCN 从密集像素预测出发。网络在整个图像上产生类别分数图,再恢复到与输入相对应的输出尺度。深层特征容易汇聚较大范围的语义信息,但空间网格较粗;较浅层保留更细的位置线索。跳跃连接把这些层次的线索结合起来。[FCN](https://arxiv.org/abs/1411.4038) 对于两只杯子,语义分割可以把它们都标为“杯子”。然而一块连通的杯子像素既可能是一只宽杯,也可能是两只相接的杯子。类别值本身不规定实例数量。 因此有两条问题线:**区域路线组织“哪些对象”与框;密集路线组织“哪些像素”与类别。** 它们可以汇合,但不是沿一条箭头依次淘汰。 [此段独立阅读](/course/notebook-blocks/e07a99e024e54a96b95494f93248d35f.html) ### Mask R-CNN:在每个对象区域内预测掩码 Mask R-CNN 保留检测的区域组织,再为每个区域增加一个像素掩码分支。区域分类/框回归回答对象是什么、在哪里;掩码分支回答该区域中哪些位置属于这个实例。[Mask R-CNN](https://arxiv.org/abs/1703.06870) 若杯一与杯二同属杯子,类别相同也能有两张分别属于它们的掩码。训练要求有对应实例的像素标注;主干可复用,但区域内的精细输出不是只换一个名称就自动出现。 这时我们碰到新的敏感点:分类可能容忍区域平移一点,逐像素边界却可能因此错一排。**边界错了,是读取时发生错位,还是表示里没有留下足够信息?** 先看读取。 [此段独立阅读](/course/notebook-blocks/12a787367f384e0488a579b23fda1697.html) ### 4. 对齐:把连续位置准确交给现有特征图 [此段独立阅读](/course/notebook-blocks/59f854c8485e42708eabc7fc8ba1b9ee.html) RoIAlign 的正面作用,是保留连续区域位置,在已有特征图上做采样,减少取整造成的区域错位。 约定原图坐标与特征坐标满足 `u=x/stride`,不引入像素中心额外偏移。若 x=35、stride=16,则 u=2.1875。它位于特征索引 2 与 3 之间,距离左邻为 0.1875。给定两个邻居值 2 与 6: $v=(1-0.1875)\times 2+0.1875\times 6=2.75.$ 若先把位置取成 2,读取值会是 2,连续位移的影响被丢掉了。真实 RoIAlign 在二维区域的网格中采样,使用双线性插值并聚合;这里的一维例子只隔离连续位置怎样影响读数。 **先预测:** 将 x 改为 36,读数是否连续变化?把 stride 改成 8 时,还能沿用特征索引 2、3 的这两个数吗?坐标约定与特征值必须一起明确。 [此段独立阅读](/course/notebook-blocks/e250e45b554d43039064b9da4f55183e.html)展开完整实现代码 ``` # 独立一维采样练习;不等同于完整二维 RoIAlign。 import math feature = [0.0,1.0,2.0,6.0,7.0] stride = 16.0 for x in [32.0,35.0,36.0,40.0,48.0]: u = x/stride lo = math.floor(u); hi = min(lo+1,len(feature)-1) alpha = u-lo v = (1-alpha)*feature[lo]+alpha*feature[hi] print(f'原图x={x:g}, 特征u={u:g}, 左邻={lo}, 插值={v:g}') assert math.isclose((1-0.1875)*2+0.1875*6,2.75) ``` [此段独立阅读](/course/notebook-blocks/4296199189944332aa0e7d0ed0d6a2dc.html) ### 5. 信息没留下,放大网格能找回来吗? [此段独立阅读](/course/notebook-blocks/9a6ef95fe6b34b36b77f310ca2c04aa9.html) 看正式问卷使用的两幅小图: - 甲:`[[1,0],[1,0]]`,左列为 1。 - 乙:`[[0,1],[0,1]]`,右列为 1。 若编码器只留下一个均值,两幅都成为 0.5。现在规定其余特征与框也相同,后续不能回看原图。读取器收到完全相同的输入,无论怎样插值或放大,都没有依据对二者作出不同判断。 这不是说所有低分辨率特征都不能表达边界。给同样一个空间格子增加通道 `左列均值−右列均值`,甲得到 +1、乙得到 −1。网格大小没变,却有了可区分信息。 | 表示 | 甲 | 乙 | 读取器有区别可用吗? | | --- | --- | --- | --- | | 全图均值 | 0.5 | 0.5 | 没有 | | 均值+左右差 | (0.5,+1) | (0.5,−1) | 有 | **先预测:** 对一张真正训练出来的粗特征图,单凭“网格很粗”能断言左右信息必定丢失吗?应检查特征与读出行为,而不能只看张量外形。 [此段独立阅读](/course/notebook-blocks/33bfeb7dd6094665b5679a28be52c251.html)展开完整实现代码 ``` # 独立 CPU 练习:表示碰撞与新增通道。 A = [[1.0,0.0],[1.0,0.0]] B = [[0.0,1.0],[0.0,1.0]] def encode(matrix): mean = sum(map(sum,matrix))/4 left_minus_right = sum(row[0] for row in matrix)/2-sum(row[1] for row in matrix)/2 return mean,left_minus_right fa,fb = encode(A),encode(B) assert fa[0]==fb[0]==0.5 assert fa==(0.5,1.0) and fb==(0.5,-1.0) for label,matrix in [('甲',A),('乙',B)]: average,side = encode(matrix) enlarged = [[average]*4 for _ in range(4)] print(label,'只留均值:',average,'放大后首行:',enlarged[0], '新增左右差:',side) print('同一个均值放大后仍相同;差别来自编码时保存了新的通道。') ``` [此段独立阅读](/course/notebook-blocks/f875004afbdc40f28e971ad3eafb9769.html) ### 回到真实训练:对齐为什么值得修复 Mask R-CNN v3 的 Table 2 使用 COCO `trainval35k` 训练、`minival` 测试;表中未另说明时报告 mask AP。以下固定 ResNet-50-C4、stride 16,并选同为 max 聚合的行: | 区域读取 | 是否保留对齐 | 是否双线性 | mask AP | mask AP75 | | --- | --- | --- | --- | --- | | RoIPool | 否 | 否 | 26.9 | 26.4 | | RoIWarp | 否 | 是 | 27.2 | 27.1 | | RoIAlign | 是 | 是 | 30.2 | 31.8 | RoIAlign 相比 RoIPool 的 AP 增加 3.3 点,AP75 增加 5.4 点。RoIWarp 也插值却没有同样改善,支持“保持坐标对应”这一机制判断。平均聚合的 RoIAlign 行是 AP30.3/AP75 31.5,引用时不能把不同聚合行混在一个对照里。Table 2(d) 换成 C5、stride32,mask AP 从 23.6 到 30.9;这是另一组设置。 这些是训练完整模型的论文结果,不是本课程重跑。它们说明读取位置值得修复,尤其严格定位受益;P44 则把输入 F 固定成完全相同,讨论任何确定性读出都无法创造差别。方法有效与构造例中的信息限制,可以同时成立。 [原论文 Table 2](https://arxiv.org/html/1703.06870v3#S4.SS2) · [备课模拟追问:论文与信息碰撞为什么不矛盾](/course/blocks/roi-information-dialogue.html) [此段独立阅读](/course/notebook-blocks/20ee5eb6f2da43b784c77a32e9ca12d7.html) ### 6. 活动:类别图与实例图怎样不同? [此段独立阅读](/course/notebook-blocks/58f9ec0b8a46438ea54c09154c54ddf4.html) 下面用一个小型教学网格表示两只杯子与一本书,独立于上方照片的人工轮廓。`0` 是背景,`1/2` 是杯一/杯二,`3` 是书。两只杯子在中间相接;实例图仍保留两个身份。 把实例 1 与 2 都映射为类别“杯子”后,语义图保留杯子整体区域,丢掉二者的身份差别。框则只记录每个实例出现的最小矩形范围,不保存矩形内部哪些格子为空。 **先预测:** 如果两个杯子的语义区域连在一起,仅凭语义图能唯一确定原来的分界吗?运行下格,比较 `instance`、`semantic` 和 `boxes`,再改变一个格子。静态读者可直接用这一解释:类别映射是多对一;两个不同实例图可以得到同一语义图。 [此段独立阅读](/course/notebook-blocks/81854aba012c40cd957e12cbb4bbd008.html)展开完整实现代码 ``` # 独立 CPU 教学标签网格;不是照片真值或检测模型输出。 instance = [ [0,0,0,0,0,0,0,0], [0,1,1,2,2,0,0,0], [0,1,1,2,2,0,0,0], [0,1,1,2,2,0,0,0], [0,0,0,0,3,3,3,0], [0,0,0,0,3,3,3,0]] class_of = {0:0,1:1,2:1,3:2} # 类别0背景,1杯子,2书 semantic = [[class_of[x] for x in row] for row in instance] boxes = {} for identity in [1,2,3]: coordinates=[(r,c) for r,row in enumerate(instance) for c,x in enumerate(row) if x==identity] rows,cols=zip(*coordinates) boxes[identity]=(min(cols),min(rows),max(cols)+1,max(rows)+1) print('实例图:'); [print(row) for row in instance] print('语义图:'); [print(row) for row in semantic] print('框(x0,y0,x1,y1;右/下边界不含):',boxes) assert semantic[1][2]==semantic[1][3]==1 assert instance[1][2]!=instance[1][3] ``` [此段独立阅读](/course/notebook-blocks/a77753adddda4578b9601eba650283c3.html) ### 7. SAM:点一下,这次要处理哪一个? [此段独立阅读](/course/notebook-blocks/673e073110a3452fbc7257bc532e6383.html) ### 提示指定本次目标,训练学会响应提示 在杯柄上给一个正点,并不唯一规定目标是杯柄、整只杯子还是更大的对象组合。提示式分割的任务是根据图像与提示返回合理 mask;提示增加信息,但不必天然消除所有歧义。 几何提示可以分工:正点表示希望包含的位置,负点表示希望排除的位置,框给出大致区域,已有 mask 可以作为进一步修正的输入。它们不是人工直接提供完整答案,却约束了本次想处理的对象。模型须结合图像线索填出边界。 原始 SAM 将图像编码、提示编码和 mask 解码分开。同一图像的较重表示可缓存,用户改点、改框时重复较轻的后半段。它也能为模糊提示给出多个 mask 与估计质量,从而容纳“部分还是整体”的不同解释。 本页教学图显示提示与目标的对应关系;若要评价模型,应保存真正返回的 mask,并先约定期望的对象粒度。用户给一个点后显示手工真值,不能替代推理证据。LAB 16 目前保留的是确定性颜色/连通域规则,适合比较接口,不冒充 SAM 权重推理。 原始 SAM 的图像编码器使用 MAE 预训练初始化。这连接了第一部分的表示学习,但“遮挡重建”目标并没有直接提供“某个正点应对应哪个对象 mask”的全部监督。后续还要进行提示式分割训练。 训练样本包含图像、目标 mask 与模拟提示。模型预测后,可以从错误区域追加正点或负点,再要求它修正;原论文训练模拟每个 mask 的多轮交互,掩码损失组合 focal 与 dice。这样,推理时的“改点、改框”对应训练中学过的任务,而不是凭空获得一个通用按钮。 数据组织也属于能力来源。SA-1B 来自模型辅助标注、半自动补充、全自动生成的逐步演进,最终收集约 1100 万张图像与 11 亿个 mask。这里的数据单位是区域轮廓,并非现成的图文语句对。 预训练参数、任务监督和使用接口可以分别复用:先以自监督表示为起点,再学习图像/提示到掩码,使用时缓存同图表示。如果只说“MAE 会补图所以自然会分割”,就跳过了任务训练这一关键桥梁。注意此处是原始 SAM;文字提示在论文中有另行探索,不等于公开几何提示 checkpoint 默认已具备任意语言理解。 [LAB 16 规则基线的准确身份](/course/blocks/sam-rule-baseline-explained.html) · [原始 SAM §2–4](https://arxiv.org/html/2304.02643v1) [此段独立阅读](/course/notebook-blocks/fd0dc77671064e8ab452f36d817bc71b.html) ### 8. 从空间提示,走向语言指定 [此段独立阅读](/course/notebook-blocks/fd2927a7e00c404ab41726f122010251.html) 现在我们可以清楚地区分四种能力:判断画面中的类别、找对象框、给每个像素分类、按实例分出掩码。方法的推进围绕计算共享、输出身份和空间读取展开。 我们已经能用框和掩码指出对象,也能用一个点告诉系统“这次处理哪一个”。但人往往会说“找到红色杯子”,或者问“谁拿着球”。**语言能否参与学习,也参与我们向系统提出任务?** 到 L03-CLS 03,沿三种可以共存的作用继续:语言成为输出、提供学习信号,以及指定当前问题。 若想先动手,到 **L03-LAB 03 · 空间信息:表示、采样与掩码**。它沿用同图材料与这里的确定性计算,重点判断该改采样还是改表示,无需训练大型检测器。 [此段独立阅读](/course/notebook-blocks/a6405459d7294dcba2d9562323768021.html) ## 课后先选一条路 不必按 Notebook 编号把所有内容从头运行。若刚听完课堂,先用 P25 的同一底图区分类别、框、语义与实例,再用 P41–45 的两个算例区分读取错位与表示碰撞。它们构成理解空间任务所需的最短连续线。 随后只选一项完整学习过程:关心对象位置就读 LAB 10,沿图像、目标、匹配、分类/位置损失、预测与错误图走完;关心面积或边界就读 LAB 11,比较 RGB 基线与 FCN、查看逐类 IoU 与窄缝错误。无需为了“完整”同时训练两本,也不要把只跑通环境当成理解模型。 LAB 09 是检测公式的工作台,遇到匹配、NMS 或 AP 不清时按问题查;LAB 03 是同源场景与空间读数的轻量练习。LAB 16 的颜色连通域和 LAB 20 的集合匹配放在选读,分别解释提示约束和对象排列,不与两项主实验争夺主线。 CLS 02 承担区域到掩码的连续导读;CLS 07、08 承担深入公式与实例。每个解释块有独立 URL,可直接带着具体问题交给 AI;链接中的正文先提供推理,再连接代码与原论文。 [打开可单独引用的空间学习路径](/course/blocks/spatial-study-route.html) [此段独立阅读](/course/notebook-blocks/6b8197023f3c4157bbcb484c8154751e.html) ## 把这一段交给 AI 时,保留哪几个条件 若问 [均值碰撞](/course/blocks/representation-collision-proof.html),保留“F 与框相同、不能回看原图”;若问 [RoIAlign 论文结果](/course/blocks/roi-align-paper-evidence.html),保留骨干、步长、聚合方式与训练/测试划分。前者是确定性算例,后者是完整模型的历史训练对照。 想查看连续文字可从 [P25](/course/pages/l3-r2-p25.html) 开始;要定位一个公式或追问,可直接引用上方独立块 URL。这样 AI 读到的是具体材料与条件,而不只是模型名字。 [此段独立阅读](/course/notebook-blocks/44be3baf1ddf4d27914e3f2ef66b6820.html) ### 继续阅读与旧链接说明 [此段独立阅读](/course/notebook-blocks/dfb0e45f02414f1e8a19806fbc3eebb0.html)