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::backend_t::internal)
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::backend_t::internal)
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::backend_t::internal)
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::backend_t::internal)
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::get_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 if (in_data.size() == 3) {
228 Base::backend_->deconv2d_q(in_data, out_data);
231 this->forward_activation(*out_data[0], *out_data[1]);
232 }
else if (in_data.size() == 6) {
233 Base::backend_->deconv2d_eq(in_data, out_data);
245 const std::vector<tensor_t*>& out_data,
246 std::vector<tensor_t*>& out_grad,
247 std::vector<tensor_t*>& in_grad)
override {
248 Base::backend_->deconv2d_q(in_data, out_data, out_grad, in_grad);
251 std::vector<index3d<serial_size_t>>
in_shape()
const override {
252 if (params_.has_bias) {
253 return { params_.in, params_.weight,
256 return { params_.in, params_.weight };
260 std::vector<index3d<serial_size_t>>
out_shape()
const override {
261 return {params_.out_unpadded, params_.out_unpadded};
264 std::string
layer_type()
const override {
return "q_deconv"; }
266 image<> weightto_image()
const {
268 const serial_size_t border_width = 1;
269 const auto pitch = params_.weight.width_ + border_width;
270 const auto width = params_.out.depth_ * pitch + border_width;
271 const auto height = params_.in.depth_ * pitch + border_width;
272 const image<>::intensity_t bg_color = 255;
273 const vec_t& W = *this->get_weights()[0];
275 img.resize(width, height);
278 auto minmax = std::minmax_element(W.begin(), W.end());
280 for (serial_size_t r = 0; r < params_.in.depth_; ++r) {
281 for (serial_size_t c = 0; c < params_.out.depth_; ++c) {
282 if (!params_.tbl.is_connected(c, r))
continue;
284 const auto top = r * pitch + border_width;
285 const auto left = c * pitch + border_width;
287 serial_size_t idx = 0;
289 for (serial_size_t y = 0; y < params_.weight.height_; ++y) {
290 for (serial_size_t x = 0; x < params_.weight.width_; ++x) {
291 idx = params_.weight.get_index(x, y, c * params_.in.depth_ + r);
292 const float_t w = W[idx];
294 img.at(left + x, top + y)
295 =
static_cast<image<>::intensity_t
>(
296 rescale(w, *minmax.first,
297 *minmax.second, 0, 255));
306 void init_backend(
const backend_t backend_type) {
307 std::shared_ptr<core::backend>
backend =
nullptr;
310 if (backend_type == backend_t::internal) {
311 backend = std::make_shared<core::tiny_backend>(¶ms_,
312 [
this](
const tensor_t& in) {
313 return copy_and_unpad_output(in);
315 [
this](
const tensor_t& delta, tensor_t& dst) {
316 return copy_and_pad_delta(delta, dst);
318 [
this](
const tensor_t& p_delta,
319 const tensor_t& out, tensor_t& c_delta) {
320 return Base::backward_activation(p_delta, out, c_delta);
322 &deconv_layer_worker_storage_);
323 }
else if (backend_type == backend_t::nnpack) {
324 backend = std::make_shared<core::nnp_backend>();
325 }
else if (backend_type == backend_t::libdnn) {
326 backend = std::make_shared<core::dnn_backend>();
328 }
else if (backend_type == backend_t::avx) {
329 backend = std::make_shared<core::avx_backend>(¶ms_,
330 [
this](
const tensor_t& in) {
331 return copy_and_unpad_output(in);
333 [
this](
const tensor_t& delta, tensor_t& dst) {
334 return copy_and_pad_delta(delta, dst);
336 [
this](
const tensor_t& p_delta,
337 const tensor_t& out, tensor_t& c_delta) {
338 return Base::backward_activation(p_delta, out, c_delta);
340 &deconv_layer_worker_storage_);
343 throw nn_error(
"Not supported backend type.");
348 Base::backend_->set_layer(
this);
350 throw nn_error(
"Could not allocate the backend.");
354 void deconv_set_params(
const shape3d& in,
355 serial_size_t w_width,
356 serial_size_t w_height,
360 serial_size_t w_stride,
361 serial_size_t h_stride,
365 shape3d(deconv_out_length(in.width_, w_width, w_stride),
366 deconv_out_length(in.height_, w_height, h_stride),
368 params_.out_unpadded =
369 shape3d(deconv_out_unpadded_length(in.width_, w_width, w_stride, ptype),
370 deconv_out_unpadded_length(in.height_, w_height, h_stride, ptype),
372 params_.weight = shape3d(w_width, w_height, in.depth_ * outc);
373 params_.has_bias = has_bias;
374 params_.pad_type = ptype;
375 params_.w_stride = w_stride;
376 params_.h_stride = h_stride;
383 if (params_.pad_type == padding::same) {
384 dws.curr_out_buf_.resize(1, vec_t(params_.in.size(), float_t(0)));
385 dws.curr_delta_padded.resize(1, vec_t(params_.out.size(), float_t(0)));
388 dws.curr_out_buf_.clear();
392 serial_size_t in_length(serial_size_t in_length,
393 serial_size_t window_size, padding pad_type)
const {
397 static serial_size_t deconv_out_length(serial_size_t in_length,
398 serial_size_t window_size,
399 serial_size_t stride) {
400 return (serial_size_t)ceil((float_t)(in_length) * stride + window_size - 1);
403 static serial_size_t deconv_out_unpadded_length(serial_size_t in_length,
404 serial_size_t window_size,
405 serial_size_t stride, padding pad_type) {
406 return pad_type == padding::same ?
407 (serial_size_t)ceil((float_t)in_length * stride) :
408 (serial_size_t)ceil((float_t)(in_length) * stride + window_size - 1);
411 static serial_size_t deconv_out_dim(serial_size_t in_width,
412 serial_size_t in_height,
413 serial_size_t window_size,
414 serial_size_t w_stride,
415 serial_size_t h_stride, padding pad_type) {
416 return deconv_out_unpadded_length(in_width, window_size, w_stride, pad_type) *
417 deconv_out_unpadded_length(in_height, window_size, h_stride, pad_type);
420 serial_size_t deconv_out_dim(serial_size_t in_width,
421 serial_size_t in_height,
422 serial_size_t window_width,
423 serial_size_t window_height,
424 serial_size_t w_stride,
425 serial_size_t h_stride, padding pad_type)
const {
426 return deconv_out_unpadded_length(in_width, window_width, w_stride, pad_type) *
427 deconv_out_unpadded_length(in_height, window_height, h_stride, pad_type);
430 void copy_and_pad_delta(
const tensor_t& delta, tensor_t& delta_padded) {
431 if (params_.pad_type == padding::valid) {
432 delta_padded = delta;
435 for (serial_size_t sample = 0; sample < delta.size(); sample++) {
436 vec_t& dst = delta_padded[sample];
437 const vec_t& src = delta[sample];
439 for (serial_size_t c = 0; c < params_.in.depth_; c++) {
440 float_t *pdst = &dst[params_.in.get_index(0, 0, c)];
441 const float_t *pin = &src[params_.in.get_index(0, 0, c)];
443 for (serial_size_t y = 0; y < params_.in.height_; y++, pdst +=
444 params_.in.width_, pin += params_.in.width_) {
445 std::copy(pin, pin + params_.in.width_, pdst);
452 void copy_and_unpad_output(
const tensor_t& out) {
454 deconv_layer_worker_storage_;
456 dws.curr_out_buf_ = tensor_t(out.size(), vec_t(params_.out_unpadded.width_*
457 params_.out_unpadded.height_*
458 params_.out_unpadded.depth_,0));
459 tensor_t* dst_tensor = &dws.curr_out_buf_;
461 if (params_.pad_type == padding::valid) {
462 dws.curr_out_unpadded_ = &out;
465 for (serial_size_t sample = 0; sample < out.size(); sample++) {
466 serial_size_t idx = 0;
467 vec_t& dst = (*dst_tensor)[sample];
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(
static_cast<serial_size_t
>(floor(params_.weight.width_ / 2)),
472 static_cast<serial_size_t
>(floor(params_.weight.height_ / 2)), c);
474 const float_t *pout = &out[sample][idx];
476 for (serial_size_t y =
static_cast<serial_size_t
>(floor(params_.weight.height_ / 2));
477 y < params_.out_unpadded.height_ +
static_cast<serial_size_t
>(floor(params_.weight.height_ / 2));
479 pout += params_.out.width_,
480 pimg += params_.out_unpadded.width_) {
482 pout + params_.out_unpadded.width_,
486 dws.curr_out_unpadded_ = &dws.curr_out_buf_;
495 backend_t backend_type_;
single-input, single-output network with activation function
Definition: feedforward_layer.h:37
Simple image utility class.
Definition: image.h:94
2D deconvolution layer
Definition: quantized_deconvolutional_layer.h:54
std::vector< index3d< serial_size_t > > in_shape() const override
array of input shapes (width x height x depth)
Definition: quantized_deconvolutional_layer.h:251
quantized_deconvolutional_layer(quantized_deconvolutional_layer &&other)
number of incoming connections for each output unit
Definition: quantized_deconvolutional_layer.h:202
std::vector< index3d< serial_size_t > > out_shape() const override
array of output shapes (width x height x depth)
Definition: quantized_deconvolutional_layer.h:260
void forward_propagation(const std::vector< tensor_t * > &in_data, std::vector< tensor_t * > &out_data) override
Definition: quantized_deconvolutional_layer.h:224
virtual serial_size_t fan_in_size() const override
number of outgoing connections for each input unit
Definition: quantized_deconvolutional_layer.h:211
quantized_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::backend_t::internal)
constructing deconvolutional layer
Definition: quantized_deconvolutional_layer.h:74
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: quantized_deconvolutional_layer.h:218
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: quantized_deconvolutional_layer.h:244
std::string layer_type() const override
name of layer, should be unique for each concrete class
Definition: quantized_deconvolutional_layer.h:264
quantized_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::backend_t::internal)
constructing deconvolutional layer
Definition: quantized_deconvolutional_layer.h:180
quantized_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::backend_t::internal)
constructing deconvolutional layer
Definition: quantized_deconvolutional_layer.h:108
quantized_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::backend_t::internal)
constructing deconvolutional layer
Definition: quantized_deconvolutional_layer.h:143
Definition: conv_params.h:40
Definition: deconv_params.h:32
Definition: deconv_params.h:39