caffe原始碼分析-DataLayer
DataLayer
作為caffe訓練時的資料層(以多執行緒的方式讀取資料加速solver
的訓練過程),繼承自BaseDataLayer/BasePrefetchingDataLayer
。
template <typename Dtype> class BaseDataLayer : public Layer<Dtype> { public: explicit BaseDataLayer(const LayerParameter& param); // This method may not be overridden except by the BasePrefetchingDataLayer. virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); // Data layers should be shared by multiple solvers in parallel virtual inline bool ShareInParallel() const { return true; } virtual void DataLayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {} // Data layers have no bottoms, so reshaping is trivial. virtual void Reshape(....) {//do nothing} virtual void Backward_cpu(....) {//do nothing} protected: TransformationParameter transform_param_; shared_ptr<DataTransformer<Dtype> > data_transformer_; bool output_labels_; };
data_transformer_主要是對輸入的圖片做crop_size,do_mirror,mean等操作.
下面看起函式定義LayerSetUp(引數初始化):
template <typename Dtype> void BaseDataLayer<Dtype>::LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { if (top.size() == 1) { output_labels_ = false; } else { output_labels_ = true; } data_transformer_.reset( new DataTransformer<Dtype>(transform_param_, this->phase_)); data_transformer_->InitRand(); // The subclasses should setup the size of bottom and top DataLayerSetUp(bottom, top); }
BasePrefetchingDataLayer還繼承了InternalThread
template <typename Dtype> class BasePrefetchingDataLayer : public BaseDataLayer<Dtype>, public InternalThread { public: explicit BasePrefetchingDataLayer(const LayerParameter& param); void LayerSetUp(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top); // Prefetches batches static const int PREFETCH_COUNT = 3; protected: virtual void InternalThreadEntry(); virtual void load_batch(Batch<Dtype>* batch) = 0; Batch<Dtype> prefetch_[PREFETCH_COUNT]; BlockingQueue<Batch<Dtype>*> prefetch_free_; BlockingQueue<Batch<Dtype>*> prefetch_full_; Blob<Dtype> transformed_data_; }; template <typename Dtype> void BasePrefetchingDataLayer<Dtype>::LayerSetUp( const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) { BaseDataLayer<Dtype>::LayerSetUp(bottom, top); //......... DLOG(INFO) << "Initializing prefetch"; this->data_transformer_->InitRand(); StartInternalThread(); DLOG(INFO) << "Prefetch initialized."; }
其中load_batch函式被DataLayer過載.
template <typename Dtype>
void BasePrefetchingDataLayer<Dtype>::InternalThreadEntry() {
while (!must_stop()) {
Batch<Dtype> *batch = prefetch_free_.pop();
load_batch(batch);
prefetch_full_.push(batch);
}
}
DataLayer中使用執行緒讀取Batch(image,label)push到佇列中,然後pop出來前向傳播:
template <typename Dtype>
void BasePrefetchingDataLayer<Dtype>::Forward_cpu(
const vector<Blob<Dtype>*>& bottom, const vector<Blob<Dtype>*>& top) {
Batch<Dtype>* batch = prefetch_full_.pop("Data layer prefetch queue empty");
// Reshape to loaded data.
top[0]->ReshapeLike(batch->data_);
// Copy the data
caffe_copy(batch->data_.count(), batch->data_.cpu_data(),
top[0]->mutable_cpu_data());
if (this->output_labels_) {
// Reshape to loaded labels.
top[1]->ReshapeLike(batch->label_);
// Copy the labels.
caffe_copy(batch->label_.count(), batch->label_.cpu_data(),
top[1]->mutable_cpu_data());
}
prefetch_free_.push(batch);
}
下面看DataLayer:
template <typename Dtype>
class DataLayer : public BasePrefetchingDataLayer<Dtype> {
public:
explicit DataLayer(const LayerParameter& param);
virtual ~DataLayer();
virtual void DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);
// DataLayer uses DataReader instead for sharing for parallelism
virtual inline bool ShareInParallel() const { return false; }
virtual inline const char* type() const { return "Data"; }
virtual inline int ExactNumBottomBlobs() const { return 0; }
virtual inline int MinTopBlobs() const { return 1; }
virtual inline int MaxTopBlobs() const { return 2; }
protected:
virtual void load_batch(Batch<Dtype>* batch);
DataReader reader_;
};
DataLayerSetUp初始化引數:
template <typename Dtype>
void DataLayer<Dtype>::DataLayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
const int batch_size = this->layer_param_.data_param().batch_size();
// Read a data point, and use it to initialize the top blob.
Datum& datum = *(reader_.full().peek());
// Use data_transformer to infer the expected blob shape from datum.
vector<int> top_shape = this->data_transformer_->InferBlobShape(datum);
this->transformed_data_.Reshape(top_shape);
// Reshape top[0] and prefetch_data according to the batch_size.
top_shape[0] = batch_size;
top[0]->Reshape(top_shape);
for (int i = 0; i < this->PREFETCH_COUNT; ++i) {
this->prefetch_[i].data_.Reshape(top_shape);
}
if (this->output_labels_) {// label
vector<int> label_shape(1, batch_size);
top[1]->Reshape(label_shape);
for (int i = 0; i < this->PREFETCH_COUNT; ++i) {
this->prefetch_[i].label_.Reshape(label_shape);
}
}
}
load_batch線上程中輪訓讀取資料庫(如lmdb)中的資料,並做crop_size,do_mirror,mean等操作,然後通過Forward_cpu傳遞給下一層.
template<typename Dtype>
void DataLayer<Dtype>::load_batch(Batch<Dtype>* batch) {
CPUTimer batch_timer;
batch_timer.Start();
double read_time = 0;nnndouble trans_time = 0;
CPUTimer timer;
const int batch_size = this->layer_param_.data_param().batch_size();
Datum& datum = *(reader_.full().peek());
// Use data_transformer to infer the expected blob shape from datum.
vector<int> top_shape = this->data_transformer_->InferBlobShape(datum);
this->transformed_data_.Reshape(top_shape);
// Reshape batch according to the batch_size.
top_shape[0] = batch_size;
batch->data_.Reshape(top_shape);
Dtype* top_data = batch->data_.mutable_cpu_data();
Dtype* top_label = NULL;
if (this->output_labels_) {
top_label = batch->label_.mutable_cpu_data();
}
for (int item_id = 0; item_id < batch_size; ++item_id) {
timer.Start();
// get a datum
Datum& datum = *(reader_.full().pop("Waiting for data"));
read_time += timer.MicroSeconds();
timer.Start();
// Apply data transformations (mirror, scale, crop...)
int offset = batch->data_.offset(item_id);
this->transformed_data_.set_cpu_data(top_data + offset);
this->data_transformer_->Transform(datum, &(this->transformed_data_));
// Copy label.
if (this->output_labels_) {
top_label[item_id] = datum.label();
}
trans_time += timer.MicroSeconds();
reader_.free().push(const_cast<Datum*>(&datum));
}
timer.Stop();
batch_timer.Stop();
// DLOG(INFO) << "Prefetch batch: " << batch_timer.MilliSeconds() << " ms.";
// DLOG(INFO) << " Read time: " << read_time / 1000 << " ms.";
// DLOG(INFO) << "Transform time: " << trans_time / 1000 << " ms.";
}
使用示例如下:
layer {
name: "mnist"
type: "Data"
top: "data"
top: "label"
include {
phase: TRAIN
}
transform_param {
scale: 0.00390625
}
data_param {
source: "/home/xy/caffe-master/examples/mnist/mnist_train_lmdb"
batch_size: 64
backend: LMDB
}
}
proto定義如下:
message DataParameter {
enum DB {
LEVELDB = 0;
LMDB = 1;
}
// Specify the data source.
optional string source = 1;
// Specify the batch size.
optional uint32 batch_size = 4;
optional uint32 rand_skip = 7 [default = 0];
optional DB backend = 8 [default = LEVELDB];
// Prefetch queue (Number of batches to prefetch to host memory.
optional uint32 prefetch = 10 [default = 4];
}
caffe
系列原始碼分析介紹
本系列深度學習框架caffe
原始碼分析主要內容如下:
自己從頭構建一遍工程,這樣能讓我更好的瞭解大型的專案的構建。當然原始的caffe的構建感覺還是比較複雜(主要是cmake),我這裡僅僅使用cmake構建,而且簡化點,當然最重要的是支援CLion直接執行除錯(如果需要這個工程可以評論留下你的郵箱,我給你傳送過去)。
2. caffe的資料記憶體分配類SyncedMemory
, 以及類Blob
資料傳輸的媒介.
主要內容:
caffe原始碼分析-SyncedMemory
caffe原始碼分析-Blob
其中Blob
分析給出了其直接與opencv的圖片相互轉化以及操作,可以使得我們更好的理解Blob
.
3. caffe layer
的原始碼分析,包括從整體上說明了layer
類別以及其proto定義與核心函式.
首先分析了最簡單的layer
Relu
,然後在是inner_product_layer全連線層
, 最後是layer_factory
caffe中 以此工廠模式create各種Layer.
4. 資料輸入層,主要是多執行緒+BlockingQueue的方式讀取資料訓練:
5. IO處理例如讀取proto檔案轉化為網路,以及網路引數的序列化
6. 最後給出了使用純C++結合多層感知機網路訓練mnist的示例
內容如下:
類似與caffe
一樣按照layer、solver、loss、net
等模組構建的神經網路實現可以見下面這篇blog,相信看懂了這個python的程式碼理解caffe框架會更簡單點.
最後如果需要cmake
+ CLion
直接執行除錯caffe
的程式碼工程,可以評論留下你的郵箱,我給你傳送過去.
相關推薦
caffe原始碼分析-DataLayer
DataLayer作為caffe訓練時的資料層(以多執行緒的方式讀取資料加速solver的訓練過程),繼承自BaseDataLayer/BasePrefetchingDataLayer。 template <typename Dtype> class
caffe 原始碼分析【三】:Euclidean loss layer
以下是Euclidean loss layer的程式碼分析,轉自: https://blog.csdn.net/seashell_9/article/details/68064294 一. 前向函式 template <typename Dtype> void Euclide
caffe 原始碼分析【二】:Layer基類
建構函式 //標頭檔案 include/caffe/layer.hpp //實現檔案 src/caffe/layer.cpp // src/caffe/layer.cu /* * 建構函式 * 子類中修改建構函式,自定義設定在SetUp()中設定
caffe 原始碼分析【一】: Blob類
Blob類的: //標頭檔案: include\caffe\blob.hpp //cpp檔案: src\caffe\blob.cpp //cu檔案: src/caffe/blob.cu //定義某layer的輸入blobs const ve
caffe原始碼分析-Blob
本文主要分析caffe原始碼分析-Blob,主要如下幾個方面: overview整體上了解caffe的Blob Blob 成員變數 Blob主要函式,核心在於Blob的使用例項以及其與opencv Mat的操作的相互轉化(附帶執行結果基於CLion) o
caffe原始碼分析-ReLULayer
啟用函式如:ReLu,Sigmoid等layer相對較為簡單,所以在分析InnerProductLayer前,我們先看下啟用函式層。 常見啟用層ReLU的使用示例如下: layer { name: "relu1" type: "ReLU" bott
caffe原始碼分析-layer_factory
caffe中有許多的layer,在net中建立連線layer是通過工廠模式的方式建立,而不是每一個new然後連線。在net.cpp中建立layer方式如下: layers_.push_back(Laye
caffe原始碼分析-InputLayer
對於輸入層,我們首先分析最簡單的InputLayer層,其常作為網路inference時的輸入,簡單的mnist使用示例如下: layer { name: "data" type: "Input
caffe原始碼分析-BlockingQueue
BlockingQueue執行緒安全的佇列, 作為caffe訓練時資料同步的重要資料結構,本文做簡要分析。 template<typename T> class BlockingQueue
caffe原始碼分析-DataTransformer
本文主要分析caffe中DataTransformer這個類, 主要作用是: 將Datum型別或者cv::Mat, 轉化為caffe的Blob<Dtype>,並按照Transformation``Parameter引數對影象做處理,例如scale
從Caffe原始碼分析訓練過程
下面開始來具體進行介紹。 先從Caffe.cpp檔案中的train()函式開始說起。 1、建立一個SolverParameter solver_param用來儲存求解(優化)的一些引數,SolverParameter這個資料結構具體被定義在caffe.proto檔案中。 2、Caffe::readP
caffe原始碼分析-cmake 工程構建
本文主要說明下,caffe原始碼分析過程中的cmake(結合IDE CLion)工程構建問題。在分析caffe原始碼的過程中,我沒有僅僅只是看程式碼,而是: 自己從頭構建一遍工程,這樣能讓我更好的瞭解大型的專案的構建。當然原始的caffe的構建感覺還是比較複
caffe原始碼分析:blob.hpp分析
以下摘自網際網路: Blob作為Caffe的四大模組之一,負責完成CPU/GPU儲存申請、同步和資料持久化對映。Caffe內部資料儲存和通訊都是通過Blob來完成,Blob提供統一的儲存操作介面,可用來儲存訓練資料、模型引數等。Blob是一個高維連續陣
caffe原始碼分析 vector& bottom
Blob:4個維度 n x c x h x w; bottom[0] 、bottom[1]代表該層有幾個輸入。 bottom[0]->count(): 輸入中,元素的總維數(個數) bottom[0]->nums(): 輸入中,塊(block)的個數,該引數還對應batch_size,即同時輸
caffe原始碼分析-inner_product_layer
本文主要分析caffe inner_product_layer原始碼,主要內容如下: 結合使用以及proto定義介紹InnerProductLayer的引數; 簡要分析Filler初始化,caffe中的layer引數,例如constant, gaussi
[caffe] 原始碼分析
caffe 1), i. using namespace caffe; ii. class Caffe{ inline static SetDevice(int i); } Caffe::SetDevice(gpus[0]);
caffe原始碼分析-db, io
本文主要分析下caffe的原始碼,io操作,以及資料庫檔案(如lmdb)讀取。 例如,從prototxt讀取網路初始化引數: NetParameter param; ReadNetParamsFromTextFileOrDie(path, ¶m)
Caffe原始碼(四):math_functions 分析
轉自:https://blog.csdn.net/seven_first/article/details/47378697#1-caffecpugemm-%E5%87%BD%E6%95%B0 主要函式 math_function 定義了caffe 中用到的一些矩陣操作和數值計算的一些函式,這
caffe原始碼深入學習6:超級詳細的im2col繪圖解析,分析caffe卷積操作的底層實現
在先前的兩篇部落格中,筆者詳細解析了caffe卷積層的定義與實現,可是在conv_layer.cpp與base_conv_layer.cpp中,卷積操作的實現仍然被隱藏,通過im2col_cpu函式和caffe_cpu_gemm函式(後者實現矩陣乘法)實現,在此篇部落格中,筆者旨在向大家展示,caf
caffe Layer基類原始碼分析
建構函式 //標頭檔案 include/caffe/layer.hpp //實現檔案 src/caffe/layer.cpp // src/caffe/layer.cu /*