您的位置:首页 > 理论基础 > 计算机网络

【Caffe代码解析】Layer网络层

2016-10-10 10:21 295 查看
Layer 功能:

是所有的网络层的基类,其中,定义了一些通用的接口,比如前馈,反馈,reshape,setup等。

#ifndef CAFFE_LAYER_H_
#define CAFFE_LAYER_H_

#include <algorithm>
#include <string>
#include <vector>

#include "caffe/blob.hpp"
#include "caffe/common.hpp"
#include "caffe/layer_factory.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/device_alternate.hpp"

namespace caffe {
// 功能:所有的网络层的基类,定义的所有的网络层的通用接口。
// 前馈接口,必须实现
// 反馈接口,需要的时候实现,计算梯度。
template <typename Dtype>
class Layer {
public:
/**
* 每个网络层需要自己定义它的setup而不需要构造函数
*/
explicit Layer(const LayerParameter& param)
: layer_param_(param) {
//通过网络层参数来构造网络层
phase_ = param.phase();
if (layer_param_.blobs_size() > 0) {
blobs_.resize(layer_param_.blobs_size());
for (int i = 0; i < layer_param_.blobs_size(); ++i) {
blobs_[i].reset(new Blob<Dtype>());
blobs_[i]->FromProto(layer_param_.blobs(i));
}
}
}
// 析构函数
virtual ~Layer() {}

/**
* 实现一些通用的设置功能
*
* @param bottom 网络层的输入的shape
* @param top 网络层的输出,需要被reshape
* 调用 LayerSetUp 来对每一个网络层进行特殊化的处理,
* 调用reshape top
* 设置 数值权重
* 这个方法可以不被重载。
*/
void SetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
CheckBlobCounts(bottom, top);
LayerSetUp(bottom, top);
Reshape(bottom, top);
SetLossWeights(top);
}

/**
* @brief 设置一些层相关的设置,定义的层需要实现这个方法以及Reshape方法
*/
//设置网络层
virtual void LayerSetUp(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {}
/**
* @brief 调整top blob以适应bottom blob。
*/
virtual void Reshape(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) = 0;

/**
* @brief 给定 bottom blobs, 计算 top blobs 以及 loss.
* 每一个网络层都需要定义cpu版本的前馈,可选gpu版本的前馈
*/
//前馈
inline Dtype Forward(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top);

/**
* @brief 给定 top blob 的梯度, 计算 bottom blob 梯度.
* @param propagate_down 向量,长度为ibottom   的个数,每个索引值表示是是否将损失梯度值反馈到该bottom中
*/
//反馈
inline void Backward(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom);

/**
* @brief 返回可学习的参数 blobs.
*/
vector<shared_ptr<Blob<Dtype> > >& blobs() {
return blobs_;
}

/**
* @brief 返回网络层参数
*/
const LayerParameter& layer_param() const { return layer_param_; }
//序列化
virtual void ToProto(LayerParameter* param, bool write_diff = false);

/**
* @brief 返回指定索引的标量损失值。
*/
inline Dtype loss(const int top_index) const {
return (loss_.size() > top_index) ? loss_[top_index] : Dtype(0);
}

/**
* @brief 设置网络层制定索引位置的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;
}

/**
* @brief 返回网络层名字,字符串描述u
*/
virtual inline const char* type() const { return ""; }
//Bottom的blob的确切数目
virtual inline int ExactNumBottomBlobs() const { return -1; }
//Bottom blob的最小数目
virtual inline int MinBottomBlobs() const { return -1; }
//Botttom的确切数目
virtual inline int MaxBottomBlobs() const { return -1; }
//Top Blob的确切数目
virtual inline int ExactNumTopBlobs() const { return -1; }
//最小的blob的数目
virtual inline int MinTopBlobs() const { return -1; }
// 最大的blob的数目
virtual inline int MaxTopBlobs() const { return -1; }
// 是否bottom 和top的数目相同
virtual inline bool EqualNumBottomTopBlobs() const { return false; }
// 是否自动Top blob
virtual inline bool AutoTopBlobs() const { return false; }
//查询某一个bottom是否强制bp
virtual inline bool AllowForceBackward(const int bottom_index) const {
return true;
}
//查询某一个blob是否bp
inline bool param_propagate_down(const int param_id) {
return (param_propagate_down_.size() > param_id) ?
param_propagate_down_[param_id] : false;
}
//设置某一个blob是否bp。
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:
// 网络层参数
LayerParameter layer_param_;
// 模式
Phase phase_;
//用blob来存储一系列向量
vector<shared_ptr<Blob<Dtype> > > blobs_;
//是否bp的向量
vector<bool> param_propagate_down_;
//存储top的loss
vector<Dtype> loss_;
//cpu版本的前馈实现
virtual void Forward_cpu(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) = 0;
//gpu版本的前馈实现
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);
}
//cpu版本的前馈实现
virtual void Backward_cpu(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) = 0;
//gpu版本的反馈实现
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);
}
// 核查bootom和top的大小是否与该layer层指定的一致。
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.";
}
}
// 用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);
}
}
}

