**
**
1.使用 deeplabv3+ 训练自己的数据集经验总结
2.window环境下进行deeplab_tensorflow实验之第一阶段
3.window环境下进行deeplab_tensorflow实验之第二阶段
4.deeplab_v3 实现 制作并训练自己的数据集——个人采坑
**
**
1.环境配置
我的环境为win10+tensorflow1.12+cuda9.0+cudnn7.3.1,使用python3.6.2-0,配置环境使用Anaconda4.7.10。
2.下载对应版本的tensorflow模型库,1.12对应库链接https://github.com/tensorflow/models/tree/r1.12.0
3.安装依赖库(详见deeplab介绍:https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/installation.md)
· Numpy
· Pillow 1.0
· tf Slim (which is included in the “tensorflow/models/research/” checkout)
· Jupyter notebook
· Matplotlib
4.Windows系统中添加tf.slim的路径至系统
windows 系统下要在py脚本中动态添加地址,即将 deeplab 文件夹下的 train.py, eval.py, vis.py, export_model.py ,model_test.py这5个脚本的开头加如下语句,且必须加在 import deeplab 语句之前。
import sys
sys.path.append(r'D:\Code\tf-models\research')
sys.path.append(r'D:\Code\tf-models\research\slim') # 以上两处的路径请按照真实的路径添加
5.环境测试
在tensorflow/models/research/下运行model_test.py
python deeplab/model_test.py
如果环境正确,则提示:
Ran 5 tests in 10.758s
6.发生错误怎么办
大多数问题在网上都可找到答案,“错啥搜啥,缺啥装啥”。至此,前期工作结束。
**
**
仿照PASCAL VOC 2012数据集格式,制作自己的数据集,使用原料为labelme;正式开始之前,最好将数据集大小整理成统一尺寸,做好命名!!!
1.下载PASCAL VOC 2012数据集并复制,清空所有文件,这里的目的是获得该数据集的结构。实际上,如果仅仅用于分割,那么并不需要完整结构,仅做成如下格式即可。
VOCdevkit
└── VOC2012
├── ImageSets
│ └── Segmentation
├── JPEGImages
├── SegmentationClass
├── SegmentationClassRaw
ImageSets/Segmentation:存放图像列表,格式为txt,内容为图像名称编号
JPEGImages: 存放图像原图
SegmentationClass: 存放标好的mask图,即labels
SegmentationClassRaw:去除colormap后的mask图。
2.使用labelme标注数据
(1)激活环境,输入 labelme,即可打开标注器进行标注,设置好原图文件夹,标注文件夹和标注类型。标注后应生成.json文件。
(2)转换.json文件,在环境下使用如下语句,配置好文件路径,即可在输出文件夹中生成解析后的子文件夹(命名为原图对应的名称),每个包含5个文件
python json_to_dataset.py D:/dataset/input -o D:/dataset/output
5个文件分别为:img.png,info.yaml,label.png,label_names.txt,label_viz.png,代表含义为:
原图,标注信息,分割图即带colormap的mask,分割名称,分割视图可视化。至此实现标注。
3.将子文件夹中的label.png文件统一转移至SegmentationClass中
为此,找到一段以前写的MATLAB程序,实现label.png文件的重命名和转移。
A:子文件夹的上一层文件夹名称
B:SegmentationClass文件夹的相对路径
clc
clear all
close all
%% 读入需要处理的图片信息
file_path = 'A\'; % 要处理的图片的文件夹
img_path_list = dir(strcat(file_path,'*.jpg')); % 要处理的图片的详细信息
img_num = length(img_path_list); % 要处理的图片的个数
%% 导出图片的路径配置
new_folder = 'B\';
mkdir(new_folder); % 创建文件夹
addpath(new_folder); % 添加文件夹路径
%% 重命名并转移文件夹
for m = 1:img_num
image_name = img_path_list(m).name;
I = imread(strcat(file_path,image_name)); % 读入第m个图片
J = imresize(I,[240 320]);
imwrite(J,[new_folder,image_name]); % 新尺寸保存在文件夹下
end
至此完成数据集制作。
**
**
1.按照官方文档将数据文件放置为如下图的目录结构(没有某个文件夹就新建一个):
deeplab/datasets/你的数据集名称
├── 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
├── tfrecord
│ ├── ....tfrecord
│ └── ...
└── VOCdevkit
└── VOC2012
├── Annotations
├── ImageSets
│ ├── Action
│ ├── Layout
│ ├── Main
│ └── Segmentation
├── JPEGImages
├── SegmentationClass
└──SegmentationClassRaw
一些说明:
evel:保存训练好的模型的iou
export:训练好的模型导出位置
vis:测试集结果可视化
train: 模型保存的文件路径,存放模型文件,需手动创建
tfrecord: 为稍后将数据转为tensorflow所需要的tfrecord格式的文件夹,需手动创建
2.移除 ground-truth (SegmentationClass文件夹中数据)中的 colormap(到SegmentationClassRaw文件夹)
# From deeplab/datasets/
python remove_gt_colormap.py --original_gt_folder=./你的数据集名称/VOCdevkit/VOC2012/SegmentationClass --output_dir=./你的数据集名称/VOCdevkit/VOC2012/SegmentationClassRaw
其中,output_dir:去除colormap后的mask存放文件夹(之后需要将这个文件夹的图片作为label,并转换成tfrecord格式数据)
3.转换为tfrecord格式数据
在datasets下运行build_voc2012_data.py,在命令行中修改参数:
python build_voc2012_data.py --image_folder=./你的数据名称/VOCdevkit/VOC2012/JPEGImages --semantic_segmentation_folder=./你的数据集名称/VOCdevkit/VOC2012/SegmentationClassRaw --list_folder='./你的数据集名称/VOCdevkit/VOC2012/ImageSets/Segmentation' --image_format="jpg" --output_dir='./你的数据集名称/tfrecord'
各参数意义如下:
image_folder:保存images的路径
semantic_segmentation_folder:保存labels的路径
list_folder:保存train\val.txt文件的路径
image_format:image的格式
output_dir:生成tfrecord格式的数据所要保存的位置
运行成功后,会提示如下信息:
>> Converting image 366/1464 shard 0
>> Converting image 732/1464 shard 1
>> Converting image 1098/1464 shard 2
>> Converting image 1464/1464 shard 3
>> Converting image 22/85 shard 0
>> Converting image 44/85 shard 1
>> Converting image 66/85 shard 2
>> Converting image 85/85 shard 3
4.注册数据集
在 segmentation_dataset.py 文件中找到这段:
_DATASETS_INFORMATION = {
'cityscapes': _CITYSCAPES_INFORMATION,
'pascal_voc_seg': _PASCAL_VOC_SEG_INFORMATION,
'ade20k': _ADE20K_INFORMATION,
'dataset_name': _DATASET_NAME, # 自己的数据集名字及对应配置放在这里
}
然后添加数据集的相关配置,名字要和上面注册的数据集相同。
_DATASET_NAME = DatasetDescriptor(
splits_to_sizes={
'train': 10000,
'val': 2000, # 这里根据Segmentation中的.txt文件名对应,
'trainval': 12000 # 数字代表对应数据集包含图像的数量
},
num_classes=151, # 类别数目,包括背景
ignore_label=255, # 有些数据集标注有白色描边(VOC 2012),不代表任何实际类别
)
在 get_dataset_colormap.py 文件中修改
# Dataset names.
_ADE20K = 'ade20k'
_CITYSCAPES = 'cityscapes'
_MAPILLARY_VISTAS = 'mapillary_vistas'
_PASCAL = 'pascal'
_DATASET_NAME='dataset_name' # 添加在这里,和注册的名字相同
# Max number of entries in the colormap for each dataset.
_DATASET_MAX_ENTRIES = {
_ADE20K: 151,
_CITYSCAPES: 19,
_MAPILLARY_VISTAS: 66,
_PASCAL: 256,
_DATASET_NAME: 151, # 在这里添加 colormap 的颜色数
}
接下来写一个函数,用途是返回一个 np.ndarray 对象,尺寸为 [classes, 3] ,即colormap共有 classes 种RGB颜色,分别代表不同的类别。
def create_dataset_name_label_colormap():
return np.asarray([
[165, 42, 42],
[0, 192, 0],
[196, 196, 196],
[190, 153, 153],
[180, 165, 180],
[102, 102, 156],
[102, 102, 156],
[128, 64, 255],
...
])
最后修改 create_label_colormap 函数,在这个调用接口中加上我们自己的数据集:
def create_label_colormap(dataset=_PASCAL):
"""Creates a label colormap for the specified dataset.
Args:
dataset: The colormap used in the dataset.
Returns:
A numpy array of the dataset colormap.
Raises:
ValueError: If the dataset is not supported.
"""
if dataset == _ADE20K:
return create_ade20k_label_colormap()
elif dataset == _CITYSCAPES:
return create_cityscapes_label_colormap()
elif dataset == _MAPILLARY_VISTAS:
return create_mapillary_vistas_label_colormap()
elif dataset == _PASCAL:
return create_pascal_label_colormap()
elif dataset == _DATASET_NAME: # 添加在这里
return create_dataset_name_label_colormap()
else:
raise ValueError('Unsupported dataset.')
**
**
1.训练,运行train.py
先从官方github上下载预训练模型(https://github.com/tensorflow/models/blob/master/research/deeplab/g3doc/model_zoo.md
),包含xception65、mobilenetv2等多个版本。这里以xception65_coco_voc_trainaug为例,下载后解压在deeplab/weights文件夹(需手动新建)中,如图所示:
训练前,运行之前,在train.py文件中,修改128~132行如下。目的是只对最后一层进行训练,因为自己的数据集和PASCAL VOC 2012并不完全相同,不修改会报错:
flags.DEFINE_boolean('initialize_last_layer', False,
'Initialize the last layer.')
flags.DEFINE_boolean('last_layers_contain_logits_only', True,
'Only consider logits as last layers or not.')
训练时,在命令行中输入如下命令,其中train_crop_size根据自己的数据集像素值修改,第一个为height+1,第二个为width+1:
python train.py --logtostderr --training_number_of_steps=100 --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=1 --fine_tune_batch_norm=False --dataset="pascal_voc_seg" --tf_initial_checkpoint=./weights/deeplabv3_pascal_train_aug/model.ckpt --train_logdir=./datasets/你的数据集名称/exp/train_on_train_set/train --dataset_dir=./datasets/你的数据集名称/tfrecord
若使用mobilenetv2,则调用如下命令
python train.py --logtostderr --training_number_of_steps=100 --train_split="train" --model_variant="mobilenet_v2" --output_stride=16 --train_crop_size=513 --train_crop_size=513 --train_batch_size=1 --fine_tune_batch_norm=False --dataset="你的数据集" --tf_initial_checkpoint=./weights/deeplabv3_pascal_train_aug/model.ckpt --train_logdir=./datasets/你的数据集名称/exp/train_on_train_set/train --dataset_dir=./datasets/你的数据集名称/tfrecord
其中,部分参数意义如下:
tf_initial_checkpoint:# 加载权重,第一次应为在官方github下载的预训练模型权重
train_logdir: 保存训练的中间结果的路径
dataset_dir: 第三步生成的tfrecord文件的路径,注意是文件路径,不是tfrecord文件
运行成功,则报出:
INFO:tensorflow:global step 24370: loss = 0.1581 (0.106 sec/step)
INFO:tensorflow:global step 24380: loss = 0.1517 (0.128 sec/step)
INFO:tensorflow:global step 24390: loss = 0.1445 (0.101 sec/step)
INFO:tensorflow:global step 24400: loss = 0.1597 (0.100 sec/step)
INFO:tensorflow:global step 24410: loss = 0.2159 (0.099 sec/step)
INFO:tensorflow:global step 24420: loss = 0.1341 (0.106 sec/step)
INFO:tensorflow:global step 24430: loss = 0.1251 (0.101 sec/step)
INFO:tensorflow:global step 24440: loss = 0.1622 (0.100 sec/step)
INFO:tensorflow:global step 24450: loss = 0.1656 (0.103 sec/step)
INFO:tensorflow:global step 24460: loss = 0.1264 (0.102 sec/step)
INFO:tensorflow:global step 24470: loss = 0.1684 (0.107 sec/step)
2.计算mIOU
运行eval.py,在deeplab下执行以下命令:
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=513 --eval_crop_size=513 --dataset="你的数据集名称" --checkpoint_dir=./datasets/你的数据集名称/exp/train_on_train_set/train --eval_logdir=./你的数据集名称/exp/train_on_train_set/eval --dataset_dir=./datasets/你的数据集名称/tfrecord
其中部分文件路径参数意义如下:
checkpoint_dir:模型checkpoint所在路径
eval_logdir:结果输出路径,该文件夹需手动创建
dataset_dir:验证集tfrecord文件所在路径,同训练步骤,此处为tfrecord文件路径
运行成功后,会报miou值,但是一直不退出,这是因为程序在等待下一个模型喂入。可无视,直接Ctrl+C退出即可。
3.训练结果可视化
运行vis.py,在deeplab下执行以下命令:
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=513 --vis_crop_size=513 --dataset="你自己的数据集" --checkpoint_dir=./datasets/你自己的数据集/exp/train_on_train_set/train --vis_logdir=./datasets/你自己的数据集/exp/train_on_train_set/vis --dataset_dir=./datasets/你自己的数据集/tfrecord
各参数意义:
checkpoint_dir: 模型checkpoint所在路径
vis_logdir: 预测结果保存路径,自己创建
dataset_dir: 生成的tfrecord数据集所在路径
运行成功,则在vis文件夹下生成测试集的分割图。此时会遇到相同的不退出问题,原因同上,直接Ctrl+C退出。
4.导出模型
在 中,修改38~41行为自己的参数(类别数:你的分类数+背景+1,数据集尺寸)
flags.DEFINE_integer('num_classes', 3, 'Number of classes.')
flags.DEFINE_multi_integer('crop_size', [241, 321],
'Crop size [height, width].')
运行 export_model.py 生成模型
python export_model.py --logtostderr --checkpoint_path=./datasets/你的数据集名称/exp/train_on_train_set/train/model.ckpt-195990 --export_path=./datasets/你的数据集名称/exp/train_on_train_set/export/graph195990.pb --model_variant="xception_65" --atrous_rates=6 --atrous_rates=12 --atrous_rates=18 --output_stride=16 --decoder_output_stride=4 --num_classes=3 --crop_size=241 --crop_size=321 \ --inference_scales=1.0
注:若使用mobilenet模型,2、3、4步修改方式类同1。
OK,it’s alright!!