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::vectorclassify(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::vectorclassifier::classify(const cv::mat& img, int n) { std::vector output = predict(img); std::vector maxn = argmax(output, n); std::vectorpredictions; 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::vectorpredictions = 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);