如何利用caffe训练自己数据集

这篇博文主要参考了另一位博主https://blog.csdn.net/hellohaibo,在此向他表示感谢

首先,博主今天的caffe崩了,毫无征兆的崩了,具体表现为博主想做一个更大的数据集,但是在生成lmbd文件时永远生成的是一个没有名字的文件夹,可是博主已经在指定的example目录里写了文件名,百度,没有答案,初步推测caffe崩了。。。

然后重新安装,真的坑,以前没有的报错都出现了,网上寻求外国友人帮助。。。真的难受这玩意。。。

重新安装好后,就可以训练自己的数据集了,前一章讲过如何制作自己的数据集,这章就忽略了,我们来讲均值文件的生成,很简单,去caffe里寻找一个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=/home/f/Downloads/test
DATA=/home/f/Downloads/test
TOOLS=/home/f/Downloads/caffe/build/tools

$TOOLS/compute_image_mean $EXAMPLE/train_lmdb \
  $DATA/train_mean.binaryproto

echo "Done."

然后终端执行该文件,这样就会产生均值文件了。

将caffe/model下随便拷贝一个文件到我们的test目录,修改以下参数,首先对于train_val的prototxt文件,将一开始的两层修改为

name: "CaffeNet"
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    mirror: true
    crop_size: 227
    mean_file: "/home/f/Downloads/test/train_mean.binaryproto"
  }
# mean pixel / channel-wise mean instead of mean image
#  transform_param {
#    crop_size: 227
#    mean_value: 104
#    mean_value: 117
#    mean_value: 123
#    mirror: true
#  }
  data_param {
    source: "/home/f/Downloads/test/train_lmdb"
    batch_size: 10
    backend: LMDB
  }
}
layer {
  name: "data"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    mirror: false
    crop_size: 227
    mean_file: "/home/f/Downloads/test/train_mean.binaryproto"
  }
# mean pixel / channel-wise mean instead of mean image
#  transform_param {
#    crop_size: 227
#    mean_value: 104
#    mean_value: 117
#    mean_value: 123
#    mirror: false
#  }
  data_param {
    source: "/home/f/Downloads/test/val_lmdb"
    batch_size: 5
    backend: LMDB
  }
}

这里面是对source的路径修改,它为lmdb的文件所在路径,mean file为均值文件所在路径

batchsize根据你的数量集来,博主由于只有几百张图片,所以size设定得很小

然后修该该文件的最后输出层

inner_product_param {
    num_output: 3
    weight_filler {
      type: "gaussian"
      std: 0.01
    }
    bias_filler {
      type: "constant"
      value: 0
    }
  }
}
layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "fc8"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "fc8"
  bottom: "label"
  top: "loss"
}

将max——output改为你的分类数

对于deploy的prototxt文件,只有修改最后一层的输出,同上。

layer {
  name: "fc8"
  type: "InnerProduct"
  bottom: "fc7"
  top: "fc8"
  inner_product_param {
    num_output: 3
  }
}
layer {
  name: "prob"
  type: "Softmax"
  bottom: "fc8"
  top: "prob"
}

然后修改solve文件,我的形式为

net: "/home/f/Downloads/test/make_model/train_val.prototxt"
test_iter: 24
test_interval: 50
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 100
display: 20
max_iter: 500
momentum: 0.9
weight_decay: 0.0005
snapshot: 50
snapshot_prefix: "/home/f/Downloads/test/final_model"
solver_mode: CPU

然后cd出来执行命令

./caffe/build/tools/caffe train   --solver=/home/f/Downloads/test/make_model/solver.prototxt  

然后就可以愉快地等待了。。。

注意,这里的目录最好都是绝对目录,caffe经常会报目录的问题,所以一定要细心。。。

注:如果训练量太大我们想中断并恢复,可以执行如下的命令,从某一snapshot开始:

    ./caffe/buiid/tools/caffe train 
    --solver=test/make_model/solver.prototxt  
    --snapshot=test/final_model/cifar10_full_iter_100.solverstate  

可以通过caffe的接口进行测试:

./caffe/build/examples/cpp_classification/classification.bin /home/f/Downloads/test/make_model/deploy.prototxt /home/f/Downloads/test/final_model/solver_iter_500.caffemodel /home/f/Downloads/test/train_mean.binaryproto /home/f/Downloads/test/label.txt /home/f/Downloads/test/val/101.jpg

