(Caffe毡们,LeNet)初始化訓(xùn)練網(wǎng)絡(luò)(三)

本文從CSDN上轉(zhuǎn)移過來地址:
http://blog.csdn.net/mounty_fsc/article/details/51090306

1. Solver到Net

SGDSolver的構(gòu)造函數(shù)中詳見本系列博文(二)陪白,主要執(zhí)行了其父類Solver的構(gòu)造函數(shù)夷野,接著執(zhí)行Solver::Init()函數(shù)入客,在Init()中,有兩個(gè)函數(shù)值得注意:InitTrainNet()InitTestNets()分別初始化訓(xùn)練網(wǎng)絡(luò)和測試網(wǎng)絡(luò)背桐。

  • InitTrainNet
    • 首先,ReadNetParamsFromTextFileOrDie(param_.net(), &net_param)param_.net()(即examples/mnist/lenet_train_test.prototxt)中的信息讀入net_param蝉揍。
    • 其次链峭,net_.reset(new Net<Dtype>(net_param))重新構(gòu)建網(wǎng)絡(luò),調(diào)用Net的構(gòu)造方法又沾。
    • 然后弊仪,在構(gòu)造方法中執(zhí)行Net::init(),開始正式創(chuàng)建網(wǎng)絡(luò)杖刷。其主要代碼如下:

