Caffeソース解読(八):訓練されたモデルを使用する

11917 ワード

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ファイルを書き換える


ステップ4

ステップ1:データ層(Data Layer)と接続データ層のLayersを取り除く


つまりトップがdataである層を削除し、Lenet_のようにtrain_test.prototxtの最初の2つのレイヤ.
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
  }
}

道理は簡単で、私たちはもう訓練しないで、訓練データを読む必要はありません.これらの層は訓練データを読むために使われているので、削除します.

ステップ2:出力層と出力層を接続する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のデータを読み込むため、これらのレイヤも切り捨てられます.

ステップ3:入力の再確立


入力を切り捨てた後、元の基礎の上で入力を再確立し、
name: "LeNet"
input: "data"
input_shape {
  dim: 1 # batchsize
  dim: 1 # number of colour channels - rgb
  dim: 28 # width
  dim: 28 # height
}

この4つのdimは、私たちが入力した画像が1枚の単一チャネルの28であることを示しています.×28サイズの画像.

ステップ4:出力の再確立


元の出力に基づいて、このようなレイヤを追加します.
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 
#include 
#include 
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<: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); //[] "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));                   //[]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");   //[] 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