tiny_dnn 1.0.0
A header only, dependency-free deep learning framework in C++11
Loading...
Searching...
No Matches
average_pooling_layer.h
1/*
2 Copyright (c) 2013, Taiga Nomi
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
17 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#pragma once
28
29#include <string>
30#include <vector>
31#include <algorithm>
32
33#include "tiny_dnn/util/util.h"
34#include "tiny_dnn/util/image.h"
35#include "tiny_dnn/layers/partial_connected_layer.h"
36#include "tiny_dnn/activations/activation_function.h"
37
38namespace tiny_dnn {
39
40// forward_propagation
41template <typename Activation>
42void tiny_average_pooling_kernel(bool parallelize,
43 const std::vector<tensor_t*>& in_data,
44 std::vector<tensor_t*>& out_data,
45 const shape3d& out_dim,
46 float_t scale_factor,
47 std::vector<typename partial_connected_layer<Activation>::wi_connections>& out2wi,
48 Activation& h) {
49
50 for_i(in_data[0]->size(), [&](size_t sample) {
51 const vec_t& in = (*in_data[0])[sample];
52 const vec_t& W = (*in_data[1])[0];
53 const vec_t& b = (*in_data[2])[0];
54 vec_t& out = (*out_data[0])[sample];
55 vec_t& a = (*out_data[1])[sample];
56
57 auto oarea = out_dim.area();
58 size_t idx = 0;
59 for (serial_size_t d = 0; d < out_dim.depth_; ++d) {
60 float_t weight = W[d] * scale_factor;
61 float_t bias = b[d];
62 for (serial_size_t i = 0; i < oarea; ++i, ++idx) {
63 const auto& connections = out2wi[idx];
64 float_t value = float_t(0);
65 for (auto connection : connections)// 13.1%
66 value += in[connection.second]; // 3.2%
67 value *= weight;
68 value += bias;
69 a[idx] = value;
70 }
71 }
72
73 assert(out.size() == out2wi.size());
74 for (serial_size_t i = 0; i < static_cast<serial_size_t>(out2wi.size()); i++) {
75 out[i] = h.f(a, i);
76 }
77 });
78}
79
80// back_propagation
81template<typename Activation>
82void tiny_average_pooling_back_kernel(const std::vector<tensor_t*>& in_data,
83 const std::vector<tensor_t*>& out_data,
84 std::vector<tensor_t*>& out_grad,
85 std::vector<tensor_t*>& in_grad,
86 const shape3d& in_dim,
87 float_t scale_factor,
88 std::vector<typename partial_connected_layer<Activation>::io_connections>& weight2io,
89 std::vector<typename partial_connected_layer<Activation>::wo_connections>& in2wo,
90 std::vector<std::vector<serial_size_t>>& bias2out) {
91
92 for_i(in_data[0]->size(), [&](size_t sample) {
93 const vec_t& prev_out = (*in_data[0])[sample];
94 const vec_t& W = (*in_data[1])[0];
95 vec_t& dW = (*in_grad[1])[sample];
96 vec_t& db = (*in_grad[2])[sample];
97 vec_t& prev_delta = (*in_grad[0])[sample];
98 vec_t& curr_delta = (*out_grad[0])[sample];
99
100 auto inarea = in_dim.area();
101 size_t idx = 0;
102 for (size_t i = 0; i < in_dim.depth_; ++i) {
103 float_t weight = W[i] * scale_factor;
104 for (size_t j = 0; j < inarea; ++j, ++idx) {
105 prev_delta[idx] = weight * curr_delta[in2wo[idx][0].second];
106 }
107 }
108
109 for (size_t i = 0; i < weight2io.size(); ++i) {
110 const auto& connections = weight2io[i];
111 float_t diff = float_t(0);
112
113 for (auto connection : connections)
114 diff += prev_out[connection.first] * curr_delta[connection.second];
115
116 dW[i] += diff * scale_factor;
117 }
118
119 for (size_t i = 0; i < bias2out.size(); i++) {
120 const std::vector<serial_size_t>& outs = bias2out[i];
121 float_t diff = float_t(0);
122
123 for (auto o : outs)
124 diff += curr_delta[o];
125
126 db[i] += diff;
127 }
128 });
129}
130
131
135template<typename Activation = activation::identity>
137 public:
139 CNN_USE_LAYER_MEMBERS;
140
148 serial_size_t in_height,
149 serial_size_t in_channels,
150 serial_size_t pool_size)
151 : average_pooling_layer(in_width, in_height, in_channels, pool_size, pool_size)
152 {}
153
155 serial_size_t pool_size,
156 serial_size_t stride)
157 : average_pooling_layer(in_shape.width_, in_shape.width_, in_shape.depth_, pool_size, stride)
158 {}
159
168 serial_size_t in_height,
169 serial_size_t in_channels,
170 serial_size_t pool_size,
171 serial_size_t stride)
172 : average_pooling_layer(in_width, in_height, in_channels, pool_size, pool_size, stride, stride, padding::valid)
173 {}
174
186 serial_size_t in_height,
187 serial_size_t in_channels,
188 serial_size_t pool_size_x,
189 serial_size_t pool_size_y,
190 serial_size_t stride_x,
191 serial_size_t stride_y,
192 padding pad_type = padding::valid)
194 conv_out_length(in_width, pool_size_x, stride_x, pad_type) *
195 conv_out_length(in_height, pool_size_y, stride_y, pad_type) * in_channels,
196 in_channels, in_channels, float_t(1) / (pool_size_x * pool_size_y)),
197 stride_x_(stride_x),
198 stride_y_(stride_y),
199 pool_size_x_(pool_size_x),
200 pool_size_y_(pool_size_y),
201 pad_type_(pad_type),
203 out_(conv_out_length(in_width, pool_size_x, stride_x, pad_type),
204 conv_out_length(in_height, pool_size_y, stride_y, pad_type), in_channels),
205 w_(pool_size_x, pool_size_y, in_channels) {
206 if ((in_width % pool_size_x) || (in_height % pool_size_y)) {
207 pooling_size_mismatch(in_width, in_height, pool_size_x, pool_size_y);
208 }
209
210 init_connection(pool_size_x, pool_size_y);
211 }
212 std::vector<index3d<serial_size_t>> in_shape() const override {
213 return { in_, w_, index3d<serial_size_t>(1, 1, out_.depth_) };
214 }
215
216 std::vector<index3d<serial_size_t>> out_shape() const override {
217 return { out_, out_ };
218 }
219
220 std::string layer_type() const override { return "ave-pool"; }
221
222 void forward_propagation(const std::vector<tensor_t*>& in_data,
223 std::vector<tensor_t*>& out_data) override {
224
227 in_data,
228 out_data,
229 out_,
230 Base::scale_factor_,
231 Base::out2wi_,
232 Base::h_);
233
234 }
235
236 void back_propagation(const std::vector<tensor_t*>& in_data,
237 const std::vector<tensor_t*>& out_data,
238 std::vector<tensor_t*>& out_grad,
239 std::vector<tensor_t*>& in_grad) override {
240
241 tensor_t& curr_delta = *out_grad[0];
242 this->backward_activation(*out_grad[0], *out_data[0], curr_delta);
243
245 in_data,
246 out_data,
247 out_grad,
248 in_grad,
249 in_,
250 Base::scale_factor_,
251 Base::weight2io_,
252 Base::in2wo_,
253 Base::bias2out_);
254 }
255
256 template <class Archive>
257 static void load_and_construct(Archive & ar, cereal::construct<average_pooling_layer> & construct) {
258 shape3d in;
259 serial_size_t stride_x, stride_y, pool_size_x, pool_size_y;
260 padding pad_type;
261
262 ar(cereal::make_nvp("in_size", in),
263 cereal::make_nvp("pool_size_x", pool_size_x),
264 cereal::make_nvp("pool_size_y", pool_size_y),
265 cereal::make_nvp("stride_x", stride_x),
266 cereal::make_nvp("stride_y", stride_y),
267 cereal::make_nvp("pad_type", pad_type)
268 );
269 construct(in.width_, in.height_, in.depth_, pool_size_x, pool_size_y, stride_x, stride_y, pad_type);
270 }
271
272 template <class Archive>
273 void serialize(Archive & ar) {
274 layer::serialize_prolog(ar);
275 ar(cereal::make_nvp("in_size", in_),
276 cereal::make_nvp("pool_size_x", pool_size_x_),
277 cereal::make_nvp("pool_size_y", pool_size_y_),
278 cereal::make_nvp("stride_x", stride_x_),
279 cereal::make_nvp("stride_y", stride_y_),
280 cereal::make_nvp("pad_type", pad_type_)
281 );
282 }
283
284 std::pair<serial_size_t, serial_size_t> pool_size() const { return std::make_pair(pool_size_x_, pool_size_y_); }
285
286 private:
287 serial_size_t stride_x_;
288 serial_size_t stride_y_;
289 serial_size_t pool_size_x_;
290 serial_size_t pool_size_y_;
291 padding pad_type_;
292 shape3d in_;
293 shape3d out_;
294 shape3d w_;
295
296 static serial_size_t pool_out_dim(serial_size_t in_size,
297 serial_size_t pooling_size,
298 serial_size_t stride) {
299 return static_cast<int>(std::ceil((
300 static_cast<float_t>(in_size) - pooling_size) / stride) + 1);
301 }
302
303 void init_connection(serial_size_t pooling_size_x, serial_size_t pooling_size_y) {
304 for (serial_size_t c = 0; c < in_.depth_; ++c) {
305 for (serial_size_t y = 0; y < in_.height_ - pooling_size_y + 1; y += stride_y_) {
306 for (serial_size_t x = 0; x < in_.width_ - pooling_size_x + 1; x += stride_x_) {
307 connect_kernel(pooling_size_x, pooling_size_y, x, y, c);
308 }
309 }
310 }
311
312 for (serial_size_t c = 0; c < in_.depth_; ++c) {
313 for (serial_size_t y = 0; y < out_.height_; ++y) {
314 for (serial_size_t x = 0; x < out_.width_; ++x) {
315 this->connect_bias(c, out_.get_index(x, y, c));
316 }
317 }
318 }
319 }
320
321 void connect_kernel(serial_size_t pooling_size_x,
322 serial_size_t pooling_size_y,
323 serial_size_t x,
324 serial_size_t y,
325 serial_size_t inc) {
326 serial_size_t dymax = std::min(pooling_size_y, in_.height_ - y);
327 serial_size_t dxmax = std::min(pooling_size_x, in_.width_ - x);
328 serial_size_t dstx = x / stride_x_;
329 serial_size_t dsty = y / stride_y_;
330 serial_size_t outidx = out_.get_index(dstx, dsty, inc);
331 for (serial_size_t dy = 0; dy < dymax; ++dy) {
332 for (serial_size_t dx = 0; dx < dxmax; ++dx) {
333 this->connect_weight(
334 in_.get_index(x + dx, y + dy, inc),
335 outidx,
336 inc);
337 }
338 }
339 }
340};
341
342} // namespace tiny_dnn
343
average pooling with trainable weights
Definition average_pooling_layer.h:136
std::vector< index3d< serial_size_t > > in_shape() const override
array of input shapes (width x height x depth)
Definition average_pooling_layer.h:212
std::string layer_type() const override
name of layer, should be unique for each concrete class
Definition average_pooling_layer.h:220
average_pooling_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t in_channels, serial_size_t pool_size, serial_size_t stride)
Definition average_pooling_layer.h:167
average_pooling_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t in_channels, serial_size_t pool_size_x, serial_size_t pool_size_y, serial_size_t stride_x, serial_size_t stride_y, padding pad_type=padding::valid)
Definition average_pooling_layer.h:185
average_pooling_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t in_channels, serial_size_t pool_size)
Definition average_pooling_layer.h:147
void back_propagation(const std::vector< tensor_t * > &in_data, const std::vector< tensor_t * > &out_data, std::vector< tensor_t * > &out_grad, std::vector< tensor_t * > &in_grad) override
return delta of previous layer (delta=\frac{dE}{da}, a=wx in fully-connected layer)
Definition average_pooling_layer.h:236
std::vector< index3d< serial_size_t > > out_shape() const override
array of output shapes (width x height x depth)
Definition average_pooling_layer.h:216
void forward_propagation(const std::vector< tensor_t * > &in_data, std::vector< tensor_t * > &out_data) override
Definition average_pooling_layer.h:222
Simple image utility class.
Definition image.h:94
serial_size_t in_size() const
!
Definition layer.h:176
bool parallelize_
Flag indicating whether the layer/node operations ara paralellized.
Definition layer.h:696
serial_size_t in_channels() const
number of outgoing edges in this layer
Definition layer.h:146
Definition partial_connected_layer.h:34