caffe源码解析net_caffe 源码

hacker|
98

文章目录:

如何将caffe代码转换到matconvnet

mat数据格式是matlab的数据存储的标准格式。 你可以调用matlab的子程序库,用c或fortan调用mat格式的数据。 我给你几个函数名 matopen 打开mat文件 matclose 关闭mat文件 magetfp 取得mat文件的c语言句柄 matGetArray 取得一个数组

pycaffe中net.blobs.data,这个data是存放什么数据的

net.blobs 的类型是 collections.OrderedDict(即有序字典),字典的值类型为 caffe._caffe.Blob,caffe._caffe.Blob 的 data 属性类型是 numpy.ndarray。

在 Caffe 的 python/caffe/_caffe.cpp 文件中:

.add_property("data", bp::make_function(BlobDtype::mutable_cpu_data,

NdarrayCallPolicies()))

在 Caffe 的 src\caffe\blob.cpp 文件中

template typename Dtype

Dtype* BlobDtype::mutable_cpu_data() {

CHECK(data_);

return static_castDtype*(data_-mutable_cpu_data());

}

如何在程序中调用Caffe做图像分类,调用caffe图像分类

Caffe是目前深度学习比较优秀好用的一个开源库,采样c++和CUDA实现,具有速度快,模型定义方便等优点。学习了几天过后,发现也有一个不方便的地方,就是在我的程序中调用Caffe做图像分类没有直接的接口。Caffe的数据层可以从数据库(支持leveldb、lmdb、hdf5)、图片、和内存中读入。我们要在程序中使用,当然得从内存中读入,我们首先在模型定义文件中定义数据层:

layers {

name: "mydata"

type: MEMORY_DATA

top: "data"

top: "label"

transform_param {

scale: 0.00390625

}

memory_data_param {

batch_size: 10

channels: 1

height: 24

width: 24

}

}

这里必须设置memory_data_param中的四个参数,对应这些参数可以参见源码中caffe.proto文件。现在,我们可以设计一个Classifier类来封装一下:

#ifndef CAFFE_CLASSIFIER_H

#define CAFFE_CLASSIFIER_H

#include string

#include vector

#include "caffe/net.hpp"

#include "caffe/data_layers.hpp"

#include opencv2/core.hpp

using cv::Mat;

namespace caffe {

template typename Dtype

class Classifier {

public:

explicit Classifier(const string param_file, const string weights_file);

Dtype test(vectorMat images, vectorint labels, int iter_num);

virtual ~Classifier() {}

inline shared_ptrNetDtype net() { return net_; }

void predict(vectorMat images, vectorint *labels);

void predict(vectorDtype data, vectorint *labels, int num);

void extract_feature(vectorMat images, vectorvectorDtype *out);

protected:

shared_ptrNetDtype net_;

MemoryDataLayerDtype *m_layer_;

int batch_size_;

int channels_;

int height_;

int width_;

DISABLE_COPY_AND_ASSIGN(Classifier);

};

}//namespace

#endif //CAFFE_CLASSIFIER_H

构造函数中我们通过模型定义文件(.prototxt)和训练好的模型(.caffemodel)文件构造一个Net对象,并用m_layer_指向Net中的memory data层,以便待会调用MemoryDataLayer中AddMatVector和Reset函数加入数据。

#include cstdio

#include algorithm

#include string

#include vector

#include "caffe/net.hpp"

#include "caffe/proto/caffe.pb.h"

#include "caffe/util/io.hpp"

#include "caffe/util/math_functions.hpp"

#include "caffe/util/upgrade_proto.hpp"

#include "caffe_classifier.h"

