Jiarui's Blog.

Deeplab v3+ 在cityscapes数据集上测试笔记

2018/04/30 Share

Ubuntu16.04下Cuda安装

为了让tensorflow在GPU下运行,需要安装cuda和cudnn。(太懒了,不想写)

参考网页 Ubuntu 16.04 上安装 CUDA 9.0 详细教程

DeepLab的准备、训练、测试

参考网页

[1] Deeplab v3 Github

[2] 图像语义分割 DeepLab v3+ 训练自己的数据集

[3] 使用TensorFlow DeepLab进行语义分割

[4] Github: Running DeepLab on Cityscapes Semantic Segmentation Dataset

第2、3篇文章都是对voc数据集进行训练,大概参考这两篇文章,然后根据第4篇github上的instruction稍加修改,就可以训练了。

准备

1 测试本地环境

首先添加slim路径,每次打开terminal都要加载路径

1
2
# From tensorflow/models/research/  
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

Quick test by running model_test.py:

1
2
# From tensorflow/models/research/
python deeplab/model_test.py

Quick running the whole code on the PASCAL VOC 2012 dataset:

1
2
# From tensorflow/models/research/deeplab
sh local_test.sh

如果都运行成功,说明本地环境已经可以了,接下来训练自己的数据集。

2 生成tfrecord格式的数据

首先在The Cityscapes Dataset Github下载Cityscapesscripts,按照convert_cityscapes.sh文件中提到的文件放置顺序放到models/research/deeplab/datasets文件路径下。

1
2
3
4
5
6
7
8
# The folder structure is assumed to be:
# + datasets
# - build_cityscapes_data.py
# - convert_cityscapes.sh
# + cityscapes
# + cityscapesscripts (downloaded scripts)
# + gtFine
# + leftImg8bit

运行如下语句

1
2
# From the ./models/research/deeplab/datasets directory.
sh convert_cityscapes.sh

转换后的dataset会存储在 ./deeplab/datasets/cityscapes/tfrecord

训练

训练与测试部分主要参考文章 使用TensorFlow DeepLab进行语义分割

0 文件结构

文件结构参考 PASCAL VOC 2012 官方推荐的文件结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
deeplab/datasets/pascal_voc_seg
├── exp
│ └── train_on_train_set
│ ├── eval
│ │ └── events.out.tfevents....
│ ├── export
│ │ └── frozen_inference_graph.pb
│ ├── train
│ │ ├── checkpoint
│ │ ├── events.out.tfevents....
│ │ ├── graph.pbtxt
│ │ ├── model.ckpt-0.data-00000-of-00001
│ │ ├── model.ckpt-0.index
│ │ ├── model.ckpt-0.meta
│ │ └── ...
│ └── vis
│ ├── graph.pbtxt
│ ├── raw_segmentation_results
│ └── segmentation_results
├── init_models
│ └── deeplabv3_pascal_train_aug
│ ├── frozen_inference_graph.pb
│ ├── model.ckpt.data-00000-of-00001
│ └── model.ckpt.index
├── tfrecord
│ ├── ....tfrecord
│ └── ...
└── VOCdevkit
└── VOC2012
├── Annotations
├── ImageSets
│ ├── Action
│ ├── Layout
│ ├── Main
│ └── Segmentation
├── JPEGImages
├── SegmentationClass
├── SegmentationClassRaw
└── SegmentationObject

Cityscapes 的文件结构如下,需要结合一下VOC的结构。

1
2
3
4
5
6
7
8
9
10
+ datasets
+ cityscapes
+ leftImg8bit
+ gtFine
+ tfrecord
+ exp
+ train_on_train_set
+ train
+ eval
+ vis

1 下载模型

官方提供了不少预训练模型

https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/model_zoo.md

这里以 deeplabv3_pascal_train_aug_2018_01_04 为例。

1
2
3
4
5
# From deeplab/datasets/cityscapes/
mkdir init_models
cd init_models
wget http://download.tensorflow.org/models/deeplabv3_cityscapes_train_2018_02_06.tar.gz
tar zxf deeplabv3_cityscapes_train_2018_02_06.tar.gz

由于我是应用在cityscapes,下载的是cityscapes部分的xception_65

2 训练

新建 deeplab/datasets/cityscapes/exp/train_on_train_set/train.sh,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mkdir -p logs/
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
now=$(date +"%Y%m%d_%H%M%S")
python ../../../../train.py \
--logtostderr \
--training_number_of_steps=90000 \
--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=769 \
--train_crop_size=769 \
--train_batch_size=2 \
--num_clones=2 \
--dataset="cityscapes" \
--fine_tune_batch_norm=false \
--tf_initial_checkpoint="../../init_models/deeplabv3_cityscapes_train/model.ckpt" \
--train_logdir="train/" \
--dataset_dir="../../tfrecord/" 2>&1 | tee logs/train_$now.txt &

