33 #include "tiny_dnn/core/backend_tiny.h"
34 #include "tiny_dnn/core/backend_nnp.h"
35 #include "tiny_dnn/core/backend_dnn.h"
37 #include "tiny_dnn/core/backend_avx.h"
40 #include "tiny_dnn/util/util.h"
41 #include "tiny_dnn/util/image.h"
42 #include "tiny_dnn/activations/activation_function.h"
44 using namespace tiny_dnn::core;
53 template<
typename Activation = activation::
identity>
57 CNN_USE_LAYER_MEMBERS;
75 serial_size_t in_height,
76 serial_size_t window_size,
77 serial_size_t in_channels,
78 serial_size_t out_channels,
79 padding pad_type = padding::valid,
81 serial_size_t w_stride = 1,
82 serial_size_t h_stride = 1,
83 backend_t backend_type = core::default_engine())
84 :
Base(std_input_order(has_bias)) {
85 deconv_set_params(
shape3d(in_width, in_height, in_channels),
86 window_size, window_size,
87 out_channels, pad_type, has_bias,
89 init_backend(backend_type);
109 serial_size_t in_height,
110 serial_size_t window_width,
111 serial_size_t window_height,
112 serial_size_t in_channels,
113 serial_size_t out_channels,
114 padding pad_type = padding::valid,
115 bool has_bias =
true,
116 serial_size_t w_stride = 1,
117 serial_size_t h_stride = 1,
118 backend_t backend_type = core::default_engine())
119 :
Base(std_input_order(has_bias)) {
120 deconv_set_params(
shape3d(in_width, in_height, in_channels),
121 window_width, window_height,
122 out_channels, pad_type, has_bias,
124 init_backend(backend_type);
144 serial_size_t in_height,
145 serial_size_t window_size,
146 serial_size_t in_channels,
147 serial_size_t out_channels,
149 padding pad_type = padding::valid,
150 bool has_bias =
true,
151 serial_size_t w_stride = 1,
152 serial_size_t h_stride = 1,
153 backend_t backend_type = core::default_engine())
154 :
Base(std_input_order(has_bias)) {
155 deconv_set_params(
shape3d(in_width, in_height, in_channels),
156 window_size, window_size,
157 out_channels, pad_type, has_bias,
160 init_backend(backend_type);
181 serial_size_t in_height,
182 serial_size_t window_width,
183 serial_size_t window_height,
184 serial_size_t in_channels,
185 serial_size_t out_channels,
187 padding pad_type = padding::valid,
188 bool has_bias =
true,
189 serial_size_t w_stride = 1,
190 serial_size_t h_stride = 1,
191 backend_t backend_type = core::default_engine())
192 :
Base(has_bias ? 3 : 2, 1, std_input_order(has_bias)) {
193 deconv_set_params(
shape3d(in_width, in_height, in_channels),
194 window_width, window_height,
195 out_channels, pad_type, has_bias,
198 init_backend(backend_type);
203 :
Base(std::move(other))
204 , params_(std::move(other.params_))
205 , backend_type_(std::move(other.backend_type_))
206 , deconv_layer_worker_storage_(std::move(other.deconv_layer_worker_storage_)) {
207 init_backend(std::move(Base::backend_type()));
212 return params_.weight.width_ *
213 params_.weight.height_ *
219 return (params_.weight.width_ * params_.w_stride) *
220 (params_.weight.height_ * params_.h_stride) *
225 std::vector<tensor_t*>& out_data)
override {
227 Base::backend_->deconv2d(in_data, out_data);
230 this->forward_activation(*out_data[0], *out_data[1]);
242 const std::vector<tensor_t*>& out_data,
243 std::vector<tensor_t*>& out_grad,
244 std::vector<tensor_t*>& in_grad)
override {
245 Base::backend_->deconv2d(in_data, out_data, out_grad, in_grad);
248 std::vector<index3d<serial_size_t>>
in_shape()
const override {
249 if (params_.has_bias) {
250 return { params_.in, params_.weight,
253 return { params_.in, params_.weight };
257 std::vector<index3d<serial_size_t>>
out_shape()
const override {
258 return {params_.out_unpadded, params_.out_unpadded};
263 image<> weightto_image()
const {
265 const serial_size_t border_width = 1;
266 const auto pitch = params_.weight.width_ + border_width;
267 const auto width = params_.out.depth_ * pitch + border_width;
268 const auto height = params_.in.depth_ * pitch + border_width;
269 const image<>::intensity_t bg_color = 255;
270 const vec_t& W = *this->get_weights()[0];
272 img.resize(width, height);
275 auto minmax = std::minmax_element(W.begin(), W.end());
277 for (serial_size_t r = 0; r < params_.in.depth_; ++r) {
278 for (serial_size_t c = 0; c < params_.out.depth_; ++c) {
279 if (!params_.tbl.is_connected(c, r))
continue;
281 const auto top = r * pitch + border_width;
282 const auto left = c * pitch + border_width;
284 serial_size_t idx = 0;
286 for (serial_size_t y = 0; y < params_.weight.height_; ++y) {
287 for (serial_size_t x = 0; x < params_.weight.width_; ++x) {
288 idx = params_.weight.get_index(x, y, c * params_.in.depth_ + r);
289 const float_t w = W[idx];
291 img.at(left + x, top + y)
292 =
static_cast<image<>::intensity_t
>(
293 rescale(w, *minmax.first,
294 *minmax.second, 0, 255));
303 void init_backend(
const backend_t backend_type) {
304 std::shared_ptr<core::backend>
backend =
nullptr;
307 if (backend_type == backend_t::internal) {
308 backend = std::make_shared<core::tiny_backend>(¶ms_,
309 [
this](
const tensor_t& in) {
310 return copy_and_unpad_output(in);
312 [
this](
const tensor_t& delta, tensor_t& dst) {
313 return copy_and_pad_delta(delta, dst);
315 [
this](
const tensor_t& p_delta,
316 const tensor_t& out, tensor_t& c_delta) {
317 return Base::backward_activation(p_delta, out, c_delta);
319 &deconv_layer_worker_storage_);
320 }
else if (backend_type == backend_t::nnpack) {
321 backend = std::make_shared<core::nnp_backend>();
322 }
else if (backend_type == backend_t::libdnn) {
323 backend = std::make_shared<core::dnn_backend>();
325 }
else if (backend_type == backend_t::avx) {
326 backend = std::make_shared<core::avx_backend>(¶ms_,
327 [
this](
const tensor_t& in) {
328 return copy_and_unpad_output(in);
330 [
this](
const tensor_t& delta, tensor_t& dst) {
331 return copy_and_pad_delta(delta, dst);
333 [
this](
const tensor_t& p_delta,
334 const tensor_t& out, tensor_t& c_delta) {
335 return Base::backward_activation(p_delta, out, c_delta);
337 &deconv_layer_worker_storage_);
340 throw nn_error(
"Not supported backend type.");
345 Base::backend_->set_layer(
this);
347 throw nn_error(
"Could not allocate the backend.");
351 void deconv_set_params(
const shape3d& in,
352 serial_size_t w_width,
353 serial_size_t w_height,
357 serial_size_t w_stride,
358 serial_size_t h_stride,
362 shape3d(deconv_out_length(in.width_, w_width, w_stride),
363 deconv_out_length(in.height_, w_height, h_stride),
365 params_.out_unpadded =
366 shape3d(deconv_out_unpadded_length(in.width_, w_width, w_stride, ptype),
367 deconv_out_unpadded_length(in.height_, w_height, h_stride, ptype),
369 params_.weight = shape3d(w_width, w_height, in.depth_ * outc);
370 params_.has_bias = has_bias;
371 params_.pad_type = ptype;
372 params_.w_stride = w_stride;
373 params_.h_stride = h_stride;
377 void init_workers(serial_size_t sample_count) {
380 if (params_.pad_type == padding::same) {
381 dws.curr_out_buf_.resize(sample_count, vec_t(params_.out_unpadded.size(), float_t(0)));
382 dws.curr_delta_padded.resize(sample_count, vec_t(params_.out.size(), float_t(0)));
385 dws.curr_out_buf_.clear();
390 serial_size_t in_length(serial_size_t in_length,
391 serial_size_t window_size, padding pad_type)
const {
395 static serial_size_t deconv_out_length(serial_size_t in_length,
396 serial_size_t window_size,
397 serial_size_t stride) {
398 return (serial_size_t)ceil((float_t)(in_length) * stride + window_size - 1);
401 static serial_size_t deconv_out_unpadded_length(serial_size_t in_length,
402 serial_size_t window_size,
403 serial_size_t stride, padding pad_type) {
404 return pad_type == padding::same ?
405 (serial_size_t)ceil((float_t)in_length * stride) :
406 (serial_size_t)ceil((float_t)(in_length) * stride + window_size - 1);
409 static serial_size_t deconv_out_dim(serial_size_t in_width,
410 serial_size_t in_height,
411 serial_size_t window_size,
412 serial_size_t w_stride,
413 serial_size_t h_stride, padding pad_type) {
414 return deconv_out_unpadded_length(in_width, window_size, w_stride, pad_type) *
415 deconv_out_unpadded_length(in_height, window_size, h_stride, pad_type);
418 serial_size_t deconv_out_dim(serial_size_t in_width,
419 serial_size_t in_height,
420 serial_size_t window_width,
421 serial_size_t window_height,
422 serial_size_t w_stride,
423 serial_size_t h_stride, padding pad_type)
const {
424 return deconv_out_unpadded_length(in_width, window_width, w_stride, pad_type) *
425 deconv_out_unpadded_length(in_height, window_height, h_stride, pad_type);
428 void copy_and_pad_delta(
const tensor_t& delta, tensor_t& delta_padded) {
429 if (params_.pad_type == padding::valid) {
430 delta_padded = delta;
433 for (serial_size_t sample = 0; sample < delta.size(); sample++) {
434 vec_t& dst = delta_padded[sample];
435 const vec_t& src = delta[sample];
437 for (serial_size_t c = 0; c < params_.in.depth_; c++) {
438 float_t *pdst = &dst[params_.in.get_index(0, 0, c)];
439 const float_t *pin = &src[params_.in.get_index(0, 0, c)];
441 for (serial_size_t y = 0; y < params_.in.height_; y++, pdst +=
442 params_.in.width_, pin += params_.in.width_) {
443 std::copy(pin, pin + params_.in.width_, pdst);
450 void copy_and_unpad_output(
const tensor_t& out) {
452 deconv_layer_worker_storage_;
454 dws.curr_out_buf_ = tensor_t(out.size(), vec_t(params_.out_unpadded.width_*
455 params_.out_unpadded.height_*
456 params_.out_unpadded.depth_,0));
457 tensor_t* dst_tensor = &dws.curr_out_buf_;
459 if (params_.pad_type == padding::valid) {
460 dws.curr_out_unpadded_ = &out;
463 for (serial_size_t sample = 0; sample < out.size(); sample++) {
464 serial_size_t idx = 0;
465 vec_t& dst = (*dst_tensor)[sample];
466 serial_size_t wieght_w_half = params_.weight.width_ / 2;
467 serial_size_t wieght_h_half = params_.weight.height_ / 2;
469 for (serial_size_t c = 0; c < params_.out_unpadded.depth_; c++) {
470 float_t *pimg = &dst[params_.out_unpadded.get_index(0, 0, c)];
471 idx = params_.out.get_index(wieght_w_half, wieght_h_half, c);
472 const float_t *pout = &out[sample][idx];
474 for (serial_size_t y = wieght_h_half;
475 y < params_.out_unpadded.height_ + wieght_h_half;
477 pout += params_.out.width_,
478 pimg += params_.out_unpadded.width_) {
480 pout + params_.out_unpadded.width_,
486 dws.curr_out_unpadded_ = &dws.curr_out_buf_;
494 backend_t backend_type_;
2D deconvolution layer
Definition: deconvolutional_layer.h:54
deconvolutional_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t window_width, serial_size_t window_height, serial_size_t in_channels, serial_size_t out_channels, const connection_table &connection_table, padding pad_type=padding::valid, bool has_bias=true, serial_size_t w_stride=1, serial_size_t h_stride=1, backend_t backend_type=core::default_engine())
constructing deconvolutional layer
Definition: deconvolutional_layer.h:180
std::string layer_type() const override
name of layer, should be unique for each concrete class
Definition: deconvolutional_layer.h:261
deconvolutional_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t window_width, serial_size_t window_height, serial_size_t in_channels, serial_size_t out_channels, padding pad_type=padding::valid, bool has_bias=true, serial_size_t w_stride=1, serial_size_t h_stride=1, backend_t backend_type=core::default_engine())
constructing deconvolutional layer
Definition: deconvolutional_layer.h:108
std::vector< index3d< serial_size_t > > in_shape() const override
array of input shapes (width x height x depth)
Definition: deconvolutional_layer.h:248
void forward_propagation(const std::vector< tensor_t * > &in_data, std::vector< tensor_t * > &out_data) override
Definition: deconvolutional_layer.h:224
deconvolutional_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t window_size, serial_size_t in_channels, serial_size_t out_channels, const connection_table &connection_table, padding pad_type=padding::valid, bool has_bias=true, serial_size_t w_stride=1, serial_size_t h_stride=1, backend_t backend_type=core::default_engine())
constructing deconvolutional layer
Definition: deconvolutional_layer.h:143
virtual serial_size_t fan_in_size() const override
number of outgoing connections for each input unit
Definition: deconvolutional_layer.h:211
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: deconvolutional_layer.h:241
virtual 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: deconvolutional_layer.h:218
std::vector< index3d< serial_size_t > > out_shape() const override
array of output shapes (width x height x depth)
Definition: deconvolutional_layer.h:257
deconvolutional_layer(deconvolutional_layer &&other)
number of incoming connections for each output unit
Definition: deconvolutional_layer.h:202
deconvolutional_layer(serial_size_t in_width, serial_size_t in_height, serial_size_t window_size, serial_size_t in_channels, serial_size_t out_channels, padding pad_type=padding::valid, bool has_bias=true, serial_size_t w_stride=1, serial_size_t h_stride=1, backend_t backend_type=core::default_engine())
constructing deconvolutional layer
Definition: deconvolutional_layer.h:74
single-input, single-output network with activation function
Definition: feedforward_layer.h:37
Simple image utility class.
Definition: image.h:94
Definition: conv_params.h:40
Definition: deconv_params.h:32
Definition: deconv_params.h:39