caffe用自己的数据训练模型,并测试输出图片类别

来源:互联网 发布:淘宝卖家发货怎么打印 编辑:程序博客网 时间:2024/04/30 09:01

一、制作自己的数据集
首先将所有图片放在一个文件夹中,文件夹中根据类别建几个子文件夹,每个子文件夹放某一类所有图片,并根据类别编号。
如我这里是要对stanfdog数据集进行分类,该数据集总共有20580张狗狗的图片,分成120类,每类狗的图片张数不一样但相差不是很大. 我的狗狗图片放在Stanford-Dogs(文件夹命名最好不要出现空格,避免中文)中,Stanford-Dogs 中有些子文件夹,每个子文件夹代表一类,子文件夹中放该类狗的图片
这里写图片描述
我这里把训练用的图片集和训练用的图片集放在一起了,你也可以把训练图片集和验证图片集分开放。

然后可以用下面的matlab代码,生成||图片路径/图片名 类别名||的trainval.txt文件,和||类别编号 类别名||的labels.txt文件,进而生成训练集的||图片路径/图片名 类别名||的train.txt文件,||图片路径/图片名 类别名||val.txt文件。( 注在生成trainval.txt和labels.txt后注意检查下生成的文件内容对不对,有时可能会出现一些其他乱七八糟的符号,直接删除保存就好,再生成train.txt和val.txt,Stanford-Dogs文件夹下不要包含其他无关文件

    clc;      clear;      %%下面生成顺序的trainval.txt和labels文件      %先设置train占数据集的百分比,余下部分为val    %  maindir='caffe-new/data/Stanford-Dogs/';     maindir='/home/nielsen/caffe-new/data/Stanford-Dogs/';  %图片文件夹存放路径,注意这里windows下是‘\',linnux下是'/'    wf = fopen('trainval.txt','w');      lbf=fopen('labels.txt','w');      train_percent=0.6;%val_percent=1-train_percent      subdir = dir(maindir);  %获取图片目录下的子目录个数(注意这里最好不要放除子图片文件夹以外的文件夹和文件,否则会一起统计进去)    ii=-1;      numoffile=0;      for i = 1:length(subdir)%第一层目录        if ~strcmp(subdir(i).name ,'.') && ~strcmp(subdir(i).name,'..')           ii=ii+1;   %标签从0开始         label = subdir(i).name;   %子文件夹的名字         fprintf(lbf,'%s\n',label);           label=strcat(label,'/');           subsubdir = dir(strcat(maindir,label));          for j=1:length(subsubdir)   %第二层目录,即子目录下的图片             if ~strcmp(subsubdir(j).name ,'.') && ~strcmp(subsubdir(j).name,'..')                  numoffile=numoffile+1;  %记录行数,即图片总数               fprintf(wf,'%s%s %d\n',label,subsubdir(j).name,ii);  %图片路径/图片名 图片所属类别编号               fprintf('处理标签为%d的第%d张图片\n',ii,j-2);  %j之所以-2是因为生成的子文件目录都包含'.'和'..',j要将这两种情况排除在外             end          end        end      end      fclose(wf);      fclose(lbf);      if 0  %不需要打乱顺序    %%      %下面将trainval的顺序打乱      file=cell(1,numoffile);      fin=fopen('trainval.txt','r');      i=1;      while ~feof(fin)          tline=fgetl(fin);  %获得每行信息        file{i}=tline;          i=i+1;      end      fclose(fin);      fprintf('\ntrainval.txt共%d行,开始打乱顺序....\n',numoffile);      pause(1);      rep=randperm(numoffile);      fout=fopen('trainval.txt','w');      for i=1:numoffile          fprintf(fout,'%s\n',file{rep(i)});  %按rep生成的顺序重排文本内容    end      fprintf('生成的trainval.txt已打乱顺序.\n');      fclose(fout);      end    %%      %下面根据打乱顺序的trainval.txt生成train.txt和val.txt      fprintf('开始生成train.txt和val.txt...\n');      pause;  %暂停一下检查一下生成的trainval.txt生成的是不是对的    train_file=fopen('train.txt','w');      text_file=fopen('val.txt','w');      trainvalfile=fopen('trainval.txt','r');      num_train=sort(randperm(numoffile,floor(numoffile*train_percent)));  %随机取出 train_percent的数据    num_test=setdiff(1:numoffile,num_train);   %去掉num_train的数据编号就是num_test数据编号    i=1;      %分割图像文件生成训练文件和测试文件    while ~feof(trainvalfile)          tline=fgetl(trainvalfile);          if ismember(i,num_train)              fprintf(train_file,'%s\n',tline);   %图片路径/图片名 图片所属类别编号(不需要加图片编号,txt会自动编号)        else              fprintf(text_file,'%s\n',tline);          end          i=i+1;      end      fclose(train_file);      fclose(text_file);      fclose(trainvalfile);      fprintf('共有图片%d张!\n',numoffile);      fprintf('Done!\n');  

生成的val.txt文件如下:
这里写图片描述
生成的labels.txt文件如下:
这里写图片描述
这里前面的编号是txt文档编辑器的编号,我们在制作txt文件时不需要加编号)

二、用creat_imagenet.sh把数据转换成LMDB或LEVELDB格式
将编译好的caffe文件夹中的examples/imagenet中的create_imagenet.sh复制到你需要的路径下,我这里是“lxq/caffe/models/bvlc_alexnet/stanfdog”,并对create_imagenet.sh文件做些修改,主要是路径的修改,还有就是我的图片大小都不一样,所以需要resize,将RESIZE=false改为RESIZE=true(这里是true而非True)

create_imagenet.sh

#!/usr/bin/env sh# Create the imagenet lmdb inputs# N.B. set the path to the imagenet train + val data dirsset -eEXAMPLE=lxq/caffe/models/bvlc_alexnet/stanfdog #生成的lmdb文件存放路径DATA=lxq/caffe/models/bvlc_alexnet/stanfdog    #train.txt和val.txt存放路径TOOLS=lxq/caffe/build/tools                   #convert_imageset.cpp文件存放路径TRAIN_DATA_ROOT=/home/nielsen/caffe-new/data/Stanford-Dogs/     #图片存放路径(这里没有把train和val分开)VAL_DATA_ROOT=/home/nielsen/caffe-new/data/Stanford-Dogs/# Set RESIZE=true to resize the images to 256x256. Leave as false if images have# already been resized using another tool.RESIZE=trueif $RESIZE; then  RESIZE_HEIGHT=227  RESIZE_WIDTH=227else  RESIZE_HEIGHT=0  RESIZE_WIDTH=0fiif [ ! -d "$TRAIN_DATA_ROOT" ]; then  echo "Error: TRAIN_DATA_ROOT is not a path to a directory: $TRAIN_DATA_ROOT"  echo "Set the TRAIN_DATA_ROOT variable in create_imagenet.sh to the path" \       "where the ImageNet training data is stored."  exit 1fiif [ ! -d "$VAL_DATA_ROOT" ]; then  echo "Error: VAL_DATA_ROOT is not a path to a directory: $VAL_DATA_ROOT"  echo "Set the VAL_DATA_ROOT variable in create_imagenet.sh to the path" \       "where the ImageNet validation data is stored."  exit 1fiecho "Creating train lmdb..."GLOG_logtostderr=1 $TOOLS/convert_imageset \    --resize_height=$RESIZE_HEIGHT \    --resize_width=$RESIZE_WIDTH \    --shuffle \                      #随机排序    $TRAIN_DATA_ROOT \               #原始图片路径    $DATA/train.txt \        #train.txt路径    $EXAMPLE/stanfdog_train_lmdb     #生成的lmdb文件名及存放路径echo "Creating val lmdb..."GLOG_logtostderr=1 $TOOLS/convert_imageset \    --resize_height=$RESIZE_HEIGHT \    --resize_width=$RESIZE_WIDTH \    --shuffle \    $VAL_DATA_ROOT \    $DATA/val.txt \    $EXAMPLE/stanfdog_val_lmdbecho "Done."

(注意create_imagenet.sh中最好不要出现中文,哪怕我这里是注释了的中文,刚开始时我是用这个添加了注释的文件运行,结果出错,也不知道错在哪儿,后来把里面的中文删掉了重新运行还是出错,最后干脆又重新复制了个文件过来改好路径,运行就对啦,我想可能是添加的中文影响了文件结构还是怎么回事,总之尽量避免出现中文)

在终端输入:

./lxq/caffe/models/bvlc_alexnet/stanfdog/create_imagenet.sh

如图:
这里写图片描述

在我对应的文件路径下生成了stanfdog_train_lmdb 和stanfdog_val_lmdb 文件夹

这里写图片描述

三、生成训练图片的均值文件
将编译好的caffe文件夹中的examples/imagenet中的make_imagenet_mean.sh复制到你需要的路径下,我这里是“lxq/caffe/models/bvlc_alexnet/stanfdog”,并对make_imagenet_mean.sh中的路径做对应的修改

make_imagenet_mean.sh

#!/usr/bin/env sh# Compute the mean image from the imagenet training lmdb# N.B. this is available in data/ilsvrc12EXAMPLE=lxq/caffe/models/bvlc_alexnet/stanfdogDATA=lxq/caffe/models/bvlc_alexnet/stanfdogTOOLS=lxq/caffe/build/tools$TOOLS/compute_image_mean $EXAMPLE/stanfdog_train_lmdb \  $DATA/imagenet_mean.binaryprotoecho "Done."

在终端输入:

./lxq/caffe/models/bvlc_alexnet/stanfdog/make_imagenet_mean.sh

这里写图片描述

在lxq/caffe/models/bvlc_alexnet/stanfdog文件夹下生成文件imagenet_mean.binaryproto

四、下载基于ImageNet训练的AlexNet模型参数文件bvlc_alexnet.caffemodel。
这个可以在https://www.cnblogs.com/leoking01/p/7123154.html 上下载,里面还有很多其他模型
五、修改模型文件train_val_Alexnet.prototxt
1. 修改数据层mean_file路径(imagenet_mean.binaryproto文件的路径),数据存放路径(stanfdog_train_lmdb,stanfdog_val_lmdb文件路径),batch_size大小
这里写图片描述
2. 由于是基于ImageNet训练的AlexNet训练我们的数据,属于fine-tuning ,ImagNet数据集有1000类,原AlexNet的fc8有1000个输出,我们只有120类,所以这一层的输出个数要改为120,由于这一层参数与原网络不同需要重新训练,将这一层参数的学习效率适当调大,一般调大为原来的10倍,由于之前的模型的参数是通过各层的名称加载的,最后一层的名称需要修改,以告诉机器这一层参数不需要加载,随之后面的层次也要做相应的修改

这里写图片描述
3. 修改模型求解文件 train_val_Alexnet_solver.prototxt

这里写图片描述

关于上面的各个参数的说明:
这里写图片描述
4. 修改模型执行文件train_val_Alexnet.sh

#!/usr/bin/env shset -eTOOLS=./lxq/caffe/build/toolsMODEL=lxq/caffe/models/bvlc_alexnet/stanfdog#画出网络模型图./lxq/caffe/python/draw_net.py ./$MODEL/train_val_Alexnet.prototxt ./$MODEL/train_val_Alexnet.png#开始训练$TOOLS/caffe train \  --solver=$MODEL/train_val_Alexnet_solver.prototxt \  --weights=$MODEL/bvlc_alexnet.caffemodel 2>&1| tee $MODEL/stanfdog_Alexnet.log $@ #保存屏幕输出到日志

经过漫长的等待,训练完成后生成:
网络模型图train_val_Alexnet.png,网络模型参数快照stanfdog_Alexnet_iter_4000.caffemodel(即我们训练得到的模型),网络训练记录文件stanfdog_Alexnet_iter_4000.solverstate(以外中断时可直接用该文件接着训练),生成的log文件stanfdog_Alexnet.log(保存屏幕输出,方便以后分析和画图)
这里写图片描述

六、测试
修改stanfdog_deploy.prototxt文件,这个可以对照文件train_val_Alexnet.prototxt修改,主要是对网络模型的修改,去掉卷积层、全连接层的参数设置,还有就是最后一层需要softmax的输出。
这里写图片描述

这里写图片描述

编写test.sh执行测试

#!/usr/bin/env shset -eROOT=lxq/caffe/build/examplesMODEL=lxq/caffe/models/bvlc_alexnet/stanfdog./$ROOT/cpp_classification/classification.bin \$MODEL/stanfdog_deploy.prototxt \$MODEL/stanfdog_Alexnet_iter_4000.caffemodel \$MODEL/imagenet_mean.binaryproto \$MODEL/labels.txt \caffe-new/data/test_Stanford-Dogs/QQ截图20161224093349.jpg

主要是相应的路径一定要写对,这里对文件的命名一定要避免空格,因为看classification.cpp可以知道classification.bin是根据空格分隔参数的,如果文件中的命名有空格,classification.bin会认为输入了多余的参数而不能运行

在命令行输入:

 ./lxq/caffe/models/bvlc_alexnet/stanfdog/test.sh

即可得到softmax输出的前5个最大的概率所对应的类别
这里写图片描述


后记
我在这里训练的过程中,发现当迭代2000次的时候,正确率有69.46%,而且正确率变化很缓慢,到4000次的时候正确率是69.9%,这个其实在2000次的时候已经发现loss变化也基本没变化,如果我这个时候需要做调整,该怎么调整呢,如果中断训练的话,由于我的snapshot=4000,如果现在中断,我之前跑得结果岂不是都没有了,这种情况下该怎么办呢

阅读全文
0 0
原创粉丝点击