欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

caffe的c++接口

程序员文章站 2023-12-25 16:06:21
caffe的c++接口:caffe中的c++接口怎么调用呢?有什么方法能够快速调用呢?接下来红黑小编就来介绍一下caffe的c++接口的调用方法,希望对大家有所帮助。 接口可以完全按照官网的分类cp...

caffe的c++接口:caffe中的c++接口怎么调用呢?有什么方法能够快速调用呢?接下来红黑小编就来介绍一下caffe的c++接口的调用方法,希望对大家有所帮助。
接口可以完全按照官网的分类cpp文件调用学习。

classification.cpp

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace caffe;  // nolint(build/namespaces)
using std::string;

/* pair (label, confidence) representing a prediction. */
typedef std::pair prediction;

class classifier {
 public:
  classifier(const string& model_file,
             const string& trained_file,
             const string& mean_file,
             const string& label_file);

  std::vector
 classify(const cv::mat& img, int n = 5);

 private:
  void setmean(const string& mean_file);

  std::vector predict(const cv::mat& img);

  void wrapinputlayer(std::vector* input_channels);

  void preprocess(const cv::mat& img,
                  std::vector* input_channels);

 private:
  shared_ptr > net_;
  cv::size input_geometry_;
  int num_channels_;
  cv::mat mean_;
  std::vector labels_;
};

classifier::classifier(const string& model_file,
                       const string& trained_file,
                       const string& mean_file,
                       const string& label_file) {
#ifdef cpu_only
  caffe::set_mode(caffe::cpu);
#else
  caffe::set_mode(caffe::gpu);
#endif

  /* load the network. */
  net_.reset(new net(model_file, test));
  net_->copytrainedlayersfrom(trained_file);

  check_eq(net_->num_inputs(), 1) << "network should have exactly one input.";
  check_eq(net_->num_outputs(), 1) << "network should have exactly one output.";

  blob* input_layer = net_->input_blobs()[0];
  num_channels_ = input_layer->channels();
  check(num_channels_ == 3 || num_channels_ == 1)
    << "input layer should have 1 or 3 channels.";
  input_geometry_ = cv::size(input_layer->width(), input_layer->height());

  /* load the binaryproto mean file. */
  setmean(mean_file);

  /* load labels. */
  std::ifstream labels(label_file.c_str());
  check(labels) << "unable to open labels file " << label_file;
  string line;
  while (std::getline(labels, line))
    labels_.push_back(string(line));

  blob* output_layer = net_->output_blobs()[0];
  check_eq(labels_.size(), output_layer->channels())
    << "number of labels is different from the output layer dimension.";
}

static bool paircompare(const std::pair& lhs,
                        const std::pair& rhs) {
  return lhs.first > rhs.first;
}

/* return the indices of the top n values of vector v. */
static std::vector argmax(const std::vector& v, int n) {
  std::vector > pairs;
  for (size_t i = 0; i < v.size(); ++i)
    pairs.push_back(std::make_pair(v[i], i));
  std::partial_sort(pairs.begin(), pairs.begin() + n, pairs.end(), paircompare);

  std::vector result;
  for (int i = 0; i < n; ++i)
    result.push_back(pairs[i].second);
  return result;
}

/* return the top n predictions. */
std::vector
 classifier::classify(const cv::mat& img, int n) {
  std::vector output = predict(img);

  std::vector maxn = argmax(output, n);
  std::vector
 predictions;
  for (int i = 0; i < n; ++i) {
    int idx = maxn[i];
    predictions.push_back(std::make_pair(labels_[idx], output[idx]));
  }

  return predictions;
}

/* load the mean file in binaryproto format. */
void classifier::setmean(const string& mean_file) {
  blobproto blob_proto;
  readprotofrombinaryfileordie(mean_file.c_str(), &blob_proto);

  /* convert from blobproto to blob */
  blob mean_blob;
  mean_blob.fromproto(blob_proto);
  check_eq(mean_blob.channels(), num_channels_)
    << "number of channels of mean file doesn't match input layer.";

  /* the format of the mean file is planar 32-bit float bgr or grayscale. */
  std::vector channels;
  float* data = mean_blob.mutable_cpu_data();
  for (int i = 0; i < num_channels_; ++i) {
    /* extract an inpidual channel. */
    cv::mat channel(mean_blob.height(), mean_blob.width(), cv_32fc1, data);
    channels.push_back(channel);
    data += mean_blob.height() * mean_blob.width();
  }

  /* merge the separate channels into a single image. */
  cv::mat mean;
  cv::merge(channels, mean);

  /* compute the global mean pixel value and create a mean image
   * filled with this value. */
  cv::scalar channel_mean = cv::mean(mean);
  mean_ = cv::mat(input_geometry_, mean.type(), channel_mean);
}

