tiny_dnn  1.0.0
A header only, dependency-free deep learning framework in C++11
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 
38 namespace tiny_dnn {
39 
40 // forward_propagation
41 template <typename Activation>
42 void 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
81 template<typename Activation>
82 void 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 
135 template<typename Activation = activation::identity>
136 class average_pooling_layer : public partial_connected_layer<Activation> {
137  public:
139  CNN_USE_LAYER_MEMBERS;
140 
147  average_pooling_layer(serial_size_t in_width,
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 
167  average_pooling_layer(serial_size_t in_width,
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 
185  average_pooling_layer(serial_size_t in_width,
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)
193  : Base(in_width * in_height * in_channels,
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),
202  in_(in_width, in_height, in_channels),
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 
225  tiny_average_pooling_kernel<Activation>(
226  parallelize_,
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 
244  tiny_average_pooling_back_kernel<Activation>(
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 > > out_shape() const override
array of output shapes (width x height x depth)
Definition: average_pooling_layer.h:216
std::string layer_type() const override
name of layer, should be unique for each concrete class
Definition: average_pooling_layer.h:220
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
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
void forward_propagation(const std::vector< tensor_t * > &in_data, std::vector< tensor_t * > &out_data) override
Definition: average_pooling_layer.h:222
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