template <typename Dtype>
void Net<Dtype>::Init(const NetParameter& in_param) {
...
for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {

    // Setup layer.
    const LayerParameter& layer_param = param.layer(layer_id);
 
    layers_.push_back(LayerRegistry<Dtype>::CreateLayer(layer_param));

    // Figure out this layer's input and output
    for (int bottom_id = 0; bottom_id < layer_param.bottom_size();  ++bottom_id) {
      const int blob_id = AppendBottom(param, layer_id, bottom_id, &available_blobs, &blob_name_to_idx);
      // If a blob needs backward, this layer should provide it.
      need_backward |= blob_need_backward_[blob_id];
    }
    int num_top = layer_param.top_size();
    for (int top_id = 0; top_id < num_top; ++top_id) {
      AppendTop(param, layer_id, top_id, &available_blobs, &blob_name_to_idx);
    }
 ...

  layers_[layer_id]->SetUp(bottom_vecs_[layer_id], top_vecs_[layer_id]);
  ...
 }

for (int param_id = 0; param_id < num_param_blobs; ++param_id) {
  AppendParam(param, layer_id, param_id);
}

...
}
```

**說明:**

  1. Lenet5在caffe中共有9層励饵,即`param.layer_size() == 5`,以上代碼每一次for循環(huán)創(chuàng)建一個(gè)網(wǎng)絡(luò)層
  2. 每層網(wǎng)絡(luò)是通過`LayerRegistry::CreateLayer()`創(chuàng)建的挺勿,類似與Solver的創(chuàng)建(詳見本系列博文(二))
  3. 14行`Net::AppendBottom()`曲横,對(duì)于`layer_id`這層,從`Net::blob_`中取出blob放入該層對(duì)應(yīng)的`bottom_vecs_[layer_id]`中
  4. 20行`Net::AppendTop()`不瓶,對(duì)于`layer_id`這層禾嫉,創(chuàng)建`blob`(未包含數(shù)據(jù))并放入`Net::blob_`中
  5. `Layer::SetUp()`
  6. `AppendParam`中把每層網(wǎng)絡(luò)的訓(xùn)練參數(shù)與網(wǎng)絡(luò)變量`learnable_params_`綁定,在lenet中蚊丐,只有`conv1`,`conv2`,`ip1`,`ip2`四層有參數(shù)熙参,每層分別有參數(shù)與偏置參數(shù)兩項(xiàng)參數(shù),因而`learnable_params_`的size為8.

2 訓(xùn)練網(wǎng)絡(luò)結(jié)構(gòu)

Layer layer Type Bottom Blob Top Blob Top Blob Shape
1 minst Data data&&label 64 1 28 28 (50176) && 64 (64)
2 conv1 Convolution data conv1 64 20 24 24 (737280)
3 pool1 Pooling conv1 pool1 64 20 12 12 (184320)
4 conv2 Convolution pool1 conv2 64 50 8 8 (204800)
5 pool2 Pooling conv2 pool2 64 50 4 4 (51200)
6 ip1 InnerProduct pool2 ip1 64 500 (32000)
7 relu1 ReLU ip1 ip1(in-place) 64 500 (32000)
8 ip2 InnerProduct ip1 ip2 64 10 (640)
9 loss SoftmaxWithLoss ip2&&label loss (1)

注:Top Blob Shape格式為:BatchSize,ChannelSize凛篙,Height黍匾,Width(Total Count)

3 第一層:Data Layer

3.1 protobuff定義

訓(xùn)練網(wǎng)絡(luò)的第一層protobuff定義為:

layer {
  name: "mnist"
  type: "Data"
  top: "data"
  top: "label"
  include {
    phase: TRAIN
  }
  transform_param {
    scale: 0.00390625
  }
  data_param {
    source: "examples/mnist/mnist_train_lmdb"
    batch_size: 64
    backend: LMDB
  }
}

3.2 函數(shù)LayerRegistry::CreateLayer

第1節(jié)中代碼第一次通過調(diào)用LayerRegistry::CreateLayer()創(chuàng)建了DataLayer類,DataLayer類的繼承關(guān)系如下圖所示呛梆,詳見[1]:

由繼承圖可知锐涯,調(diào)用DataLayer()的構(gòu)造函數(shù),依次執(zhí)行的順序?yàn)槠浠悩?gòu)造函數(shù):Layer()填物、BaseDataLayer()纹腌、InternalThread()(詳見(Caffe)基本類InternalThread(三) )、BasePrefetchingDataLayer()滞磺、及DataLayer()升薯。

其中,值得注意的是DataLayer()击困,在調(diào)用基類構(gòu)造函數(shù)BasePrefetchingDataLayer()之后涎劈,對(duì) DataReader reader_ 進(jìn)行賦值,在該DataLayer對(duì)象中維護(hù)了一個(gè)DataReader對(duì)象reader_,其作用是添加讀取數(shù)據(jù)任務(wù)至炮障,一個(gè)專門讀取數(shù)據(jù)庫(examples/mnist/mnist_train_lmdb)的線程(若還不存在該線程目派,則創(chuàng)建該線程)坤候,此處一共取出了4*64個(gè)樣本至BlockingQueue<Datum*> DataReader::QueuePair::full_。詳見(Caffe)基本類DataReader企蹭、QueuePair白筹、Body(四)

template <typename Dtype>
DataLayer<Dtype>::DataLayer(const LayerParameter& param)
  : BasePrefetchingDataLayer<Dtype>(param),
    reader_(param) {
}

3.3 函數(shù)Layer::SetUp

  • 此處按程序執(zhí)行順序值得關(guān)注的有:
    DataLayer::DataLayerSetUp中根據(jù)3.2DataReader中介紹的讀取的數(shù)據(jù)中取出一個(gè)樣本推測blob的形狀

  • BasePrefetchingDataLayer::LayerSetUp如下代碼prefetch_[i].data_.mutable_cpu_data()用到了涉及到gpu、cpu間復(fù)制數(shù)據(jù)的問題谅摄,見(Caffe)基本類Blob徒河,Layer,Net(一)1.4SyncedMemory及引用[2]

     // Before starting the prefetch thread, we make cpu_data and gpu_data
     // calls so that the prefetch thread does not accidentally make simultaneous
     // cudaMalloc calls when the main thread is running. In some GPUs this
     // seems to cause failures if we do not so.
     for (int i = 0; i < PREFETCH_COUNT; ++i) {
       prefetch_[i].data_.mutable_cpu_data();
       if (this->output_labels_) {
         prefetch_[i].label_.mutable_cpu_data();
       }
     }
    
  • BasePrefetchingDataLayer類繼承了InternalThread送漠,BasePrefetchingDataLayer<Dtype>::LayerSetUp中通過調(diào)用StartInternalThread()開啟了一個(gè)新線程顽照,從而執(zhí)行BasePrefetchingDataLayer::InternalThreadEntry

  • BasePrefetchingDataLayer::InternalThreadEntry關(guān)鍵代碼如下,其中load_batch(batch)為闽寡,從2.2介紹的BlockingQueue<Datum*> DataReader::QueuePair::full_(包含從數(shù)據(jù)庫讀出的數(shù)據(jù))中讀取一個(gè)batch_size的數(shù)據(jù)到BlockingQueue<Batch<Dtype>*> BasePrefetchingDataLayer::prefetch_full_中代兵。由于該線程在prefetch_free_為空時(shí)將掛起等待(PREFETCH_COUNT=3),prefetch_full_中用完的Batch將放回prefetch_free_中爷狈。<u>該線程何時(shí)停止植影?</u>

        while (!must_stop()) {
          Batch<Dtype>* batch = prefetch_free_.pop();
          load_batch(batch);
    #ifndef CPU_ONLY
          if (Caffe::mode() == Caffe::GPU) {
            batch->data_.data().get()->async_gpu_push(stream);
            CUDA_CHECK(cudaStreamSynchronize(stream));
          }
    #endif
          prefetch_full_.push(batch);
        }
    

關(guān)于線程的總結(jié)

  1. 此外一共涉及到兩個(gè)線程,分別為都是繼承了InnerThreadBasePrefetchingDataLayer(DataLayer)類和DataReader中的Body
  2. Body為面向數(shù)據(jù)庫的線程涎永,不斷從某個(gè)數(shù)據(jù)庫中讀出數(shù)據(jù)思币,存放至緩存為隊(duì)列DataReader::QueuePair::BlockingQueue<Datum*>,一般保存4*64個(gè)單位數(shù)據(jù)羡微,單位為Datum
  3. BasePrefetchingDataLayer為面向網(wǎng)絡(luò)的線程谷饿,從Body的緩存中不斷讀取數(shù)據(jù)。BasePrefetchingDataLayer的緩存為隊(duì)列BlockingQueue<Batch*>妈倔,一般存放3個(gè)單位的數(shù)據(jù)博投,單位為Batch
static const int PREFETCH_COUNT = 3;
Batch<Dtype> prefetch_[PREFETCH_COUNT];
BlockingQueue<Batch<Dtype>*> prefetch_free_;
BlockingQueue<Batch<Dtype>*> prefetch_full_;

template <typename Dtype>
BasePrefetchingDataLayer<Dtype>::BasePrefetchingDataLayer(
    const LayerParameter& param)
    : BaseDataLayer<Dtype>(param),
      prefetch_free_(), prefetch_full_() {
  for (int i = 0; i < PREFETCH_COUNT; ++i) {
    prefetch_free_.push(&prefetch_[i]);
  }
}
  • prefetch_full_prefetch_free_中的元素由prefetch_提供

4 第二層:Convolution Layer

4.1 protobuff定義

layer {
  name: "conv1"
  type: "Convolution"
  bottom: "data"
  top: "conv1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  convolution_param {
    num_output: 20
    kernel_size: 5
    stride: 1
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}

4.2 函數(shù)LayerRegistry::CreateLayer

這里寫圖片描述

說明:

  1. 不像DataLayer 直接執(zhí)行的是構(gòu)造函數(shù),此時(shí)執(zhí)行的是GetConvolutuionLayer()启涯,然后調(diào)用ConvolutionLayer()贬堵,原因如下:

REGISTER_LAYER_CREATOR(Convolution, GetConvolutionLayer);

4.3 Layer::SetUp

Layer::SetUp中,調(diào)用了ConvolutionLayer的基類BaseConvolutionLayerLayerSetUp及Reshape函數(shù)结洼,該類的主要成員變量如下:

/**
 * @brief Abstract base class that factors out the BLAS code common to
 *        ConvolutionLayer and DeconvolutionLayer.
 */
template <typename Dtype>
class BaseConvolutionLayer : public Layer<Dtype> {
 public:
  explicit BaseConvolutionLayer(const LayerParameter& param)
      : Layer<Dtype>(param) {}
  virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);
  virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
      const vector<Blob<Dtype>*>& top);

 ...
  /// @brief The spatial dimensions of a filter kernel.
  Blob<int> kernel_shape_;
  /// @brief The spatial dimensions of the stride.
  Blob<int> stride_;
  /// @brief The spatial dimensions of the padding.
  Blob<int> pad_;
  /// @brief The spatial dimensions of the dilation.
  Blob<int> dilation_;
  /// @brief The spatial dimensions of the convolution input.
  Blob<int> conv_input_shape_;
  /// @brief The spatial dimensions of the col_buffer.
  vector<int> col_buffer_shape_;
  /// @brief The spatial dimensions of the output.
  vector<int> output_shape_;
  const vector<int>* bottom_shape_;
...
};

說明:

  1. LayerSetUp函數(shù)中黎做,主要是初始化了kernel_shape_、stride_松忍、pad_蒸殿、dilation_以及初始化網(wǎng)絡(luò)參數(shù),并存放與Layer::blobs_中。
  2. Reshape函數(shù)中宏所,conv_input_shape_酥艳、bottom_shape_等

5 第三層:Pooling Layer

5.1 protobuff定義

layer {
  name: "pool1"
  type: "Pooling"
  bottom: "conv1"
  top: "pool1"
  pooling_param {
    pool: MAX
    kernel_size: 2
    stride: 2
  }
}

5.2 Layer::SetUp

通過調(diào)用虛函數(shù)LayerSetUpReshape對(duì)以下成員變量進(jìn)行初始化

/**
 * @brief Pools the input image by taking the max, average, etc. within regions.
 *
 * TODO(dox): thorough documentation for Forward, Backward, and proto params.
 */
template <typename Dtype>
class PoolingLayer : public Layer<Dtype> {
 ....
  int kernel_h_, kernel_w_;
  int stride_h_, stride_w_;
  int pad_h_, pad_w_;
  int channels_;
  int height_, width_;
  int pooled_height_, pooled_width_;
  bool global_pooling_;
  Blob<Dtype> rand_idx_;
  Blob<int> max_idx_;
};

6 第四層、第五層

基本同第二層爬骤、第三層

7 第六層:InnerProduct Layer

7.1 protobuff定義

layer {
  name: "ip1"
  type: "InnerProduct"
  bottom: "pool2"
  top: "ip1"
  param {
    lr_mult: 1
  }
  param {
    lr_mult: 2
  }
  inner_product_param {
    num_output: 500
    weight_filler {
      type: "xavier"
    }
    bias_filler {
      type: "constant"
    }
  }
}

7.2 Layer::SetUp

/**
 * @brief Also known as a "fully-connected" layer, computes an inner product
 *        with a set of learned weights, and (optionally) adds biases.
 *
 * TODO(dox): thorough documentation for Forward, Backward, and proto params.
 */
template <typename Dtype>
class InnerProductLayer : public Layer<Dtype> {
 ...
  int M_;
  int K_;
  int N_;
  bool bias_term_;
  Blob<Dtype> bias_multiplier_;
};

說明:

  1. N_為輸出大小充石,即等于protobuff中定義的num_output
  2. K_為輸入大小,對(duì)于該層Bottom Blob形狀為(N, C, H, W)霞玄,N為batch_size骤铃,K_=CHW(Caffe)基本類Blob,Layer坷剧,Net(一)惰爬,M_=N。其中只有C惫企、H撕瞧、W跟內(nèi)積相關(guān)

8 第七層:ReLU Layer

8.1 protobuff定義

layer {
  name: "relu1"
  type: "ReLU"
  bottom: "ip1"
  top: "ip1"
}

8.2 說明

ReLULayer主要是用來做計(jì)算的,其繼承關(guān)系如下狞尔,詳細(xì)參加[4]丛版、[5]

9 第八層:InnerProduct Layer

參見第7節(jié)

10 第九層:SoftmaxWithLoss Layer

10.1 protobuff定義

layer {
  name: "loss"
  type: "SoftmaxWithLoss"
  bottom: "ip2"
  bottom: "label"
  top: "loss"
}

10.2 LayerRegistry::CreateLayer

這里寫圖片描述

10.3 Layer::SetUp

值得注意的是:

  1. SoftmaxWithLossLayer包含類SoftmaxLayer的實(shí)例
    shared_ptr<Layer<Dtype> > softmax_layer_

  2. softmax_layer_LayerSetUp中賦值。

  3. 此函數(shù)內(nèi)調(diào)用Layer::SetLossWeights初始化了該層的Top Blob(loss)

  4. 兩個(gè)類間的關(guān)系如下圖:

    這里寫圖片描述
  5. 成員變量prob_作為Softmaxlayer的top blob

  6. bottom blob[0]作為softmaxlayer的bottom blob

  7. 所以經(jīng)過softmaxlayer計(jì)算之后沪么,得出64*10(每個(gè)樣本的每個(gè)類別上的概率)存放在prob_中

11 剩余的工作

至此硼婿,訓(xùn)練網(wǎng)絡(luò)基本創(chuàng)建完畢,接下來剩下的工作主要有:

  1. 反向檢查一次網(wǎng)絡(luò)禽车,看哪些blobs會(huì)對(duì)loss產(chǎn)生影響寇漫,在LeNet5中,前面的9層均有影響
  2. 初始化權(quán)值共享

[1].http://caffe.berkeleyvision.org/doxygen/classcaffe_1_1BasePrefetchingDataLayer.html
[2].http://caffe.berkeleyvision.org/tutorial/net_layer_blob.html Implementation Details
[3].http://caffe.berkeleyvision.org/doxygen/classcaffe_1_1ConvolutionLayer.html
[4].http://caffe.berkeleyvision.org/doxygen/classcaffe_1_1ReLULayer.html
[5].http://caffe.berkeleyvision.org/tutorial/layers.html ReLU / Rectified-Linear and Leaky-ReLU

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末殉摔,一起剝皮案震驚了整個(gè)濱河市州胳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌逸月,老刑警劉巖栓撞,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碗硬,居然都是意外死亡瓤湘,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門恩尾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弛说,“玉大人,你說我怎么就攤上這事翰意∧救耍” “怎么了信柿?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長醒第。 經(jīng)常有香客問我渔嚷,道長,這世上最難降的妖魔是什么稠曼? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任形病,我火速辦了婚禮,結(jié)果婚禮上蒲列,老公的妹妹穿的比我還像新娘窒朋。我一直安慰自己搀罢,他們只是感情好蝗岖,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著榔至,像睡著了一般抵赢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上唧取,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天铅鲤,我揣著相機(jī)與錄音,去河邊找鬼枫弟。 笑死邢享,一個(gè)胖子當(dāng)著我的面吹牛宙暇,可吹牛的內(nèi)容都是我干的胆剧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼核无,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼韩容!你這毒婦竟也來了款违?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤群凶,失蹤者是張志新(化名)和其女友劉穎插爹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體请梢,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡赠尾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毅弧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片气嫁。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖形真,靈堂內(nèi)的尸體忽然破棺而出杉编,到底是詐尸還是另有隱情超全,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布邓馒,位于F島的核電站嘶朱,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏光酣。R本人自食惡果不足惜疏遏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望救军。 院中可真熱鬧财异,春花似錦、人聲如沸唱遭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拷泽。三九已至疫鹊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間司致,已是汗流浹背拆吆。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脂矫,地道東北人枣耀。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像庭再,于是被迫代替她去往敵國和親捞奕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容