跑通caffe-ssd demo代码(训练测试自己数据集)

Posted A big bliss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跑通caffe-ssd demo代码(训练测试自己数据集)相关的知识,希望对你有一定的参考价值。

跑通caffe-ssd demo代码(训练、测试自己数据集)

ssd网络我就不多介绍了,CSDN上面一搜一大把。这篇主要讲讲如何跑通caffe代码~
github:caffe-ssd

一、代码结构


在caffe-ssd中能用到的文件我全部在上述图片中标出来了,到时候具体的再细说~
caffe-ssd的环境自己百度吧,网上很多安装教程~

二、数据集准备

训练模型,首先第一个事情就是准备数据集。在利用caffe训练分类模型的时候,通常使用lmdb或者hdf5格式的数据,但是在该项目中使用的是lmdb格式的(其他格式的数据肯定也行,但是就是需要自己c++手写数据处理层了~太麻烦了)

1.

首先,准备VOC格式的数据

这是VOC数据集的格式,其中,Annotations里面存放的是所有数据图片相对应的xml标签文件,imagesets里面存放的是一些txt文件,后续用到再详细说,JPEGImages里面存放的就是训练图片,最后两个文件夹是用于实例分割的,在目标检测中用不到,所以就不用管它。(这里,为了简单,所以只使用VOC_trainval_2007中前36张图片)
JPEGImages:

其中,trainval里面存放训练图片,test存放测试图片。这个划分根据你自己项目进行决定就行。一般来说,trainval:test=4:1,这里我在test存放8张随机图片,剩余的存放在trainval文件夹中。值得一提,全部的图片还是放在trainval和test文件夹同级目录中,这样便于后续生成trainval.txt和test.txt。
Annotations:

Imagesets:

2.

下面介绍如何生成Imagesets里面的这四个txt文件~
先说trainval.txt和test.txt这两个文件。

#! /usr/bin/python  
# -*- coding:UTF-8 -*-  
 
import os, sys  
import glob  

trainval_dir = r"D:\\voc\\VOC_test\\JPEGImages\\trainval"  #训练集图片存放地址
test_dir = r"D:\\voc\\VOC_test\\JPEGImages\\test"  #测试图片存放地址
 
trainval_img_lists = glob.glob(trainval_dir + '/*.jpg') #如果你的图片是png格式的,只需要修改最后的后缀
trainval_img_names = []        
for item in trainval_img_lists:  
    temp1, temp2 = os.path.splitext(os.path.basename(item))  
    trainval_img_names.append(temp1)  
 
test_img_lists = glob.glob(test_dir + '/*.jpg') #如果你的图片是png格式的,只需要修改最后的后缀
test_img_names = []  
for item in test_img_lists:  
    temp1, temp2 = os.path.splitext(os.path.basename(item))  
    test_img_names.append(temp1)  
#图片路径和xml路径  
dist_img_dir = r"D:\\voc\\VOC_test\\JPEGImages" #JPEGImages路径
dist_anno_dir = r"D:\\voc\\VOC_test\\Annotations" #存放所有数据的xml文件路径
 
trainval_fd = open(r"D:\\voc\\VOC_test\\ImageSets\\trainval.txt", 'w')  #trainval.txt存放地址
test_fd = open(r"D:\\voc\\VOC_test\\ImageSets\\test.txt", 'w')  #test.txt存放地址
   
for item in trainval_img_names:  
    trainval_fd.write(dist_img_dir + '/' + str(item) + '.jpg' + ' ' + dist_anno_dir + '/' + str(item) + '.xml\\n')  
 
for item in test_img_names:  
    test_fd.write(dist_img_dir + '/' + str(item) + '.jpg' + ' ' + dist_anno_dir + '/' + str(item) + '.xml\\n')

生成的trainval.txt:

test.txt:

注意:这里我建议大家使用绝对路径,到时候在训练的时候比较清楚点

3.

下面介绍labelmap_voc.prototxt:
labelmap_voc.prototxt文件在你下载的caffe-ssd中有一个副本,位置在:you_caffe_root/data/VOC0712/里面,这里面的数据要根据你自己的需求进行修改,因为我这里就是VOC数据集,所以我不用改变的。不过假如我想进行猫狗目标检测算法,那我就得这么改:

这里,label为0的是背景一类,不管你是检测多少种物体,这一类是不能动的。

4.

下面就是test_name_size.txt生成方式:

#! /usr/bin/python
# -*- coding:UTF-8 -*-
import os, sys
import glob
from PIL import Image #读图

