如何在C++程序中调用Caffe做图像分类?

caffe本身就是用c++实现的,python和matlab才是额外的接口。
c++使用caffe只需#include相应的头文件,按照API文档写就是了。
另外,可以参考./tools/caffe.cpp或者extract_features.cpp的实现。

初始化网络

#include "caffe/caffe.hpp"
#include <string>
#include <vector>
using namespace caffe;char *proto = "deploy.prototxt"; /* 加载CaffeNet的配置 */
Phase phase = TEST; /* or TRAIN */
Caffe::set_mode(Caffe::CPU);
// Caffe::set_mode(Caffe::GPU);
// Caffe::SetDevice(0);//! Note: 后文所有提到的net,都是这个net
boost::shared_ptr< Net<float> > net(new caffe::Net<float>(proto, phase));

加载已训练好的模型

char *model = "bvlc_reference_caffenet.caffemodel";
net->CopyTrainedLayersFrom(model);

读取模型中的每层的结构配置参数

char *model = "bvlc_reference_caffenet.caffemodel";
NetParameter param;
ReadNetParamsFromBinaryFileOrDie(model, ¶m);
int num_layers = param.layer_size();
for (int i = 0; i < num_layers; ++i)
{// 结构配置参数:name,type,kernel size,pad,stride等LOG(ERROR) << "Layer " << i << ":" << param.layer(i).name() << "\t" << param.layer(i).type();if (param.layer(i).type() == "Convolution"){ConvolutionParameter conv_param = param.layer(i).convolution_param();LOG(ERROR) << "\t\tkernel size: " << conv_param.kernel_size()<< ", pad: " << conv_param.pad()<< ", stride: " << conv_param.stride();}
}

读取图像均值

char *mean_file = "magenet_mean.binaryproto";
Blob<float> image_mean;
BlobProto blob_proto;
const float *mean_ptr;
unsigned int num_pixel;bool succeed = ReadProtoFromBinaryFile(mean_file, &blob_proto);
if (succeed)
{image_mean.FromProto(blob_proto);num_pixel = image_mean.count(); /* NCHW=1x3x256x256=196608 */mean_ptr = (const float *) image_mean.cpu_data();
}

根据指定数据,前向传播网络

//! Note: data_ptr指向已经处理好(去均值的,符合网络输入图像的长宽和Batch Size)的数据
void caffe_forward(boost::shared_ptr< Net<float> > & net, float *data_ptr)
{Blob<float>* input_blobs = net->input_blobs()[0];switch (Caffe::mode()){case Caffe::CPU:memcpy(input_blobs->mutable_cpu_data(), data_ptr,sizeof(float) * input_blobs->count());break;case Caffe::GPU:cudaMemcpy(input_blobs->mutable_gpu_data(), data_ptr,sizeof(float) * input_blobs->count(), cudaMemcpyHostToDevice);break;default:LOG(FATAL) << "Unknown Caffe mode.";} net->ForwardPrefilled();
}

根据Feature层的名字获取其在网络中的Index

//! Note: Net的Blob是指,每个层的输出数据,即Feature Maps
// char *query_blob_name = "conv1";
unsigned int get_blob_index(boost::shared_ptr< Net<float> > & net, char *query_blob_name)
{std::string str_query(query_blob_name);    vector< string > const & blob_names = net->blob_names();for( unsigned int i = 0; i != blob_names.size(); ++i ) { if( str_query == blob_names[i] ) { return i;} }LOG(FATAL) << "Unknown blob name: " << str_query;
}

读取网络指定Feature层数据

//! Note: 根据CaffeNet的deploy.prototxt文件,该Net共有15个Blob,从data一直到prob
char *query_blob_name = "conv1"; /* data, conv1, pool1, norm1, fc6, prob, etc */
unsigned int blob_id = get_blob_index(net, query_blob_name);boost::shared_ptr<Blob<float> > blob = net->blobs()[blob_id];
unsigned int num_data = blob->count(); /* NCHW=10x96x55x55 */
const float *blob_ptr = (const float *) blob->cpu_data();

根据文件列表,获取特征,并存为二进制文件详见get_features.cpp文件:

主要包括三个步骤

  • 生成文件列表,格式与训练用的类似,每行一个图像包括文件全路径、空格、标签(没有的话,可以置0)
  • 根据train_val或者deploy的prototxt,改写生成feat.prototxt主要是将输入层改为image_data层,最后加上prob和argmax(为了输出概率和Top1/5预测标签)
  • 根据指定参数,运行程序后会生成若干个二进制文件,可以用MATLAB读取数据,进行分析

根据Layer的名字获取其在网络中的Index

//! Note: Layer包括神经网络所有层,比如,CaffeNet共有23层
// char *query_layer_name = "conv1";
unsigned int get_layer_index(boost::shared_ptr< Net<float> > & net, char *query_layer_name)
{std::string str_query(query_layer_name);    vector< string > const & layer_names = net->layer_names();for( unsigned int i = 0; i != layer_names.size(); ++i ) { if( str_query == layer_names[i] ) { return i;} }LOG(FATAL) << "Unknown layer name: " << str_query;
}

读取指定Layer的权重数据

//! Note: 不同于Net的Blob是Feature Maps,Layer的Blob是指Conv和FC等层的Weight和Bias
char *query_layer_name = "conv1";
const float *weight_ptr, *bias_ptr;
unsigned int layer_id = get_layer_index(net, query_layer_name);
boost::shared_ptr<Layer<float> > layer = net->layers()[layer_id];
std::vector<boost::shared_ptr<Blob<float>  >> blobs = layer->blobs();
if (blobs.size() > 0)
{weight_ptr = (const float *) blobs[0]->cpu_data();bias_ptr = (const float *) blobs[1]->cpu_data();
}
//! Note: 训练模式下,读取指定Layer的梯度数据,与此相似,唯一的区别是将cpu_data改为cpu_diff

