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