前阵子帮人 debug 一个语义分割的复现项目,我在搜索框里顺手敲下“分割”两个字,联想词条直接把我看笑了:字符串分割、word划分割虚线、DataX字段分隔符、渔网分割shp、二层交换机网段分割、嘉立创内电层分割、息肉分割数据集、古月居occ地面分割……从文本处理到网络工程,从PCB设计到医学影像,全都叫“分割”。这个画面其实就是写这篇“分割方向论文精读”的最好切入点:分割在大众语境里是一个动作,在计算机视觉里是一条完整的技术线,这条线内部又分出语义分割、实例分割、全景分割、点云分割等多个分支。这篇文章我想按照论文精读的方式,把这些分支的代表方法拆开来讲,同时分享一套我个人用了很久的论文精读流程,以及论文里不会写的落地坑。
1. 从“word划分割虚线”说起:分割方向论文的阅读地图
1.1 热搜词里藏着一张完整的分割技术谱系
把上面那些词按“处理对象”归类,会发现一件很有意思的事:它们虽然分布在完全不同的工程领域,但“分割”这件事的内在逻辑惊人地一致。
| 热搜词 | 处理对象 | 边界形式 |
|---|---|---|
| 字符串分割 | 文本数据 | 分隔符字符 |
| DataX字段分隔符 | 数据管道 | 分隔符配置 |
| word划分割虚线 | 文档编辑 | 视觉虚线边界 |
| 语义分割 | 图像像素 | 像素类别边界 |
| YOLO实例分割 | 图像目标 | 实例掩码边界 |
| 息肉分割数据集 | 医学影像 | 病灶边界 |
| DBSCAN点云分割 | 三维点云 | 密度聚类边界 |
| 古月居occ地面分割 | 占据栅格 | 地面与非地面边界 |
| 渔网分割shp | GIS空间数据 | 网格线边界 |
| 嘉立创内电层分割 | PCB铜皮 | 电源网络区域边界 |
| 二层交换机网段分割 | 网络流量 | VLAN标签边界 |
这张表值得多看一眼。字符串分割靠的是分隔符,语义分割靠的是像素类别,点云分割靠的是空间密度或几何特征,PCB内电层分割靠的是铜皮上的隔离线,二层交换机的网段分割靠的是VLAN标签——对象千差万别,但核心永远是两件事:先定义边界,再决定归属。这个共识在后面讲实例分割、讲点云分割、讲论文复现时,会反复出现。很多人读分割论文读不进去,是因为把注意力全放在网络结构上,却忘了问一句:这个方法定义的边界是什么、凭什么这样定义。带着这个问题去读,论文的骨架立刻清晰。
1.2 计算机视觉里“分割”的四个分支
做视觉的人嘴里说的“分割”,通常指四个方向,它们是论文精读的主战场。
- 语义分割(Semantic Segmentation):对每个像素预测一个类别标签。所有“人”的像素归为一类,不区分张三李四。代表工作是FCN、U-Net、DeepLab系列。
- 实例分割(Instance Segmentation):在像素级分类的基础上,还要区分同一类别的不同个体。比如画面里有三个人,你要输出三个独立的掩码,而不是一片“人”的标签。Mask R-CNN是绕不开的里程碑。
- 全景分割(Panoptic Segmentation):把语义分割和实例分割统一到一个框架里,对“stuff”(天空、道路这类无实体边界的背景)做语义分割,对“thing”(人、车这类独立个体)做实例分割。这个方向在自动驾驶场景很常见。
- 点云分割(Point Cloud Segmentation):处理对象从二维图像变成三维点云,可以是语义级(每个点一个类别),也可以是实例级(同类别不同物体分开),还可以是更粗粒度的地面分割、聚类分割。DBSCAN、区域生长、RANSAC平面拟合、基于深度学习的PointNet++都属于这条线。
精读论文之前,先确认这篇论文属于哪个分支、输出是什么、评测指标是什么。很多初学者把语义分割和实例分割混在一起读,读到NMS、读到mask分支就懵,根子上是地图没建好。接下来我按分支逐个讲精读重点。
2. 语义分割的精读重点:从FCN到DeepLab的注意力迁移
2.1 FCN为什么是分水岭:全卷积化与感受野的代价
FCN(Fully Convolutional Networks)是语义分割绕不开的起点。它做的关键决策只有一句话:把分类网络最后的全连接层全部替换成卷积层。这个改动为什么是分水岭?因为全连接层要求输入尺寸固定,一旦换成卷积层,网络就能接受任意尺寸的输入,并且保留空间位置信息。
但全卷积化不是没有代价。分类网络里的池化层把特征图一路从 H×W 缩小到 H/32×W/32,空间分辨率大幅下降。FCN的解决办法是反卷积上采样,把特征图恢复到原图尺寸,再对每个像素做分类。这里有一个精读时容易忽略的细节:反卷积上采样恢复的是“分辨率”,不是“精细结构”。池化过程中丢失的小目标、边缘细节,上采样是找不回来的。
FCN的第二个贡献是跳跃结构(skip connection)。它把浅层的、高分辨率的特征和深层的、语义强的特征融合起来,让最终预测同时具备“看得清边界”和“认得出类别”的能力。精读FCN时,我建议你画一张特征图尺寸变化表:输入尺寸、每个卷积/池化层之后的尺寸、上采样倍数、跳跃融合的层位置,这张表画完,FCN的骨相就全出来了。
2.2 DeepLab系列的核心增量:空洞卷积与ASPP
DeepLab系列是我个人建议精读的第二站,它的发展脉络非常清晰,每一代解决一个问题。
DeepLab v1/v2的核心是空洞卷积(Atrous Convolution,也叫膨胀卷积)。它的作用是在不增加参数量的前提下扩大感受野。你可以把空洞卷积理解成“跳着看”的卷积:普通卷积看一个连续区域,空洞卷积跳过中间的点,隔几个像素采一个。rate=2时,一个3×3的卷积实际覆盖9个点,但视野扩展到了7×7的范围。DeepLab用空洞卷积替换掉分类网络最后的池化层,让特征图保持较高分辨率,这一步直接缓解了FCN的信息丢失问题。
DeepLab v2的另一个标志是ASPP(Atrous Spatial Pyramid Pooling),就是并行使用多个不同rate的空洞卷积,再把结果拼起来。为什么要做多尺度?因为图像里的目标大小差异太大。一个小息肉可能只有几十个像素,一辆公交车可能占据上千像素。单一个rate看不全。ASPP的思路是:用不同扩张率的卷积同时采样,就像用不同倍数的放大镜看同一张图,最后把看到的画面拼在一起。精读时注意看论文里rate的选择,一般是6、12、18、24,这些值不是拍脑袋定的,跟输入尺寸和backbone的stride有关。
到了DeepLab v3+,作者把encoder-decoder结构加了回来。空洞卷积+ASPP负责编码多尺度语义信息,decoder部分逐步恢复边界细节。读到这里你会发现一个趋势:语义分割的演进本质上是在“语义强”和“边界精细”之间反复找平衡。FCN偏语义,丢掉细节;U-Net偏细节,靠skip连接补;DeepLab靠空洞卷积两头发力。这个“平衡视角”是精读完一个系列后最值钱的收获。
2.3 从息肉分割数据集看医学影像分割的难点
热搜词里有个“息肉分割数据集”,这个词可以把语义分割的讨论从通用场景拉进医学影像。息肉分割和Cityscapes上分割汽车、道路完全不是一个难度量级。
息肉在肠镜图像里通常对比度低、边界模糊,很多病灶的边缘和周围黏膜颜色接近,人眼都要仔细分辨。加上息肉大小差异极大,小的可能只有几十像素,这对模型的多尺度能力是巨大考验。还有一个医学影像通病——类别极度不平衡:一张图里病灶区域常常只占1%甚至更少,如果直接用普通的交叉熵损失训练,模型会学成一个“什么都是背景”的复读机。
我在处理这类数据时通常的做法是:用混合损失函数,把Dice Loss和二值交叉熵加权相加。Dice Loss直接优化分割结果和标注的重合度,对类别不平衡不敏感;BCE负责稳定的梯度信号,两者互补。精读医学分割论文时,重点看三个地方:损失函数怎么设计、数据增强怎么处理镜面反光与运动模糊、验证集怎么划分。这三点比网络结构更决定最终分数。
2.4 精读语义分割论文时最值得记录的几个数字
读论文不能只读故事,得把关键数字抄下来。我自己的习惯是做一个表格,每精读一篇就填一行:
| 论文 | Backbone | 输出stride | 训练的crop size | 单/多尺度测试 | 主指标(mIoU等) | 训练集 |
|---|---|---|---|---|---|---|
| FCN | VGG-16 | 32 | 固定resize | 单 | 62.2(PASCAL VOC) | VOC 2012 |
| DeepLab v3+ | ResNet-101 | 8或16 | 513×513 | 多尺度 | 89.0(PASCAL VOC) | VOC 2012 + COCO |
填多了你会发现规律:mIoU的绝对值没有跨数据集可比性,同一篇论文在PASCAL VOC、Cityscapes、ADE20K上的数字差了20个点起步。所以精读时不能只看摘要里的“state-of-the-art”,要盯着实验表格看它是在哪个数据集、什么backbone、什么测试策略下拿到的分数。一个常见的坑是论文用多尺度测试+翻转测试刷分,部署时却只能跑单尺度,精度立刻掉一截,这在后续落地章节还会展开讲。
3. 实例分割与点云分割:当目标从“类别”变成“个体”
3.1 Mask R-CNN的级联设计:检测框里的像素分类
语义分割输出“像素属于哪一类”,实例分割要输出“每个个体是谁、占据哪些像素”。解决这个问题最直接的想法是“先检测,再分割”——先把每个目标用检测框框出来,再在框内做一次像素分类。Mask R-CNN就是这个思路的集大成者。
精读Mask R-CNN时要抓住三个关键点,少一个你都不算真正读懂它。
第一,它在Faster R-CNN的检测头旁边平行接了一个mask分支,每个ROI输出一个 K×m×m 的掩码,K是类别数。注意,mask分支和分类分支是解耦的——分类分支预测ROI属于哪一类,mask分支为每个类别都预测一个掩码,最后只取分类结果对应的那一张。这种解耦设计避免了“先分类再分割”的级联误差。
第二,ROI Align。Faster R-CNN里的ROI Pooling在把不同大小的ROI统一到固定尺寸时做了两次量化,坐标取整会丢失几个像素的位置精度。ROI Align用双线性插值替代取整,不做量化,位置误差从像素级降到亚像素级。对分割任务来说,这个改进是决定性的,因为分割对空间位置极其敏感。
第三,掩码分支只在正样本ROI上训练,负样本不计算mask loss。这个细节很多复现者会忽略,结果是loss曲线异常、掩码质量差。
3.2 YOLO实例分割:one-stage怎么做掩码
如果说Mask R-CNN是两阶段的代表,那YOLO系列里的实例分割走的是另一条路——不搞“检测+再分割”,而是试图一个网络直接输出掩码。
YOLACT的思路是把实例分割拆成“原型掩码”和“掩码系数”两部分。网络先对整张图预测一组原型掩码(prototype masks),相当于一组覆盖常见形状的基础图层;同时为每个实例预测一组系数;最后用线性组合的方式把原型掩码按系数加权求和,得到每个实例的掩码。这个过程可以被理解为“用乐高积木拼形状”——原型掩码是不同颜色形状的积木块,系数决定了每块积木用多少。
YOLOv8-seg的路线又不一样,它输出的掩码是用轮廓点表示的,后处理阶段再把轮廓点还原成像素掩码。这种设计的优势是速度快,天然适合视频流实时处理。精读这类论文时,我建议你用“精度换速度”的视角去分析:原型掩码的数量、嵌入向量维度、掩码后处理的复杂度,都是在精度和延迟之间做取舍。你在草稿纸上推一下Flops就会发现,如果把YOLACT的掩码分辨率从28×28提高到112×112,后处理和显存占用都会成倍上涨。
3.3 DBSCAN、区域生长与点云分割:传统聚类仍然能打
热搜词里“dbscan用于点云分割”直接点出了一个关键事实:点云分割不一定非要用深度学习,传统几何和聚类方法在大量场景下仍然是首选。
DBSCAN是密度聚类算法,核心是两个参数:eps(邻域半径)和min_samples(一个核心点邻域内最少点数)。它不需要预先指定聚类数量,能发现任意形状的簇,还能把稀疏的噪声点单独标记出来。用在点云上,正好匹配“地面、墙面、车辆、行人自然形成不同密度区域”的物理直觉。但DBSCAN对eps极其敏感:设小了,一辆车被切成好几块;设大了,车和旁边的墙连成一团。我实操时一般先用体素滤波把点云降采样到均匀密度,再根据点间距统计值来设定eps,不要拍脑袋。
和DBSCAN并列的传统路线是区域生长。思路很简单:从一个种子点出发,如果邻居点和种子点的法向量夹角足够小、距离足够近,就把邻居并进来,然后迭代生长。区域生长适合提取平面结构,在室内场景重建里很常用,但要先算好每个点的法向量,碰到尖锐边缘容易过生长。
精读点云分割论文前,我强烈建议先用Open3D把DBSCAN、RANSAC平面分割、区域生长各跑一遍。这些传统方法跑通了,再看深度学习的点云分割文章,你才能判断出一个模型到底是真学到了几何结构,还是仅仅在拟合聚类结果。
3.4 地面分割与占用栅格:自动驾驶的“可行驶区域”怎么定义
古月居occ地面分割这个词,把点云分割拉到了自动驾驶的实战场。occ在这里指Occupancy Grid Map(占用栅格地图),是自动驾驶感知里常见的地图表示。构建占用栅格时,点云必须先把地面分出来——不是要把地面当障碍物填进栅格里。
地面分割的经典方案是RANSAC平面拟合:从点云里随机采样三个点拟合一个平面,统计有多少点落在这个平面附近,迭代若干次留下内点最多的平面。这个方法速度极快,在平整路面上效果很好,但遇到坡道、颠簸路段时就容易把坡顶误判成障碍物。
工程上更稳的方案是射线坡度法:把点云按传感器坐标转换成极坐标,沿每条射线比较相邻点的坡度,坡度超过阈值的点标记为障碍物。它做的是“相对高度变化”判断,天然适应缓坡和颠簸路面。精读和复现这类论文时,建议把重点放在坐标变换和邻域搜索的效率上,地面分割本身的算法不难,难的是在嵌入式设备上跑到实时。
4. 把论文读穿的方法:我精读50篇分割论文后沉淀的流程
4.1 精读顺序:先搭“问题-方法-评测”三角框架
很多人读论文从头到尾逐字读,读到最后也没记住核心内容。我精读一篇分割论文的顺序是这样的:
- 标题+摘要+图表:3分钟。只看论文解决什么问题、用的什么方法、在什么数据集上达到什么水平。
- Introduction的motivation段落:5分钟。作者为什么要做这个工作?现有方法的短板是什么?这个“短板”就是论文的立论根基。
- Method的模型总图:10分钟。先不看公式,把输入、输出、中间模块的流向看懂,用笔在图上标出每个模块的作用。
- 实验表格的对比行:5分钟。重点看论文的方法比baseline高多少、消融实验里每个模块贡献了多少。
- 再看公式和细节:读到这一步时,你已经知道论文的核心贡献是什么,公式只是为了精确描述它,这时候看公式就不会迷路。
这个顺序的核心逻辑是:先用粗粒度建立局部地图,再用细粒度填充局部细节。直接扎进公式里去读,就像不看地图直接钻进巷子,很容易迷路。
4.2 精读必须动手做的三件事
光看不练,论文永远是别人的。我每精读一篇分割论文,至少会做以下三件事中的两件:
第一,画结构图。把论文里的模型架构图重画一遍,用自己的符号体系。不画不知道,一画就发现很多论文的图省略了细节:特征图尺寸没标、skip connection谁和谁连没画清楚、loss从哪个分支出没写。画图的过程就是逼自己补齐这些空缺的过程。
第二,算复杂度。用FLOPs和参数量两个指标给模型做“体检”。计算方式很简单:卷积层的FLOPs约等于输出通道数×输出尺寸×卷积核尺寸×输入通道数。精读时我会快速估算backbone和分割头的FLOPs比例,如果分割头占比超过30%,部署到边缘设备时就要警惕延迟问题。
**第三,复现消融实验中的核心模块。**不用完整复现整篇论文,只把论文里最核心的模块(比如ASPP、ROI Align、原型掩码生成)单独摘出来,在一个小数据集上验证它是否真的有效。这一步能帮你建立对方法的“手感”,知道它强在哪、弱在哪。
4.3 分割论文里最容易迷惑人的三个地方
第一个是mIoU的计算方式。不同的论文对ignore_index、类别权重、边界像素的处理方式可能不同,直接对比两个论文的mIoU数字有时没有意义。有的实现会把图像边缘一圈像素ignore掉,有的不会;有的按类别频率加权,有的不加权。精读时一定要去附录或开源代码里确认清楚。
第二个是训练与验证的数据划分。很多语义分割论文用Cityscapes的train+val一起训练,然后报test集上的分数;有的只用train训练。这两种setting出来的结果没有可比性。看论文实验表格时,先看表头下面的footnote,再看训练细节。
第三个是多尺度测试(multi-scale testing)和翻转测试(flip testing)。这是“刷分利器”:同一张图缩放成多个尺度分别推理,再把结果融合,mIoU能涨1-2个点。部署时如果做不到同等操作,复现出来的分数一定会比论文低,这不是你的代码写错了,而是测试策略不同。明白这一点,能省掉无数次无谓的自我怀疑。
5. 从论文到交付:落地坑与“分割”的跨领域真相
5.1 渔网分割、网段分割、内电层分割和像素分割,本质是同一件事
回到开头那张热搜词表格。渔网分割shp是在GIS数据里按网格切分空间范围,每块网格是一个独立单元;二层交换机实现同一网段下的局域网分割,是用VLAN标签把广播域切开;嘉立创内电层分割后,不同电源网络的铜皮靠分割线物理隔离。这些工作表面上看和论文精读毫无关系,但它们的核心问题都是:边界怎么定义,边界两侧怎么处理。
PCB内电层分割里有个很具体的坑:内电层分割完,不在对应区域的电源网络怎么走线?答案是用过孔把信号引到其他布线层,从一个电源区域跳到另一个电源区域,不能直接在铜皮上跨越隔离带。这和语义分割里“不同类别像素不能混淆”是同一个逻辑。DataX里字段分隔符怎么改、字符串分割用什么分隔符,也是一样——分隔符选错了,整条数据解析链就断了。所以我对想入行视觉分割的读者有个建议:不要只盯着深度学习框架,抽点时间理解你所在业务领域的“天然边界”是什么,这个理解往往比调参更值钱。
5.2 分割模型部署时的实战坑位
论文里跑通的网络,离生产环境还有一段路。我在部署分割模型时踩过的坑,列出来给你避雷。
动态尺寸问题。训练时可以随机crop到512×512,部署时输入的图片可能是1920×1080。直接resize到固定尺寸再推理,小目标和细边界的损失会非常明显。我的做法是设计一个对输入尺寸不敏感的推理pipeline:保持长宽比resize到模型能接受的最大边长,再padding到模型输入的整数倍,推理完裁掉padding区域。
后处理时长远超预期。很多人在网络推理上抠时间,却忽略了后处理:连通域标记、最大连通域提取、掩码转轮廓、轮廓转多边形,这些操作在CPU上跑可能比GPU推理还慢。我建议用OpenCV的connectedComponentsWithStats和findContours,并且只在掩码的降采样版本上做后处理,精度损失很小,速度能快一个数量级。
半精度和量化后的小目标消失。FP16推理时,小息肉、远处行人这类低置信度区域容易被精度截断,输出掩码出现空洞。上线前一定要用验证集跑一遍量化前后的mIoU对比,如果dice下降超过2个点,就要考虑混合精度或者给分割head单独保留FP32。
5.3 跟进新论文和复现的节奏
分割方向论文更新很快,天天追新会累死。我的节奏是这样:每周固定时间过一遍新发布的论文标题和摘要,只精读两类——一类是在主流数据集上刷新了大指标的,另一类是提出新问题或新评价指标的。后者比前者更重要,因为它可能定义下一个阶段的方向。
复现的优先级也有讲究:先用官方开源代码跑通小数据集,再读代码,最后才自己重写。官方代码跑通能帮你确认环境、数据格式、评价指标这些“外围工程”是对的;读代码能帮你理解论文里没写清的细节;自己重写才是真的内化。我不建议一上来就关掉官方代码自己撸,那是在浪费宝贵时间。
另外,复现时最好固定一套“复现环境基线”:同一个PyTorch版本、同一个CUDA版本、同一套数据增强库。分割模型的训练对随机种子和数据增强非常敏感,环境不一致会导致你调了很久的bug其实只是版本差异。
写在最后
精读分割方向论文,我不是追求数量,而是追求建立一张“自己的检查清单”:拿到一篇新论文,我知道该看什么、该记录什么、该复现什么、该放弃什么。这篇文章里出现的所有方法——从FCN到DeepLab,从Mask R-CNN到点云分割——它们的精读逻辑是通用的:先找边界,再看归属,最后算代价。
如果你现在正在复现某篇分割论文遇到困难,我的建议是别急着改模型结构,先检查你的数据划分、损失函数和评价指标是不是和论文一致。我在实际项目中有一半以上的“复现失败”,最后都发现是这三个环节出了问题,而不是模型本身写得不对。搞定了这些,你再看分割论文时,每一篇都会变成真正能被你消化吸收的东西,而不是又一篇躺在收藏夹里的PDF。