img_dir = r"D:/voc/VOC_test/JPEGImages/test" #测试图片存放路径

#获取制定路径下的所有jpg图片的名称
img_lists = glob.glob(img_dir + '/*.jpg')

test_name_size = open(r"D:/voc/VOC_test/ImageSets/test_name_size.txt", 'w') #test_name_size.txt存放路径

for item in img_lists:
    img = Image.open(item)
    width, height = img.size
    temp1, temp2 = os.path.splitext(os.path.basename(item))
    test_name_size.write(temp1 + ' ' + str(height) + ' ' + str(width) + '\\n')

最后生成的test_name_size.txt:

其中,每一列中第一个表示测试图片名称,第二个和第三个表示的是该测试图片的高和宽。


这样,所有准备工作都做完了~用上述所有文件就可以生成lmdb数据了

5.

将VOC文件夹放在you_caffe_root/data中

定位到you_caffe_root/data/VOC0712,下面应该有两个shell脚本文件:create_list.sh和create_data.sh。前者其实就是生成trainval.txt和test.txt,因为我们已经用python脚本生成好了,所以就可以直接用后者来生成lmdb数据了。
create_data.sh:

cur_dir=$(cd $( dirname ${BASH_SOURCE[0]} ) && pwd )
root_dir=$cur_dir/../.. #你安装caffe的根目录

cd $root_dir

redo=1
data_root_dir="" #上述VOC总文件夹的位置
mapfile="" #上述生成的labelmap_voc.prototxt存放位置
anno_type="detection"
db="lmdb"
min_dim=0
max_dim=0
width=0
height=0

extra_cmd="--encode-type=jpg --encoded"
if [ $redo ]
then
  extra_cmd="$extra_cmd --redo"
fi
for subset in test trainval
do
  python $root_dir/scripts/create_annoset.py #该sh脚本本质上是调用的是scripts/create_annoset.py,你找到create_annoset.py位置就行
   --anno-type=$anno_type 
   --label-map-file=$mapfile 
   --min-dim=$min_dim 
   --max-dim=$max_dim 
   --resize-width=$width 
   --resize-height=$height 
   # 很多人最后训练代码出错其实就是最后一行没有设置正确
   --check-label 
   $extra_cmd #这个不用管
   $data_root_dir #这个不用管
   $root_dir/data/$dataset_name/$subset.txt #这个位置是上述生成的trainval.txt和test.txt文件路径,这个要设置好
   $data_root_dir/$dataset_name/$db/$dataset_name"_"$subset"_"$db #这一个参数是设置生成lmdb文件的路径,一般来说,最好设置在VOC总文件夹下面,即同JPEGImages、Annotations、Images在同一个路径下,当然,也可以事先自己在VOC总文件夹下面创建一个lmdb的文件夹,该lmdb文件夹下面又有两个子文件夹,分别代表的是训练lmdb数据和测试lmdb数据
   examples/$dataset_name
done

注意点:如果代码运行报错(明明图片和xml标签路径是正确的,但是就是无法生成lmdb),那么找到create_annoset.py第87行:

img_file, anno = line.strip("\\n").split(" ")

改为

img_file, anno = line.strip("\\n").strip("\\r").split(" ")

三、开始训练

与以往caffe实现分类网络不同的是,该项目是通过py脚本进行训练的,而不是直接通过caffe的c++接口进行训练。
该py脚本的位置在:you_caffe_root/examples/ssd/ssd_pascal.py。

上述图片中还有一个ssd_detect.py脚本,该脚本就是用于测试单张图片用的,这个后续再说。
ssd_pascal.py
具体需要修改的地方会在下面标注清楚的

from __future__ import print_function
import caffe
from caffe.model_libs import *
from google.protobuf import text_format

import math
import os
import shutil
import stat
import subprocess
import sys