进入 deeplab/datasets/cityscapes/exp/train_on_train_set/

运行 sh train.sh 即可训练。

3 验证

可一边训练一边验证,注意使用其它的GPU或合理分配显存。

新建 deeplab/datasets/cityscapes/exp/train_on_train_set/eval.sh,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
python ../../../../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=1025 \
--eval_crop_size=2049 \
--dataset="cityscapes" \
--checkpoint_dir="train/" \
--eval_logdir="eval/" \
--dataset_dir="../../tfrecord/" &
# --max_number_of_evaluations=1 &

进入 deeplab/datasets/cityscapes/exp/train_on_train_set/

运行 CUDA_VISIBLE_DEVICES="1" sh eval.sh 即可验证(这里指定了第二个 GPU)。

4 可视化 log

可一边训练一边可视化训练的 log,访问 http://localhost:6006/ 即可看到 loss 等的变化。

1
2
# From deeplab/datasets/cityscapes/exp/train_on_train_set
tensorboard --logdir train/

可视化验证的 log,可看到 miou_1.0 的变化,这里指定了另一个端口。

1
2
# From deeplab/datasets/cityscapes/exp/train_on_train_set
tensorboard --logdir eval/ --port 6007

或同时可视化训练与验证的log:

1
2
# From deeplab/datasets/cityscapes/exp/train_on_train_set
tensorboard --logdir .

5 可视化分割结果

可一边训练一边可视化分割结果。

新建 deeplab/datasets/cityscapes/exp/train_on_train_set/vis.sh,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
python ../../../../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=1025 \
--vis_crop_size=2049 \
--dataset="cityscapes" \
--colormap_type="cityscapes" \
--checkpoint_dir="train/" \
--vis_logdir="vis/" \
--dataset_dir="../../tfrecord/" &

进入 deeplab/datasets/cityscapes/exp/train_on_train_set/

运行 sh vis.sh 即可生成分割结果,vis/segmentation_results/ 里有彩色化的分割结果,vis/raw_segmentation_results/ 里有原始的分割结果。

测试

1 导出模型

训练完成后得到一些 checkpoint 文件在 deeplab/datasets/cityscapes/exp/train_on_train_set/train/ 中,如:

1
2
3
4
graph.pbtxt
model.ckpt-1000.data-00000-of-00001
model.ckpt-1000.info
model.ckpt-1000.meta

其中 meta 文件保存了 graph 和 metadata,ckpt 文件保存了网络的 weights。

而进行预测时只需模型和权重,不需要 metadata,故可使用官方提供的脚本生成推导图。

新建 deeplab/datasets/cityscapes/exp/train_on_train_set/export_model.sh,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
python ../../../../export_model.py \
--logtostderr \
--checkpoint_path="train/model.ckpt-$1" \
--export_path="export/frozen_inference_graph-$1.pb" \
--model_variant="xception_65" \
--atrous_rates=6 \
--atrous_rates=12 \
--atrous_rates=18 \
--output_stride=16 \
--decoder_output_stride=4 \
--num_classes=19 \
--crop_size=769 \
--crop_size=769 \
--inference_scales=1.0

进入 deeplab/datasets/pascal_voc_seg/exp/train_on_train_set/

运行 sh export_model.sh 1000 即可导出模型 export/frozen_inference_graph-1000.pb

2 测试图片

运行 deeplab_demo.ipynb 并修改其中的各种路径即可。

