原文:Fully Convolutional Networks for Semantic Segmentation
语义分割(Semantic Segmentation)的目标是,对于一张图片,能够为每个像素点做出分类,判断其属于哪一类物体或背景,但是对于每一类物体不做具体的实例辨别,即不用区分同一类的不同个体,只进行像素点级的分类。
FCN是语义分割的一个早期做法,思路也很简单。先用CNN提取特征,对于下采样后的特征图,用卷积操作替换全连接层,调整通道数至物体类别数,最后通过一个转置卷积(transpose convolution)上采样,恢复到输入图像的大小,每个通道对应一类的分类结果。
![0d4bd00ef56874ed596404fd7080aaec.png](https://i-blog.csdnimg.cn/blog_migrate/7e5cc1b02a712492d4e17d2f303c8947.jpeg)
网络结构
主干网络采用了AlexNet、VGG、GoogLeNet等网络,只考虑下采样情况即可。网络共经过5次MaxPooling,下采样32倍,卷积操作不改变特征图大小。
之后的全卷积层替换了全连接层:
- 21表示voc数据集的物体类别数。
为了保证网络能够同时处理较小分辨率的图像,使
最后为一个上采样层,通过转置卷积完成。转置卷积中stride的大小控制上采样率,上采样结果基于输入图像尺寸进行crop操作,得到与输入图像大小一致的语义分割结果。
根据有stride的反卷积计算公式:
-
分别表示反卷积的输入输出图像大小,
表示stride,
表示卷积核大小。
即上采样率主要由
由于上采样过程直接使用最终的特征图,效果不是很好,FCN中又尝试使用低层的特征图来进行特征融合。根据输出层的结构的不同,分为FCN-32s,FCN-16s,FCN-8s。
![cf2d17bc163919887d97d76477d81d43.png](https://i-blog.csdnimg.cn/blog_migrate/866ae056b74a1e94599dc416083bbe6c.jpeg)
FCN-32s即为以上描述的基本网络结构,没有额外的变化,对应图片第一行。32s的含义是最后的转置卷积采用stride=32,上采样32×。
代码中的过程为:
n.fc6, n.relu6 = conv_relu(n.pool5, 4096, ks=7, pad=0)
n.drop6 = L.Dropout(n.relu6, dropout_ratio=0.5, in_place=True)
n.fc7, n.relu7 = conv_relu(n.drop6, 4096, ks=1, pad=0)
n.drop7 = L.Dropout(n.relu7, dropout_ratio=0.5, in_place=True)
n.score_fr = L.Convolution(n.drop7, num_output=21, kernel_size=1, pad=0) # conv7
n.upscore = L.Deconvolution(n.score_fr,
convolution_param=dict(num_output=21, kernel_size=64, stride=32) # 32x
n.score = crop(n.upscore, n.data)
- 在计算scoce_fr时调整通道数为21,后续的转置卷积保持通道数不变。
FCN-16s在得到conv7(score_fr)后,先对conv7使用stride=2的转置卷积和crop,上采样2×;同时对pool4使用
代码如下:
n.fc6, n.relu6 = conv_relu(n.pool5, 4096, ks=7, pad=0)
n.drop6 = L.Dropout(n.relu6, dropout_ratio=0.5, in_place=True)
n.fc7, n.relu7 = conv_relu(n.drop6, 4096, ks=1, pad=0)
n.drop7 = L.Dropout(n.relu7, dropout_ratio=0.5, in_place=True)
n.score_fr = L.Convolution(n.drop7, num_output=21, kernel_size=1, pad=0) # conv7
n.upscore2 = L.Deconvolution(n.score_fr,
convolution_param=dict(num_output=21, kernel_size=4, stride=2)# 2x conv7
n.score_pool4 = L.Convolution(n.pool4, num_output=21, kernel_size=1, pad=0)
n.score_pool4c = crop(n.score_pool4, n.upscore2) # conv4
n.fuse_pool4 = L.Eltwise(n.upscore2, n.score_pool4c,operation=P.Eltwise.SUM)
n.upscore16 = L.Deconvolution(n.fuse_pool4,
convolution_param=dict(num_output=21, kernel_size=32, stride=16) # 16x
n.score = crop(n.upscore16, n.data)
FCN-8s也是类似的过程,将上采样4×的conv7、上采样2×的pool4(同样通过转置卷积)以及pool3进行融合,得到特征图像大小为
总体来说,FCN-8s的融合程度更高。
Loss
loss形式为交叉熵损失,不计算背景的损失:
n.loss = L.SoftmaxWithLoss(n.score, n.label,
loss_param=dict(normalize=False, ignore_label=255))
评价指标
符号定义:
本文中采用的实验评价指标有:
pixel accuracy:
mean accuracy:
mean IU:
frequency weighted IU:
实验结果
文章中间对于不同网络模型的比较:
![1d6a5384c8c8de6379dfc8a77bcf3a89.png](https://i-blog.csdnimg.cn/blog_migrate/654aa0bc857bc1c2377f6fa660d7a789.jpeg)
- 第一行只在最后一层进行fine-tune,其他为端到端训练。
- 经过特征融合后,IoU提升比较明显。
VOC上的结果比较:
![1004183fdf946be2f0acae97ccb3e790.png](https://i-blog.csdnimg.cn/blog_migrate/35e3ab4791cf00e17f64483f87496f70.png)
- 无论速度还是准确度都有很大提升。
分割结果的质量:
![c5e3dbaa9d13bf9df5e7d20cd90b3481.png](https://i-blog.csdnimg.cn/blog_migrate/39112ad2cbc89b9566e534c7ff92d5e7.jpeg)
FCN作为语义分割的早期做法,最后通过上采样的过程跨度太大,感觉对于反卷积核的依赖比较大,可能会影响分割的质量。
涉及的特征融合的过程,全卷积及1×1卷积调整通道数,觉得都是很出色的做法。
参考
- https://zhuanlan.zhihu.com/p/22976342
- https://www.cnblogs.com/xiaoboge/p/10502697.html
- https://github.com/shelhamer/fcn.berkeleyvision.org