DISABLE_COPY_AND_ASSIGN(Layer);
};  // class Layer

// 前馈,根据caffe的mode 调用相对应的cpu实现或者是gpu实现,并且计算损失函数值。
template <typename Dtype>
inline Dtype Layer<Dtype>::Forward(const vector<Blob<Dtype>*>& bottom,
const vector<Blob<Dtype>*>& top) {
Dtype loss = 0;
Reshape(bottom, top);
switch (Caffe::mode()) {
case Caffe::CPU:
Forward_cpu(bottom, top);
for (int top_id = 0; top_id < top.size(); ++top_id) {
if (!this->loss(top_id)) { continue; }
const int count = top[top_id]->count();
const Dtype* data = top[top_id]->cpu_data();
const Dtype* loss_weights = top[top_id]->cpu_diff();
loss += caffe_cpu_dot(count, data, loss_weights);
}
break;
case Caffe::GPU:
Forward_gpu(bottom, top);
#ifndef CPU_ONLY
for (int top_id = 0; top_id < top.size(); ++top_id) {
if (!this->loss(top_id)) { continue; }
const int count = top[top_id]->count();
const Dtype* data = top[top_id]->gpu_data();
const Dtype* loss_weights = top[top_id]->gpu_diff();
Dtype blob_loss = 0;
caffe_gpu_dot(count, data, loss_weights, &blob_loss);
loss += blob_loss;
}
#endif
break;
default:
LOG(FATAL) << "Unknown caffe mode.";
}
return loss;
}

//反向传播梯度,根据Caffe的mode是在GPU还是CPU,调用相对应版本的函数
//propagate_down 用于控制对应的层是否bp
template <typename Dtype>
inline void Layer<Dtype>::Backward(const vector<Blob<Dtype>*>& top,
const vector<bool>& propagate_down,
const vector<Blob<Dtype>*>& bottom) {
switch (Caffe::mode()) {
case Caffe::CPU:
Backward_cpu(top, propagate_down, bottom);
break;
case Caffe::GPU:
Backward_gpu(top, propagate_down, bottom);
break;
default:
LOG(FATAL) << "Unknown caffe mode.";
}
}

// 序列化网络层参数到协议缓存,最终是调用blob写入协议缓存。
template <typename Dtype>
void Layer<Dtype>::ToProto(LayerParameter* param, bool write_diff) {
param->Clear();
param->CopyFrom(layer_param_);
param->clear_blobs();
for (int i = 0; i < blobs_.size(); ++i) {
blobs_[i]->ToProto(param->add_blobs(), write_diff);
}
}

}  // namespace caffe

#endif  // CAFFE_LAYER_H_
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314

版权声明:本文为博主原创文章,未经博主允许不得转载。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: