Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/tesseract/src/lstm/series.cpp @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /////////////////////////////////////////////////////////////////////// | |
| 2 // File: series.cpp | |
| 3 // Description: Runs networks in series on the same input. | |
| 4 // Author: Ray Smith | |
| 5 // | |
| 6 // (C) Copyright 2013, Google Inc. | |
| 7 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 8 // you may not use this file except in compliance with the License. | |
| 9 // You may obtain a copy of the License at | |
| 10 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 11 // Unless required by applicable law or agreed to in writing, software | |
| 12 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 // See the License for the specific language governing permissions and | |
| 15 // limitations under the License. | |
| 16 /////////////////////////////////////////////////////////////////////// | |
| 17 | |
| 18 #include "series.h" | |
| 19 | |
| 20 #include "fullyconnected.h" | |
| 21 #include "networkscratch.h" | |
| 22 #include "scrollview.h" | |
| 23 #include "tesserrstream.h" // for tesserr | |
| 24 #include "tprintf.h" | |
| 25 | |
| 26 namespace tesseract { | |
| 27 | |
| 28 // ni_ and no_ will be set by AddToStack. | |
| 29 Series::Series(const std::string &name) : Plumbing(name) { | |
| 30 type_ = NT_SERIES; | |
| 31 } | |
| 32 | |
| 33 // Returns the shape output from the network given an input shape (which may | |
| 34 // be partially unknown ie zero). | |
| 35 StaticShape Series::OutputShape(const StaticShape &input_shape) const { | |
| 36 StaticShape result(input_shape); | |
| 37 int stack_size = stack_.size(); | |
| 38 for (int i = 0; i < stack_size; ++i) { | |
| 39 result = stack_[i]->OutputShape(result); | |
| 40 } | |
| 41 return result; | |
| 42 } | |
| 43 | |
| 44 // Sets up the network for training. Initializes weights using weights of | |
| 45 // scale `range` picked according to the random number generator `randomizer`. | |
| 46 // Note that series has its own implementation just for debug purposes. | |
| 47 int Series::InitWeights(float range, TRand *randomizer) { | |
| 48 num_weights_ = 0; | |
| 49 tprintf("Num outputs,weights in Series:\n"); | |
| 50 for (auto &i : stack_) { | |
| 51 int weights = i->InitWeights(range, randomizer); | |
| 52 tprintf(" %s:%d, %d\n", i->spec().c_str(), i->NumOutputs(), weights); | |
| 53 num_weights_ += weights; | |
| 54 } | |
| 55 tprintf("Total weights = %d\n", num_weights_); | |
| 56 return num_weights_; | |
| 57 } | |
| 58 | |
| 59 // Recursively searches the network for softmaxes with old_no outputs, | |
| 60 // and remaps their outputs according to code_map. See network.h for details. | |
| 61 int Series::RemapOutputs(int old_no, const std::vector<int> &code_map) { | |
| 62 num_weights_ = 0; | |
| 63 tprintf("Num (Extended) outputs,weights in Series:\n"); | |
| 64 for (auto &i : stack_) { | |
| 65 int weights = i->RemapOutputs(old_no, code_map); | |
| 66 tprintf(" %s:%d, %d\n", i->spec().c_str(), i->NumOutputs(), weights); | |
| 67 num_weights_ += weights; | |
| 68 } | |
| 69 tprintf("Total weights = %d\n", num_weights_); | |
| 70 no_ = stack_.back()->NumOutputs(); | |
| 71 return num_weights_; | |
| 72 } | |
| 73 | |
| 74 // Sets needs_to_backprop_ to needs_backprop and returns true if | |
| 75 // needs_backprop || any weights in this network so the next layer forward | |
| 76 // can be told to produce backprop for this layer if needed. | |
| 77 bool Series::SetupNeedsBackprop(bool needs_backprop) { | |
| 78 needs_to_backprop_ = needs_backprop; | |
| 79 for (auto &i : stack_) { | |
| 80 needs_backprop = i->SetupNeedsBackprop(needs_backprop); | |
| 81 } | |
| 82 return needs_backprop; | |
| 83 } | |
| 84 | |
| 85 // Returns an integer reduction factor that the network applies to the | |
| 86 // time sequence. Assumes that any 2-d is already eliminated. Used for | |
| 87 // scaling bounding boxes of truth data. | |
| 88 // WARNING: if GlobalMinimax is used to vary the scale, this will return | |
| 89 // the last used scale factor. Call it before any forward, and it will return | |
| 90 // the minimum scale factor of the paths through the GlobalMinimax. | |
| 91 int Series::XScaleFactor() const { | |
| 92 int factor = 1; | |
| 93 for (auto i : stack_) { | |
| 94 factor *= i->XScaleFactor(); | |
| 95 } | |
| 96 return factor; | |
| 97 } | |
| 98 | |
| 99 // Provides the (minimum) x scale factor to the network (of interest only to | |
| 100 // input units) so they can determine how to scale bounding boxes. | |
| 101 void Series::CacheXScaleFactor(int factor) { | |
| 102 stack_[0]->CacheXScaleFactor(factor); | |
| 103 } | |
| 104 | |
| 105 // Runs forward propagation of activations on the input line. | |
| 106 // See NetworkCpp for a detailed discussion of the arguments. | |
| 107 void Series::Forward(bool debug, const NetworkIO &input, const TransposedArray *input_transpose, | |
| 108 NetworkScratch *scratch, NetworkIO *output) { | |
| 109 int stack_size = stack_.size(); | |
| 110 ASSERT_HOST(stack_size > 1); | |
| 111 // Revolving intermediate buffers. | |
| 112 NetworkScratch::IO buffer1(input, scratch); | |
| 113 NetworkScratch::IO buffer2(input, scratch); | |
| 114 // Run each network in turn, giving the output of n as the input to n + 1, | |
| 115 // with the final network providing the real output. | |
| 116 stack_[0]->Forward(debug, input, input_transpose, scratch, buffer1); | |
| 117 for (int i = 1; i < stack_size; i += 2) { | |
| 118 stack_[i]->Forward(debug, *buffer1, nullptr, scratch, i + 1 < stack_size ? buffer2 : output); | |
| 119 if (i + 1 == stack_size) { | |
| 120 return; | |
| 121 } | |
| 122 stack_[i + 1]->Forward(debug, *buffer2, nullptr, scratch, | |
| 123 i + 2 < stack_size ? buffer1 : output); | |
| 124 } | |
| 125 } | |
| 126 | |
| 127 // Runs backward propagation of errors on the deltas line. | |
| 128 // See NetworkCpp for a detailed discussion of the arguments. | |
| 129 bool Series::Backward(bool debug, const NetworkIO &fwd_deltas, NetworkScratch *scratch, | |
| 130 NetworkIO *back_deltas) { | |
| 131 if (!IsTraining()) { | |
| 132 return false; | |
| 133 } | |
| 134 int stack_size = stack_.size(); | |
| 135 ASSERT_HOST(stack_size > 1); | |
| 136 // Revolving intermediate buffers. | |
| 137 NetworkScratch::IO buffer1(fwd_deltas, scratch); | |
| 138 NetworkScratch::IO buffer2(fwd_deltas, scratch); | |
| 139 // Run each network in reverse order, giving the back_deltas output of n as | |
| 140 // the fwd_deltas input to n-1, with the 0 network providing the real output. | |
| 141 if (!stack_.back()->IsTraining() || | |
| 142 !stack_.back()->Backward(debug, fwd_deltas, scratch, buffer1)) { | |
| 143 return false; | |
| 144 } | |
| 145 for (int i = stack_size - 2; i >= 0; i -= 2) { | |
| 146 if (!stack_[i]->IsTraining() || | |
| 147 !stack_[i]->Backward(debug, *buffer1, scratch, i > 0 ? buffer2 : back_deltas)) { | |
| 148 return false; | |
| 149 } | |
| 150 if (i == 0) { | |
| 151 return needs_to_backprop_; | |
| 152 } | |
| 153 if (!stack_[i - 1]->IsTraining() || | |
| 154 !stack_[i - 1]->Backward(debug, *buffer2, scratch, i > 1 ? buffer1 : back_deltas)) { | |
| 155 return false; | |
| 156 } | |
| 157 } | |
| 158 return needs_to_backprop_; | |
| 159 } | |
| 160 | |
| 161 // Splits the series after the given index, returning the two parts and | |
| 162 // deletes itself. The first part, up to network with index last_start, goes | |
| 163 // into start, and the rest goes into end. | |
| 164 void Series::SplitAt(unsigned last_start, Series **start, Series **end) { | |
| 165 *start = nullptr; | |
| 166 *end = nullptr; | |
| 167 if (last_start >= stack_.size()) { | |
| 168 tesserr << "Invalid split index " << last_start | |
| 169 << " must be in range [0," << stack_.size() - 1 << "]!\n"; | |
| 170 return; | |
| 171 } | |
| 172 auto *master_series = new Series("MasterSeries"); | |
| 173 auto *boosted_series = new Series("BoostedSeries"); | |
| 174 for (unsigned s = 0; s <= last_start; ++s) { | |
| 175 if (s + 1 == stack_.size() && stack_[s]->type() == NT_SOFTMAX) { | |
| 176 // Change the softmax to a tanh. | |
| 177 auto *fc = static_cast<FullyConnected *>(stack_[s]); | |
| 178 fc->ChangeType(NT_TANH); | |
| 179 } | |
| 180 master_series->AddToStack(stack_[s]); | |
| 181 stack_[s] = nullptr; | |
| 182 } | |
| 183 for (unsigned s = last_start + 1; s < stack_.size(); ++s) { | |
| 184 boosted_series->AddToStack(stack_[s]); | |
| 185 stack_[s] = nullptr; | |
| 186 } | |
| 187 *start = master_series; | |
| 188 *end = boosted_series; | |
| 189 delete this; | |
| 190 } | |
| 191 | |
| 192 // Appends the elements of the src series to this, removing from src and | |
| 193 // deleting it. | |
| 194 void Series::AppendSeries(Network *src) { | |
| 195 ASSERT_HOST(src->type() == NT_SERIES); | |
| 196 auto *src_series = static_cast<Series *>(src); | |
| 197 for (auto &s : src_series->stack_) { | |
| 198 AddToStack(s); | |
| 199 s = nullptr; | |
| 200 } | |
| 201 delete src; | |
| 202 } | |
| 203 | |
| 204 } // namespace tesseract. |