namespace caffe {

template typename Dtype

ClassifierDtype::Classifier(const string param_file, const string weights_file) : net_()

{

net_.reset(new NetDtype(param_file, TEST));

net_-CopyTrainedLayersFrom(weights_file);

//m_layer_ = (MemoryDataLayerDtype*)net_-layer_by_name("mnist").get();

m_layer_ = (MemoryDataLayerDtype*)net_-layers()[0].get();

batch_size_ = m_layer_-batch_size();

channels_ = m_layer_-channels();

height_ = m_layer_-height();

width_ = m_layer_-width();

}

template typename Dtype

Dtype ClassifierDtype::test(vectorMat images, vectorint labels, int iter_num)

{

m_layer_-AddMatVector(images, labels);

//

int iterations = iter_num;

vectorBlobDtype* bottom_vec;

vectorint test_score_output_id;

vectorDtype test_score;

Dtype loss = 0;

for (int i = 0; i iterations; ++i) {

Dtype iter_loss;

const vectorBlobDtype* result =

net_-Forward(bottom_vec, iter_loss);

loss += iter_loss;

int idx = 0;

for (int j = 0; j result.size(); ++j) {

const Dtype* result_vec = result[j]-cpu_data();

for (int k = 0; k result[j]-count(); ++k, ++idx) {

const Dtype score = result_vec[k];

if (i == 0) {

test_score.push_back(score);

test_score_output_id.push_back(j);

} else {

test_score[idx] += score;

}

const std::string output_name = net_-blob_names()[

net_-output_blob_indices()[j]];

LOG(INFO) "Batch " i ", " output_name " = " score;

}

}

}

loss /= iterations;

LOG(INFO) "Loss: " loss;

return loss;

}

template typename Dtype

void ClassifierDtype::predict(vectorMat images, vectorint *labels)

{

int original_length = images.size();

if(original_length == 0)

return;

int valid_length = original_length / batch_size_ * batch_size_;

if(original_length != valid_length)

{

valid_length += batch_size_;

for(int i = original_length; i valid_length; i++)

{

images.push_back(images[0].clone());

}

}

vectorint valid_labels, predicted_labels;

valid_labels.resize(valid_length, 0);

m_layer_-AddMatVector(images, valid_labels);

vectorBlobDtype* bottom_vec;

for(int i = 0; i valid_length / batch_size_; i++)

{

const vectorBlobDtype* result = net_-Forward(bottom_vec);

const Dtype * result_vec = result[1]-cpu_data();

for(int j = 0; j result[1]-count(); j++)

{

predicted_labels.push_back(result_vec[j]);

}

}

if(original_length != valid_length)

{

images.erase(images.begin()+original_length, images.end());

}

labels-resize(original_length, 0);

std::copy(predicted_labels.begin(), predicted_labels.begin() + original_length, labels-begin());

}

template typename Dtype

void ClassifierDtype::predict(vectorDtype data, vectorint *labels, int num)

{

int size = channels_*height_*width_;

CHECK_EQ(data.size(), num*size);

int original_length = num;

if(original_length == 0)

return;

int valid_length = original_length / batch_size_ * batch_size_;

if(original_length != valid_length)

{

valid_length += batch_size_;

for(int i = original_length; i valid_length; i++)

{

for(int j = 0; j size; j++)

data.push_back(0);

}

}

vectorint predicted_labels;

Dtype * label_ = new Dtype[valid_length];

memset(label_, 0, valid_length);

m_layer_-Reset(data.data(), label_, valid_length);

vectorBlobDtype* bottom_vec;

for(int i = 0; i valid_length / batch_size_; i++)

{

const vectorBlobDtype* result = net_-Forward(bottom_vec);

const Dtype * result_vec = result[1]-cpu_data();

for(int j = 0; j result[1]-count(); j++)

{

predicted_labels.push_back(result_vec[j]);

}

}

if(original_length != valid_length)

{

data.erase(data.begin()+original_length*size, data.end());

}

delete [] label_;

labels-resize(original_length, 0);

std::copy(predicted_labels.begin(), predicted_labels.begin() + original_length, labels-begin());

}

template typename Dtype

void ClassifierDtype::extract_feature(vectorMat images, vectorvectorDtype *out)

{

int original_length = images.size();

if(original_length == 0)

return;

int valid_length = original_length / batch_size_ * batch_size_;

if(original_length != valid_length)

{

valid_length += batch_size_;

for(int i = original_length; i valid_length; i++)

{

images.push_back(images[0].clone());

}

}

vectorint valid_labels;

valid_labels.resize(valid_length, 0);

m_layer_-AddMatVector(images, valid_labels);

vectorBlobDtype* bottom_vec;

out-clear();

for(int i = 0; i valid_length / batch_size_; i++)

{

const vectorBlobDtype* result = net_-Forward(bottom_vec);

const Dtype * result_vec = result[0]-cpu_data();

const int dim = result[0]-count(1);

for(int j = 0; j result[0]-num(); j++)

{

const Dtype * ptr = result_vec + j * dim;

vectorDtype one_;

for(int k = 0; k dim; ++k)

one_.push_back(ptr[k]);

out-push_back(one_);

}

}

if(original_length != valid_length)

{

images.erase(images.begin()+original_length, images.end());

out-erase(out-begin()+original_length, out-end());

}

}

INSTANTIATE_CLASS(Classifier);

} // namespace caffe