# Add extra layers on top of a "base" network (e.g. VGGNet or Inception).
def AddExtraLayers(net, use_batchnorm=True, lr_mult=1):
    use_relu = True

    # Add additional convolutional layers.
    # 19 x 19
    from_layer = net.keys()[-1]

    # TODO(weiliu89): Construct the name using the last layer to avoid duplication.
    # 10 x 10
    out_layer = "conv6_1"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 256, 1, 0, 1,
        lr_mult=lr_mult)

    from_layer = out_layer
    out_layer = "conv6_2"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 512, 3, 1, 2,
        lr_mult=lr_mult)

    # 5 x 5
    from_layer = out_layer
    out_layer = "conv7_1"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 128, 1, 0, 1,
      lr_mult=lr_mult)

    from_layer = out_layer
    out_layer = "conv7_2"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 256, 3, 1, 2,
      lr_mult=lr_mult)

    # 3 x 3
    from_layer = out_layer
    out_layer = "conv8_1"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 128, 1, 0, 1,
      lr_mult=lr_mult)

    from_layer = out_layer
    out_layer = "conv8_2"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 256, 3, 0, 1,
      lr_mult=lr_mult)

    # 1 x 1
    from_layer = out_layer
    out_layer = "conv9_1"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 128, 1, 0, 1,
      lr_mult=lr_mult)

    from_layer = out_layer
    out_layer = "conv9_2"
    ConvBNLayer(net, from_layer, out_layer, use_batchnorm, use_relu, 256, 3, 0, 1,
      lr_mult=lr_mult)

    return net


### Modify the following parameters accordingly ###
# The directory which contains the caffe code.
# We assume you are running the script at the CAFFE_ROOT.
caffe_root = os.getcwd()

# Set true if you want to start training right after generating all files.
run_soon = True
# Set true if you want to load from most recently saved snapshot.
# Otherwise, we will load from the pretrain_model defined below.
resume_training = True
# If true, Remove old model files.
remove_old_models = False

# The database file for training data. Created by data/VOC0712/create_data.sh
train_data = "examples/VOC0712/VOC0712_trainval_lmdb"  #该地址为上述生成的lmdb格式的训练数据,注意的是,该地址为存放lmdb数据的上一级文件夹
# The database file for testing data. Created by data/VOC0712/create_data.sh
test_data = "examples/VOC0712/VOC0712_test_lmdb" #该地址为上述生成的lmdb格式的测试数据,注意的是,该地址为存放lmdb数据的上一级文件夹
# Specify the batch sampler.
resize_width = 300 #该模型接收输入图片的宽
resize_height = 300 #该模型接收输入图片的高
resize = "{}x{}".format(resize_width, resize_height)
batch_sampler = [
        {
                'sampler': {
                        },
                'max_trials': 1,
                'max_sample': 1,
        },
        {
                'sampler': {
                        'min_scale': 0.3,
                        'max_scale': 1.0,
                        'min_aspect_ratio': 0.5,
                        'max_aspect_ratio': 2.0,
                        },
                'sample_constraint': {
                        'min_jaccard_overlap': 0.1,
                        },
                'max_trials': 50,
                'max_sample': 1,
        },
        {
                'sampler': {
                        'min_scale': 0.3,
                        'max_scale': 1.0,
                        'min_aspect_ratio': 0.5,
                        'max_aspect_ratio': 2.0,
                        },
                'sample_constraint': {
                        'min_jaccard_overlap': 0.3,
                        },
                'max_trials': 50,
                'max_sample': 1,
        },
        {
                'sampler': {
                        'min_scale': 0.3,
                        'max_scale': 1.0,
                        'min_aspect_ratio': 0.5,
                        'max_aspect_ratio': 2.0,
                        },
                'sample_constraint': {
                        'min_jaccard_overlap': 0.5,
                        },
                'max_trials': 50,
                'max_sample': 1,
        },
        {
                'sampler': {
                        'min_scale': 0.3,
                        'max_scale': 1.0,
                        'min_aspect_ratio': 0.5,
                        'max_aspect_ratio': 2.0,
                        },
                'sample_constraint': {
                        'min_jaccard_overlap': 0.7,
                        },
                'max_trials': 50,
                'max_sample': 1,
        },
        {
                'sampler': {
                        'min_scale': 0.3,
                        'max_scale': 1.0,
                        'min_aspect_ratio': 0.5,
                        'max_aspect_ratio': 2.0,
                        },
                'sample_constraint': {
                        'min_jaccard_overlap': 0.9,
                        },
                'max_trials': 50,
                'max_sample': 1,
        },
        {
                'sampler': {
                        'min_scale': 0.3,
                        'max_scale': 1.0,
                        'min_aspect_ratio': 0.5,
                        'max_aspect_ratio': 2.0,
                        },
                'sample_constraint': {
                        'max_jaccard_overlap': 1.0,
                        },
                'max_trials': 50,
                'max_sample': 1,
        },
        ]
train_transform_param = {  #这个字典里面就是进行数据增强的操作,其实我感觉可以不要该操作,但是没有尝试过注释后代码还能不能跑通
        'mirror': True,
        'mean_value': [104, 117, 123], #图片均值
        'resize_param': {
                'prob': 1,
                'resize_mode': P.Resize.WARP,
                'height': resize_height,
                'width': resize_width,
                'interp_mode': [
                        P.Resize.LINEAR,
                        P.Resize.AREA,
                        P.Resize.NEAREST,
                        P.Resize.CUBIC,
                        P.Resize.LANCZOS4,
                        ],
                },
        'distort_param': {
                'brightness_prob': 0.5,
                'brightness_delta': 32,
                'contrast_prob': 0.5,
                'contrast_lower': 0.5,
                'contrast_upper': 1.5,
                'hue_prob': 0.5,
                'hue_delta': 18,
                'saturation_prob': 0.5,
                'saturation_lower': 0.5,
                'saturation_upper': 1.5,
                'random_order_prob': 0.0,
                },
        'expand_param': {
                'prob': 0.5,
                'max_expand_ratio': 4.0,
                },
        'emit_constraint': {
            'emit_type': caffe_pb2.EmitConstraint.CENTER,
            }
        }
test_transform_param = {
        'mean_value': [104, 117, 123],
        'resize_param': {
                'prob': 1,
                'resize_mode': P.Resize.WARP,
                'height': resize_height,
                'width': resize_width,
                'interp_mode': [P.Resize.LINEAR],
                },
        }

# If true, use batch norm for all newly added layers.
# Currently only the non batch norm version has been tested.
use_batchnorm = False
lr_mult = 1
# Use different initial learning rate.
if use_batchnorm:
    base_lr = 0.0004
else:
    # A learning rate for batch_size = 1, num_gpus = 1.
    base_lr = 0.00004  #一般来说,我们会调用这个学习率,但是实际在训练的时候的学习率应该为base_lr * 25,所以说如果想增减学习率,只需要修改此处就可以

# Modify the job name if you want.
job_name = "SSD_{}".format(resize)
# The name of the model. Modify it if you want.
model_name = "VGG_VOC0712_{}".format(job_name)

# Directory which stores the model .prototxt file.
save_dir = "models/VGGNet/VOC0712/{}".format(job_name) #最后生成caffemodel的位置
# Directory which stores the snapshot of models.
snapshot_dir = "models/VGGNet/VOC0712/{}".format(job_name) 
# Directory which stores the job script and log file.
job_dir = "jobs/VGGNet/VOC0712/{}".format(job_name)
# Directory which stores the detection results.
output_result_dir = "{}/data/VOCdevkit/results/VOC2007/{}/Main".format(os.environ['HOME'], job_name)

# model definition files.
train_net_file = "{}/train.prototxt".format(save_dir) #train.prototxt位置
test_net_file = "{}/test.prototxt".format(save_dir) #test.prototxt位置
deploy_net_file = "{}/deploy.prototxt".format(save_dir)
solver_file = "{}/solver.prototxt".format(save_dir)
# snapshot prefix.
snapshot_prefix = "{}/{}".format(snapshot_dir, model_name)
# job script path.
job_file = "{}/{}.sh".format(job_dir, model_name)

# Stores the test image names and sizes. Created by data/VOC0712/create_list.sh
name_size_file = "data/VOC0712/test_name_size.txt" #上述生成的test_name_size.txt位置,最后用绝对路径
# The pretrained model. We use the Fully convolutional reduced (atrous) VGGNet.
pretrain_model = "models/VGGNet/VGG_ILSVRC_16_layers_fc_reduced.caffemodel" #预训练模型,会很大程度减少自己项目的训练时间
# Stores LabelMapItem.
label_map_file = "data/VOC0712/labelmap_voc.prototxt" #上述生成的labelmap_voc.prototxt位置,最后用绝对路径

# MultiBoxLoss parameters.
num_classes = 21 #该位置要换成你自己项目的物体类别个数,别忘了要加上背景
share_location = True
background_label_id=0
train_on_diff_gt = True
normalization_

以上是关于跑通caffe-ssd demo代码(训练测试自己数据集)的主要内容,如果未能解决你的问题,请参考以下文章

跑通代码---CVPR2020--StegaStamp: Invisible Hyperlinks in Physical Photographs

深度学习之初识篇——小白也能跑通的深度学习万能框架交通标识牌检测

Ubuntu16.04 + caffe-ssd + [CPU_ONLY] + KITTI 训练总结

mask-rcnn训练完自己的数据集之后的测试demo

mask-rcnn训练完自己的数据集之后的测试demo

跑通代码 - 图像隐写术专栏