【Caffe代码解析】Layer网络层
2016-10-10 10:21
295 查看
Layer 功能:
是所有的网络层的基类,其中,定义了一些通用的接口,比如前馈,反馈,reshape,setup等。
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
版权声明:本文为博主原创文章,未经博主允许不得转载。
是所有的网络层的基类,其中,定义了一些通用的接口,比如前馈,反馈,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
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- 【Caffe代码解析】Layer网络层
- 代码笔记:caffe-reid中reid_data_layer源码解析
- Caffe-代码解析-Layer
- 代码笔记:caffe-reid中PairEuclideanLayer源码解析
- 神经网络:caffe特征可视化的代码样例
- 第一行代码总结:10网络:10.3解析XML格式数据:
- caffe深度学习网络relu层代码注释
- Caffe-代码解析-compute_image_mean
- caffe源码解析之添加新的Layer(maxout)
- 访问网络数据+json解析代码片段
- 神经网络 caffe 的 vs2013 版本代码
- Caffe源码解析3:Layer
- NetReceive函数--精简的网络数据包解析代码,支持802,VLAN
- Caffe源码解析4: Data_layer
- [Caffe]源码解析之Layer
- Caffe源码解析7:Pooling_Layer
- 第一行代码总结:10网络:10.3.2 SAX解析方式
- caffe源码解析之Layer层(1)
- android 网络图片路径解析和本地图片路径解析的方法 ,base64加密报文解析成bitmap【代码示例】
- Caffe-代码解析-Blob