项目说明
本项目利用PaddlePaddle及PaddleSeg套件对论文“Context Encoding for Semantic Segmentation (CVPR2018)”进行了Paddle版本的实现,取得了较为不错的结果。
一、简介
论文引入了上下文编码模块(Context Encoding Module)用于捕获全局上下文信息和突出与场景相关联的类别信息,这相当于加入场景的先验知识,类似于attention机制。结合现先进的扩张卷积策略和多尺度策略提出了语义分割框架EncNet(Context Encoding Network)。论文提出的EncNet在多个数据集上获得了state-of-the-art结果。
EncNet Architecture:
主要模块:
- Encoding Module:对前面网络提取出的丰富的特征使用全连接层FC进行编码,其中一个编码分支直接送给SE-loss,进行场景中出现类别的预测;另一个分支对每个类别预测加权的尺度因子,然后这个加权的尺度因子对前面提出的每个通道的类别进行加权,然后再进行后面的上采样,最终计算loss。
- Featuremap Attention:dense feature map经过一个encoding layer得到context embedding,然后通过FC得到一个classwise的score,作为权重。
- Semantic Encoding loss:在编码层之上添加了一个带Sigmoid激活的FC层用于单独预测场景中出现的目标类别,并学习二进制交叉熵损失。不同于逐像素损失,SE loss 对于大小不同的目标有相同的贡献,这能够提升小目标的检测性能。
二、复现精度
Model | mIOU |
ResNet101-EncNet(mmseg-pytorch) | 78.5 |
ResNet101-EncNet(本项目Paddle) | 78.3 |
由于训练的随机性,比现有复现低了一点点…但是也算是成功的复现啦~
NOTE:训练是4卡v100 batchsize=8(每张卡2)80k的结果。
三、数据集
使用的数据集为:Cityscapes
- 数据集大小:19个类别的密集像素标注,5000张1024*2048大小的高质量像素级注释图像/20000个弱注释帧
- 训练集:2975个图像
- 验证集:500个图像
- 测试集:1525个图像
数据集应有的结构:
data/
├── cityscapes
│ ├── gtFine
│ │ ├── test
│ │ ├── train
│ │ └── val
│ ├── leftImg8bit
│ │ ├── test
│ │ │ ├── berlin
│ │ │ ├── ...
│ │ │ └── munich
│ │ ├── train
│ │ │ ├── aachen
│ │ │ ├── ...
│ │ │ └── zurich
│ │ └── val
│ │ ├── frankfurt
│ │ ├── lindau
│ │ └── munster
│ ├── train.txt
│ ├── val.txt
│ ├── test.txt
四、代码
论文的详细内容还是需要结合代码才能理解得更深刻。本项目基于PaddleSeg开发套件进行。所有的训练评估方式都与PaddleSeg相同。可查阅PaddleSeg。
代码主要分为模型和损失两部分。
- MODEL:位于ENCNet/paddleseg/models/encnet.py
主要模块:
class EncModule(nn.Layer):
"""Encoding Module used in EncNet.
Args:
in_channels (int): Input channels.
num_codes (int): Number of code words.
"""
def __init__(self, in_channels, num_codes):
super(EncModule, self).__init__()
self.encoding_project = layers.ConvBNReLU(in_channels,in_channels,1)
# change to 1d
self.encoding = nn.Sequential(
Encoding(in_channels, num_codes),
nn.BatchNorm1D(num_codes),
nn.ReLU())
self.fc = nn.Sequential(
nn.Linear(in_channels, in_channels), nn.Sigmoid())
def forward(self, x):
"""Forward function."""
encoding_projection = self.encoding_project(x)
encoding_feat = self.encoding(encoding_projection).mean(axis=1)
batch_size, channels, _, _ = x.shape
gamma = self.fc(encoding_feat)
y = gamma.reshape((batch_size, channels, 1, 1))
output = F.relu_(x + x * y)
return encoding_feat, output
- SE-LOSS:位于ENCNet/paddleseg/models/losses/encoding_cross_entropy_loss.py 的EncodingBCELoss
主要是将语义分割标签转为one-hot编码后与模型输出的semantic-encoding结果进行二值交叉熵损失的计算。
数据集准备
# 创建cityscape文件夹
!mkdir data/cityscapes/
# 解压数据集中的gtFine
!unzip -nq -d data/gtFine/ data/data48855/gtFine_train.zip
!unzip -nq -d data/gtFine/ data/data48855/gtFine_val.zip
!unzip -nq -d data/gtFine/ data/data48855/gtFine_test.zip
!mv data/gtFine/ data/cityscapes/
# 解压数据集中的leftImg8bit
!unzip -nq -d data/leftImg8bit/ data/data48855/leftImg8bit_train.zip
!unzip -nq -d data/leftImg8bit/ data/data48855/leftImg8bit_val.zip
!unzip -nq -d data/leftImg8bit/ data/data48855/leftImg8bit_test.zip
!mv data/leftImg8bit/ data/cityscapes/
# 训练train.txt val.txt等文件的生成
!python ENCNet/tools/create_dataset_list.py /home/aistudio/data/cityscapes/ --type cityscapes --separator ","
训练
项目提供预训练的模型与日志,已经挂载到数据集中解压后可查看。output文件夹下有训练日志和可视化日志。
!python ENCNet/train.py --config ENCNet/configs/encnet/encnet_r101_d8_512x1024_80k_cityscapes.yml --num_workers 0 --use_vdl --do_eval --save_interval 1000 --save_dir encnet_r101_d8_512x1024_80k_cityscapes
训练可视化
评估
通过修改“–model_path /home/aistudio/output/model.pdparams"进行预训练模型选择,进行评估。
!python ENCNet/val.py --config ENCNet/configs/encnet/encnet_r101_d8_512x1024_80k_cityscapes.yml --model_path data/data118662/model.pdparams
总结
上下文内容对于像素任务而言非常重要,建模像素间关系对于改善语义分割结果很有好处。