读论文这件事,我一直觉得最有价值的不是把摘要和那张架构图画进笔记里,而是搞清楚作者为什么这么做。KiU-Net这篇关于医学图像分割的工作,标题里“Over-complete Representations”这个词组就很值得抠一抠——它不像是单纯堆一个更深的网络,而是对“感受野”和“分辨率”这对矛盾的一次正面回应。这篇论文我前前后后读了几遍,也动手复现过,今天就从我的视角把它拆开来讲:它到底解决了什么问题、网络是怎么设计的,以及复现的时候你会遇到哪些论文里没写的坑。
我一直觉得,医学图像分割这块,U-Net的统治力太强了,强到很多人已经忘了问一句“它真的够用吗”。KiU-Net这篇论文的出发点,恰恰就是对这个默认答案的一次质疑。它要解决的场景很具体:皮肤病灶、脑部肿瘤这类边界模糊、形状高度不规则的目标。常规编码器-解码器架构把分辨率一路降下去,再一路升上来,虽然能拿到全局语义,但局部细节在这个过程里丢得挺厉害。KiU-Net给出的解法是,单独拉一条高分辨率支路,用扩张卷积来撑感受野,和传统的U-Net互补。这篇文章适合谁看呢?我觉得两类人收获最大:一是正在做医学图像分割但觉得U-Net已经到了天花板的同学,二是想理解“除了跳连接之外,还能怎么设计多尺度特征融合”的做视觉任务的人。这篇分享我会把网络结构、损失函数、实验细节和复现过程中的经验都过一遍,尽量讲得实在一些。
1. 论文到底在解决什么问题
1.1 先聊聊U-Net的家底和它的“别扭”
要理解KiU-Net,先得理解U-Net为什么管用,以及它哪里让人不放心。U-Net的思路是编码器一路下采样,把输入从全分辨率压到很低的特征图,这个过程中感受野越来越大,网络能看到越来越“全局”的信息;然后再通过解码器一层一层上采样,把低分辨率的语义图恢复回原图尺寸。它巧妙的地方在于用了跳跃连接,把编码器每一层的细节特征直接拼到解码器对应层,相当于给“恢复细节”这条路开了个外挂。
但U-Net有个绕不开的矛盾:下采样带来更大的感受野,却也永久性地丢失了空间细节。你可以把下采样想象成把一张高清照片压缩成缩略图,缩略图能告诉你“照片里有一只猫”,但猫的胡须在哪几根像素上,压缩完就彻底没了。即使后面有跳跃连接,也只是把压缩之前的特征拿过来救场,真正全分辨率的信息流在整个网络里是不存在的。对一些比较大的器官分割,这个问题不明显,因为器官本身大,细节损失一点无所谓;但到了皮肤病灶、小肿瘤这类目标上,边界就是那几条像素的事,丢了细节,边界就糊了。
这就是KiU-Net的作者看到的痛点:医学影像分割里很多目标不是靠“大而全”的语义就能搞定的,它需要网络同时具备两样东西——足够大的感受野去理解目标整体是什么,又始终保有全分辨率的高频细节去锁定边界。
1.2 “最坏情况下的感受野”这句话怎么理解
论文里有个提法我印象特别深,叫“最坏情况下的感受野”。我第一次读的时候愣了一下,心想感受野还有好坏之分?后来想明白了,它说的其实是网络对输入不同区域的关注力不均衡。卷积核的权重分布决定了感受野内部各个位置的贡献不是均等的,中心区域贡献大,向边缘快速衰减。很多小目标如果恰好落在感受野的边缘区域,网络对它的响应就会很弱,这种“感受野名义上覆盖到了、实际上没看见”的情况,就是所谓的“最坏情况”。
传统U-Net靠层层堆叠卷积来扩大感受野,摊到每一个像素头上,它对远距离信息的利用效率并不高。KiU-Net的回应很直接:既然下采样丢细节,那我就不下采样,直接用扩张卷积把感受野撑开;既然单条支路搞不定,那我就拉两条支路,一条负责任细活,一条负责任大局,最后再合起来。
这个思路说实话不复杂,但它的价值在于结束了一个默认做法——U-Net的下采样-上采样结构并非不可撼动。读论文的时候,这种“先质疑默认前提,再给出替代设计”的论证方式,其实比具体的网络结构更值得学习。
2. KiU-Net的网络架构怎么看
2.1 双支路并不是简单堆两个网络
KiU-Net整体上是双支路结构,一条叫Kite网络,负责用“过完备表示”捕获细节;一条是U-Net风格的编码器-解码器,负责用“欠完备表示”提炼高层语义。这里首先要解释一下标题里那个词——“Over-complete”。Signal Processing领域里,过完备表示指的是用数量多于必要基底的字典来表示信号,好处是对信号的变化更鲁棒。放在网络结构里,KiU-Net的处理方式是让特征图始终保持高分辨率,用扩张卷积逐层加大感受野,而不是通过池化或步长卷积来换视野。你可以理解为,U-Net像一个人先退到远处看全貌再走近画细节,而Kite支路这个人从头到尾都站在画布跟前,但通过戴上一副“看得更远”的眼镜来兼顾全局。
两条支路的定位完全不同。Kite支路的输入是原始分辨率的图像,全程不做空间尺寸缩减,每一层卷积都保留全分辨率特征;U支路就是我们熟悉的U-Net,一路下采样走到很深的低分辨率特征,再上采样回来。一个管高频细节,一个管全局语义,各干各的活,最后把两边的特征图拼起来做联合预测。听起来有点像多尺度融合的老套路,但关键区别在于,Kite支路输出的不是“下采样后增强过的特征”,而是真正的、原汁原味的高分辨率特征图,这就把U-Net结构里天生缺失的那一路信息给补上了。
2.2 Over-complete的Kite支路:全程高分辨率怎么实现
Kite支路的设计细节很多人没细看就直接复现了,其实它有几个关键点。第一,每个Block内部用了几层卷积,但池化和步长卷积是被刻意排除在外的。特征图的高度和宽度从输入到输出始终不变,这条支路从头到尾都是一个“高分辨率保真”通道。第二,感受野的扩大完全靠扩张卷积扛着。论文里设置的扩张率是逐层递增的,让网络在每一个分辨率层级上都能“看见”越来越大的范围。这种做法的好处很直观:你得到了接近下采样结构的感受野,但又没有付出分辨率下降的代价。
我在复现的时候仔细算了笔账:三四个Block跑下来,输出特征图的尺寸依然和原始输入一模一样。这意味着什么?意味着这条支路的特征图通道数和空间尺寸都是最“贵”的那种配置,显存消耗比普通编码器大得多。这也是为什么KiU-Net在2D图像上跑得动,但直接往3D数据上搬会非常吃力——高分辨率特征图的张量体量在3D情况下是指数级增长的,这个我在后面讲复现坑的时候会再展开。
2.3 Under-complete的U支路:为什么要保留下采样
我一开始有个疑问:既然Kite支路能全程保持高分辨率,只靠扩张卷积来加感受野,那U-Net那条支路是不是多余的?论文里的逻辑很清醒:扩张卷积虽然能扩大视野,但它对全局结构的抽象能力是不如下采样的。下采样迫使网络在每个空间位置上去挤压信息,把注意力集中到“这个区域里到底是什么”,这种强制压缩会逼出更抽象、更全局的表征。而且,扩张卷积虽然名义上覆盖了大范围,但它本质上是稀疏采样的,中间很多细节它其实跳过了,对于需要精细边界的目标,光靠它反而不够稳。
所以U支路的价值在于提供一个“语义锚点”。它把输入压缩到很低的维度,牢牢把握住“这个目标大概长什么样、大概在哪个位置”,然后通过上采样把这种全局判断扩散回全分辨率。Kite支路则负责把边界的每一处起伏都抠得清清楚楚。两条支路一个像城市规划师,看的是整体布局;一个像施工队,看的是每一块砖怎么砌。两者缺一不可。
2.4 两支路的融合方式与跳连细节
KiU-Net不是简单把两条支路在输出端相加,而是在网络内部做了多次融合。具体操作是:Kite支路的每一层高分辨率特征,都会通过跳跃连接送到对应的解码层,和U支路上采样回来的特征拼接起来,再送进下一层卷积。这样从浅层开始,全局语义和局部细节就在不断交换信息,而不是等到最后才汇合。
这里有个需要特别注意的设计:Kite支路的特征图分辨率始终和输入一致,但U支路经过多次下采样又上采样之后,解码器中间层的分辨率并不一定和Kite支路完全对齐。所以复现的时候需要在跳跃连接前加一步分辨率对齐操作,通常是对Kite特征做一个轻量的重采样或者用插值调整尺寸。这个细节论文里写得很模糊,我第一次跑的时候就是因为跳连尺寸没对齐,直接报了张量维度不匹配的错误,折腾了好一会儿才定位到问题。
另外,两支路输出的融合采用了拼接而不是相加。拼接的好处是保留了两边的完整信息,让后续卷积自己决定怎么加权,而不是在融合之前就强制压掉一部分信息。考虑到Kite支路和U支路的特征语义差异很大,一个偏细节、一个偏语义,直接在元素级相加确实有点粗暴,拼接明显更稳妥。
3. 损失函数与训练策略:三个监督缺一不可
3.1 Dice损失为什么是医学分割的主损失
KiU-Net的损失函数由三项组成,对两条支路的输出分别计算监督损失,再加上一项一致性约束。医学分割任务里,正负样本极度不平衡是常态——一个肿瘤在整张切片里可能只占几个百分点,普通像素级交叉熵会让网络直接学会“全都预测成背景”,因为这么做损失已经很小了。Dice损失直接优化区域重叠度,天然不摆正负样本数量的架子,所以成了这类任务的主力。
两条支路各有一个独立的Dice损失:Kite支路的输出算一个,U支路的输出算一个。为什么要分开监督?因为如果只对最终融合输出计算损失,两条支路内部的中间特征就缺少直接的优化信号,训练时容易沦为“一条支路干活、另一条支路摸鱼”的状态。每个支路各算各的损失,能强制每条支路都学到有意义的分割表示,这也是论文里一个不太起眼但很关键的设计选择。
3.2 MSE一致性约束承担了什么角色
第三个损失项是我觉得KiU-Net最有意思的地方:让两条支路的特征图在深层上尽可能一致,用的是均方误差(MSE)。我当时读到这个设计的第一反应是有点反常——这两条支路一个走细节、一个走语义,硬要它们在特征空间上对齐,会不会反而把各自的优势抹平了?
细想想就明白了,这里的MSE约束不是要把两支路完全拉成一样,而是在深层特征层面上给它们一个“共同话题”。底层特征差异大没问题,越到深层,网络越应该形成对目标的稳定理解。用MSE把深层特征拉近,相当于告诉网络:不管你是从细节路线过来的还是从语义路线过来的,你对这个目标本质的判断应该收敛到同一个地方。这其实是一种一致性正则化,能在一定程度上防止两条支路各学各的、融合时互相打架。
复现的时候有个实际问题:MSE约束是在哪一层做的?论文的做法是取U支路编码器最深处的那层低分辨率特征,和Kite支路对应级别的特征,先做空间对齐再算MSE。这里注意,两条支路的特征图尺寸不同,不能直接减,必须先把Kite支路的高分辨率特征池化或者插值到与U支路深层特征一致,再做逐像素比较。
3.3 训练配置与阶段性技巧
训练方面,KiU-Net原文采用的是标准的监督训练方式,优化器、学习率和数据增强策略跟很多分割网络用的是同一套。我没有完全照抄论文的超参,而是按照自己设备的情况做了调整,这里分享一下我实际用下来比较稳的配置。
基础学习率我习惯放在1e-4,优化器用Adam,权重衰减不敢开太大,1e-5到1e-4之间即可,因为KiU-Net整体参数量不小,正则化太狠容易欠拟合。Batch size要看显存说话,全分辨率Kite支路太吃显存了,2D图像我一般用8,如果输入图像尺寸偏大,还得降到4。数据增强方面,随机翻转、随机旋转、弹性形变这些常规操作都能用,但要注意不要用那种会破坏边界细节的强增强,毕竟这个网络卖点本来就是对细节敏感,增强过度反而把目标给弄没了。
训练阶段有个小技巧:先让U支路的梯度占据主导地位,跑上几十个epoch之后再逐渐加大Kite支路输出的损失权重。原理很简单,U支路的语义引导先让网络找到一个大致靠谱的目标区域,这时候Kite支路再去抠边界细节,收敛会顺很多。如果一开始就让Kite支路主导,网络只顾着抠边界,目标整体位置还没找准,容易陷进局部最优。
4. 实验结果怎么读:性能数字之外的信息
4.1 数据集与对比设置
论文在公开的皮肤病变分割基准和脑部肿瘤分割基准上做了验证,对比对象包括标准U-Net以及几个代表性的改进版本。从结果看,KiU-Net的Dice分数在多个类别上超过了U-Net,提升幅度大概在2到4个百分点。我读实验部分的时候,重点倒不是那几个百分点,而是护着看它到底在哪些类别上提升最大。
观察下来,受益最明显的基本都是边界不规则、对比度低的小目标。皮肤病变就是这样,边缘往往呈现锯齿状和不均匀的晕染,U-Net输出经常会把边界抹得很光滑,而KiU-Net因为Kite支路保留了全分辨率特征,在边界处的定位明显更精准。脑部肿瘤分割里,肿瘤核心区域和水肿区域的边界也很微妙,KiU-Net在这两类上的优势同样验证了它的设计动机。
4.2 消融实验说明的问题
消融实验里的信息量很大。去掉Kite支路,整个模型退化成接近普通U-Net,性能回落明显,说明Kite支路确实在提供它该提供的东西。去掉U支路,只留Kite支路,性能同样会掉,而且边界虽然细了,整体的目标定位会变得不太稳。这说明两条支路不是冗余,而是互补。
还有一个消融让我印象很深:如果把Kite支路内部的扩张卷积换成普通卷积,也就是保持全分辨率但感受野不够大,分割效果会出现明显下滑。这验证了“高分辨率不是万能的,感受野必须同步跟上”这个核心观点。只看细节不看全局,会盯着一堆局部纹理却拼不出完整的目标轮廓。
4.3 合适什么任务,不适合什么任务
我复现完KiU-Net之后,给它的能力画像大概是这样:最适合的是那些“目标不大但边界极其讲究”的2D医学图像分割任务,比如皮肤镜图像里的病灶分割、病理切片里的腺体分割,以及一些细胞级别的分割任务。这类任务里,U-Net容易把边界过度平滑,其他纯Transformer类的模型又容易丢失细节,KiU-Net正好卡在中间,性能和显存消耗的平衡性很好。
但也要泼一盆冷水:KiU-Net不适合直接往大尺寸目标分割上硬套。如果目标是肝脏、肺部这类占了图像很大区域的器官,U-Net本来就做得不错,KiU-Net的提升有限,却要付出远超U-Net的显存代价,性价比不高。它也不适合那种实时性要求极高的场景,因为Kite支路的高分辨率特征计算量摆在那里,轻量化改造的空间不大。
5. 复现过程中踩过的坑
5.1 显存爆炸:全分辨率支路的代价
我复现KiU-Net时遇到的第一道坎就是显存。Kite支路全程保持高分辨率,图片输入尺寸稍一大,中间特征图直接把显存吃穿。举个例子,输入是512x512的2D图像,Kite支路每个Block都出一批512x512的特征图,通道数再一多,显存账根本不敢细算。
我的建议是,如果你的显卡显存有限,先把输入尺寸从512降到256试试,或者把Kite支路每个Block的通道数往下调一些,比如从32降到16,性能损失通常可以接受。还有一个技巧是关闭Kite支路某些层的梯度——具体做法是让该支路的特征在反向传播时不产生梯度,只参与前向计算,具体操作是把该支路特征用detach隔开。不过这个操作要谨慎,只在训练后期收敛稳定时再用,前期需要两边梯度都通畅才行。
5.2 MSE权重怎么调才不翻车
MSE约束项的权重大小很敏感。太小了等于没有,两条支路的深层特征各说各话,融合效果跟直接拼接没有本质区别;太大了会出另一个问题——Kite支路被U支路“带偏”,全分辨率细节优势被磨平,整体退化成一条高分辨率版U-Net。
我试过几组权重,最后比较稳的范围是放在0.1到0.01之间,跟Dice损失的主项差了至少一个数量级。这背后的逻辑是,MSE只是辅助约束,不该喧宾夺主。训练过程中我还会做一件事:如果观察到Kite支路的输出边界开始变糊,第一反应不是降学习率,而是把MSE权重往下调一档,多半能救回来。
5.3 扩展3D数据时的分辨率陷阱
把KiU-Net往3D医学数据上搬是很多人都会想做的事,但我劝你先掂量一下。3D数据的特征图是三个空间维度都保持全分辨率,Kite支路要是照着2D的做法来,显存瞬间能被吃空。我在实验里尝试过对3D数据只对中间层做高分辨率保留,浅层该下采样就下采样,相当于做了一个“不完全Over-complete”的折中版本,才能勉强跑起来。
如果你想在3D场景里沿用KiU-Net的思路,更务实的做法是修改Kite支路的策略:别让所有层都保持全分辨率,而是在浅层保留高分辨率,到了深层就开始逐步缩小特征图尺寸,靠扩张卷积去撑感受野。这样一来,它就不再是原版KiU-Net了,但保留了“一支路保细节、一支路提语义”的核心精神。
5.4 数据增强的取舍与训练更稳的小技巧
训练医学分割网络,增强策略我也会做一些调整。KiU-Net对边界敏感,那像随机裁剪这种增强就要注意别把目标切碎了;弹性形变可以用,但幅度别太大,不然边界被扭曲到失真,Kite支路学到的边界信息就是歪的,反而干扰U支路的语义判断。
还有个不常被人提到的小技巧:因为两条支路的特征差异大,融合层的初始化对训练稳定性影响很大。我建议给融合层卷积的偏置设一个比较小的初始值,或者干脆用Xavier初始化而不是默认的均匀分布,能明显减少前几个epoch的震荡。
6. 常见问题速查表
| 问题现象 | 可能原因 | 处理建议 |
|---|---|---|
| 训练时显存溢出 | Kite支路全分辨率特征图消耗过大 | 降低输入尺寸或Kite支路通道数 |
| 跳连时张量尺寸不匹配 | Kite支路与U支路解码层分辨率没有对齐 | 在拼接前用双线性插值对齐Kite特征 |
| 输出边界很模糊 | MSE约束权重过大,Kite支路被U支路带偏 | 将MSE权重下调到Dice损失的1/100以下 |
| 两条支路融合后性能反降 | 融合方式不合理或初始化不合适 | 尝试把拼接改为逐元素相加,或换初始化方式 |
| 小目标整体漏检 | 感受野仍不够大 | 增大扩张率或加深Kite支路Block数 |
| 训练早期震荡剧烈 | 冻结或detach了Kite支路梯度 | 只在训练后期再做梯度隔离 |
我自己的习惯是先把论文里的默认配置跑通一遍,再逐项做替换实验,比如改一改MSE权重、调一调Kite支路的扩张率,看看每个旋钮对最终结果的影响有多大。只有亲手试过,才能真正理解作者在论文里寥寥几笔带过的那些设计的份量。
最后再分享一个我在复现和扩展时的体会:KiU-Net这样的双支路架构思路,真正的价值并不在于某个具体的网络结构能直接搬到所有任务上,而是它提供了一个“思路分叉”——当U-Net式结构在某个任务上遇到瓶颈时,你不一定要往深了堆层数,往宽了加通道,可能更值得尝试的是拉一条独立的高分辨率支路进来,让细节和语义各走各的道,最后再汇合。沿着这个思路,你可以把Kite支路替换成任何你觉得更适合保细节的模块,把U支路替换成更擅长建模长距离依赖的结构,整体框架仍然是成立的。这种结构上的自由,才是读完这篇论文之后最值得带走的东西。