tiny_dnn  1.0.0
A header only, dependency-free deep learning framework in C++11
max_pooling_layer.h
1 /*
2  Copyright (c) 2015, 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/core/backend_tiny.h"
34 #include "tiny_dnn/core/backend_nnp.h"
35 #include "tiny_dnn/core/backend_dnn.h"
36 #ifdef CNN_USE_AVX
37 #include "tiny_dnn/core/backend_avx.h"
38 #endif
39 
40 #include "tiny_dnn/core/kernels/maxpool_op.h"
41 #include "tiny_dnn/core/kernels/maxpool_grad_op.h"
42 
43 #include "tiny_dnn/util/util.h"
44 #include "tiny_dnn/util/image.h"
45 #include "tiny_dnn/activations/activation_function.h"
46 
47 namespace tiny_dnn {
48 
52 template <typename Activation = activation::identity>
53 class max_pooling_layer : public feedforward_layer<Activation> {
54  public:
55  CNN_USE_LAYER_MEMBERS;
57 
64  max_pooling_layer(serial_size_t in_width,
65  serial_size_t in_height,
66  serial_size_t in_channels,
67  serial_size_t pooling_size,
68  backend_t backend_type = core::default_engine())
69  : max_pooling_layer(in_width, in_height, in_channels, pooling_size,
70  pooling_size, backend_type) {}
71 
73  serial_size_t pooling_size,
74  serial_size_t stride,
75  backend_t backend_type = core::default_engine())
76  : max_pooling_layer(in_shape.width_, in_shape.height_, in_shape.depth_,
77  pooling_size, stride, backend_type) {}
78 
79  max_pooling_layer(serial_size_t in_width,
80  serial_size_t in_height,
81  serial_size_t in_channels,
82  serial_size_t pooling_size,
83  serial_size_t stride,
84  backend_t backend_type = core::default_engine())
85  : max_pooling_layer(in_width, in_height, in_channels, pooling_size,
86  pooling_size, stride, stride, padding::valid,
87  backend_type) {}
88 
96  max_pooling_layer(serial_size_t in_width,
97  serial_size_t in_height,
98  serial_size_t in_channels,
99  serial_size_t pooling_size_x,
100  serial_size_t pooling_size_y,
101  serial_size_t stride_x,
102  serial_size_t stride_y,
103  padding pad_type = padding::valid,
104  backend_t backend_type = core::default_engine())
105  : Base({ vector_type::data }) {
106  set_maxpool_params(
107  shape3d(in_width, in_height, in_channels),
108  shape3d(conv_out_length(in_width, pooling_size_x, stride_x, pad_type),
109  conv_out_length(in_height, pooling_size_y, stride_y, pad_type),
110  in_channels),
111  pooling_size_x, pooling_size_y, stride_x, stride_y, pad_type);
112 
113  init_connection();
114  init_backend(backend_type);
115  Base::set_backend_type(backend_type);
116  }
117 
118  // move constructor
119  max_pooling_layer(max_pooling_layer&& other) // NOLINT
120  : Base(std::move(other))
121  , params_(std::move(other.params_)) {
122  init_connection();
123  init_backend(std::move(Base::engine()));
124  }
125 
126  serial_size_t fan_in_size() const override {
127  return static_cast<serial_size_t>(params_.out2in[0].size());
128  }
129 
130  serial_size_t fan_out_size() const override {
131  return 1;
132  }
133 
134  void forward_propagation(const std::vector<tensor_t*>& in_data,
135  std::vector<tensor_t*>& out_data) override {
136  // forward convolutional op context
137  auto ctx = OpKernelContext(in_data, out_data);
138  ctx.setParallelize(layer::parallelize());
139  ctx.setEngine(layer::engine());
140 
141  // launch convolutional kernel
142  kernel_fwd_->compute(ctx);
143 
144  // activations
145  this->forward_activation(*out_data[0], *out_data[1]);
146  }
147 
148  void back_propagation(const std::vector<tensor_t*>& in_data,
149  const std::vector<tensor_t*>& out_data,
150  std::vector<tensor_t*>& out_grad,
151  std::vector<tensor_t*>& in_grad) override {
152  // activations
153  // TODO(edgar/nyanp): refactor and move activations outside
154  this->backward_activation(*out_grad[0], *out_data[0], *out_grad[1]);
155 
156  // backward convolutional op context
157  auto ctx = OpKernelContext(in_data, out_data, out_grad, in_grad);
158  ctx.setParallelize(layer::parallelize());
159  ctx.setEngine(layer::engine());
160 
161  // launch convolutional kernel
162  kernel_back_->compute(ctx);
163  }
164 
165  std::vector<index3d<serial_size_t>>
166  in_shape() const override { return { params_.in }; }
167 
168  std::vector<index3d<serial_size_t>>
169  out_shape() const override { return { params_.out, params_.out }; }
170 
171  std::string layer_type() const override {
172  return std::string("max-pool");
173  }
174 
175  std::string kernel_file() const override {
176  return std::string("../tiny_cnn/core/kernels/cl_kernels/pooling.cl");
177  }
178 
179  std::pair<serial_size_t, serial_size_t> pool_size() const {
180  return std::make_pair(params_.pool_size_x, params_.pool_size_y);
181  }
182 
183  void set_sample_count(serial_size_t sample_count) override {
184  Base::set_sample_count(sample_count);
185  params_.out2inmax.resize(
186  sample_count, std::vector<serial_size_t>(params_.out.size()));
187  }
188 
189 
190  template <class Archive>
191  static void
192  load_and_construct(Archive & ar,
193  cereal::construct<max_pooling_layer> & construct) {
194  shape3d in;
195  serial_size_t stride_x, stride_y, pool_size_x, pool_size_y;
196  padding pad_type;
197 
198  ar(cereal::make_nvp("in_size", in),
199  cereal::make_nvp("pool_size_x", pool_size_x),
200  cereal::make_nvp("pool_size_y", pool_size_y),
201  cereal::make_nvp("stride_x", stride_x),
202  cereal::make_nvp("stride_y", stride_y),
203  cereal::make_nvp("pad_type", pad_type));
204  construct(in.width_, in.height_, in.depth_, pool_size_x, pool_size_y,
205  stride_x, stride_y, pad_type);
206  }
207 
208  template <class Archive>
209  void serialize(Archive & ar) {
210  layer::serialize_prolog(ar);
211  ar(cereal::make_nvp("in_size", params_.in),
212  cereal::make_nvp("pool_size_x", params_.pool_size_x),
213  cereal::make_nvp("pool_size_y", params_.pool_size_y),
214  cereal::make_nvp("stride_x", params_.stride_x),
215  cereal::make_nvp("stride_y", params_.stride_y),
216  cereal::make_nvp("pad_type", params_.pad_type));
217  }
218 
219 private:
220  /* The Max Poling operation params */
221  maxpool_params params_;
222 
223  /* Forward and backward ops */
224  std::shared_ptr<core::OpKernel> kernel_fwd_;
225  std::shared_ptr<core::OpKernel> kernel_back_;
226 
227  void connect_kernel(serial_size_t pooling_size_x,
228  serial_size_t pooling_size_y,
229  serial_size_t outx,
230  serial_size_t outy,
231  serial_size_t c) {
232  serial_size_t dxmax = static_cast<serial_size_t>(
233  std::min(static_cast<serial_size_t>(pooling_size_x),
234  params_.in.width_ - outx * params_.stride_x));
235 
236  serial_size_t dymax = static_cast<serial_size_t>(
237  std::min(static_cast<serial_size_t>(pooling_size_y),
238  params_.in.height_ - outy * params_.stride_y));
239 
240  for (serial_size_t dy = 0; dy < dymax; dy++) {
241  for (serial_size_t dx = 0; dx < dxmax; dx++) {
242  serial_size_t in_index = params_.in.get_index(
243  static_cast<serial_size_t>(outx * params_.stride_x + dx),
244  static_cast<serial_size_t>(outy * params_.stride_y + dy), c);
245  serial_size_t out_index = params_.out.get_index(outx, outy, c);
246 
247  if (in_index >= params_.in2out.size()) {
248  throw nn_error("index overflow");
249  }
250  if (out_index >= params_.out2in.size()) {
251  throw nn_error("index overflow");
252  }
253  params_.in2out[in_index] = out_index;
254  params_.out2in[out_index].push_back(in_index);
255  }
256  }
257  }
258 
259  void init_connection() {
260  params_.in2out.resize(params_.in.size());
261  params_.out2in.resize(params_.out.size());
262 
263  for (serial_size_t c = 0; c < params_.in.depth_; ++c) {
264  for (serial_size_t y = 0; y < params_.out.height_; ++y) {
265  for (serial_size_t x = 0; x < params_.out.width_; ++x) {
266  connect_kernel(params_.pool_size_x,
267  params_.pool_size_y,
268  x, y, c);
269  }
270  }
271  }
272  }
273 
274  void init_backend(backend_t backend_type) {
275  core::OpKernelConstruction ctx =
276  core::OpKernelConstruction(layer::device(), &params_);
277 
278  if (backend_type == backend_t::internal ||
279  backend_type == backend_t::nnpack ||
280  backend_type == backend_t::avx) {
281 
282  kernel_fwd_.reset(new MaxPoolOp(ctx));
283  kernel_back_.reset(new MaxPoolGradOp(ctx));
284  return;
285  }
286  else {
287  throw nn_error("Not supported engine: " + to_string(backend_type));
288  }
289 
290  }
291 
292  void set_maxpool_params(const shape3d& in,
293  const shape3d& out,
294  serial_size_t pooling_size_x,
295  serial_size_t pooling_size_y,
296  serial_size_t stride_x,
297  serial_size_t stride_y,
298  padding pad_type) {
299  params_.in = in;
300  params_.out = out;
301  params_.pool_size_x = pooling_size_x;
302  params_.pool_size_y = pooling_size_y;
303  params_.stride_x = stride_x;
304  params_.stride_y = stride_y;
305  params_.pad_type = pad_type;
306  }
307 };
308 
309 } // namespace tiny_dnn
310 
single-input, single-output network with activation function
Definition: feedforward_layer.h:37
serial_size_t in_channels() const
number of outgoing edges in this layer
Definition: layer.h:146
applies max-pooing operaton to the spatial data
Definition: max_pooling_layer.h:53
std::vector< index3d< serial_size_t > > in_shape() const override
array of input shapes (width x height x depth)
Definition: max_pooling_layer.h:166
max_pooling_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t in_channels, serial_size_t pooling_size, backend_t backend_type=core::default_engine())
Definition: max_pooling_layer.h:64
serial_size_t fan_out_size() const override
number of outgoing connections for each input unit used only for weight/bias initialization methods w...
Definition: max_pooling_layer.h:130
std::string layer_type() const override
name of layer, should be unique for each concrete class
Definition: max_pooling_layer.h:171
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: max_pooling_layer.h:148
max_pooling_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t in_channels, serial_size_t pooling_size_x, serial_size_t pooling_size_y, serial_size_t stride_x, serial_size_t stride_y, padding pad_type=padding::valid, backend_t backend_type=core::default_engine())
Definition: max_pooling_layer.h:96
std::vector< index3d< serial_size_t > > out_shape() const override
array of output shapes (width x height x depth)
Definition: max_pooling_layer.h:169
serial_size_t fan_in_size() const override
number of incoming connections for each output unit used only for weight/bias initialization methods ...
Definition: max_pooling_layer.h:126
void forward_propagation(const std::vector< tensor_t * > &in_data, std::vector< tensor_t * > &out_data) override
Definition: max_pooling_layer.h:134