caffe-Net.hpp

从prototxt文件解析Net的结构,以 Lenet 为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <vector>
#include <caffe/blob.hpp>
#include <caffe/net.hpp>
#include <caffe/util/io.hpp>

using namespace caffe;
using namespace std;

int main() {
// prototxt文件路径
std::string proto("../Lenet.prototxt");
// 创造一个Net对象。phase设为TEST,测试网络
Net<float> nn(proto, caffe::TEST);
// 获取这个Net的layer names:
vector<string> ln = nn.layer_names();
for(auto i:ln){
cout<<i<<" ";
}
cout<<endl;
// 取这个Net的`blob_names`
vector<string> bn = nn.blob_names();
for(auto i:bn){
cout<<i<<" ";
}
cout<<endl;
return 0;
}

返回这个 TEST Net 中的blob name:

1
2
3
4
# layer names
mnist conv1 pool1 conv2 pool2 ip1 relu1 ip2 loss
# blob names
data label conv1 pool1 conv2 pool2 ip1 ip2 loss

BLob对象存放每个Layer的输出和输入结果。每个Layer对输入Blob进行某种计算。layer name 和 blob names 不存在任何关系。所有的Layer和Blob用名字区分,

先看一个Net对象都有什么成员属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
protected
// 这个 Net 的名称
string name_;
// 这个 Net 用于 TRAIN or TEST
Phase phase_;
// 记录这个 Net 中的每一层
vector<shared_ptr<Layer<Dtype>>> layers_;
// 记录每一层的名称
vector<string> layer_names_;
// 记录每一层与其位置Index的对应关系
map<string, int> layer_names_index_;
// 记录每层是否需要反向传播
vector<bool> layer_need_backward_;

// 存储层之间的中间结果
vector<shared_ptr<Blob<Dtype>>> blobs_;
// 记录每个blob的名称
vector<string> blob_names_;
// 记录每个Blob与其位置Index的对应关系
map<string, int> blob_names_index_;
// 记录每个blob是否需要反向计算
vector<bool> blob_need_backward_;
/// bottom_vecs stores the vectors containing the input for each layer.
/// They don't actually host the blobs (blobs_ does), so we simply store
/// pointers.
// 记录每个Layer的输入Blob,但并不是Blob的内容,而是Blob的地址。
vector<vector<Blob<Dtype>*>> bottom_vecs_;
// 与上者相关,
vector<vector<int>> bottom_id_vecs_;
vector<vector<bool>> bottom_need_backward_;
/// top_vecs stores the vectors containing the output for each layer
vector<vector<Blob<Dtype>*>> top_vecs_;
vector<vector<int>> top_id_vecs_;
/// Vector of weight in the loss (or objective) function of each net blob,
/// indexed by blob_id.
vector<Dtype> blob_loss_weights_;

vector<vector<int>> param_id_vecs_;
vector<int> param_owners_;
vector<string> param_display_names_;
vector<pair<int, int>> param_layer_indices_;
map<string, int> param_names_index_;

/// blob indices for the input and the output of the net
// 这个Net 的输入输出Blob 在 blobs_ 中的索引
vector<int> net_input_blob_indices_;
vector<int> net_output_blob_indices_;
// 输入输出Blob
vector<Blob<Dtype>*> net_input_blobs_;
vector<Blob<Dtype>*> net_output_blobs_;

// 这个 Net 中的参数,权值
vector<shared_ptr<Blob<Dtype>>> params_;
// 这个 Net 中可训练的权值
vector<Blob<Dtype>*> learnable_params_;
/**
* The mapping from params_ -> learnable_params_: we have
* learnable_param_ids_.size() == params_.size(),
* and learnable_params_[learnable_param_ids_[i]] == params_[i].get()
* if and only if params_[i] is an "owner"; otherwise, params_[i] is a sharer
* and learnable_params_[learnable_param_ids_[i]] gives its owner.
*/
vector<int> learnable_param_ids_;
/// the learning rate multipliers for learnable_params_
vector<float> params_lr_;
vector<bool> has_params_lr_;
/// the weight decay multipliers for learnable_params_
vector<float> params_weight_decay_;
vector<bool> has_params_decay_;
/// The bytes of memory used by this net
size_t memory_used_;
/// Whether to compute and display debug info for the net.
bool debug_info_;
// Callbacks
vector<Callback*> before_forward_;
vector<Callback*> after_forward_;
vector<Callback*> before_backward_;
vector<Callback*> after_backward_;

说明一下:

  • 其实并不能单单从属性的名字中知道它是干啥的。其与原理相关,需要在试验中分析每个属性的作用。
  • 上述属性中大部分是vector容器,所以猜想,每个容器存放这个Net的所有Layer的对应属性。
  • 上述大部分的类属性都有一个getter()函数,返回这个Net中每个对象。

Net中由两类Blob,以param开头的是权值Blob;以blob开头的是数据Blob。前者决定了模型是什么样的,后者是每一个Layer的输入和输出(样本数据),是这个Net中被处理的数据。