修改某层的Weight数据

const float* data_ptr;          /* 指向待写入数据的指针, 源数据指针*/
float* weight_ptr = NULL;       /* 指向网络中某层权重的指针,目标数据指针*/
unsigned int data_size;         /* 待写入的数据量 */
char *layer_name = "conv1";     /* 需要修改的Layer名字 */unsigned int layer_id = get_layer_index(net, query_layer_name);
boost::shared_ptr<Blob<float> > blob = net->layers()[layer_id]->blobs()[0];CHECK(data_size == blob->count());
switch (Caffe::mode())
{
case Caffe::CPU:weight_ptr = blob->mutable_cpu_data();break;
case Caffe::GPU:weight_ptr = blob->mutable_gpu_data();break;
default:LOG(FATAL) << "Unknown Caffe mode";
}
caffe_copy(blob->count(), data_ptr, weight_ptr);//! Note: 训练模式下,手动修改指定Layer的梯度数据,与此相似
// mutable_cpu_data改为mutable_cpu_diff,mutable_gpu_data改为mutable_gpu_diff


保存新的模型

char* weights_file = "bvlc_reference_caffenet_new.caffemodel";
NetParameter net_param;
net->ToProto(&net_param, false);
WriteProtoToBinaryFile(net_param, weights_file);

C++下caffe使用教程相关推荐

  1. Caffe官方教程翻译(3):Siamese Network Training with Caffe

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

  2. Caffe官方教程翻译(1):LeNet MNIST Tutorial

    前言 最近打算重新跟着官方教程学习一下caffe,顺便也自己翻译了一下官方的文档.自己也做了一些标注,都用斜体标记出来了.中间可能额外还加了自己遇到的问题或是运行结果之类的.欢迎交流指正,拒绝喷子! ...

  3. Caffe简明教程1:Caffe简介

    您可以查看所有文章的索引:Caffe简明教程0:文章列表 1.1 简介(Introduction) Caffe是一个很常用的深度学习框架,官网:http://caffe.berkeleyvision. ...

  4. ROCm与tensorflow在ubuntu 18.04下的安装教程

    ROCm与tensorflow在ubuntu 18.04下的安装教程     本来准备买Nvidai的显卡,可是囊中羞涩再加上听说AMD的卡也能使用tensorflow进行深度学习加速了,所以1149 ...

  5. 71 mac boook pro 无 gpu 下caffe 安装

    71 mac boook pro 无 gpu 下caffe 安装 1.首先安装homebrew工具,相当于Mac下的yum或apt ruby -e "$(curl -fsSL https:/ ...

  6. Windows下编译tensorflow-gpu教程

    这两个也要看: https://zhuanlan.zhihu.com/p/29029860 https://zhuanlan.zhihu.com/p/34942873 Windows下编译tensor ...

  7. mysql-win安装教程,WINDOWS下安装MYSQL教程详解

    1.下载安装包 2.配置环境变量 2.1 解压所下载的压缩包 2.2 环境变量 win 10 电脑 这么进去 3.生成data文件 在你解压的目录下,eg:F:\Program Files\mysql ...

  8. caffe linux 教程,CentOS7安装Caffe的教程详解

    安装依赖包 sudo yum install protobuf-devel leveldb-devel snappy-devel opencv-devel boost-devel hdf5-devel ...

  9. android studio3.12,Android Studio V3.12环境下TV开发教程(六)提供卡片视图

    Android Studio V3.12环境下TV开发教程 文章源自:光谷佳武 https://blog.csdn.net/jiawuhan/article/details/80619656 在上一课 ...

最新文章

  1. ubuntu 鼠标变成黑色的叉并且图标消失
  2. 分布式系统的发展演变以及RPC简介
  3. win10 64位下运行汇编
  4. CodeForces - 1303E Erase Subsequences(dp)
  5. java 解析 datatabe,在JAVA实现DataTable对象(一)
  6. 微信 小程序 python 渲染_干货 | 微信小程序自动化测试最佳实践(附 Python 源码)...
  7. 知识图谱研讨实录08丨肖仰华教授带你读懂知识图谱的质量控制
  8. c语言 和 运算顺序,二 如何学习C语言的运算符和运算顺序
  9. 64位电脑上安装MySQL进行MFC开发的相关问题
  10. 幼儿园数学目标_幼儿园数学区目标
  11. MBI5020 16位恒流驱动芯片
  12. 阴阳师魂十挂机实现(后台句柄截屏+鼠标点击)
  13. 【CSS】三行实现一个黑白网格背景(渐变)
  14. Xamarin Mono For Android
  15. java毕业设计校园快递柜存取件系统(附源码、数据库)
  16. bilibili缓存文件在哪里_都9012了,听说你还不了解缓存?
  17. PAUL:Patch-based Discriminative Feature Learning for Unsupervised Person Re-identification阅读总结
  18. html5 幽灵按钮,弥散阴影幽灵按钮
  19. Python OJ输入输出
  20. 任务栏谷歌图标和其他图标重叠(如钉钉)的解决方法

热门文章

  1. Docker 安装 nexus 私服
  2. Android隐藏软件盘
  3. flume多节点集群搭建
  4. Mac OS X 背后的故事(三)Mach之父Avie Tevanian 1
  5. 【svn】 如何在Linux服务器上添加svn账户的教程
  6. nRF52832 — 串口BLE例程逐行解析【转载】
  7. python中int函数的用法浅析_python中int函数怎么用,
  8. (六)python共享代码步骤
  9. 解决TortoiseSVN文件夹没有绿色对号
  10. 必备工具!程序员高效率工作工具推荐