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 {
232 }
else if (
in_data.size() == 6) {
245 const std::vector<tensor_t*>&
out_data,
247 std::vector<tensor_t*>&
in_grad)
override {
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 {
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;
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);
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) {
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) {
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,
360 serial_size_t w_stride,
361 serial_size_t h_stride,
366 deconv_out_length(in.height_,
w_height, h_stride),
368 params_.out_unpadded =
370 deconv_out_unpadded_length(in.height_,
w_height, h_stride,
ptype),
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,
403 static serial_size_t deconv_out_unpadded_length(serial_size_t in_length,
405 serial_size_t
stride, padding pad_type) {
406 return pad_type == padding::same ?
411 static serial_size_t deconv_out_dim(serial_size_t
in_width,
414 serial_size_t w_stride,
415 serial_size_t h_stride, padding pad_type) {
420 serial_size_t deconv_out_dim(serial_size_t
in_width,
424 serial_size_t w_stride,
425 serial_size_t h_stride, padding pad_type)
const {
431 if (params_.pad_type == padding::valid) {
439 for (serial_size_t
c = 0;
c < params_.in.depth_;
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));
461 if (params_.pad_type == padding::valid) {
462 dws.curr_out_unpadded_ = &out;
466 serial_size_t
idx = 0;
469 for (serial_size_t
c = 0;
c < params_.out_unpadded.depth_;
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);
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_;