输出结果:

接着我们在opencv上测试

将deploy文件和caffemodel文件和我们自己做的标签文件放入测试程序目录中,修改deploy的第一层为

    name: "CaffeNet"  
    input: "data"  
    input_dim: 10   
    input_dim: 3   
    input_dim: 227   
    input_dim: 227  

测试程序为

 #include <opencv2/dnn.hpp>  
    #include <opencv2/imgproc.hpp>  
    #include <opencv2/highgui.hpp>  
    #include <opencv2/core/utils/trace.hpp>  
    using namespace cv;  
    using namespace cv::dnn;  
      
    #include <fstream>  
    #include <iostream>  
    #include <cstdlib>  
    using namespace std;  
      
    //寻找出概率最高的一类  
    static void getMaxClass(const Mat &probBlob, int *classId, double *classProb)  
    {  
        Mat probMat = probBlob.reshape(1, 1);  
        Point classNumber;  
      
        minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);  
        *classId = classNumber.x;  
    }  
    //从标签文件读取分类 空格为标志  
    static std::vector<String> readClassNames(const char *filename = "label.txt")  
    {  
        std::vector<String> classNames;  
      
        std::ifstream fp(filename);  
        if (!fp.is_open())  
        {  
            std::cerr << "File with classes labels not found: " << filename << std::endl;  
            exit(-1);  
        }  
      
        std::string name;  
        while (!fp.eof())  
        {  
            std::getline(fp, name);  
            if (name.length())  
                classNames.push_back(name.substr(name.find(' ') + 1));  
        }  
        fp.close();  
        return classNames;  
    }  
    //主程序  
    int main(int argc, char **argv)  
    {  
        //初始化  
        CV_TRACE_FUNCTION();  
        //读取模型参数和模型结构文件  
        String modelTxt = "deploy.prototxt";  
        String modelBin = "caffenet.caffemodel";  
        //读取图片  
        String imageFile = (argc > 1) ? argv[1] : "1.jpg";  
      
        //合成网络  
        Net net = dnn::readNetFromCaffe(modelTxt, modelBin);  
        //判断网络是否生成成功  
        if (net.empty())  
        {  
            std::cerr << "Can't load network by using the following files: " << std::endl;  
            exit(-1);  
        }  
        cerr << "net read successfully" << endl;  
      
        //读取图片  
        Mat img = imread(imageFile);  
        imshow("image", img);  
        if (img.empty())  
        {  
            std::cerr << "Can't read image from the file: " << imageFile << std::endl;  
            exit(-1);  
        }  
        cerr << "image read sucessfully" << endl;  
      
    /*  Mat inputBlob = blobFromImage(img, 1, Size(224, 224), 
                                        Scalar(104, 117, 123)); */   
      
        //构造blob,为传入网络做准备,图片不能直接进入网络  
        Mat inputBlob = blobFromImage(img, 1, Size(227, 227));  
          
        Mat prob;  
        cv::TickMeter t;  
        for (int i = 0; i < 10; i++)  
        {  
            CV_TRACE_REGION("forward");  
            //将构建的blob传入网络data层  
            net.setInput(inputBlob,"data");   
            //计时  
            t.start();  
            //前向预测  
            prob = net.forward("prob");    
            //停止计时  
            t.stop();  
        }  
      
        int classId;  
        double classProb;  
        //找出最高的概率ID存储在classId,对应的标签在classProb中  
        getMaxClass(prob, &classId, &classProb);  
      
        //打印出结果  
        std::vector<String> classNames = readClassNames();  
        std::cout << "Best class: #" << classId << " '" << classNames.at(classId) << "'" << std::endl;  
        std::cout << "Probability: " << classProb * 100 << "%" << std::endl;  
        //打印出花费时间  
        std::cout << "Time: " << (double)t.getTimeMilli() / t.getCounter() << " ms (average from " << t.getCounter() << " iterations)" << std::endl;  
      
        //便于观察结果  
        waitKey(0);  
        return 0;  
    }   

然后观察结果

我由于实验的数据很不好,导致结果出现了问题,我放了猫,结果是狗。。。。但至少证明了实验可以成功,也说明了数据集的重要。。。

猜你喜欢

转载自blog.csdn.net/SLAM_masterFei/article/details/80399180