win10+tensorflow+cuda+cudnn,实现deeplabv3语义分割自己的数据集

**

参考:

**
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文件夹(需手动新建)中,如图所示:
win10+tensorflow+cuda+cudnn,实现deeplabv3语义分割自己的数据集_第1张图片
训练前,运行之前,在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!!

你可能感兴趣的:(tensorflow,python,深度学习)