#include "series.h"
#include "fullyconnected.h"
#include "networkscratch.h"
#include "scrollview.h"
#include "tesserrstream.h"
#include "tprintf.h"
namespace tesseract {
Series::Series(const std::string &name) : Plumbing(name) {
type_ = NT_SERIES;
}
StaticShape Series::OutputShape(const StaticShape &input_shape) const {
StaticShape result(input_shape);
int stack_size = stack_.size();
for (int i = 0; i < stack_size; ++i) {
result = stack_[i]->OutputShape(result);
}
return result;
}
int Series::InitWeights(float range, TRand *randomizer) {
num_weights_ = 0;
tprintf("Num outputs,weights in Series:\n");
for (auto &i : stack_) {
int weights = i->InitWeights(range, randomizer);
tprintf(" %s:%d, %d\n", i->spec().c_str(), i->NumOutputs(), weights);
num_weights_ += weights;
}
tprintf("Total weights = %d\n", num_weights_);
return num_weights_;
}
int Series::RemapOutputs(int old_no, const std::vector<int> &code_map) {
num_weights_ = 0;
tprintf("Num (Extended) outputs,weights in Series:\n");
for (auto &i : stack_) {
int weights = i->RemapOutputs(old_no, code_map);
tprintf(" %s:%d, %d\n", i->spec().c_str(), i->NumOutputs(), weights);
num_weights_ += weights;
}
tprintf("Total weights = %d\n", num_weights_);
no_ = stack_.back()->NumOutputs();
return num_weights_;
}
bool Series::SetupNeedsBackprop(bool needs_backprop) {
needs_to_backprop_ = needs_backprop;
for (auto &i : stack_) {
needs_backprop = i->SetupNeedsBackprop(needs_backprop);
}
return needs_backprop;
}
int Series::XScaleFactor() const {
int factor = 1;
for (auto i : stack_) {
factor *= i->XScaleFactor();
}
return factor;
}
void Series::CacheXScaleFactor(int factor) {
stack_[0]->CacheXScaleFactor(factor);
}
void Series::Forward(bool debug, const NetworkIO &input, const TransposedArray *input_transpose,
NetworkScratch *scratch, NetworkIO *output) {
int stack_size = stack_.size();
ASSERT_HOST(stack_size > 1);
NetworkScratch::IO buffer1(input, scratch);
NetworkScratch::IO buffer2(input, scratch);
stack_[0]->Forward(debug, input, input_transpose, scratch, buffer1);
for (int i = 1; i < stack_size; i += 2) {
stack_[i]->Forward(debug, *buffer1, nullptr, scratch, i + 1 < stack_size ? buffer2 : output);
if (i + 1 == stack_size) {
return;
}
stack_[i + 1]->Forward(debug, *buffer2, nullptr, scratch,
i + 2 < stack_size ? buffer1 : output);
}
}
bool Series::Backward(bool debug, const NetworkIO &fwd_deltas, NetworkScratch *scratch,
NetworkIO *back_deltas) {
if (!IsTraining()) {
return false;
}
int stack_size = stack_.size();
ASSERT_HOST(stack_size > 1);
NetworkScratch::IO buffer1(fwd_deltas, scratch);
NetworkScratch::IO buffer2(fwd_deltas, scratch);
if (!stack_.back()->IsTraining() ||
!stack_.back()->Backward(debug, fwd_deltas, scratch, buffer1)) {
return false;
}
for (int i = stack_size - 2; i >= 0; i -= 2) {
if (!stack_[i]->IsTraining() ||
!stack_[i]->Backward(debug, *buffer1, scratch, i > 0 ? buffer2 : back_deltas)) {
return false;
}
if (i == 0) {
return needs_to_backprop_;
}
if (!stack_[i - 1]->IsTraining() ||
!stack_[i - 1]->Backward(debug, *buffer2, scratch, i > 1 ? buffer1 : back_deltas)) {
return false;
}
}
return needs_to_backprop_;
}
void Series::SplitAt(unsigned last_start, Series **start, Series **end) {
*start = nullptr;
*end = nullptr;
if (last_start >= stack_.size()) {
tesserr << "Invalid split index " << last_start
<< " must be in range [0," << stack_.size() - 1 << "]!\n";
return;
}
auto *master_series = new Series("MasterSeries");
auto *boosted_series = new Series("BoostedSeries");
for (unsigned s = 0; s <= last_start; ++s) {
if (s + 1 == stack_.size() && stack_[s]->type() == NT_SOFTMAX) {
auto *fc = static_cast<FullyConnected *>(stack_[s]);
fc->ChangeType(NT_TANH);
}
master_series->AddToStack(stack_[s]);
stack_[s] = nullptr;
}
for (unsigned s = last_start + 1; s < stack_.size(); ++s) {
boosted_series->AddToStack(stack_[s]);
stack_[s] = nullptr;
}
*start = master_series;
*end = boosted_series;
delete this;
}
void Series::AppendSeries(Network *src) {
ASSERT_HOST(src->type() == NT_SERIES);
auto *src_series = static_cast<Series *>(src);
for (auto &s : src_series->stack_) {
AddToStack(s);
s = nullptr;
}
delete src;
}
}