Caffe源码解读(八):使用训练好的模型

在介绍如何使用caffemodel之前,先介绍下均值文件。大型数据库都会要求减去均值文件后再进行训练和测试,会提高速度和精度。caffe提供了专门的工具生成均值文件:

compute_image_mean [train_lmdb] [mean.binaryproto]

然后在DataLayer层的预处理中指定该均值文件:

transform_param {
    scale: 0.00390625
    mean_file_size: “examples/cifar10/mean.binaryproto"  # 用一个配置文件来进行均值操作
    mirror: 1
    crop_size: 227  
  }

下面介绍使用如何使用已经训练好的模型

改写deploy文件

分四步操作

步骤一:把数据层(Data Layer)和连接数据层的Layers去掉

也就是把top是data的层去掉,如Lenet_train_test.prototxt中的前两层。

name: "LeNet"
layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_train_lmdb"
    batch_size: 64
    backend: LMDB
  }
}
layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TEST
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_test_lmdb"
    batch_size: 100
    backend: LMDB
  }
}

道理很简单,我们不再训练了,没必要再读训练数据了,这些层是用来读训练数据的,所以要去掉。

步骤二:去掉输出层和连接输出层的Layers

也就是去掉bottom是label的层,如下:

layer {
  name: "accuracy"
  type: "Accuracy"
  bottom: "ip2"
  bottom: "label"
  top: "accuracy"
  include {
    phase: TEST
  }
}
layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
  top: "loss"
}

这些层是用来计算loss以及测试准确性的,而我们要读入的是未知label的数据,所以这些层也砍掉。

步骤三:重新建立输入

砍掉输入后,在原来的基础上重新建立输入,

name: "LeNet"
input: "data"
input_shape {
  dim: 1 # batchsize
  dim: 1 # number of colour channels - rgb
  dim: 28 # width
  dim: 28 # height
}

这四个dim表示我们输入的图片为1张单通道的28×28大小的图片。

步骤四:重新建立输出

在原来输出基础上,增加这样一个层。

layer {
  name: "prob"
  type: "Softmax"
  bottom: "ip2"
  top: "prob"
}

注意top要与name保持一致。

编写caffemodel的使用程序

编写如下程序,该程序使用opencv的库,做了如下操作:
1、读入deploy、caffemodel和输入图像
2、利用caffemodel生成神经网络Net
3、把图像输入到该网络
4、神经网络做forward操作,得到输出结果
5、根据输出结果计算出该图片最终属于哪一类,以及属于这一类的概率。

#include "opencv2/dnn.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace cv::dnn;

#include <fstream>
#include <iostream>
#include <cstdlib>
using namespace std;

/* Find best class for the blob (i. e. class with maximal probability) */ 
void getMaxClass(dnn::Blob &probBlob, int *classId, double *classProb)
{
    Mat probMat = probBlob.matRefConst().reshape(1, 1); //reshape the blob to 1x1000 matrix
    Point classNumber;
    minMaxLoc(probMat, NULL, classProb, NULL, &classNumber);
    *classId = classNumber.x;
}


int main(int argc,char* argv[]){

    String modelTxt = "mnist_deploy.prototxt";
    String modelBin = "lenet_iter_10000.caffemodel";
    String imageFile = (argc > 1) ? argv[1] : "5.jpg";

    //! [Create the importer of Caffe model] 导入一个caffe模型接口 
    Ptr<dnn::Importer> importer; 
    importer = dnn::createCaffeImporter(modelTxt, modelBin);

    if (!importer){
        std::cerr << "Can't load network by using the following files: " << std::endl;
        std::cerr << "prototxt:   " << modelTxt << std::endl;
        std::cerr << "caffemodel: " << modelBin << std::endl;
        exit(-1);
    }

    //! [Initialize network] 通过接口创建和初始化网络
    Net net;
    importer->populateNet(net);  
    importer.release();

    //! [Prepare blob] 读取一张图片并转换到blob数据存储
    Mat img = imread(imageFile,0); //[<Important>] "0" for 1 channel, Mnist accepts 1 channel
    if (img.empty())
    {
        std::cerr << "Can't read image from the file: " << imageFile << std::endl;
        exit(-1);
    }
    resize(img, img, Size(28, 28));                   //[<Important>]Mnist accepts only 28x28 RGB-images

    dnn::Blob inputBlob = cv::dnn::Blob(img);   //Convert Mat to dnn::Blob batch of images

    //! [Set input blob] 将blob输入到网络
    net.setBlob(".data", inputBlob);        //set the network input

    //! [Make forward pass] 进行前向传播
    net.forward();                          //compute output

    //! [Gather output] 获取概率值
    dnn::Blob prob = net.getBlob("prob");   //[<Important>] gather output of "prob" layer
    int classId;
    double classProb;
    getMaxClass(prob, &classId, &classProb);//find the best class

    //! [Print results] 输出结果
    std::cout << "Best class: #" << classId << "'" << std::endl;
    std::cout << "Probability: " << classProb * 100 << "%" << std::endl;

    return 0;
}

利用opencv库,使用如下命令编译

g++ -o test_mnist test_mnist.cpp -lopencv_dnn -lopencv_highgui -lopencv_imgcodecs -lopencv_imgproc -lstdc++ -lopencv_core
阅读更多

没有更多推荐了,返回首页