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的低功耗、低延遲特性。