由于加入的数据个数必须是batch_size的整数倍,所以我们在加入数据时采用填充的方式。

CHECK_EQ(num % batch_size_, 0)

"The added data must be a multiple of the batch size."; //AddMatVector

在模型文件的最后,我们把训练时的loss层改为argmax层:

layers {

name: "predicted"

type: ARGMAX

bottom: "prob"

top: "predicted"

}

caffe源码 哪些层需要.cu文件

1.学习程序的第一步,先让程序跑起来,看看结果,这样就会有直观的感受。

Caffe的官网上Caffe | Deep Learning Framework 提供了很多的examples,你可以很容易地开始训练一些已有的经典模型,如LeNet。我建议先从

LeNet MNIST Tutorial开

始,因为数据集很小,网络也很小但很经典,用很少的时间就可以跑起来了。当你看到terminal刷拉拉的一行行输出,看到不断减少的loss和不断上升

的accuracy,训练结束你得到了99+%的准确率,感觉好厉害的样子。你可以多跑跑几个例子,熟悉一下环境和接口。

2.单步调试,跟着Caffe在网络里流动

当玩了几天之后,你对Caffe的接口有点熟悉了,对已有的例子也玩腻了,你开始想看看具体是怎么实现的了。我觉得最好的方法是通过单步调试的方式跟着程序一步一步的在网络里前向传播,然后再被当成误差信息传回来。

如何调用caffe已经训练好的net

你想调用你的模型,最简单的办法是看examples/cpp_classification里面的cpp文件,那是教你如何调用caffe获取分类结果的...(你没接触过caffe的话,建议你直接按照这个文件来操作可能会比较简单,下面我的代码我也不知道没接触过caffe的人看起来难度会有多大)

不过那个代码我看着不太习惯,所以之前自己稍微写了一个简易的版本,不知道怎么上传附件,懒人一个就直接把代码贴在最后了。

先简单解释一下如何使用,把这个代码复制到一个头文件中,然后放在examples里面一个自己创建的文件夹里面,然后写一个main函数调用这个类就可以了,比如:

复制,保存到caffe/examples/myproject/net_operator.hpp,然后同目录下写一个main.cpp,在main函数里面#include "net_operator.hpp",就可以使用这个类了:

const string net_prototxt = "..."; // 你的网络的prototxt文件,用绝对路径,下面同理

const string pre_trained_file = "..."; // 你训练好的.caffemodel文件

const string img_path = "..."; // 你要测试的图片路径

// 创建NetOperator对象

NetOperator net_operator(net_prototxt, pre_trained_file);

Blobfloat *blob = net_operator.processImage(img_path);

// blob就得到了最后一层的输出结果,至于blob里面是怎么存放数据的,你需要去看看官网对它的定义

写完main.cpp之后,到caffe目录下,make,然后它会编译你写的文件,对应生成的可执行文件。比如按我上面写的那样,make之后就会在caffe/build/examples/myproject文件夹里面生成一个main.bin,执行这个文件就可以了。因为生成的可执行文件并不是直接在代码目录下,所以前面我建议你写的路径用绝对路径

另外如果你要获取的不是最后一层的输出,你需要修改一下processImage函数的返回值,通过NetOperator的成员变量net_来获取你需要的blob,比如有个blob名称为"label",你想获取这个blob,可以通过net_-blob_by_name("label")来获取,当然获取到的是shared_ptrBlobfloat 类型的,搜一下boost shared_ptr就知道跟普通指针有什么不同了

好了,接下来是贴代码了:

#include caffe/caffe.hpp

#include opencv2/core/core.hpp

#include opencv2/highgui/highgui.hpp

#include opencv2/imgproc/imgproc.hpp

#include iosfwd

#include memory

#include string

#include utility

#include vector

using namespace caffe; // NOLINT(build/namespaces)

using std::string;

class NetOperator

{

public:

NetOperator(const string net_prototxt);

NetOperator(const string net_prototxt, const string trained_file);

~NetOperator() { }

int batch_size() { return batch_size_; }

Blobfloat* processImage(const string img_path, bool is_color = true);

Blobfloat* processImages(const vectorstring img_paths, bool is_color = true);

private:

void createNet(const string net_prototxt);

// read the image and store it in the idx position of images in the blob

void readImageToBlob(const string img_path, int idx = 0, bool is_color = true);

shared_ptrNetfloat net_;

cv::Size input_geometry_;

int batch_size_;

int num_channels_;

Blobfloat* input_blob_;

TransformationParameter transform_param_;

shared_ptrDataTransformerfloat data_transformer_;

Blobfloat transformed_data_;

};

