#include "reconfig.h"
namespace tesseract {
Reconfig::Reconfig(const std::string &name, int ni, int x_scale, int y_scale)
: Network(NT_RECONFIG, name, ni, ni * x_scale * y_scale)
, x_scale_(x_scale)
, y_scale_(y_scale) {}
StaticShape Reconfig::OutputShape(const StaticShape &input_shape) const {
StaticShape result = input_shape;
result.set_height(result.height() / y_scale_);
result.set_width(result.width() / x_scale_);
if (type_ != NT_MAXPOOL) {
result.set_depth(result.depth() * y_scale_ * x_scale_);
}
return result;
}
int Reconfig::XScaleFactor() const {
return x_scale_;
}
bool Reconfig::Serialize(TFile *fp) const {
return Network::Serialize(fp) && fp->Serialize(&x_scale_) && fp->Serialize(&y_scale_);
}
bool Reconfig::DeSerialize(TFile *fp) {
if (!fp->DeSerialize(&x_scale_)) {
return false;
}
if (!fp->DeSerialize(&y_scale_)) {
return false;
}
no_ = ni_ * x_scale_ * y_scale_;
return true;
}
void Reconfig::Forward(bool debug, const NetworkIO &input, const TransposedArray *input_transpose,
NetworkScratch *scratch, NetworkIO *output) {
output->ResizeScaled(input, x_scale_, y_scale_, no_);
back_map_ = input.stride_map();
StrideMap::Index dest_index(output->stride_map());
do {
int out_t = dest_index.t();
StrideMap::Index src_index(input.stride_map(), dest_index.index(FD_BATCH),
dest_index.index(FD_HEIGHT) * y_scale_,
dest_index.index(FD_WIDTH) * x_scale_);
for (int x = 0; x < x_scale_; ++x) {
for (int y = 0; y < y_scale_; ++y) {
StrideMap::Index src_xy(src_index);
if (src_xy.AddOffset(x, FD_WIDTH) && src_xy.AddOffset(y, FD_HEIGHT)) {
output->CopyTimeStepGeneral(out_t, (x * y_scale_ + y) * ni_, ni_, input, src_xy.t(), 0);
}
}
}
} while (dest_index.Increment());
}
bool Reconfig::Backward(bool debug, const NetworkIO &fwd_deltas, NetworkScratch *scratch,
NetworkIO *back_deltas) {
back_deltas->ResizeToMap(fwd_deltas.int_mode(), back_map_, ni_);
StrideMap::Index src_index(fwd_deltas.stride_map());
do {
int in_t = src_index.t();
StrideMap::Index dest_index(back_deltas->stride_map(), src_index.index(FD_BATCH),
src_index.index(FD_HEIGHT) * y_scale_,
src_index.index(FD_WIDTH) * x_scale_);
for (int x = 0; x < x_scale_; ++x) {
for (int y = 0; y < y_scale_; ++y) {
StrideMap::Index dest_xy(dest_index);
if (dest_xy.AddOffset(x, FD_WIDTH) && dest_xy.AddOffset(y, FD_HEIGHT)) {
back_deltas->CopyTimeStepGeneral(dest_xy.t(), 0, ni_, fwd_deltas, in_t,
(x * y_scale_ + y) * ni_);
}
}
}
} while (src_index.Increment());
return needs_to_backprop_;
}
}