论文:https://arxiv.org/pdf/1802.02611.pdf
源码:https://github.com/tensorflow/models/tree/master/research/deeplab
环境:ubuntu16.04 + cuda9.0 + cudnn7.6 + tensorflow-gpu1.11
cuda9.0 + cudnn7.6安装配置可参照:https://blog.csdn.net/wgshun616/article/details/81019182
多个版本cuda安装切换可参照:https://blog.csdn.net/yinxingtianxia/article/details/80462892
// 查看GPU型号
lspci | grep -i nvidia
// 查看NVIDIA驱动版本
sudo dpkg --list | grep nvidia-*
// 查看CUDA版本,需一致
cat /usr/local/cuda/version.txt
nvcc -V
// 查看CUDNN版本
cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2
deeplabv3+依赖库安装参照:https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/installation.md
安装tensorflow-gpu时输入:
pip install tensorflow-gpu==1.11
记得在gedit ~/.bashrc配置文件中加入:
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
运行网上数据集过程请参照:https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/pascal.md
运行自己数据集:
1. 建立数据集
先在datasets目录下建立如下目录结构:
+ pascal_voc_seg
+ VOCdevkit
+ VOC2012
+ JPEGImages
+ SegmentationClass
+ ImageSets
+ Main
+ tfrecord
+ exp
+ train_on_train_set
+ train
+ val
+ vis
其中JPEGImages放置原图,SegmentationClass放置标注的分割图(注意标注时类别的像素值设置为0,1,2…,255为ignore_label)。Main中放置train.txt, val.txt, trainval.txt,为训练测试时所使用的数据,只包含数据名去掉后缀。
接下来生成tfrecord格式的数据集,修改download_and_convert_voc2012.sh文件:
// 注释60行:
# download_and_uncompress "${BASE_URL}" "${FILENAME}"
// 89行根据自己数据集JPEGImages后缀名修改
--image_format="jpg" \
直接在datasets目录下运行:
bash download_and_convert_voc2012.sh
这样就会在tfrecord下生成训练测试所需的数据集。
2. 训练
加载的预训练模型:http://download.tensorflow.org/models/deeplabv3_pascal_train_aug_2018_01_04.tar.gz,读者也可以尝试train from scrach。
运行之前,修改deprecated/segmentation_dataset.py,改成你自己的数据集的量和类别数:
_PASCAL_VOC_SEG_INFORMATION = DatasetDescriptor(
splits_to_sizes={
'train': 1464, // 训练数据量
#'train_aug': 10582,
'trainval': 2913, // train+val
'val': 1449, // 测试数据量
},
num_classes=21, // 类别数
ignore_label=255,
)
看到一些博客,预训练时不加载logit层,因为类别数不同,修改train_utils.py的159行:
#exclude_list = ['global_step']
exclude_list = ['global_step','logit']
并且设置
initialize_last_layer=False
last_layers_contain_logits_only=True
博主设置后效果反而不好,读者可自行尝试。
在research下运行:
python deeplab/train.py \
--logtostderr \
--training_number_of_steps=30000 \
--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="361,481" \
--train_batch_size=4 \
--dataset="pascal_voc_seg" \
--tf_initial_checkpoint="./deeplab/datasets/deeplabv3_pascal_train_aug/model.ckpt" \
--train_logdir="./deeplab/datasets/pascal_voc_seg/exp/train_on_train_set/train" \
--dataset_dir="./deeplab/datasets/pascal_voc_seg/tfrecord"
--fine_tune_batch_norm=False
这里说明几点:
1)因为只有一块GPU,train_batch_size设置为4,相应的fine_tune_batch_norm=False(当batchsize大于等于12才为True);数据集尺寸为480×360,train_crop_size设置的原则是减1除以4为整数,设置时第一个值是高,第二个值是宽,这个值大了也可能内存不够,但不小于300,否则会影响ASPP多尺度的效果,读者可根据自己的情况调整。
2)模型选择model_variant可根据自己情况自行选择,支持resnet, xception, mobilenet,不同模型可能decoder_output_stride可能有所不同,读者可自行阅读源码设置。
3)上面的参数均是可以调整的,包括训练步数,基网络output_stride,ASPP使用的空洞卷积rate等等,读者可自行阅读论文找到最合适的设置方式。
4)训练时学习率的衰减有两种方式,可选择线性poly和指数step,在train.py的77行:
flags.DEFINE_enum('learning_policy', 'poly', ['poly', 'step'],
'Learning rate policy for training.')
80-97行这几个关于学习率的参数与这两种方式的学习率计算公式有关:
# Use 0.007 when training on PASCAL augmented training set, train_aug. When
# fine-tuning on PASCAL trainval set, use learning rate=0.0001.
flags.DEFINE_float('base_learning_rate', .0001,
'The base learning rate for model training.')
flags.DEFINE_float('learning_rate_decay_factor', 0.1,
'The rate to decay the base learning rate.')
flags.DEFINE_integer('learning_rate_decay_step', 2000,
'Decay the base learning rate at a fixed step.')
flags.DEFINE_float('learning_power', 0.9,
'The power value used in the poly learning policy.')
flags.DEFINE_integer('training_number_of_steps', 30000,
'The number of steps used for training')
flags.DEFINE_float('momentum', 0.9, 'The momentum value to use')
学习率计算公式在utils/train_utils.py的230行有说明:
(1) The learning policy for "step" is computed as follows:
current_learning_rate = base_learning_rate *
learning_rate_decay_factor ^ (global_step / learning_rate_decay_step)
See tf.train.exponential_decay for details.
(2) The learning policy for "poly" is computed as follows:
current_learning_rate = base_learning_rate *
(1 - global_step / training_number_of_steps) ^ learning_power
基本上线性衰减关注训练总步数train_number_of_steps和learning_power,指数衰减关注learning_rate_decay_factor和learning_rate_decay_step,global_step表示当前的步数。
5) 关于数据均衡,因为不同类别样本像素个数不一样,可能存在样本不均衡的情况,可在损失函数里给不同类别不同的权重,在train_utils.py的85行:
not_ignore_mask = tf.to_float(tf.not_equal(scaled_labels, ignore_label)) * loss_weight
默认设置的时只要不是ignore_label(255),权重就是loss_weight(1)。因为看到一些博客有修改这个地方,但我修改后效果反而变差了。。。读者可自行尝试。
6)训练时,可运行:
tensorboard --logdir exp/train_on_train_set // 定位到你的train_on_train_set目录
在tensorboard中查看训练情况。
3. 测试评价
运行:
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 \
--train_crop_size="361,481" \
--dataset="pascal_voc_seg" \
--checkpoint_dir="./deeplab/datasets/pascal_voc_seg/exp/train_on_train_set/train" \
--eval_logdir="./deeplab/datasets/pascal_voc_seg/exp/train_on_train_set/eval" \
--dataset_dir="./deeplab/datasets/pascal_voc_seg/tfrecord"
注意修改eval.py中第78行max_number_of_evaluations=1,否则它会一直循环等待训练生成的新的model.ckpt进行评价。
另外eval.py不会在终端输出miou等评价指标(当然可以在tensorboard中看到),在eval.py的155行创建一个新的会话输出miou值:
miou, update_op = tf.metrics.mean_iou( predictions, labels, dataset.num_of_classes,
weights=weights)
tf.summary.scalar(predictions_tag, miou)
// 新加入的代码
print_miou = tf.Print(miou,[miou],'miou is:')
tf.summary,scalar('print_miou',print_miou)
summary_op = tf.summary.merge_all()
读者可自行加入像素准确率等评价指标。
4. vis可视化
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 \
--train_crop_size="361,481" \
--dataset="pascal_voc_seg" \
--checkpoint_dir="./deeplab/datasets/pascal_voc_seg/exp/train_on_train_set/train" \
--vis_logdir="./deeplab/datasets/pascal_voc_seg/exp/train_on_train_set/vis" \
--dataset_dir="./deeplab/datasets/pascal_voc_seg/tfrecord"
同样设置max_number_of_evaluations=1。