std::vector classifier::predict(const cv::mat& img) {
  blob* input_layer = net_->input_blobs()[0];
  input_layer->reshape(1, num_channels_,
                       input_geometry_.height, input_geometry_.width);
  /* forward dimension change to all layers. */
  net_->reshape();

  std::vector input_channels;
  wrapinputlayer(&input_channels);

  preprocess(img, &input_channels);

  net_->forwardprefilled();

  /* copy the output layer to a std::vector */
  blob* output_layer = net_->output_blobs()[0];
  const float* begin = output_layer->cpu_data();
  const float* end = begin + output_layer->channels();
  return std::vector(begin, end);
}

/* wrap the input layer of the network in separate cv::mat objects
 * (one per channel). this way we save one memcpy operation and we
 * don't need to rely on cudamemcpy2d. the last preprocessing
 * operation will write the separate channels directly to the input
 * layer. */
void classifier::wrapinputlayer(std::vector* input_channels) {
  blob* input_layer = net_->input_blobs()[0];

  int width = input_layer->width();
  int height = input_layer->height();
  float* input_data = input_layer->mutable_cpu_data();
  for (int i = 0; i < input_layer->channels(); ++i) {
    cv::mat channel(height, width, cv_32fc1, input_data);
    input_channels->push_back(channel);
    input_data += width * height;
  }
}

void classifier::preprocess(const cv::mat& img,
                            std::vector* input_channels) {
  /* convert the input image to the input image format of the network. */
  cv::mat sample;
  if (img.channels() == 3 && num_channels_ == 1)
    cv::cvtcolor(img, sample, cv_bgr2gray);
  else if (img.channels() == 4 && num_channels_ == 1)
    cv::cvtcolor(img, sample, cv_bgra2gray);
  else if (img.channels() == 4 && num_channels_ == 3)
    cv::cvtcolor(img, sample, cv_bgra2bgr);
  else if (img.channels() == 1 && num_channels_ == 3)
    cv::cvtcolor(img, sample, cv_gray2bgr);
  else
    sample = img;

  cv::mat sample_resized;
  if (sample.size() != input_geometry_)
    cv::resize(sample, sample_resized, input_geometry_);
  else
    sample_resized = sample;

  cv::mat sample_float;
  if (num_channels_ == 3)
    sample_resized.convertto(sample_float, cv_32fc3);
  else
    sample_resized.convertto(sample_float, cv_32fc1);

  cv::mat sample_normalized;
  cv::subtract(sample_float, mean_, sample_normalized);

  /* this operation will write the separate bgr planes directly to the
   * input layer of the network because it is wrapped by the cv::mat
   * objects in input_channels. */
  cv::split(sample_normalized, *input_channels);

  check(reinterpret_cast(input_channels->at(0).data)
        == net_->input_blobs()[0]->cpu_data())
    << "input channels are not wrapping the input layer of the network.";
}

int main(int argc, char** argv) {
  if (argc != 6) {
    std::cerr << "usage: " << argv[0]
              << " deploy.prototxt network.caffemodel"
              << " mean.binaryproto labels.txt img.jpg" << std::endl;
    return 1;
  }

  ::google::initgooglelogging(argv[0]);

  string model_file   = argv[1];
  string trained_file = argv[2];
  string mean_file    = argv[3];
  string label_file   = argv[4];
  classifier classifier(model_file, trained_file, mean_file, label_file);

  string file = argv[5];

  std::cout << "---------- prediction for "
            << file << " ----------" << std::endl;

  cv::mat img = cv::imread(file, -1);
  check(!img.empty()) << "unable to decode image " << file;
  std::vector
 predictions = classifier.classify(img);

  /* print the top n predictions. */
  for (size_t i = 0; i < predictions.size(); ++i) {
    prediction p = predictions[i];
    std::cout << std::fixed << std::setprecision(4) << p.second << " - \""
              << p.first << "\"" << std::endl;
  }
}

海康的星空下的巫师一个脚本:

 

/************************初始化网络**************************/
#include "caffe/caffe.hpp"
#include 
#include 
using namespace caffe;

char *proto = "h:\\models\\caffe\\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 > net(new caffe::net(proto, phase));
/************************加载已训练好的模型**************************/
char *model = "h:\\models\\caffe\\bvlc_reference_caffenet.caffemodel";    
net->copytrainedlayersfrom(model);
/*******************读取模型中的每层的结构配置参数*************************/

char *model = "h:\\models\\caffe\\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 = "h:\\models\\caffe\\imagenet_mean.binaryproto";
blob 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 > & net, float *data_ptr)
{
    blob* 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 > & 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 = net->blobs()[blob_id];
unsigned int num_data = blob->count(); /* nchw=10x96x55x55 */
const float *blob_ptr = (const float *) blob->cpu_data();
/*********************根据文件列表,获取特征,并存为二进制文件*****************/

/*
主要包括三个步骤

生成文件列表,格式与训练用的类似,每行一个图像 包括文件全路径、空格、标签(没有的话,可以置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 > & 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 = net->layers()[layer_id];
std::vector  >> 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 = 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);

上一篇:

下一篇: