SSD配置记录

整合了几个教程,加上自己遇到的坑,终于能愉快的使用

硬件:TITAN X * 2

软件:Ubuntu14.04 + CUDA8.0 + CuDnn v6

SSD安装

  • 获取SSD的代码
git clone https://github.com/weiliu89/caffe.git
cd caffe
git checkout ssd
  • 进入下载好的目录,复制配置文件
cd ~/caffe
cp Makefile.config.example Makefile.config
  • 编译caffe
# Modify Makefile.config according to your Caffe installation.
cp Makefile.config.example Makefile.config
make -j8
# Make sure to include $CAFFE_ROOT/python to your PYTHONPATH.
make py
make test -j8
# (Optional)
make runtest -j8
  • 两点注意

    1. 安装用到的python依赖

      sudo apt-get install python-numpy python-scipy python-matplotlib python-sklearn python-skimage python-h5py python-protobuf python-leveldb python-networkx python-nose python-pandas python-gflags Cython ipython
      

    2. 添加PYTHONPATH。参考:ubuntu下修改环境变量以及添加PYTHONPATH方法

      1. 用于当前终端

        在当前终端中输入:export PATH=$PATH:<你的要加入的路径>

        不过上面的方法只适用于当前终端,一旦当前终端关闭或在另一个终端中,则无效。

      2. 用户变量

        在用户主目录下有一个 .bashrc 隐藏文件,可以在此文件中加入 PATH 的设置如下:

        $ gedit ~/.bashrc

        加入:

        export PATH=<yourpath>:$PATH

        如果要加入多个路径,只要:

        export PATH=<yourpath1>:<yourpath2>: ...... :$PATH

        当中每个路径要以冒号分隔。

        这样每次登录都会生效

        添加PYTHONPATH的方法也是这样,在.bashrc中添加

        export PYTHONPATH=/home/ssd/caffe:$PYTHONPATH

        保存后在终端输入$ source ~/.bashrc使环境变量立即生效。

      3. 系统变量

        $ sudo gedit /etc/profile

        加入:
        export PATH=<yourpath>:$PATH

        终端输入:echo $PATH 可以查看环境变量。

        注意,修改环境变量后,除了第一种方法立即生效外,第二第三种方法要立即生效,可以source ~/.bashrc或者注销再次登录后就可以了!

准备工作(官方样例)

  1. Download fully convolutional reduced (atrous) VGGNet. By default, we assume the model is stored in $CAFFE_ROOT/models/VGGNet/
  2. Download VOC2007 and VOC2012 dataset. By default, we assume the data is stored in $HOME/data/
  # Download the data.
  cd $HOME/data
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2012/VOCtrainval_11-May-2012.tar
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
  wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
  # Extract the data.
  tar -xvf VOCtrainval_11-May-2012.tar
  tar -xvf VOCtrainval_06-Nov-2007.tar
  tar -xvf VOCtest_06-Nov-2007.tar
  1. Create the LMDB file.
  cd $CAFFE_ROOT
  # Create the trainval.txt, test.txt, and test_name_size.txt in data/VOC0712/
  ./data/VOC0712/create_list.sh
  # You can modify the parameters in create_data.sh if needed.
  # It will create lmdb files for trainval and test with encoded original image:
  #   - $HOME/data/VOCdevkit/VOC0712/lmdb/VOC0712_trainval_lmdb
  #   - $HOME/data/VOCdevkit/VOC0712/lmdb/VOC0712_test_lmdb
  # and make soft links at examples/VOC0712/
  ./data/VOC0712/create_data.sh
  1. 这里用的脚本实现批处理,可能会出现:no module named caffe等错误,这是由于caffe的Python环境变量未配置好,可按照下面方法解决:(这种方法没有试过)
   echo "export PYTHONPATH=/home/usrname/caffe/python" >> ~/.profile  
   source ~/.profile  
   echo $PYTHONPATH #检查环境变量的值

训练/评估

  1. Train your model and evaluate the model on the fly.
# It will create model definition files and save snapshot models in:
#   - $CAFFE_ROOT/models/VGGNet/VOC0712/SSD_300x300/
# and job file, log file, and the python script in:
#   - $CAFFE_ROOT/jobs/VGGNet/VOC0712/SSD_300x300/
# and save temporary evaluation results in:
#   - $HOME/data/VOCdevkit/results/VOC2007/SSD_300x300/
# It should reach 77.* mAP at 120k iterations.
python examples/ssd/ssd_pascal.py

If you don’t have time to train your model, you can download a pre-trained model at here.

  1. Evaluate the most recent snapshot.
# If you would like to test a model you trained, you can do:
python examples/ssd/score_ssd_pascal.py
  1. Test your model using a webcam. Note: press esc to stop.
# If you would like to attach a webcam to a model you trained, you can do:
python examples/ssd/ssd_pascal_webcam.py

打开caffe/examples/ssd/ssd_pascal.py这个文件,找到gpus=’0,1,2,3’这一行,如果机器有一块显卡,则将123删去,如果有两个显卡,则删去23,以此类推。如果机器没有gpu支持,则注销以下几行,程序会以cpu形式训练。(这个是解决问题cudasuccess(10vs0)的方法

#Ifnum_gpus >0:

# batch_size_per_device =int(math.ceil(float(batch_size) / num_gpus))

#iter_size =int(math.ceil(float(accum_batch_size) / (batch_size_per_device * num_gpus)))

# solver_mode =P.Solver.GPU
# device_id =int(gpulist[0])

保存后终端运行:

cd  /home/username/caffe
python examples/ssd/ssd_pascal.py

如果出现问题cudasuccess(2vs0)则说明您的显卡计算量有限,再次打开caffe/examples/ssd/ssd_pascal.py这个文件,找到batch_size =32这一行,修改数字32,可以修改为16,或者8,甚至为4,保存后再次终端运行python examples/ssd/ssd_pascal.py

使用自己的数据集进行训练

首先需要建立自己的文件夹,文件夹中包含Annotations、Imagesets、JPEGImages三个子文件夹。

Annotations 为图片对应的xml信息文件,里面主要存放图像中objects的位置类别等信息

Imagesets中存放Layout,Main,Segmentation三个文件夹选项,这里主要使用Main 文件夹,里面用于存放train.txt,train_val.txt,val.txt,test.txt

JPEGImages中存放图片

1. 准备图片

TODO:这一步有一个小疑问暂时未解决,到底图片中可不可以没有lable信息,即一张纯背景的图片要不要使用?之前出现这种情况的时候出了错误,但是具体为什么目前还不知道,看完源码来填坑。

2. 生成Annitations

1. 无GT信息

使用标注工具进行标注,推荐使用https://github.com/tzutalin/labelImg,炒鸡方便,直接生成xml。
mark

2. 有GT信息

通过代码生成xml
(1)假设GT.txt如下

000001.jpg dog 48 240 195 371
000001.jpg person 8 12 352 498
000003.jpg sofa 123 155 215 195
000003.jpg chair 239 156 307 205
000002.jpg train 39 200 207 301

(2)matlab转化程序

%%  
%该代码可以做voc2007数据集中的xml文件,  
%txt文件每行格式为:000001.jpg dog 48 240 195 371  
%即每行由图片名、目标类型、包围框坐标组成,空格隔开  
%如果一张图片有多个目标,则格式如下:(比如两个目标)  
% 000001.jpg dog 48 240 195 371  
% 000001.jpg person 8 12 352 498  
% 000002.jpg train 139 200 207 301  
% 000003.jpg sofa 123 155 215 195  
% 000003.jpg chair 239 156 307 205  
%包围框坐标为左上角和右下角  
%%  
clc;  
clear;  
%注意修改下面四个变量  
imgpath='img\';%图像存放文件夹  
txtpath='img\output.txt';%txt文件  
xmlpath_new='Annotations/';%修改后的xml保存文件夹  
foldername='VOC2007';%xml的folder字段名  
  
  
fidin=fopen(txtpath,'r');  
lastname='begin';  
  
while ~feof(fidin)  
     tline=fgetl(fidin);  
     str = regexp(tline, ' ','split');  
     filepath=[imgpath,str{1}];  
     img=imread(filepath);  
     [h,w,d]=size(img);  
      imshow(img);  
      rectangle('Position',[str2double(str{3}),str2double(str{4}),str2double(str{5})-str2double(str{3}),str2double(str{6})-str2double(str{4})],'LineWidth',4,'EdgeColor','r');  
      pause(0.1);  
        
        if strcmp(str{1},lastname)%如果文件名相等,只需增加object  
           object_node=Createnode.createElement('object');  
           Root.appendChild(object_node);  
           node=Createnode.createElement('name');  
           node.appendChild(Createnode.createTextNode(sprintf('%s',str{2})));  
           object_node.appendChild(node);  
            
           node=Createnode.createElement('pose');  
           node.appendChild(Createnode.createTextNode(sprintf('%s','Unspecified')));  
           object_node.appendChild(node);  
            
           node=Createnode.createElement('truncated');  
           node.appendChild(Createnode.createTextNode(sprintf('%s','0')));  
           object_node.appendChild(node);  
  
           node=Createnode.createElement('difficult');  
           node.appendChild(Createnode.createTextNode(sprintf('%s','0')));  
           object_node.appendChild(node);  
            
           bndbox_node=Createnode.createElement('bndbox');  
           object_node.appendChild(bndbox_node);  
  
           node=Createnode.createElement('xmin');  
           node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{3}))));  
           bndbox_node.appendChild(node);  
  
           node=Createnode.createElement('ymin');  
           node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{4}))));  
           bndbox_node.appendChild(node);  
  
           node=Createnode.createElement('xmax');  
           node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{5}))));  
           bndbox_node.appendChild(node);  
  
           node=Createnode.createElement('ymax');  
           node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{6}))));  
           bndbox_node.appendChild(node);  
        else %如果文件名不等,则需要新建xml  
           copyfile(filepath, 'JPEGImages');  
            %先保存上一次的xml  
           if exist('Createnode','var')  
              tempname=lastname;  
              tempname=strrep(tempname,'.jpg','.xml');  
              xmlwrite(tempname,Createnode);     
           end  
              
              
            Createnode=com.mathworks.xml.XMLUtils.createDocument('annotation');  
            Root=Createnode.getDocumentElement;%根节点  
            node=Createnode.createElement('folder');  
            node.appendChild(Createnode.createTextNode(sprintf('%s',foldername)));  
            Root.appendChild(node);  
            node=Createnode.createElement('filename');  
            node.appendChild(Createnode.createTextNode(sprintf('%s',str{1})));  
            Root.appendChild(node);  
            source_node=Createnode.createElement('source');  
            Root.appendChild(source_node);  
            node=Createnode.createElement('database');  
            node.appendChild(Createnode.createTextNode(sprintf('The VOC2007 Database')));  
            source_node.appendChild(node);  
            node=Createnode.createElement('annotation');  
            node.appendChild(Createnode.createTextNode(sprintf('PASCAL VOC2007')));  
            source_node.appendChild(node);  
  
           node=Createnode.createElement('image');  
           node.appendChild(Createnode.createTextNode(sprintf('flickr')));  
           source_node.appendChild(node);  
  
           node=Createnode.createElement('flickrid');  
           node.appendChild(Createnode.createTextNode(sprintf('NULL')));  
           source_node.appendChild(node);  
           owner_node=Createnode.createElement('owner');  
           Root.appendChild(owner_node);  
           node=Createnode.createElement('flickrid');  
           node.appendChild(Createnode.createTextNode(sprintf('NULL')));  
           owner_node.appendChild(node);  
  
           node=Createnode.createElement('name');  
           node.appendChild(Createnode.createTextNode(sprintf('watersink')));  
           owner_node.appendChild(node);  
           size_node=Createnode.createElement('size');  
           Root.appendChild(size_node);  
  
          node=Createnode.createElement('width');  
          node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(w))));  
          size_node.appendChild(node);  
  
          node=Createnode.createElement('height');  
          node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(h))));  
          size_node.appendChild(node);  
  
         node=Createnode.createElement('depth');  
         node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(d))));  
         size_node.appendChild(node);  
           
          node=Createnode.createElement('segmented');  
          node.appendChild(Createnode.createTextNode(sprintf('%s','0')));  
          Root.appendChild(node);  
          object_node=Createnode.createElement('object');  
          Root.appendChild(object_node);  
          node=Createnode.createElement('name');  
          node.appendChild(Createnode.createTextNode(sprintf('%s',str{2})));  
          object_node.appendChild(node);  
            
          node=Createnode.createElement('pose');  
          node.appendChild(Createnode.createTextNode(sprintf('%s','Unspecified')));  
          object_node.appendChild(node);  
            
          node=Createnode.createElement('truncated');  
          node.appendChild(Createnode.createTextNode(sprintf('%s','0')));  
          object_node.appendChild(node);  
  
          node=Createnode.createElement('difficult');  
          node.appendChild(Createnode.createTextNode(sprintf('%s','0')));  
          object_node.appendChild(node);  
            
          bndbox_node=Createnode.createElement('bndbox');  
          object_node.appendChild(bndbox_node);  
  
         node=Createnode.createElement('xmin');  
         node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{3}))));  
         bndbox_node.appendChild(node);  
  
         node=Createnode.createElement('ymin');  
         node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{4}))));  
         bndbox_node.appendChild(node);  
  
        node=Createnode.createElement('xmax');  
        node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{5}))));  
        bndbox_node.appendChild(node);  
  
        node=Createnode.createElement('ymax');  
        node.appendChild(Createnode.createTextNode(sprintf('%s',num2str(str{6}))));  
        bndbox_node.appendChild(node);  
         
       lastname=str{1};  
        end  
        %处理最后一行  
        if feof(fidin)  
            tempname=lastname;  
            tempname=strrep(tempname,'.jpg','.xml');  
            xmlwrite(tempname,Createnode);  
        end  
end  
fclose(fidin);  
  
file=dir(pwd);  
for i=1:length(file)  
   if length(file(i).name)>=4 && strcmp(file(i).name(end-3:end),'.xml')  
    fold=fopen(file(i).name,'r');  
    fnew=fopen([xmlpath_new file(i).name],'w');  
    line=1;  
    while ~feof(fold)  
        tline=fgetl(fold);  
        if line==1  
           line=2;  
           continue;  
        end  
        expression = '   ';  
        replace=char(9);  
        newStr=regexprep(tline,expression,replace);  
        fprintf(fnew,'%s\n',newStr);  
    end  
    fprintf('已处理%s\n',file(i).name);  
    fclose(fold);  
    fclose(fnew);  
    delete(file(i).name);  
   end  
end  

:由于即使一张图片生成多个xml也可以,所以学长直接使用了个xml模板,只在上面做修改,感觉也很不错。

TXT生成

生成Imagesets/Main/下的train.txt,train_val.txt,val.txt,test.txt,matlab程序如下:

%%  
%该代码根据已生成的xml,制作VOC2007数据集中的trainval.txt;train.txt;test.txt和val.txt  
%trainval占总数据集的50%,test占总数据集的50%;train占trainval的50%,val占trainval的50%;  
%上面所占百分比可根据自己的数据集修改,如果数据集比较少,test和val可少一些  
%  
%注意修改下面四个值  
%%  
xmlfilepath='E:\Annotations';  
txtsavepath='E:\ImageSets\Main\';  
trainval_percent=0.5;%trainval占整个数据集的百分比,剩下部分就是test所占百分比  
train_percent=0.5;%train占trainval的百分比,剩下部分就是val所占百分比  
  
xmlfile=dir(xmlfilepath);  
numOfxml=length(xmlfile)-2;%减去.和.. ?总的数据集大小  
  
  
trainval=sort(randperm(numOfxml,floor(numOfxml*trainval_percent)));  
test=sort(setdiff(1:numOfxml,trainval));  
  
  
trainvalsize=length(trainval);%trainval的大小  
train=sort(trainval(randperm(trainvalsize,floor(trainvalsize*train_percent))));  
val=sort(setdiff(trainval,train));  
  
  
ftrainval=fopen([txtsavepath 'trainval.txt'],'w');  
ftest=fopen([txtsavepath 'test.txt'],'w');  
ftrain=fopen([txtsavepath 'train.txt'],'w');  
fval=fopen([txtsavepath 'val.txt'],'w');  
  
  
for i=1:numOfxml  
      if ismember(i,trainval)  
            fprintf(ftrainval,'%s\n',xmlfile(i+2).name(1:end-4));  
            if ismember(i,train)  
                fprintf(ftrain,'%s\n',xmlfile(i+2).name(1:end-4));  
            else  
                fprintf(fval,'%s\n',xmlfile(i+2).name(1:end-4));  
            end  
      else  
             fprintf(ftest,'%s\n',xmlfile(i+2).name(1:end-4));  
      end  
end  
fclose(ftrainval);  
fclose(ftrain);  
fclose(fval);  
fclose(ftest);  

(5)到此所有数据就准备完毕,第(3)(4)的程序下载链接:http://download.csdn.net/detail/qq_14845119/9700102
同时建议,上面的操作最好在Linux下完成,如果在windows下完成,还需要涉及一下格式的转化。因为DOS的编辑器和Linux对文末eneter的处理规则不一样,这里送上2个锦囊,帮助众童鞋解除困扰,
去除txt中所有的^M指令: :%s/^M//g#
vim 中替换指令: :%s/sour/dst/g  (将sour替换为dst)
如此这般,create_list.sh就可以生成正确的 trainval.txt,test.txt,test_name_size.txt
然后执行,create_data.sh就可以生成正确的test_lmdb和trainval_lmdb,并在caffe-root/examples下面生成相应的symbolic link,
然后,修改,caffe-root/examples/ssd/pascal.py
57行:训练数据路径
59行:测试数据路径
197-203行:save_dir,snapshot_dir,job_dir,output_result_dir路径
216-220行:name_size_file,label_map_file路径
223行:类别数目(1+类别数)
315行:测试图片数目
上面的这些修改完毕,就可以执行 python examples/ssd/ssd_pascal.py进行训练,小伙伴们又可以静静的等待了。
(6)如果你没有自己的图片,或者不想花时间处理了,可以直接使用VOC里面的图片,下面的程序可以实现解析VOC XML,从中提取出你需要的类别的图片。当然需要xml_io_tools这个matlab版本的解析库,下载地址,http://download.csdn.net/detail/qq_14845119/9711846
[plain] view plain copy
trainval=importdata('/home/data/VOCdevkit/VOC2007/ImageSets/Main/test.txt','0',6000);  
tv=fopen('te.txt','w');  
tval=fopen('test.txt','w');  
for i=1:size(trainval,1)  
    i  
    xmlpath=strcat('/home/data/VOCdevkit/VOC2007/Annotationsori/',strcat(trainval{i},'.xml'));  
    info=xml_read(xmlpath);  
    for j=1:size(info.object,1)%下面加上需要的类别,例如,车,人等  
        if (strcmp(info.object(j).name,'car')==1||...  
            strcmp(info.object(j).name,'person')==1)  
            fprintf(tv, '%s %s %g %g %g %g\n', info.filename,info.object(j).name,...  
                info.object(j).bndbox.xmin,info.object(j).bndbox.ymin,info.object(j).bndbox.xmax,info.object(j).bndbox.ymax);  
            fprintf(tval,'%s\n',info.filename(1:length(info.filename)-4));  
        end  
    end  
  
end  

参考

【1】SSD配置

【2】SSD(Single Shot MultiBox Detector)不得不说的那些事

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值