DeepLab的基本环境和基本demo要运行成功。
如何使用DeepLabV3+训练CityScapes。
我的数据集是3分类问题,但因为数据集的保密协议,在后面的demo中我没有放出原图片,我会尽量将训练细节写出来。为了方便记录,我又使用了CamVid数据集
(从这里下载)测试了一下。
数据集处理分成三大步:
相关资源:
对于CamVid
数据集,我将制作好的TFRecord上传到了CSDN上,如果只是单单测试程序的话,可以直接下载使用。
同时,对应的用于生成CamVid
不同数据集的index文件我也上传到github了。
这里需要提前说明一个概念,我自己在这里耽误了很长时间:
如果你的数据集存在ignore_label
,注意不要把ignore_label
和background
混淆。 ignore_label
是没有做标注的,不在预测范围内的,ignore_label
是不参与计算loss的。我们在mask中将ignore_label
的灰度值标记为255
。
CamVid
有11个分类,我自己的数据集有3个分类。生成的mask必须为单通道(灰度图),建议为png格式。
注意,在制作mask时,对所有object的灰度像素值有要求。
对于所有object包括background
在内,在mask中要将灰度值标注为0~n,虽然产生的图片很难看出区别,但是这对训练是有效的。注意,不要把object的灰度值标注成10,20,100…(这样代码会直接将灰度值和class匹配,这在调整权重等操作会有麻烦~)
再强调一下:我在制作个人的数据集上将background
标注为0,注意这是background
而不是ignore_label
.
最终,我在个人的数据集上关于图像的mask,设置如下:
background
的灰度值设置为0ignore_label
,所以没有点设置为255(我的数据集和CamVid都是没有的,如果存在ingore_label
,在视觉上是白色的)对于CamVid
,原标注的数据集格式满足要求。示例如下,可以看到这里面是不存在ignore_label
(没有白色),取一个图片示例如下:
再制作TFRecord之前,需要有文件指引将数据集分类成训练/测试/验证集,故我们需要创建指引文件。
将上述生成的所有mask和原输入图片分在两个文件夹下,我的设置如下:
/root/dataset/CamVid/image
:存放所有的输入图片,共有701张,这其中包括训练/测试/验证集的图片/root/dataset/CamVid/mask
:存放所有的labeled图片,共有701张,和输入图片是一一对应的对于CamVid
数据集,创建了一个目录/root/dataset/CamVid/index
,该目录下包含三个.txt文件:
train.txt
:所有训练集的文件名称trainval.txt
:所有验证集的文件名称val.txt
:所有测试集的文件名称对应的CamVid
数据集目录如下:
#from /root/dataset/CamVid/
+ image
+ mask
+ index # 自己创建
- train.txt
- trainval.txt
- val.txt
+ tfrecord #自己创建
上述的三个.txt文件,也是从CamVid上下载的,参照制作脚本的要求。
详细的来讲,只存放图片的名称,对应train/val.txt文件部分截取(可以使用Sublime或其他文本编辑工具统一find然后删除):
# train.txt
0001TP_006690
0001TP_006720
...
0016E5_08640
#共367行
# val.txt
0016E5_07959
...
0016E5_08157
0016E5_08159
# 共101行
对应的用于生成CamVid
不同数据集的index文件我也上传到github了。
将上述制作的数据集打包成TFRecord,使用的是build_voc2012_data.py,参考download_and_convert_voc2012.sh中的指令格式。
对于CamVid
数据集,我将制作好的TFRecord上传到了CSDN上,如果只是单单测试程序的话,可以直接下载使用。
标准的指令格式如下:
python ./build_voc2012_data.py \
--image_folder="${IMAGE_FOLDER}" \
--semantic_segmentation_folder="${SEMANTIC_SEG_FOLDER}" \
--list_folder="${LIST_FOLDER}" \
--image_format="jpg" \
--output_dir="${OUTPUT_DIR}"
${IMAGE_FOLDER}
:数据集中原输入数据的文件目录地址${SEMANTIC_SEG_FOLDER}
:数据集中标签的文件目录地址${LIST_FOLDER}
: 将数据集分类成训练集、验证集等的指示目录文件目录image_format
:输入图片数据的格式,CamVid
的是png格式output_dir
:制作的TFRecord
存放的目录地址(自己创建)依据上面对于数据集的处理,对于CamVid
数据集,制作TFRecord,使用的指令如下:
# from /research/deeplab/dataset
python ./build_voc2012_data.py \
--image_folder="/root/dataset/CamVid/image" \
--semantic_segmentation_folder="/root/dataset/CamVid/mask" \
--list_folder="/root/dataset/CamVid/index" \
--image_format="png" \
--output_dir="/root/dataset/CamVid/tfrecord"
指定运行结果部分输出如下:
#trainval.txt
>> Converting image 59/233 shard 0
>> Converting image 118/233 shard 1
>> Converting image 177/233 shard 2
>> Converting image 233/233 shard 3
#train.txt
>> Converting image 92/367 shard 0
>> Converting image 184/367 shard 1
>> Converting image 276/367 shard 2
>> Converting image 367/367 shard 3
#val.txt
>> Converting image 26/101 shard 0
>> Converting image 52/101 shard 1
>> Converting image 78/101 shard 2
>> Converting image 101/101 shard 3
可以在对应的/root/dataset/CamVid/tfrecord
目录下查看已经制作好的TFRecord文件:
# from /root/dataset/CamVid/tfrecord
$: ls
train-00000-of-00004.tfrecord trainval-00002-of-00004.tfrecord
train-00001-of-00004.tfrecord trainval-00003-of-00004.tfrecord
train-00002-of-00004.tfrecord val-00000-of-00004.tfrecord
train-00003-of-00004.tfrecord val-00001-of-00004.tfrecord
trainval-00000-of-00004.tfrecord val-00002-of-00004.tfrecord
trainval-00001-of-00004.tfrecord val-00003-of-00004.tfrecord
这样关于数据集的处理都完事了。
在DeepLabv3+模型的基础上,主要需要修改以下几个文件
segmentation_dataset.py
文件train_utils.py
修改segmentation_dataset.py
的110行,添加对应的关于_CAMVID
数据集的描述设置:
# segmentation_dataset.py line 110
_CAMVID_INFORMATION = DatasetDescriptor(
splits_to_sizes={
'train': 367, # num of samples in images/training
'val': 101, # num of samples in images/validation
},
num_classes=12,
ignore_label=255,
)
因为CamVid共有11个classes,所以加上ignore_label
共12个。
对于我个人的数据集,一共有object1,object2,background三个类别,加上ignore_label
,所以num_classes=4.
_MYDATA_INFORMATION = DatasetDescriptor(
splits_to_sizes={
'train': 444, # num of samples in images/training
'val': 46, # num of samples in images/validation
},
num_classes=4,
ignore_label=255,
)
同时在segmentation_dataset.py
文件的112行,上添加对应数据集的名称:
_DATASETS_INFORMATION = {
'cityscapes': _CITYSCAPES_INFORMATION,
'pascal_voc_seg': _PASCAL_VOC_SEG_INFORMATION,
'ade20k': _ADE20K_INFORMATION,
'mydata':_MYDATA_INFORMATION, #我自己的数据集
'camvid':_CAMVID_INFORMATION, #camvid示例
}
对应的train_utils.py
中,先将109行关于exclude_list
的设置修改,作用是在使用预训练权重时候,不加载该logit
层:
# Variables that will not be restored.
exclude_list = ['global_step','logits']
if not initialize_last_layer:
exclude_list.extend(last_layers)
参考DeepLabv3+一作aquariusjay的解疑,如果你的问题是二分类或者和我的数据集类似,存在object之间imablance,这需要在train_utils.py的70行修改权重.
因为CamVid
数据集这个问题可以忽略,这里重点说我个人数据集,因为是三分类问题,其中background
占了非常大的比例,并且object2比object1要稍微少一点,最终的设置的权重比例为1:10:15
:
irgore_weight = 0
label0_weight =1 # 对应灰度值0,即background
label1_weight = 10 # 对应object1, mask 中灰度值1
label2_weight = 15 # 对应object2,.mask 中灰度值2
not_ignore_mask =
tf.to_float(tf.equal(scaled_labels, 0)) * label0_weight +
tf.to_float(tf.equal(scaled_labels, 1)) * label1_weight +
tf.to_float(tf.equal(scaled_labels, 2)) * label2_weight +
tf.to_float(tf.equal(scaled_labels, ignore_label)) * irgore_weight
tf.losses.softmax_cross_entropy(
one_hot_labels,
tf.reshape(logits, shape=[-1, num_classes]),
weights=not_ignore_mask,
scope=loss_scope)
在这个步骤,我曾把ignore_label
和background
混淆了,最后我在mask 中将background的标注值为0,对应的label0_weight=1,object1的标注值为1,对应的为label1_weight = 10,… 最后才训练成功。
参考aquariusjay在github上的解疑.
如果想在DeepLab的基础上fine-tune其他数据集, 可在train.py中修改输入参数。有一些选项:
initialize_last_layer=True
initialize_last_layer=False
和last_layers_contain_logits_only=False
logits
,因为如果是自己的数据集,对应的classes不同(这个我们前面已经设置不加载logits),可设置initialize_last_layer=False
和last_layers_contain_logits_only=True
最终,我的设置是:
initialize_last_layer=False
last_layers_contain_logits_only=True
注意:我在训练CamVid
时,是没有考虑类别之间的的平衡问题,所以没有做imblance的修正,如果你是二分类或者存在严重的imblance情况,可以参考部分troubleshot中我遇到的问题。
依据repo上的训练示例,注意如下几个参数:
tf_initial_checkpoint
:预训练的权重,因为CamVid和我的数据集都和CityScapes类似,所以我使用的是CityScapes的预训练权重
train_logdir
:训练产生的文件存放位置
dataset_dir
:数据集的TFRecord文件dataset
:设置为我们在segmentation_dataset.py
文件设置的数据集名称我在CamVid上的训练指令如下:
python deeplab/train.py \
--logtostderr \
--training_number_of_steps=300 \
--train_split="train" \
--model_variant="xception_65" \
--atrous_rates=6 \
--atrous_rates=12 \
--atrous_rates=18 \
--output_stride=16 \
--decoder_output_stride=4 \
--train_crop_size=513 \
--train_crop_size=513 \
--train_batch_size=2 \
--dataset="camvid" \
--tf_initial_checkpoint='/root/newP/official_tf/models-master/research/deeplab/backbone/deeplabv3_cityscapes_train/model.ckpt' \
--train_logdir='/root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train' \
--dataset_dir='/root/dataset/CamVid/tfrecord'
这里只设置了300个step,对于crop_size设置为513,只是为了测试训练是否能够正确执行。 考虑到我的计算资源显示,我设置batchsize=2。
部分的训练输出如下:
INFO:tensorflow:Starting Session.
INFO:tensorflow:Saving checkpoint to path /root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train/model.ckpt
INFO:tensorflow:Starting Queues.
INFO:tensorflow:global_step/sec: 0
INFO:tensorflow:Recording summary at step 0.
INFO:tensorflow:global step 10: loss = 2.7773 (0.550 sec/step)
INFO:tensorflow:global step 20: loss = 2.6438 (0.531 sec/step)
INFO:tensorflow:global step 30: loss = 2.4824 (0.555 sec/step)
INFO:tensorflow:global step 40: loss = 2.4652 (0.564 sec/step)
#...
INFO:tensorflow:global step 300: loss = 1.9276 (0.534 sec/step)
INFO:tensorflow:Stopping Training.
INFO:tensorflow:Finished training! Saving model to disk.
deepLab提供了可视化和评估工具,这里对于刚才在CamVid上训练的权重测试。
因为CamVid的图片大小和CityScapes是不同的,这里相关的参数设置为:
vis_split
:设置为测试集vis_crop_size
:设置360,480为图片的大小dataset
:设置为我们在segmentation_dataset.py
文件设置的数据集名称dataset_dir
:设置为创建的TFRecordcolormap_type
:可视化标注的颜色最终,可视化的指令如下:
# From tensorflow/models/research/
python deeplab/vis.py \
--logtostderr \
--vis_split="val" \
--model_variant="xception_65" \
--atrous_rates=6 \
--atrous_rates=12 \
--atrous_rates=18 \
--output_stride=16 \
--decoder_output_stride=4 \
--vis_crop_size=360 \
--vis_crop_size=480 \
--dataset="camvid" \
--colormap_type="pascal" \
--checkpoint_dir='/root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train' \
--vis_logdir='/root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/vis' \
--dataset_dir='/root/dataset/CamVid/tfrecord'
可视化指令的输出部分如下:
INFO:tensorflow:Restoring parameters from /root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train/model.ckpt-300
INFO:tensorflow:Visualizing batch 1 / 101
INFO:tensorflow:Visualizing batch 2 / 101
INFO:tensorflow:Visualizing batch 3 / 101
...
INFO:tensorflow:Visualizing batch 100 / 101
INFO:tensorflow:Visualizing batch 101 / 101
我截取了可视化输出图:
可以看到模型是可以正确分类的,虽然结果不怎么好。
同样的,eval的参数也需要做一些改变:
eval_split
:设置为测试集crop_size
:同样设置为360和480dataset
:设置为camviddataset_dir
:设置为我们创建的数据集我们评估的指令如下:
python deeplab/eval.py \
--logtostderr \
--eval_split="val" \
--model_variant="xception_65" \
--atrous_rates=6 \
--atrous_rates=12 \
--atrous_rates=18 \
--output_stride=16 \
--decoder_output_stride=4 \
--eval_crop_size=360 \
--eval_crop_size=480 \
--dataset="camvid" \
--checkpoint_dir='/root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train' \
--eval_logdir='/root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/eval' \
--dataset_dir='/root/dataset/CamVid/tfrecord'
评估指令的输出部分如下:
INFO:tensorflow:Restoring parameters from /root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train/model.ckpt-300
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Starting evaluation at 2018-07-06-06:34:28
INFO:tensorflow:Evaluation [10/101]
INFO:tensorflow:Evaluation [20/101]
#...
INFO:tensorflow:Evaluation [101/101]
INFO:tensorflow:Finished evaluation at 2018-07-06-06:34:34
miou_1.0[0.149601415]
结果一般般,但是证明了我们训练过程是没有大问题~
在前面初始训练后,针对CamVid
数据集,我做了进一步参考修改,简单测试了一下新的结果。
我将前面存储在train_logdir里面的权重删除了,一些参数的修改:
training_number_of_steps
设置为3000crop_size
缩小为321batch_size
可以提高到4进阶的训练指令如下:
python deeplab/train.py \
--logtostderr \
--training_number_of_steps=3000 \
--train_split="train" \
--model_variant="xception_65" \
--atrous_rates=6 \
--atrous_rates=12 \
--atrous_rates=18 \
--output_stride=16 \
--decoder_output_stride=4 \
--train_crop_size=321 \
--train_crop_size=321 \
--train_batch_size=4 \
--dataset="camvid" \
--tf_initial_checkpoint='/root/newP/official_tf/models-master/research/deeplab/backbone/deeplabv3_cityscapes_train/model.ckpt' \
--train_logdir='/root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train' \
--dataset_dir='/root/dataset/CamVid/tfrecord'
进阶训练的输出部分如下:
INFO:tensorflow:global step 2960: loss = 0.6281 (0.407 sec/step)
INFO:tensorflow:Saving checkpoint to path /root/newP/official_tf/models-master/research/deeplab/exp/camvid_train/train/model.ckpt
INFO:tensorflow:global_step/sec: 2.45499
INFO:tensorflow:Recording summary at step 2962.
INFO:tensorflow:global step 2970: loss = 0.8240 (0.439 sec/step)
INFO:tensorflow:global step 2980: loss = 0.9588 (0.385 sec/step)
INFO:tensorflow:global step 2990: loss = 0.8880 (0.412 sec/step)
INFO:tensorflow:global step 3000: loss = 0.8292 (0.392 sec/step)
重新使用eval.py做了验证:
INFO:tensorflow:Evaluation [101/101]
INFO:tensorflow:Finished evaluation at 2018-07-06-07:03:30
miou_1.0[0.4015598]
可以看到,新的训练结果有了显著的提示。
重新使用vis.py,部分可视化结果:
可以看到明显比前面好多了。
一开始我是一直在DeepLabv3+上测试自己的数据集,故问题都是集中于自己的数据集上。
我主要犯了三个错误:
对于mask的生成,我在前面详细的讲了如何生成,这是非常重要的一步。,我犯的错误是将不同的object和background的像素值设置为0,100,150.这导致后续的预测会有问题,无法解决imblance。
对于ignore_label
我曾经设置为0,对应的segmentation_dataset.py
文件:
# segmentation_dataset.py
_CAMVID_INFORMATION = DatasetDescriptor(
splits_to_sizes={
'train': 367, # num of samples in images/training
'val': 101, # num of samples in images/validation
},
num_classes=3,
ignore_label=0,
)
这里我错误的把ignore_label
设置为0,并且错误的将num_classes设置为3.
在train_utils.py
文件中计算如下:
ignore_weight = 0
label0_weight =20
label1_weight = 20
not_ignore_mask =
tf.to_float(tf.equal(scaled_labels, 1)) * label0_weight
+ tf.to_float(tf.equal(scaled_labels, 2)) * label1_weight
+ tf.to_float(tf.equal(scaled_labels, ignore_label)) * ignore_weight
因为ignore_label
设置为0了,这会导致结果背景不做任何loss,因为我每次都是训练了200个step,可以看到如下两个图,是有学习到信息,但是在预测上是有存在问题的。
对应各个类别之间权重设置有问题,预测权重设置出现了问题:
## 输出全蓝色
irgore_weight = 0
label0_weight =10
label1_weight = 20
## 输出全黑色
irgore_weight = 10
label0_weight =10
label1_weight = 10
## 输出全绿色
irgore_weight = 0
label0_weight =20
label1_weight = 10
输出结果为全蓝色/黑色/绿色,对应的object2/background/object1设置过大,且没有考虑background,这导致模型不计算object2/background/object1的loss,一股脑的预测蓝色/黑色/绿色就能得到不错的loss。
我的数据集中大部分都是background,object1一般会比object2大一些,故最终测试的权重比例为1:10:15
,在实际过程中可通过像素统计给出一个更为精确的值:
irgore_weight = 0
label0_weight =1 # background
label1_weight = 10 # object1
label2_weight = 15 #object2
not_ignore_mask =
tf.to_float(tf.equal(scaled_labels, 0)) * label0_weight +
tf.to_float(tf.equal(scaled_labels, 1)) * label1_weight +
tf.to_float(tf.equal(scaled_labels, 2)) * label2_weight +
tf.to_float(tf.equal(scaled_labels, ignore_label)) * irgore_weight
这是我在训练200个step和4000个step之间模型的测试结果如下:
参考aquariusjay关于训练参数的设置:
aquariusjay关于imblance的设置:
参考github-@zhaolewen的关于数据标签的回答: