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

一、制作自己的数据集
首先将所有图片放在一个文件夹中,文件夹中根据类别建几个子文件夹,每个子文件夹放某一类所有图片,并根据类别编号。
如我这里是要对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 dirs
set -e

EXAMPLE=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=true
if $RESIZE; then
  RESIZE_HEIGHT=227
  RESIZE_WIDTH=227
else
  RESIZE_HEIGHT=0
  RESIZE_WIDTH=0
fi

if [ ! -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 1
fi

if [ ! -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 1
fi

echo "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_lmdb

echo "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/ilsvrc12

EXAMPLE=lxq/caffe/models/bvlc_alexnet/stanfdog
DATA=lxq/caffe/models/bvlc_alexnet/stanfdog
TOOLS=lxq/caffe/build/tools

$TOOLS/compute_image_mean $EXAMPLE/stanfdog_train_lmdb \
  $DATA/imagenet_mean.binaryproto

echo "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 sh
set -e

TOOLS=./lxq/caffe/build/tools
MODEL=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 sh
set -e
ROOT=lxq/caffe/build/examples
MODEL=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,如果现在中断,我之前跑得结果岂不是都没有了,这种情况下该怎么办呢

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值