基于空洞卷积的语义分割上采样问题求助(Caffe框架)
我之前在Caffe上做语义分割项目时,也碰到过一模一样的问题——经过空洞卷积堆叠后特征图尺寸缩小,导致和原始尺寸的label无法匹配SoftmaxWithLoss的要求。下面是几个我实际用过的可行方案,你可以根据自己的需求选择:
1. 用反卷积(Deconvolution)层做可训练上采样
这是语义分割里最常用的方案,反卷积层可以通过学习权重,把缩小的特征图还原到和输入/label一致的尺寸。关键是要算准反卷积的参数,确保输出尺寸刚好是1158x1544。
比如如果你的特征图是输入尺寸的1/8,那么可以这么配置反卷积层:
layer { name: "seg_upsample" type: "Deconvolution" bottom: "final_conv_feature" # 网络最后一层卷积的输出特征图 top: "upsampled_feature" param { lr_mult: 1 } convolution_param { num_output: 21 # 替换成你的实际类别数 kernel_size: 16 stride: 8 pad: 4 bias_term: false weight_filler { type: "bilinear" } # 用双线性插值初始化,训练更稳定 } }
用双线性插值初始化权重的好处是,训练初期就能得到比较合理的上采样结果,避免随机初始化带来的震荡。
2. 用Interp层快速插值上采样
如果你不想引入可训练参数,或者需要快速验证效果,Caffe的Interp层是个不错的选择——它可以直接指定输出的宽高,或者按比例缩放,不需要复杂的参数计算。
配置示例:
layer { name: "interp_resize" type: "Interp" bottom: "final_conv_feature" top: "upsampled_feature" interp_param { height: 1158 # 和你的label高度一致 width: 1544 # 和你的label宽度一致 # 也可以用scale: 8 来指定缩放比例,前提是你明确知道特征图是输入的1/8 } }
这个层的优点是简单高效,缺点是没有可训练参数,上采样效果完全依赖插值算法,精度可能比反卷积稍差一点。
3. 调整前端网络结构,让特征图尺寸天然匹配label
如果想从根源解决问题,可以回头检查前面所有卷积(包括空洞卷积)的pad、stride和rate参数,通过调整这些值,让最后一层卷积的输出尺寸刚好等于1158x1544。
空洞卷积的输出尺寸计算公式是:输出尺寸 = (输入尺寸 + 2*pad - kernel_size - (kernel_size-1)*(rate-1)) / stride + 1
你可以逐层计算,调整每一层的pad或者rate,确保最终输出和label尺寸一致。这种方法不需要额外加采样层,但需要仔细核对每一层的计算,避免出错。
4. 临时方案:下采样label(不推荐)
如果只是临时调试,可以把label下采样到和特征图一致的尺寸,比如用Pooling层:
layer { name: "label_downsample" type: "Pooling" bottom: "label" top: "downsampled_label" pooling_param { pool: MAX kernel_size: 8 stride: 8 } }
但这个方法会丢失label的精细细节,严重影响分割精度,只适合快速验证网络是否能跑通,正式项目绝对不建议用。
内容的提问来源于stack exchange,提问作者Kangkan Bharadwaj

