caffe源码分析
Ⅰ 如何看懂caffe代码
问我意利咖啡馆哪我肯定说caffe grecocaffe greco ~家张于1760咖啡馆仍保持着百变装潢侍者既往身着高雅黑色礼服佩戴领结都丝苟甚至都像随性意利作风看簇新咖啡机甚至怀疑自穿越侯2百前罗马~咖啡未必意利我却减少我嗜咖啡追寻殿堂级师脚步拜伦、歌德、王尔德、瓦格纳、李斯特名字都闪耀着艺术光辉《罗马假》安妮公主记者家店享受咖啡与香槟~咖啡味道已重要品尝已仅仅咖啡更积淀百历史与风情意利充满着文与艺术即使破旧却永远掩饰其光华古现代共存美丽永远名字
Ⅱ 在VS2013中打开caffe源代码,都能编译成功,下一步应该怎么训练模型
你想调用你的模型,最简单的办法是看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);
Blob<float> *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_ptr<Blob<float> >类型的,搜一下boost shared_ptr就知道跟普通指针有什么不同了
Ⅲ 如何在程序中调用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(vector<Mat> &images, vector<int> &labels, int iter_num);
virtual ~Classifier() {}
inline shared_ptr<Net<Dtype> > net() { return net_; }
void predict(vector<Mat> &images, vector<int> *labels);
void predict(vector<Dtype> &data, vector<int> *labels, int num);
void extract_feature(vector<Mat> &images, vector<vector<Dtype>> *out);
protected:
shared_ptr<Net<Dtype> > net_;
MemoryDataLayer<Dtype> *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>
Classifier<Dtype>::Classifier(const string& param_file, const string& weights_file) : net_()
{
net_.reset(new Net<Dtype>(param_file, TEST));
net_->CopyTrainedLayersFrom(weights_file);
//m_layer_ = (MemoryDataLayer<Dtype>*)net_->layer_by_name("mnist").get();
m_layer_ = (MemoryDataLayer<Dtype>*)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 Classifier<Dtype>::test(vector<Mat> &images, vector<int> &labels, int iter_num)
{
m_layer_->AddMatVector(images, labels);
//
int iterations = iter_num;
vector<Blob<Dtype>* > bottom_vec;
vector<int> test_score_output_id;
vector<Dtype> test_score;
Dtype loss = 0;
for (int i = 0; i < iterations; ++i) {
Dtype iter_loss;
const vector<Blob<Dtype>*>& 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 Classifier<Dtype>::predict(vector<Mat> &images, vector<int> *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());
}
}
vector<int> valid_labels, predicted_labels;
valid_labels.resize(valid_length, 0);
m_layer_->AddMatVector(images, valid_labels);
vector<Blob<Dtype>* > bottom_vec;
for(int i = 0; i < valid_length / batch_size_; i++)
{
const vector<Blob<Dtype>*>& 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::(predicted_labels.begin(), predicted_labels.begin() + original_length, labels->begin());
}
template <typename Dtype>
void Classifier<Dtype>::predict(vector<Dtype> &data, vector<int> *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);
}
}
vector<int> predicted_labels;
Dtype * label_ = new Dtype[valid_length];
memset(label_, 0, valid_length);
m_layer_->Reset(data.data(), label_, valid_length);
vector<Blob<Dtype>* > bottom_vec;
for(int i = 0; i < valid_length / batch_size_; i++)
{
const vector<Blob<Dtype>*>& 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::(predicted_labels.begin(), predicted_labels.begin() + original_length, labels->begin());
}
template <typename Dtype>
void Classifier<Dtype>::extract_feature(vector<Mat> &images, vector<vector<Dtype>> *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());
}
}
vector<int> valid_labels;
valid_labels.resize(valid_length, 0);
m_layer_->AddMatVector(images, valid_labels);
vector<Blob<Dtype>* > bottom_vec;
out->clear();
for(int i = 0; i < valid_length / batch_size_; i++)
{
const vector<Blob<Dtype>*>& 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;
vector<Dtype> 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和tensorflow源码用什么IDE
caffe 可以试试anjuta
Ⅳ 新手试运行了一个 caffe 的 python 代码,出现这个错误是怎么回事
一、问题
在成功编译caffe的源码之后,可以在Python环境中使用caffe。
在Ubuntu环境下,打开python解释程序,输入import caffe时:出现以下错误
>>>import caffe
Traceback (most recent call last):
File "<stdin>", line 1, in <mole>
ImportError: No mole named caffe
二、解决思路
基本思路是把caffe中的python导入到解释器中
三、解决方法
第一种方法:设置环境变量
在终中输入:
export PYTHONPATH=~/caffe/python #caffe的路径下面的python
则该终端起作用,关掉终端后或重新打开一终端,则失效。
放到配置文件中,可以永久有效果,命令操作如下:
A.把环境变量路径放到 ~/.bashrc文件中
sudo echo export PYTHONPATH="~/caffe/python" >> ~/.bashrc
B.使环境变量生效
source ~/.bashrc
第二种方法:通过代码来实现
在每个python代码中使用以下代码: (这个方法在写python代码时有用)
caffe_root = '~/caffe/python '
import sys
sys.path.insert(0, caffe_root + 'python')
import caffe
Ⅵ 深度学习caffe的代码怎么读
1.学习程序的第一步,先让程序跑起来,看看结果,这样就会有直观的感受。
Caffe的官网上Caffe | Deep Learning Framework 提供了很多的examples,你可以很容易地开始训练一些已有的经典模型,如LeNet。我建议先从 LeNet MNIST Tutorial开始,因为数据集很小,网络也很小但很经典,用很少的时间就可以跑起来了。当你看到terminal刷拉拉的一行行输出,看到不断减少的loss和不断上升的accuracy,训练结束你得到了99+%的准确率,感觉好厉害的样子。你可以多跑跑几个例子,熟悉一下环境和接口。
2.单步调试,跟着Caffe在网络里流动
当玩了几天之后,你对Caffe的接口有点熟悉了,对已有的例子也玩腻了,你开始想看看具体是怎么实现的了。我觉得最好的方法是通过单步调试的方式跟着程序一步一步的在网络里前向传播,然后再被当成误差信息传回来。
Caffe就像一个你平常编程中Project,你可以使用IDE或者GDB去调试它,这里我们不细说调试的过程。你可以先跟踪前向传播的过程,无非就是从高层次到低层次的调用Forward函数,Solver->Net->Layer->Specific Layer (Convolution等...).后向传播也类似,但因为你对Caffe里面的各种变量运算不熟悉,当你跟踪完前向传播时可能已经头晕眼花了,还是休息一下,消化一下整个前向传播的流程。
刚刚开始你没有必要对每个Layer的计算细节都那么较真,大概知道程序的运算流程就好,这样你才可以比较快的对Caffe有个大体的把握。
3.个性化定制Caffe
到这里,你已经可以说自己有用过Caffe了,但是还不能算入门,因为你还不知道怎么修改源码,满足自己特定的需求。我们很多时候都需要自己定义新的层来完成特定的运算,这时你需要在Caffe里添加新的层。
你一开肯定无从下手,脑子一片空白。幸运的是Caffe github上的Wiki Development · BVLC/caffe Wiki · GitHub已经有了教程了,而且这是最接近latest Caffe的源码结构的教程,你在网上搜到的Blog很多是有点过时的,因为Caffe最近又重构了代码。你可以跟着它的指导去添加自己的层。
虽然你已经知道要在哪里添加自己的东西了,但你遇到最核心的问题是如何写下面这四个函数。
forward_cpu()
forward_gpu()
backward_cpu()
backward_gpu()
你可以先模仿已有的层去实现这四个函数,而且我相信forward函数很快就可以写出来了,但backward的还是一头雾水。这时我们就要补补神经网络里最核心的内容了——Backpropagation.
4.理解并实现Backpropagation
这个我觉得是与平台无关的,不管你是使用Caffe、Torch 7,还是Theano,你都需要深刻理解并掌握的。因为我比较笨,花了好长时间才能够适应推导中的各种符号。其实也不难,就是误差顺着Chain rule法则流回到前面的层。我不打算自己推导后向传播的过程,因为我知道我没有办法将它表达得很好,而且网上已经有很多非常好的教程了。下面是我觉得比较好的学习步骤吧。
从浅层的神经网络(所谓的全连接层)的后向传播开始,因为这个比较简单,而且现在我们常说的CNN和LSTM的梯度计算也最终会回归到这里。
第一个必看的是Ng深入浅出的Ufldl教程UFLDL Tutorial,还有中文版的,这对不喜欢看英语的同学是个好消息。当然你看一遍不理解,再看一遍,忘了,再看,读个几遍你才会对推导过程和数学符号熟悉。我头脑不大行,来来回回看了好多次。
当然,Ufldl的教程有点短,我还发现了一个讲得更细腻清晰的教程, Michael Nielsen写的Neural networks and deep learning。它讲得实在太好了,以至于把我的任督二脉打通了。在Ufldl的基础上读这个,你应该可以很快掌握全连接层的反向传播。
最后在拿出standford大牛karpathy的一篇博客Hacker's guide to Neural Networks,这里用了具体的编程例子手把手教你算梯度,并不是推导后向传播公式的,是关于通用梯度计算的。用心去体会一下。
这时你跃跃欲试,回去查看Caffe源码里Convolution层的实现,但发现自己好像没看懂。虽说卷积层和全连接层的推导大同小异,但思维上还是有个gap的。我建议你先去看看Caffe如何实现卷积的,Caffe作者贾扬清大牛在知乎上的回答在 Caffe 中如何计算卷积?让我茅塞顿开。重点理解im2col和col2im.
这时你知道了Convolution的前向传播,还差一点就可以弄明白后向传播怎么实现了。我建议你死磕Caffe中Convolution层的计算过程,把每一步都搞清楚,经过痛苦的过程之后你会对反向传播有了新的体会的。在这之后,你应该有能力添加自己的层了。再补充一个完整的添加新的层的教程Making a Caffe Layer • Computer Vision Enthusiast。这篇教程从头开始实现了一个Angle To Sine Cosine Layer,包含了梯度推导,前向与后向传播的CPU和GPU函数,非常棒的一个教程。
最后,建议学习一下基本的GPU Cuda编程,虽然Caffe中已经把Cuda函数封装起来了,用起来很方便,但有时还是需要使用kernel函数等Cuda接口的函数。这里有一个入门的视频教程,讲得挺不错的NVIDIA CUDA初级教程视频。
作者:Gein Chen
来源:知乎
Ⅶ caffe到底是什么,要怎么入门
我觉定吧深度习平台没坏能说每平台特点都选哪都关键选定平台准备始做候尽量要换我目前用caffe其实网络自平台PaddlePaddle--、想读源码数基础定要强
Ⅷ 如何用caffe解决回归问题
近在基于caffe做目标检测的问题,需要利用caffe来训练一个回归网络,用来预测object在图像中的位置(x1,y1,width,height)。但是现有的caffe版本(happynear版本)只适用于二分类问题的数据集转换,所以需要修改caffe源码,使之也可以转换回归问题的数据集。
主要是参照 http://blog.csdn.net/baobei0112/article/details/47606559 进行修改。但是这份博客使用的不是happynear的caffe版本,所以源码改动的地方差异较大。下面我会记录我改动的地方。
一.源码修改
1.修改caffe.proto,位于/src/caffe/proto
36行改成 repeated float label = 5;,然后运行extract_proto.bat
2.修改data_layer.hpp
Ⅸ 深度学习框架Caffe到底是怎么支持ResNet的
从Geoffrey Hinton 2006年的论文算起,这一波深度学习(DL)浪潮才10年,而如果只算国内,深度学习的流行也不过5年,尽管如此,深度学习现在已经扎根中国互联网,成为BAT、京东、360、今日头条等公司的基础技术和战略技术,与之伴随的,则是深度学习技术人员的快速成长,例如,阿里云工程师卜居(赵永科)博客,2014年才开始接触深度学习实战,如今已在深度学习及计算优化方面方面有很独到的见解。卜居在最近写了一本浓缩其深度学习实战经验的书——《深度学习—21天实战Caffe》,该书获得了机器学习前辈的肯定。日前,卜居接受CSDN记者专访,介绍了他在深度学习领域的实践经验和成长心得,以及完成Caffe着作背后的原因和故事。
卜居认为,深度学习具备强大的表达能力和灵活多变的模型结构,并在各种硬件加速方案的支撑下不断成熟,而Caffe具有高效的C++/CUDA实现、Matlab/Python接口、独特的网络描述方式、清晰的代码框架等优势,徒手hack代码的乐趣更多,同时Caffe框代码于稳定,掌握了阅读技巧可以事半功倍,因而可以作为初学者学习的第一个深度学习框架,由此逐步深入了解使用C++/CUDA代码实现深度学习的计算过程。
谈到新书《深度学习—21天实战Caffe》,卜居表示,这是一本透过源码解读深度学习的书,也是一本注重“实战”的书。读者可以从本书中学习Caffe设计模式、编程技巧,以及深度学习最新的进展和生产环境批量部署等内容。而书中的一些思考题需要深入实践和思考之后才能得到答案,这可以让读者养成独立思考的习惯,从而更加从容地面对实际问题。
此外,对于不同的硬件加速方案,卜居认为,深度学习本身在不断演进,没有哪个计算架构能够一劳永逸,得到某方面优势会丧失另一部分特性,最终起决定作用的仍然是应用需求,例如批量离线处理更适合利CPU/GPU集群的规模优势,而在线应用、移动端应用更适合利用FPGA/ASIC的低功耗、低延迟特性。