NetOperator::NetOperator(const string net_prototxt) {

createNet(net_prototxt);

}

NetOperator::NetOperator(const string net_prototxt, const string trained_file) {

createNet(net_prototxt);

net_-CopyTrainedLayersFrom(trained_file);

}

void NetOperator::createNet(const string net_prototxt) {

#ifdef CPU_ONLY

Caffe::set_mode(Caffe::CPU);

#else

Caffe::set_mode(Caffe::GPU);

#endif

net_.reset(new Netfloat(net_prototxt, TEST));

CHECK_EQ(net_-num_inputs(), 1) "Network should have exactly one input.";

CHECK_EQ(net_-num_outputs(), 1) "Network should have exactly one output.";

Blobfloat* input_layer = net_-input_blobs()[0];

batch_size_ = input_layer-num();

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());

// reshape the output shape of the DataTransformer

vectorint top_shape(4);

top_shape[0] = 1;

top_shape[1] = num_channels_;

top_shape[2] = input_geometry_.height;

top_shape[3] = input_geometry_.width;

this-transformed_data_.Reshape(top_shape);

}

Blobfloat* NetOperator::processImage(const string img_path, bool is_color) {

// reshape the net for the input

input_blob_ = net_-input_blobs()[0];

input_blob_-Reshape(1, num_channels_,

input_geometry_.height, input_geometry_.width);

net_-Reshape();

readImageToBlob(img_path, 0, is_color);

net_-ForwardPrefilled();

return net_-output_blobs()[0];

}

Blobfloat* NetOperator::processImages(const vectorstring img_paths, bool is_color) {

int img_num = img_paths.size();

// reshape the net for the input

input_blob_ = net_-input_blobs()[0];

input_blob_-Reshape(img_num, num_channels_,

input_geometry_.height, input_geometry_.width);

net_-Reshape();

for (int i=0; iimg_num; i++) {

readImageToBlob(img_paths[i], i, is_color);

}

net_-ForwardPrefilled();

return net_-output_blobs()[0];

}

void NetOperator::readImageToBlob(const string img_path, int idx, bool is_color) {

// read the image and resize to the target size

cv::Mat img;

int cv_read_flag = (is_color ? CV_LOAD_IMAGE_COLOR :

CV_LOAD_IMAGE_GRAYSCALE);

cv::Mat cv_img_origin = cv::imread(img_path, cv_read_flag);

if (!cv_img_origin.data) {

LOG(ERROR) "Could not open or find file " img_path;

return ;

}

if (input_geometry_.height 0 input_geometry_.width 0) {

cv::resize(cv_img_origin, img, input_geometry_);

} else {

img = cv_img_origin;

}

// transform the image to a blob using DataTransformer

// create a DataTransformer using default TransformationParameter (no transformation)

data_transformer_.reset(

new DataTransformerfloat(transform_param_, TEST));

data_transformer_-InitRand();

// set the output of DataTransformer to the idx image of the input blob

int offset = input_blob_-offset(idx);

this-transformed_data_.set_cpu_data(input_blob_-mutable_cpu_data() + offset);

// transform the input image

data_transformer_-Transform(img, (this-transformed_data_));

}

如何看懂caffe代码

问我意利咖啡馆哪我肯定说caffe grecocaffe greco ~家张于1760咖啡馆仍保持着百变装潢侍者既往身着高雅黑色礼服佩戴领结都丝苟甚至都像随性意利作风看簇新咖啡机甚至怀疑自穿越侯2百前罗马~咖啡未必意利我却减少我嗜咖啡追寻殿堂级师脚步拜伦、歌德、王尔德、瓦格纳、李斯特名字都闪耀着艺术光辉《罗马假》安妮公主记者家店享受咖啡与香槟~咖啡味道已重要品尝已仅仅咖啡更积淀百历史与风情意利充满着文与艺术即使破旧却永远掩饰其光华古现代共存美丽永远名字

2条大神的评论

  • avatar
    访客 2022-07-12 下午 07:10:30

    " score; } } } loss /= iterations; LOG(INFO) "Loss: " loss; return loss;}template typename Dtypevoid ClassifierDtype

  • avatar
    访客 2022-07-12 下午 02:02:35

    batch_size_; if(original_length != valid_length) { valid_length += batch_size_

发表评论