目标检测——SSD-TensorFlow训练自己的数据集踩坑记

一、首先下载代码:https://github.com/balancap/SSD-Tensorflow   目前是github基于TensorFlow星星最高的开源SSD。

2、解压至某个文件夹,我这里解压的路径是 /media/comway/data/dial_SSD/SSD-Tensorflow-master

若是其他路径,后面进行相应的更改。

3、制作2007VOC数据集(谷歌一下,一大堆资料),通过labelImg制作每张图片的标签。然后制作2007VOC数据集。如下图所示。简单解释下:Annotations文件夹下有保存每张图片的xml文件。ImageSets有四个xml文件,用来划分训练验证测试集。JPEGImages文件夹下保存的是图片数据。

目标检测——SSD-TensorFlow训练自己的数据集踩坑记_第1张图片

附分割训练测试验证集的代码:

import os
import random 
 
xmlfilepath=r'/media/comway/data/DialVOC/Annotations'
saveBasePath=r"/media/comway/data/DialVOC"
 
trainval_percent=0.9
train_percent=0.9
total_xml = os.listdir(xmlfilepath)
num=len(total_xml)  
list=range(num)  
tv=int(num*trainval_percent)  
tr=int(tv*train_percent)  
trainval= random.sample(list,tv)  
train=random.sample(trainval,tr)  
 
print("train and val size",tv)
print("traub suze",tr)
ftrainval = open(os.path.join(saveBasePath,'ImageSets/Main/trainval.txt'), 'w')  
ftest = open(os.path.join(saveBasePath,'ImageSets/Main/test.txt'), 'w')  
ftrain = open(os.path.join(saveBasePath,'ImageSets/Main/train.txt'), 'w')  
fval = open(os.path.join(saveBasePath,'ImageSets/Main/val.txt'), 'w')  
 
for i  in list:  
    name=total_xml[i][:-4]+'\n'  
    if i in trainval:  
        ftrainval.write(name)  
        if i in train:  
            ftrain.write(name)  
        else:  
            fval.write(name)  
    else:  
        ftest.write(name)  
  
ftrainval.close()  
ftrain.close()  
fval.close()  
ftest .close()  

附将数据重命名为六位数据代码:

# -*- coding:utf8 -*-
 
import os
 
class BatchRename():
    '''
    批量重命名文件夹中的图片文件
    '''
    def __init__(self):
        #我的图片文件夹路径horse
        self.path = '/media/comway/data/dialData'
 
    def rename(self):
        filelist = os.listdir(self.path)
        total_num = len(filelist)
        i = 1
	n = 6
        for item in filelist:
            if item.endswith('.jpg'):
		n = 6 - len(str(i))
                src = os.path.join(os.path.abspath(self.path), item)
                dst = os.path.join(os.path.abspath(self.path), str(0)*n + str(i) + '.jpg')
                try:
                    os.rename(src, dst)
                    print 'converting %s to %s ...' % (src, dst)
                    i = i + 1
		    
                except:
                    continue
        print 'total %d to rename & converted %d jpgs' % (total_num, i)
 
if __name__ == '__main__':
    demo = BatchRename()
    demo.rename()

 

4、 将VOC2007数据转换文件格式,变成TensorFlow可接受的数据格式tfrecord。

a、首先,打开进入SSD-Tensorflow-master—>datasets—>pascalvoc_common.py 更改代码,根据自己情况更改,有几类就改成几类。

VOC_LABELS = { 
    'none': (0, 'Background'), 
    'aeroplane': (1, 'Vehicle'), 
    'bicycle': (2, 'Vehicle'), 
    'bird': (3, 'Animal'), 
    'boat': (4, 'Vehicle'), 
    'bottle': (5, 'Indoor'), 
    'bus': (6, 'Vehicle'), 
    'car': (7, 'Vehicle'), 
    'cat': (8, 'Animal'), 
    'chair': (9, 'Indoor'), 
    'cow': (10, 'Animal'), 
    'diningtable': (11, 'Indoor'), 
    'dog': (12, 'Animal'), 
    'horse': (13, 'Animal'), 
    'motorbike': (14, 'Vehicle'), 
    'Person': (15, 'Person'), 
    'pottedplant': (16, 'Indoor'), 
    'sheep': (17, 'Animal'), 
    'sofa': (18, 'Indoor'), 
    'train': (19, 'Vehicle'), 
    'tvmonitor': (20, 'Indoor'), 
}

b、SSD-Tensorflow-master—>datasets—>pascalvoc_to_tfrecords.py   然后更改文件的83行读取方式为’rb’) 

目标检测——SSD-TensorFlow训练自己的数据集踩坑记_第2张图片

 如下图所示,SAMPLES_PER_FILES的竖直,意思是200张图片转换为一个tfrecord文件。

目标检测——SSD-TensorFlow训练自己的数据集踩坑记_第3张图片

c 、在SSD-Tensorflow-master文件夹下创建converttfrecord.sh文件,将下列代码写进去。

python tf_convert_data.py \
    --dataset_name=pascalvoc \  #不可更改
    --dataset_dir=/media/comway/data/dial_SSD/DialVOC/ \   #你的制作的VOC数据集。
    --output_name=voc_2007_train \  #输出的record文件前缀
    --output_dir=/media/comway/data/dial_SSD/SSD-Tensorflow-master/dialvoc-train-tfrecords  #输出tfreord的路径。

5、训练模型前,更改文件中数据

train_ssd_network.py修改第154行的最大训练步数,将None改为比如50000。(tf.contrib.slim.learning.training函数中max-step为None时训练会无限进行。) 

需要修改的地方:

a. train_ssd_network.py,135行,这里本来是21,我这里改成了2。可以根据自己的类别数更改,数字为类别数加1。

目标检测——SSD-TensorFlow训练自己的数据集踩坑记_第4张图片

 b.   nets/ssd_vgg_300.py,我们分析train_ssd_network.py文件就知道,其中引入了from nets import nets_factory模块,在看nets_factory文件,就可以知道引入了ssd_vgg_300。如下图所示,所以我们要对ssd_vgg_300更改。

目标检测——SSD-TensorFlow训练自己的数据集踩坑记_第5张图片

需要更改的部分如下,在文件96,97行进行更改,将num_classes,no_annotation_label,更改为你的类别数加1,我这里只有一类,所以是2:

 目标检测——SSD-TensorFlow训练自己的数据集踩坑记_第6张图片

c. datasets/pascalvoc_2007.py ,我们分析train_ssd_network.py文件就知道,其中引入了from datasets import dataset_factory模块,再看dataset_factory文件,如下图就可以知道引入了pascalvoc_2007。如下图所示,所以我们要对pascalvoc_2007更改。记住,必须在训练之前改,否则就会出错。

目标检测——SSD-TensorFlow训练自己的数据集踩坑记_第7张图片

需要更改的部分:

TRAIN_STATISTICS = {
    'none': (0, 0),
    'aeroplane': (238, 306),
    'bicycle': (243, 353),
    'bird': (330, 486),
    'boat': (181, 290),
    'bottle': (244, 505),
    'bus': (186, 229),
    'car': (713, 1250),
    'cat': (337, 376),
    'chair': (445, 798),
    'cow': (141, 259),
    'diningtable': (200, 215),
    'dog': (421, 510),
    'horse': (287, 362),
    'motorbike': (245, 339),
    'person': (2008, 4690),
    'pottedplant': (245, 514),
    'sheep': (96, 257),
    'sofa': (229, 248),
    'train': (261, 297),
    'tvmonitor': (256, 324),
    'total': (5011, 12608),
}
TEST_STATISTICS = {
    'none': (0, 0),
    'aeroplane': (1, 1),
    'bicycle': (1, 1),
    'bird': (1, 1),
    'boat': (1, 1),
    'bottle': (1, 1),
    'bus': (1, 1),
    'car': (1, 1),
    'cat': (1, 1),
    'chair': (1, 1),
    'cow': (1, 1),
    'diningtable': (1, 1),
    'dog': (1, 1),
    'horse': (1, 1),
    'motorbike': (1, 1),
    'person': (1, 1),
    'pottedplant': (1, 1),
    'sheep': (1, 1),
    'sofa': (1, 1),
    'train': (1, 1),
    'tvmonitor': (1, 1),
    'total': (20, 20),
}
#以上两部分,我没改好像也没错,我查了下好像没用到这个dict。不过也可以改。
SPLITS_TO_SIZES = {
    'train': 2229,   #这个地方要改成你的训练数据量
    'test': 276,   #这个地方改成测试数据量
}
SPLITS_TO_STATISTICS = {
    'train': TRAIN_STATISTICS,
    'test': TEST_STATISTICS,
}
NUM_CLASSES = 1  #记住,这个地方一定要改,否则就会出现shape不匹配等问题。本身应该是20,我这里改成了1.因为我的类别数是1.

 

d eval_ssd_network.py 修改类别,72行,把um_classes改成你的类别数加1.

 

这四部分已经改完,接下来就可以进行训练了。

