您的位置:首页 > Web前端

Caffe学习笔记5--deploy文件的修改与使用

2017-02-06 23:15 603 查看
deploy文件的修改目是为了我们能够真正使用训练好的模型进行预测,输出概率及最佳结果的重要过程。

问题背景:

如我们前面已经生成了一个预测手写体识别的模型,我们现在如何预测某个人写的数字是多少呢?预测的概率是多少呢?



最终解决的结果:



为了达到以上的结果,我们需要做3步骤

第一步,修改mnist_deploy.prorotxt文件

第二步,编写test_mnist.cpp文件

第三步,编译运行输出结果

第一步,修改prorotxt文件:

我们首先要对之前propotxt进行修改,用来满足我们的需求。

在修改propotxt之前我们可以对之前的网络结构进行一个直观的认识:可以使用http://ethereon.github.io/netscope/#/editor 这个网址。将propotxt文件内容复制后会得到可视化模型,之前训练模型如图所示:



其实我们的目标就是使用模型的权重最后输出类别概率,所以loss,label我们都不要了。根据上面的图我们对原始结构进行修改,如下:

name: "LeNet"
input: "data"
input_shape {
dim: 1 # batchsize
dim: 1 # number of colour channels - rgb
dim: 28 # width
dim: 28 # height
}
layer {
name: "conv1"
type: "Convolution"
bottom: "data"
top: "conv1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 20
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "pool1"
type: "Pooling"
bottom: "conv1"
top: "pool1"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "conv2"
type: "Convolution"
bottom: "pool1"
top: "conv2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
convolution_param {
num_output: 50
kernel_size: 5
stride: 1
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "pool2"
type: "Pooling"
bottom: "conv2"
top: "pool2"
pooling_param {
pool: MAX
kernel_size: 2
stride: 2
}
}
layer {
name: "ip1"
type: "InnerProduct"
bottom: "pool2"
top: "ip1"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 500
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "relu1"
type: "ReLU"
bottom: "ip1"
top: "ip1"
}
layer {
name: "ip2"
type: "InnerProduct"
bottom: "ip1"
top: "ip2"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 10
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "prob"
type: "Softmax"
bottom: "ip2"
top: "prob"
}


新的结构生成一下可视化图:



修改完propotxt后,我们命名为mnist_deploy.prototxt。

第二步,编写运行代码 test_mnist.cpp:

#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;
}


第三步,编译运行:

目前文件需要确认的一共有4样:5.jpg(测试数据)  lenet_iter_10000.caffemodel(上一篇文章生成的模型) mnist_deploy.prototxt(这次修改的prototxt文件) test_mnist.cpp (编译文件)

随后执行命令:

g++-o test_mnist test_mnist.cpp -lopencv_dnn -lopencv_highgui -lopencv_imgcodecs-lopencv_imgproc -lstdc++ -lopencv_core

./test_mnist

恭喜你就能看到最终结果

参考内容

------------------

《Dataguru课程-caffe学习与应用》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: