caffe-Layer中有什么

一个Layer对象以一个Blob为输入(bottom),另一个Blob为输出(top)。主要机选包括前向计算和后向计算:前向计算对输入blob进行处理,得到输出blob。后向计算对输出blob的diff部分做处理得到输入blob的diff。

注意了,caffe中的topbottom都是vector<shared_ptr<Blob<Dtype>>>其元素为多个指向blob的指针。而并非值一个blob对象!

既然blobs_是训练参数,那么向该层输入的数据在哪???

下面内容位于Layer.hpp文件。

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
class Layer {
// 先看类成员属性,以下划线结尾的变量,对类内可见,对该类之外不可见。
protected:
// 保存该层参数的 protobuf
// LayerParameter类声明在这里:
// .build_release/src/caffe/proto/caffe.pb.h 这是编译后自动生成的文件
LayerParameter layer_param_;
// 这层所处是哪个阶段,train OR test
Phase phase_;
// 多个Blob指针,指向这层内部的学习参数
vector<shared_ptr<Blob<Dtype>>> blobs_;
// 是否计算对应参数的误差梯度
vector<bool> param_propagate_down_;
// 目标函数中是否每个Top blob都有非零权值
vector<Dtype> loss_;

// 上述三个vector的长度一样!

public:
// 构造,从LayerParameter对象中加载参数
explicit Layer(const LayerParameter& param)
: layer_param_(param) {
// 设置阶段
phase_ = param.phase();
// 如果有数据,则设置blob,具体是从磁盘读取到这个Layer的blob
if (layer_param_.blobs_size() > 0) {
// WHY blob的个数resize到blob的大小 ???
blobs_.resize(layer_param_.blobs_size());
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
// 这个blob[i]指针接管一个新的blob指针
blobs_[i].reset(new Blob<Dtype>());
// 从磁盘读取数据到当前blob[i]
blobs_[i]->FromProto(layer_param_.blobs(i));
}
}
}
virtual ~Layer() {}

// 不能覆盖这个方法,提供4个功能
void SetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
//1. 检查bottom 和topblob是否满足这层的要求
CheckBlobCounts(bottom, top);
//2. 调用自己实现的层配置函数
LayerSetUp(bottom, top);
//3. 对输出blob 变形
Reshape(bottom, top);
//4.
SetLossWeights(top);
}

// 层的相关配置,由自己实现(子类实现)
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {}

// 自己实现(子类实现),调整top blob和中间buffer的形状
// 以适应bottom blob的形状。纯虚函数
virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) = 0;


// 根据bottom blob 计算top blob和loss。返回这一层的总loss。
// 该函数调用Forward_cpu()和Forward_gpu()执行真正的计算;
// 如果该层有非零权值,则计算并返回loss。
// 在子类实现Forward_cpu()和Forward_gpu()。毕竟不同层的计算方式不同。
inline Dtype Forward(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);


// 反向传播计算,给定top 的梯度,计算bottom的梯度。
// 参数中top 中含有上层来的梯度误差diff
// propagate_down 其长度与bottom长度相同,
// 其中每一个值表示是否将对应的误差传到对应的bottom。
// bottom 输入blobs,经过Backward()计算后, 其diff 保存误差梯度,
// 实际上的后向传播的执行由Backward_cpu() 和 Backward_gpu()实现。
// 子类需要实现Backward_cpu() 和 Backward_gpu()
inline void Backward(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom);

// 返回这层中可训练参数 blob向量
vector<shared_ptr<Blob<Dtype> > >& blobs() {
return blobs_;
}

// 返回该层的 曾参数(由protobuff提供)
const LayerParameter& layer_param() const {
return layer_param_;
}

// 将该层层参数写入 protobuff
virtual void ToProto(LayerParameter* param, bool write_diff = false);

// 返回top指定index的blob的loss值
inline Dtype loss(const int top_index) const {
return (loss_.size() > top_index) ? loss_[top_index] : Dtype(0);
}

// 为top指定index的blob的loss 设值
inline void set_loss(const int top_index, const Dtype value) {
if (loss_.size() <= top_index) {
loss_.resize(top_index + 1, Dtype(0));
}
loss_[top_index] = value;
}

// 返回该层的类型
virtual inline const char* type() const { return ""; }

// 返回该层需要输入或输出的blobs数,由子类实现。
virtual inline int ExactNumBottomBlobs() const { return -1; }
virtual inline int MinBottomBlobs() const { return -1; }
virtual inline int MaxBottomBlobs() const { return -1; }
virtual inline int ExactNumTopBlobs() const { return -1; }
virtual inline int MinTopBlobs() const { return -1; }
virtual inline int MaxTopBlobs() const { return -1; }