6、训练模型

这里很容易出现问题,请记住,两种情况训练,第一种情况,不加载模型,直接全部训练。第二种情况,加载预训练模型,训练部分参数。

这里比较容易犯错就是,加载训练模型,又全部训练所有参数。如下所示进行训练:

python3 train_ssd_network.py \
    --train_dir=/media/comway/data/dial_SSD/SSD-Tensorflow-master/train_log/ \
    --dataset_dir=/media/comway/data/dial_SSD/SSD-Tensorflow-master/dialvoc-train-tfrecords \
    --dataset_name=pascalvoc_2007 \
    --dataset_split_name=train \
    --model_name=ssd_300_vgg \
    --checkpoint_path=/media/comway/data/dial_SSD/SSD-Tensorflow-master/checkpoints/ssd_300_vgg.ckpt \
    --save_summaries_secs=60 \
    --save_summaries_secs=600 \
    --save_interval_secs=600 \
    --weight_decay=0.0005 \
    --optimizer=adam \
    --learning_rate=0.001 \
    --learning_rate_decay_factor=0.94 \
    --batch_size=16 \
    --gpu_memory_fraction=0.9

如果你的sh脚本文件按这样训练就会出现如下类似错误:

InvalidArgumentError (see above for traceback): Assign requires shapes of both tensors to match. lhs shape= [12] rhs shape= [126]
         [[Node: save_1/Assign_29 = Assign[T=DT_FLOAT, _class=["loc:@ssd_300_vgg/block8_box/conv_cls/biases"], use_locking=true, validate_shape=true, _device="/job:localhost/replica:0/task:0/cpu:0"](s
sd_300_vgg/block8_box/conv_cls/biases, save_1/RestoreV2_29)]]

所以只能按我说的两种情况进行训练:

第一种: 不加载模型,直接全部训练

python3 train_ssd_network.py \
    --train_dir=/media/comway/data/dial_SSD/SSD-Tensorflow-master/train_log/ \
    --dataset_dir=/media/comway/data/dial_SSD/SSD-Tensorflow-master/dialvoc-train-tfrecords \
    --dataset_name=pascalvoc_2007 \
    --dataset_split_name=train \
    --model_name=ssd_300_vgg \
    --save_summaries_secs=60 \
    --save_interval_secs=600 \
    --weight_decay=0.0005 \
    --optimizer=adam \
    --learning_rate=0.001 \
    --learning_rate_decay_factor=0.94 \
    --batch_size=16 

第二种: 加载预训练模型,训练部分参数。从vgg开始训练其中某些层的参数。其实就是加了--checkpoint_exclude_scopes,与--trainable_scopes。

# 通过checkpoint_exclude_scopes指定哪些层的参数不需要从预训练模型模型里面加载进来
# 通过trainable_scopes指定哪些层的参数是需要训练的,未指定的参数保持不变,若注释掉此命令,所有的参数均需要训练
python3 train_ssd_network.py \
    --train_dir=/media/comway/data/dial_SSD/SSD-Tensorflow-master/train_log/ \   #训练生成模型的存放路径
    --dataset_dir=/media/comway/data/dial_SSD/SSD-Tensorflow-master/dialvoc-train-tfrecords \  #数据存放路径
    --dataset_name=pascalvoc_2007 \  #数据名的前缀,我觉得应该通过这个调用是2007还是2012
    --dataset_split_name=train \  #是加载训练集还是测试集
    --model_name=ssd_300_vgg \  #加载的模型的名字
    --checkpoint_path=/media/comway/data/dial_SSD/SSD-Tensorflow-master/checkpoints/ssd_300_vgg.ckpt \  #所加载模型的路径
 --checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
    --trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
    --save_summaries_secs=60 \#每60s保存一下日志
    --save_interval_secs=600 \  #每600s保存一下模型
    --weight_decay=0.0005 \   #正则化的权值衰减的系数
    --optimizer=adam \  #选取的最优化函数
    --learning_rate=0.001 \  #学习率
    --learning_rate_decay_factor=0.94 \  #学习率的衰减因子
    --batch_size=16 \   
    --gpu_memory_fraction=0.9  #指定占用gpu内存的百分比

终结!!!!!!! 

 

参考资料:

https://blog.csdn.net/comway_Li/article/details/85240291

https://www.cnblogs.com/pprp/p/9552402.html#%E9%AA%8C%E8%AF%81

https://github.com/balancap/SSD-Tensorflow

 

你可能感兴趣的:(TensorFlow,深度学习网络模型,目标检测)