Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/tesseract/src/lstm/plumbing.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: plumbing.cpp | |
| 3 // Description: Base class for networks that organize other networks | |
| 4 // eg series or parallel. | |
| 5 // Author: Ray Smith | |
| 6 // | |
| 7 // (C) Copyright 2014, Google Inc. | |
| 8 // Licensed under the Apache License, Version 2.0 (the "License"); | |
| 9 // you may not use this file except in compliance with the License. | |
| 10 // You may obtain a copy of the License at | |
| 11 // http://www.apache.org/licenses/LICENSE-2.0 | |
| 12 // Unless required by applicable law or agreed to in writing, software | |
| 13 // distributed under the License is distributed on an "AS IS" BASIS, | |
| 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 15 // See the License for the specific language governing permissions and | |
| 16 // limitations under the License. | |
| 17 /////////////////////////////////////////////////////////////////////// | |
| 18 | |
| 19 #include "plumbing.h" | |
| 20 | |
| 21 namespace tesseract { | |
| 22 | |
| 23 // ni_ and no_ will be set by AddToStack. | |
| 24 Plumbing::Plumbing(const std::string &name) : Network(NT_PARALLEL, name, 0, 0) {} | |
| 25 | |
| 26 // Suspends/Enables training by setting the training_ flag. Serialize and | |
| 27 // DeSerialize only operate on the run-time data if state is false. | |
| 28 void Plumbing::SetEnableTraining(TrainingState state) { | |
| 29 Network::SetEnableTraining(state); | |
| 30 for (auto &i : stack_) { | |
| 31 i->SetEnableTraining(state); | |
| 32 } | |
| 33 } | |
| 34 | |
| 35 // Sets flags that control the action of the network. See NetworkFlags enum | |
| 36 // for bit values. | |
| 37 void Plumbing::SetNetworkFlags(uint32_t flags) { | |
| 38 Network::SetNetworkFlags(flags); | |
| 39 for (auto &i : stack_) { | |
| 40 i->SetNetworkFlags(flags); | |
| 41 } | |
| 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 randomizer is a borrowed pointer that should outlive the network | |
| 47 // and should not be deleted by any of the networks. | |
| 48 // Returns the number of weights initialized. | |
| 49 int Plumbing::InitWeights(float range, TRand *randomizer) { | |
| 50 num_weights_ = 0; | |
| 51 for (auto &i : stack_) { | |
| 52 num_weights_ += i->InitWeights(range, randomizer); | |
| 53 } | |
| 54 return num_weights_; | |
| 55 } | |
| 56 | |
| 57 // Recursively searches the network for softmaxes with old_no outputs, | |
| 58 // and remaps their outputs according to code_map. See network.h for details. | |
| 59 int Plumbing::RemapOutputs(int old_no, const std::vector<int> &code_map) { | |
| 60 num_weights_ = 0; | |
| 61 for (auto &i : stack_) { | |
| 62 num_weights_ += i->RemapOutputs(old_no, code_map); | |
| 63 } | |
| 64 return num_weights_; | |
| 65 } | |
| 66 | |
| 67 // Converts a float network to an int network. | |
| 68 void Plumbing::ConvertToInt() { | |
| 69 for (auto &i : stack_) { | |
| 70 i->ConvertToInt(); | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 // Provides a pointer to a TRand for any networks that care to use it. | |
| 75 // Note that randomizer is a borrowed pointer that should outlive the network | |
| 76 // and should not be deleted by any of the networks. | |
| 77 void Plumbing::SetRandomizer(TRand *randomizer) { | |
| 78 for (auto &i : stack_) { | |
| 79 i->SetRandomizer(randomizer); | |
| 80 } | |
| 81 } | |
| 82 | |
| 83 // Adds the given network to the stack. | |
| 84 void Plumbing::AddToStack(Network *network) { | |
| 85 if (stack_.empty()) { | |
| 86 ni_ = network->NumInputs(); | |
| 87 no_ = network->NumOutputs(); | |
| 88 } else if (type_ == NT_SERIES) { | |
| 89 // ni is input of first, no output of last, others match output to input. | |
| 90 ASSERT_HOST(no_ == network->NumInputs()); | |
| 91 no_ = network->NumOutputs(); | |
| 92 } else { | |
| 93 // All parallel types. Output is sum of outputs, inputs all match. | |
| 94 ASSERT_HOST(ni_ == network->NumInputs()); | |
| 95 no_ += network->NumOutputs(); | |
| 96 } | |
| 97 stack_.push_back(network); | |
| 98 } | |
| 99 | |
| 100 // Sets needs_to_backprop_ to needs_backprop and calls on sub-network | |
| 101 // according to needs_backprop || any weights in this network. | |
| 102 bool Plumbing::SetupNeedsBackprop(bool needs_backprop) { | |
| 103 if (IsTraining()) { | |
| 104 needs_to_backprop_ = needs_backprop; | |
| 105 bool retval = needs_backprop; | |
| 106 for (auto &i : stack_) { | |
| 107 if (i->SetupNeedsBackprop(needs_backprop)) { | |
| 108 retval = true; | |
| 109 } | |
| 110 } | |
| 111 return retval; | |
| 112 } | |
| 113 // Frozen networks don't do backprop. | |
| 114 needs_to_backprop_ = false; | |
| 115 return false; | |
| 116 } | |
| 117 | |
| 118 // Returns an integer reduction factor that the network applies to the | |
| 119 // time sequence. Assumes that any 2-d is already eliminated. Used for | |
| 120 // scaling bounding boxes of truth data. | |
| 121 // WARNING: if GlobalMinimax is used to vary the scale, this will return | |
| 122 // the last used scale factor. Call it before any forward, and it will return | |
| 123 // the minimum scale factor of the paths through the GlobalMinimax. | |
| 124 int Plumbing::XScaleFactor() const { | |
| 125 return stack_[0]->XScaleFactor(); | |
| 126 } | |
| 127 | |
| 128 // Provides the (minimum) x scale factor to the network (of interest only to | |
| 129 // input units) so they can determine how to scale bounding boxes. | |
| 130 void Plumbing::CacheXScaleFactor(int factor) { | |
| 131 for (auto &i : stack_) { | |
| 132 i->CacheXScaleFactor(factor); | |
| 133 } | |
| 134 } | |
| 135 | |
| 136 // Provides debug output on the weights. | |
| 137 void Plumbing::DebugWeights() { | |
| 138 for (auto &i : stack_) { | |
| 139 i->DebugWeights(); | |
| 140 } | |
| 141 } | |
| 142 | |
| 143 // Returns a set of strings representing the layer-ids of all layers below. | |
| 144 void Plumbing::EnumerateLayers(const std::string *prefix, std::vector<std::string> &layers) const { | |
| 145 for (size_t i = 0; i < stack_.size(); ++i) { | |
| 146 std::string layer_name; | |
| 147 if (prefix) { | |
| 148 layer_name = *prefix; | |
| 149 } | |
| 150 layer_name += ":" + std::to_string(i); | |
| 151 if (stack_[i]->IsPlumbingType()) { | |
| 152 auto *plumbing = static_cast<Plumbing *>(stack_[i]); | |
| 153 plumbing->EnumerateLayers(&layer_name, layers); | |
| 154 } else { | |
| 155 layers.push_back(layer_name); | |
| 156 } | |
| 157 } | |
| 158 } | |
| 159 | |
| 160 // Returns a pointer to the network layer corresponding to the given id. | |
| 161 Network *Plumbing::GetLayer(const char *id) const { | |
| 162 char *next_id; | |
| 163 int index = strtol(id, &next_id, 10); | |
| 164 if (index < 0 || static_cast<unsigned>(index) >= stack_.size()) { | |
| 165 return nullptr; | |
| 166 } | |
| 167 if (stack_[index]->IsPlumbingType()) { | |
| 168 auto *plumbing = static_cast<Plumbing *>(stack_[index]); | |
| 169 ASSERT_HOST(*next_id == ':'); | |
| 170 return plumbing->GetLayer(next_id + 1); | |
| 171 } | |
| 172 return stack_[index]; | |
| 173 } | |
| 174 | |
| 175 // Returns a pointer to the learning rate for the given layer id. | |
| 176 float *Plumbing::LayerLearningRatePtr(const char *id) { | |
| 177 char *next_id; | |
| 178 int index = strtol(id, &next_id, 10); | |
| 179 if (index < 0 || static_cast<unsigned>(index) >= stack_.size()) { | |
| 180 return nullptr; | |
| 181 } | |
| 182 if (stack_[index]->IsPlumbingType()) { | |
| 183 auto *plumbing = static_cast<Plumbing *>(stack_[index]); | |
| 184 ASSERT_HOST(*next_id == ':'); | |
| 185 return plumbing->LayerLearningRatePtr(next_id + 1); | |
| 186 } | |
| 187 if (static_cast<unsigned>(index) >= learning_rates_.size()) { | |
| 188 return nullptr; | |
| 189 } | |
| 190 return &learning_rates_[index]; | |
| 191 } | |
| 192 | |
| 193 // Writes to the given file. Returns false in case of error. | |
| 194 bool Plumbing::Serialize(TFile *fp) const { | |
| 195 if (!Network::Serialize(fp)) { | |
| 196 return false; | |
| 197 } | |
| 198 uint32_t size = stack_.size(); | |
| 199 // Can't use PointerVector::Serialize here as we need a special DeSerialize. | |
| 200 if (!fp->Serialize(&size)) { | |
| 201 return false; | |
| 202 } | |
| 203 for (uint32_t i = 0; i < size; ++i) { | |
| 204 if (!stack_[i]->Serialize(fp)) { | |
| 205 return false; | |
| 206 } | |
| 207 } | |
| 208 if ((network_flags_ & NF_LAYER_SPECIFIC_LR) && !fp->Serialize(learning_rates_)) { | |
| 209 return false; | |
| 210 } | |
| 211 return true; | |
| 212 } | |
| 213 | |
| 214 // Reads from the given file. Returns false in case of error. | |
| 215 bool Plumbing::DeSerialize(TFile *fp) { | |
| 216 for (auto data : stack_) { | |
| 217 delete data; | |
| 218 } | |
| 219 stack_.clear(); | |
| 220 no_ = 0; // We will be modifying this as we AddToStack. | |
| 221 uint32_t size; | |
| 222 if (!fp->DeSerialize(&size)) { | |
| 223 return false; | |
| 224 } | |
| 225 for (uint32_t i = 0; i < size; ++i) { | |
| 226 Network *network = CreateFromFile(fp); | |
| 227 if (network == nullptr) { | |
| 228 return false; | |
| 229 } | |
| 230 AddToStack(network); | |
| 231 } | |
| 232 if ((network_flags_ & NF_LAYER_SPECIFIC_LR) && !fp->DeSerialize(learning_rates_)) { | |
| 233 return false; | |
| 234 } | |
| 235 return true; | |
| 236 } | |
| 237 | |
| 238 // Updates the weights using the given learning rate, momentum and adam_beta. | |
| 239 // num_samples is used in the adam computation iff use_adam_ is true. | |
| 240 void Plumbing::Update(float learning_rate, float momentum, float adam_beta, int num_samples) { | |
| 241 for (size_t i = 0; i < stack_.size(); ++i) { | |
| 242 if (network_flags_ & NF_LAYER_SPECIFIC_LR) { | |
| 243 if (i < learning_rates_.size()) { | |
| 244 learning_rate = learning_rates_[i]; | |
| 245 } else { | |
| 246 learning_rates_.push_back(learning_rate); | |
| 247 } | |
| 248 } | |
| 249 if (stack_[i]->IsTraining()) { | |
| 250 stack_[i]->Update(learning_rate, momentum, adam_beta, num_samples); | |
| 251 } | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 // Sums the products of weight updates in *this and other, splitting into | |
| 256 // positive (same direction) in *same and negative (different direction) in | |
| 257 // *changed. | |
| 258 void Plumbing::CountAlternators(const Network &other, TFloat *same, TFloat *changed) const { | |
| 259 ASSERT_HOST(other.type() == type_); | |
| 260 const auto *plumbing = static_cast<const Plumbing *>(&other); | |
| 261 ASSERT_HOST(plumbing->stack_.size() == stack_.size()); | |
| 262 for (size_t i = 0; i < stack_.size(); ++i) { | |
| 263 stack_[i]->CountAlternators(*plumbing->stack_[i], same, changed); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 } // namespace tesseract. |