// 该层的top blobs个数和bottom blobs个数是否相同。子类实现
virtual inline bool EqualNumBottomTopBlobs() const { return false; }


// 是否需要自动创造匿名top blobs,
// 如果返回true,Net::Init()会创建足够多的匿名top blobs来满足
// ExactNumTopBlobs() 或MinTopBlobs().
virtual inline bool AutoTopBlobs() const { return false; }


virtual inline bool AllowForceBackward(const int bottom_index) const {
return true;
}

inline bool param_propagate_down(const int param_id) {
return (param_propagate_down_.size() > param_id) ?
param_propagate_down_[param_id] : false;
}

inline void set_param_propagate_down(const int param_id, const bool value) {
if (param_propagate_down_.size() <= param_id) {
param_propagate_down_.resize(param_id + 1, true);
}
param_propagate_down_[param_id] = value;
}

protected:

// cpu和gpu 前行计算,其具体实现在具体的层中,将一直看到
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) = 0;
virtual void Forward_gpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
// LOG(WARNING) << "Using CPU code as backup.";
return Forward_cpu(bottom, top);
}
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) = 0;
virtual void Backward_gpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) {
// LOG(WARNING) << "Using CPU code as backup.";
Backward_cpu(top, propagate_down, bottom);
}

/**
* Called by the parent Layer's SetUp to check that the number of bottom
* and top Blobs provided as input match the expected numbers specified by
* the {ExactNum,Min,Max}{Bottom,Top}Blobs() functions.
*/
// 最后两个函数由父类Layer 的SetUp()函数调用
virtual void CheckBlobCounts(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
if (ExactNumBottomBlobs() >= 0) {
CHECK_EQ(ExactNumBottomBlobs(), bottom.size())
<< type() << " Layer takes " << ExactNumBottomBlobs()
<< " bottom blob(s) as input.";
}
if (MinBottomBlobs() >= 0) {
CHECK_LE(MinBottomBlobs(), bottom.size())
<< type() << " Layer takes at least " << MinBottomBlobs()
<< " bottom blob(s) as input.";
}
if (MaxBottomBlobs() >= 0) {
CHECK_GE(MaxBottomBlobs(), bottom.size())
<< type() << " Layer takes at most " << MaxBottomBlobs()
<< " bottom blob(s) as input.";
}
if (ExactNumTopBlobs() >= 0) {
CHECK_EQ(ExactNumTopBlobs(), top.size())
<< type() << " Layer produces " << ExactNumTopBlobs()
<< " top blob(s) as output.";
}
if (MinTopBlobs() >= 0) {
CHECK_LE(MinTopBlobs(), top.size())
<< type() << " Layer produces at least " << MinTopBlobs()
<< " top blob(s) as output.";
}
if (MaxTopBlobs() >= 0) {
CHECK_GE(MaxTopBlobs(), top.size())
<< type() << " Layer produces at most " << MaxTopBlobs()
<< " top blob(s) as output.";
}
if (EqualNumBottomTopBlobs()) {
CHECK_EQ(bottom.size(), top.size())
<< type() << " Layer produces one top blob as output for each "
<< "bottom blob input.";
}
}

/**
* Called by SetUp to initialize the weights associated with any top blobs in
* the loss function. Store non-zero loss weights in the diff blob.
*/
inline void SetLossWeights(const vector<Blob<Dtype>*>& top) {
const int num_loss_weights = layer_param_.loss_weight_size();
if (num_loss_weights) {
CHECK_EQ(top.size(), num_loss_weights) << "loss_weight must be "
"unspecified or specified once per top blob.";
for (int top_id = 0; top_id < top.size(); ++top_id) {
const Dtype loss_weight = layer_param_.loss_weight(top_id);
if (loss_weight == Dtype(0)) { continue; }
this->set_loss(top_id, loss_weight);
const int count = top[top_id]->count();
Dtype* loss_multiplier = top[top_id]->mutable_cpu_diff();
caffe_set(count, loss_weight, loss_multiplier);
}
}
}

private:
DISABLE_COPY_AND_ASSIGN(Layer);
}; // class Layer

Layer.cpp文件内容:可见Layer的真正实现都在其子类中:src/caffe/layers/*.cpp

1
2
3
4
#include "caffe/layer.hpp"
namespace caffe {
INSTANTIATE_CLASS(Layer);
}

其中:

1
2
3
4
5
// Instantiate a class with float and double specifications.
#define INSTANTIATE_CLASS(classname) \
char gInstantiationGuard##classname; \
template class classname<float>; \
template class classname<double>