分类输出一个标签,检测输出一个框。分割要的是 一张和原图一样大的图,每个像素都标着它属于什么。 这个要求看起来只多了"精细"两个字,但它把 CNN 的结构逼出了一个根本性的矛盾。
回看《CNN 卷积神经网络》:分类用的 CNN 会一路把分辨率缩下去——224 → 112 → 56 → 28 → 14 → 7。 这是它"越深看得越抽象"的机制,但代价是位置精度一路降低。
互动 · 同一张图,分辨率一路降下去,位置精度跟着丢
分割 = 在"看得懂"和"看得清"之间做一次往返旅行。
降分辨率让它看得懂(知道这是猫还是狗),升分辨率让它看得清(知道猫的耳朵在第几个像素)。
"先降后升"这个结构叫编码器-解码器。编码器常直接拿一个在 ImageNet 上预训练好的分类 CNN 来当。 ImageNet 是约 120 万张图、1000 类的图像分类数据集;在它上面训过的 CNN 已经会认各种物体, 拿来当编码器正好——它早就学会了"看懂",这一章只要补上"看清"。但光这样还不够——升回来的过程是凭空猜的, 细节早就丢了。U-Net 加的那一招才是关键:跳连(skip connection)。
下面那几个读数先交代清楚:TP = 这一类预测对的像素,FP = 多标的, FN = 漏标的;IoU = 对的 ÷(对的 + 多的 + 漏的),1 最好; mIoU = 各类 IoU 的平均,第 4 节会细讲。 这个互动用"把降采样前的清晰图按比例混回来"近似跳连,真实 U-Net 是把编码器的特征图拼(cat)到解码器同样大小那一层。
互动 · 亲手做一次分割往返(真实的
原图 + 真实标注
模型的预测
把「使用跳连」关掉:像素准确率从 99.8% 掉到 78.1%,边界从锐利变成一格一格的台阶——因为
打开跳连:解码器在每一层都能直接拿到
注意:这里的跳连和 ResNet 的跳连不是一回事。ResNet 的跳连是把一层的输入直接加到输出上,让梯度好传;
U-Net 的跳连是把编码器某一层的特征图直接送到解码器同样大小的那一层,补回位置细节。名字一样,目的不同。
四种
棋盘伪影来自转置卷积的工作方式:每个输入像素乘上整个卷积核,铺到输出上,再叠加。 既然要叠加,输出上每一格被叠的次数就可能不一样——下面这张图真的数给你看。
互动 · 棋盘伪影到底是哪来的(真的数每一格被叠了几次)
| 方法 | 怎么算 | 结果 | 用在哪 |
|---|---|---|---|
| 最近邻 | 直接复制最近的像素 | 锯齿状方块,能明显看出格子 | 分割里更常用双线性;而 Distill 上 Odena 等人 2016 年讲棋盘伪影的文章(链接)发现,在生成图片的任务(后面的生成模型章节讲)里「最近邻放大 + 卷积」效果最好 |
| 双线性 | 周围 4 个点按距离加权平均 | 平滑,无 |
现代分割网络的主流选择 |
| 转置卷积 | 把卷积"反过来"做(每个输入像素铺开成整个核) | 可学习,但容易产生棋盘伪影 | 早期分割、生成模型 |
| PixelShuffle | 把每个像素身上的多个通道值摊开、铺成更大的图 | 无伪影;它本身没有参数,可学习的是它前面那层卷积 | 超分辨率 |
转置卷积的做法是:每个输入像素乘上整个卷积核,铺到输出上,然后叠加。
如果核大小不能被步长整除(比如核 3、步长 2),那么输出图上不同位置的叠加次数不一样——
有的位置被叠了 2 次、有的被叠了 1 次。于是出现规则的明暗格子,就是棋盘伪影。
解法:用"先插值再卷积",或者把核大小设成步长的整数倍。
现代做法干脆换成双线性插值 + 一层 3×3 卷积:在分割里(DeepLab v3+ 就是这么做的)效果同样好,也不会有伪影。
分割的准确率不能简单用"对的像素比例"。想象一张图 95% 是背景—— 一个把所有像素都预测成背景的模型,准确率就有 95%,但它毫无用处: 背景类 IoU 是 0.95,猫类 IoU 是 0,mIoU 只有 0.475。IoU 的分母是"并集",多圈(FP)和漏掉(FN)都要受罚。
互动 · 真实的 IoU 计算(拖动
把鼠标停在公式里的字母上(TP / FP / FN / TN 都可以)——下面哪一个滑块会亮,就说明那个符号指的就是它。
在很多论文里你会看到 TP / (TP + FP + FN) 和
(预测正确 ∩ 真实正确) / (并集) 两种写法。它们其实等价——只是分子记法不同。
但有个真实的歧义:不同框架算 mIoU 时,"背景类"算不算进去、
"忽略区"(如边界附近的 don't care 像素)怎么处理,都可能有差别。
比较两个模型的 mIoU 时,先确认口径一致。
要一个真实世界的参照:PASCAL VOC 2012 上,DeepLab v3+ 报的 mIoU 是 89.0% (test set;模型直接输出,不再用额外的算法修边)——那是 21 个类(20 个前景 + 背景)在所有测试图上的平均, 比上面这个只有两类的小例子难得多。
| 代际 | 代表 | 核心贡献 |
|---|---|---|
| 第一代 全卷积 |
FCN (2015) | 第一次把分类网络的全连接层换成卷积, 让网络输出从"一个标签"变成"一张标签图"。是所有分割网络的地基 |
| 第二代 编码器-解码器 |
U-Net (2015)、SegNet | 跳连。U-Net 至今仍是医学图像分割的默认选择—— 因为它在标注图很少时表现极好:原文的训练集只有 30 张图 |
| 第三代 多尺度 + 空洞卷积 |
DeepLab v1-v3+、PSPNet | 用空洞卷积(在卷积核的格子之间插空)在不降分辨率的情况下扩大 |
| 第四代 Transformer 与通用分割 |
SegFormer、Mask2Former、SAM | Transformer 做分割(后面有专章);SAM 把"分割任何东西"做成了一个可提示的通用模型—— 给个点或框就能分割,不需要针对新类别重新训练。套路和后面大语言模型的 「先大规模预训练、再用提示指挥它干活」一样 |
前面五节一直在说「分割要逐像素判对」。但「判对」到底怎么变成一个数字? 这一章的打分公式只有一个分数,它的上下两个数都是数像素数出来的。 拖那个预测框:三块颜色一变,分数就跟着变。
核心大图 · 三块像素,就是公式里的三个字母
这个分数就是 IoU:你圈住的,和真的,重叠了多少? 而 mIoU 就是把它对每个类别各算一次、再平均——下面这张图就是那个「平均」。
微型图解 · 三个类别各算一个分数,等权平均成 mIoU
| 成本 | 说明 |
|---|---|
| 标注成本高得离谱 | 分类要点 1 下,检测要画 1 个框,分割要沿着物体边缘描一圈—— 像素级标注是这三个任务里最费人的 |
| 计算量大 | 输出和输入同尺寸。224×224 的图,输出是 50176 个像素 × 类别数, 而分类只需要输出 1 个标签。这些分数最后每个像素取最大的那一类(argmax),就得到标签图 |
| 边界永远有争议 | 猫的耳朵边缘算不算猫毛?半透明的玻璃属于室内还是室外? 不同标注员会把同一个像素标成不同类别——这是 mIoU 天花板的一部分 |
| 实例分割更难 | 语义分割只要"这里是人",实例分割还要区分"这是第 1 个人、这是第 2 个人"。 两只重叠的羊怎么分?这是 Mask R-CNN 专门解决的问题 |
| 类别极不平衡 | 背景像素往往远多于前景。 |
互动 · 三个任务,各要吐出多少个数字
这一章的每一处结构,都可以用一句平常的话解释:你没有的东西,就不能指望它回来。
回到第 2 节那张「亲手做一次分割往返」。把「跳连」切到「不用跳连」——
下面那行 mIoU 从 0.992 掉到 0.519,圆和方块的边变成带台阶的糊边;
再把「
那几步你看到的就是“学习即压缩”:
这一章主要落在下面三条暗线上(字母是六条暗线的编号)。
| 暗线 | 这一章的回答 |
|---|---|
| A 信息流动 | 括号里是“高 × 宽 × 通道数”:(H, W, 3) → 跳连额外引入一条横向的数据流:同一分辨率的编码器特征被“抄”进解码器。 出口是分类、检测、分割这三个任务里唯一一个和输入同尺寸的输出:224×224×21 类 = 105 万个数字, 而分类只要 21 个 |
| C 参数账本 | 输出尺寸就是账单:224×224×21(Pascal VOC 的 21 类)= 105 万个输出值,
而分类只要 21 个——同样的骨架,分割头的输出要贵 50176 倍。 U-Net 的账更直观:最深处 28×28×512 → |
| F 违背了哪个直觉 | 两条。 ① “输出和输入一样大”听起来更简单,实际上更难: 更多的像素、更贵的计算、更难的标注,而且必须先把图弄糊才能看懂它—— 为了看得清,先得看不见。 ② 像素准确率 95% 的分割模型可能毫无用处(把每个像素都猜成背景就能拿到), 这就是为什么这个任务用 mIoU 而不是准确率(回看第 4 节) |
它接住了上一章的什么:《目标检测》给出的是“框”—— 一个粗略的矩形。这一章把要求推到了像素级,而且直接继承了检测的一个坑: 类别极不平衡。
它给后面留了什么:第四代分割(SegFormer / Mask2Former)已经是 Transformer 了, 因为 U-Net 那种“先降后升”的局部结构仍然受限—— 完整的答案在 《ViT》。
分割要求输出和原图一样大的标签图,而 CNN 的设计恰恰在不断丢位置信息——
这个矛盾决定了整个结构:先降分辨率提取语义,再升回来恢复位置。
U-Net 的跳连是解决细节丢失的关键,注意它和 ResNet 的跳连名字一样、目的完全不同
(一个传位置细节,一个传梯度)。
打分用 mIoU 而不是像素准确率——因为它惩罚"乱标",而准确率几乎不会。
SAM 把分割变成了"给个提示就能抠任何东西"的通用能力。
上面讲的都是「够用」的版本。想往下挖,这里有三个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。