或自写 inference 脚本,如 deeplab/datasets/cityscapes/exp/train_on_train_set/infer.py。(不太确定label 0是不是background,待更)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import sys
sys.path.append('../../../../utils/')
from matplotlib import pyplot as plt
import numpy as np
from PIL import Image
import tensorflow as tf
import get_dataset_colormap
LABEL_NAMES = np.asarray([
'unlabeled', 'road', 'sidewalk', 'building', 'wall', 'fence', 'pole',
'traffic light', 'traffic sign', 'vegetation', 'terrain', 'person', 'rider', 'car', 'truck',
'bus', 'train', 'motorcycle', 'bicycle'
])
FULL_LABEL_MAP = np.arange(len(LABEL_NAMES)).reshape(len(LABEL_NAMES), 1)
FULL_COLOR_MAP = get_dataset_colormap.label_to_color_image(FULL_LABEL_MAP)
class DeepLabModel(object):
"""Class to load deeplab model and run inference."""
INPUT_TENSOR_NAME = 'ImageTensor:0'
OUTPUT_TENSOR_NAME = 'SemanticPredictions:0'
INPUT_SIZE = 769
def __init__(self, model_path):
"""Creates and loads pretrained deeplab model."""
self.graph = tf.Graph()
with open(model_path) as fd:
graph_def = tf.GraphDef.FromString(fd.read())
with self.graph.as_default():
tf.import_graph_def(graph_def, name='')
self.sess = tf.Session(graph=self.graph)
def run(self, image):
"""Runs inference on a single image.
Args:
image: A PIL.Image object, raw input image.
Returns:
resized_image: RGB image resized from original input image.
seg_map: Segmentation map of `resized_image`.
"""
width, height = image.size
resize_ratio = 1.0 * self.INPUT_SIZE / max(width, height)
target_size = (int(resize_ratio * width), int(resize_ratio * height))
resized_image = image.convert('RGB').resize(target_size,
Image.ANTIALIAS)
batch_seg_map = self.sess.run(
self.OUTPUT_TENSOR_NAME,
feed_dict={
self.INPUT_TENSOR_NAME: [np.asarray(resized_image)]
})
seg_map = batch_seg_map[0]
return resized_image, seg_map
def vis_segmentation(image, seg_map):
plt.figure()
plt.subplot(221)
plt.imshow(image)
plt.axis('off')
plt.title('input image')
plt.subplot(222)
seg_image = get_dataset_colormap.label_to_color_image(
seg_map, get_dataset_colormap.get_pascal_name()).astype(np.uint8)
plt.imshow(seg_image)
plt.axis('off')
plt.title('segmentation map')
plt.subplot(223)
plt.imshow(image)
plt.imshow(seg_image, alpha=0.7)
plt.axis('off')
plt.title('segmentation overlay')
unique_labels = np.unique(seg_map)
ax = plt.subplot(224)
plt.imshow(
FULL_COLOR_MAP[unique_labels].astype(np.uint8),
interpolation='nearest')
ax.yaxis.tick_right()
plt.yticks(range(len(unique_labels)), LABEL_NAMES[unique_labels])
plt.xticks([], [])
ax.tick_params(width=0)
plt.show()
if __name__ == '__main__':
if len(sys.argv) < 3:
print('Usage: python {} image_path model_path'.format(sys.argv[0]))
exit()
image_path = sys.argv[1]
model_path = sys.argv[2]
model = DeepLabModel(model_path)
orignal_im = Image.open(image_path)
resized_im, seg_map = model.run(orignal_im)
vis_segmentation(resized_im, seg_map)

运行以下命令即可:

1
2
3
4
# From deeplab/datasets/cityscapes/exp/train_on_train_set/
python infer.py \
../../../../g3doc/img/image1.jpg \
export/frozen_inference_graph.pb

遇到的问题

小白入门deeplab,遇到好多傻问题,记录一下。

1 Import error

1
ImportError: No module named deeplab

models/research/路径下输入

1
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim

2 InvalidArgumentError

1
InvalidArgumentError (see above for traceback): Assign requires shapes of both tensors to match. lhs shape= [21] rhs shape= [19]

这是因为最后的num_classesinit modelnum_classes不一致导致的。我这里是因为忘记把dataset改成cityscapes了。因为在segmenation_dataset.py里面voc的num_classes是21,我的init modelnum_classes是cityscapes的,是19,所以会不match。

在写train.sh文件的时候,加入下面这一行就解决了。

1
--dataset="cityscapes" \

3 Linux终止脚本进程

ctrl+C没有用时,可以用ps -ef | grep 进程名 查出进程,然后kill该进程。

kill 的用法:kill[信号代码]进程ID

注:信号代码可以省略;我们常用的信号代码是 -9 ,表示强制终止;

kill

参考网页 linux停止正在执行脚本

CATALOG
  1. 1. Ubuntu16.04下Cuda安装
  2. 2. DeepLab的准备、训练、测试
    1. 2.1. 参考网页
    2. 2.2. 准备
      1. 2.2.1. 1 测试本地环境
      2. 2.2.2. 2 生成tfrecord格式的数据
    3. 2.3. 训练
      1. 2.3.1. 0 文件结构
      2. 2.3.2. 1 下载模型
      3. 2.3.3. 2 训练
      4. 2.3.4. 3 验证
      5. 2.3.5. 4 可视化 log
      6. 2.3.6. 5 可视化分割结果
    4. 2.4. 测试
      1. 2.4.1. 1 导出模型
      2. 2.4.2. 2 测试图片
  3. 3. 遇到的问题
    1. 3.0.1. 1 Import error
    2. 3.0.2. 2 InvalidArgumentError
    3. 3.0.3. 3 Linux终止脚本进程