tesseract  3.05.02
neural_net.cpp
Go to the documentation of this file.
1 // Copyright 2008 Google Inc.
2 // All Rights Reserved.
3 // Author: ahmadab@google.com (Ahmad Abdulkader)
4 //
5 // neural_net.cpp: Declarations of a class for an object that
6 // represents an arbitrary network of neurons
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 #include <vector>
18 #include <string>
19 #include "neural_net.h"
20 #include "input_file_buffer.h"
21 
22 namespace tesseract {
23 
25  Init();
26 }
27 
29  // clean up the wts chunks vector
30  for (int vec = 0; vec < static_cast<int>(wts_vec_.size()); vec++) {
31  delete wts_vec_[vec];
32  }
33  // clean up neurons
34  delete []neurons_;
35  // clean up nodes
36  for (int node_idx = 0; node_idx < neuron_cnt_; node_idx++) {
37  delete []fast_nodes_[node_idx].inputs;
38  }
39 
40 }
41 
42 // Initiaization function
44  read_only_ = true;
45  auto_encoder_ = false;
46  alloc_wgt_cnt_ = 0;
47  wts_cnt_ = 0;
48  neuron_cnt_ = 0;
49  in_cnt_ = 0;
50  out_cnt_ = 0;
51  wts_vec_.clear();
52  neurons_ = NULL;
53  inputs_mean_.clear();
54  inputs_std_dev_.clear();
55  inputs_min_.clear();
56  inputs_max_.clear();
57 }
58 
59 // Does a fast feedforward for read_only nets
60 // Templatized for float and double Types
61 template <typename Type> bool NeuralNet::FastFeedForward(const Type *inputs,
62  Type *outputs) {
63  int node_idx = 0;
64  Node *node = &fast_nodes_[0];
65  // feed inputs in and offset them by the pre-computed bias
66  for (node_idx = 0; node_idx < in_cnt_; node_idx++, node++) {
67  node->out = inputs[node_idx] - node->bias;
68  }
69  // compute nodes activations and outputs
70  for (;node_idx < neuron_cnt_; node_idx++, node++) {
71  double activation = -node->bias;
72  for (int fan_in_idx = 0; fan_in_idx < node->fan_in_cnt; fan_in_idx++) {
73  activation += (node->inputs[fan_in_idx].input_weight *
74  node->inputs[fan_in_idx].input_node->out);
75  }
76  node->out = Neuron::Sigmoid(activation);
77  }
78  // copy the outputs to the output buffers
79  node = &fast_nodes_[neuron_cnt_ - out_cnt_];
80  for (node_idx = 0; node_idx < out_cnt_; node_idx++, node++) {
81  outputs[node_idx] = node->out;
82  }
83  return true;
84 }
85 
86 // Performs a feedforward for general nets. Used mainly in training mode
87 // Templatized for float and double Types
88 template <typename Type> bool NeuralNet::FeedForward(const Type *inputs,
89  Type *outputs) {
90  // call the fast version in case of readonly nets
91  if (read_only_) {
92  return FastFeedForward(inputs, outputs);
93  }
94  // clear all neurons
95  Clear();
96  // for auto encoders, apply no input normalization
97  if (auto_encoder_) {
98  for (int in = 0; in < in_cnt_; in++) {
99  neurons_[in].set_output(inputs[in]);
100  }
101  } else {
102  // Input normalization : subtract mean and divide by stddev
103  for (int in = 0; in < in_cnt_; in++) {
104  neurons_[in].set_output((inputs[in] - inputs_min_[in]) /
105  (inputs_max_[in] - inputs_min_[in]));
106  neurons_[in].set_output((neurons_[in].output() - inputs_mean_[in]) /
107  inputs_std_dev_[in]);
108  }
109  }
110  // compute the net outputs: follow a pull model each output pulls the
111  // outputs of its input nodes and so on
112  for (int out = neuron_cnt_ - out_cnt_; out < neuron_cnt_; out++) {
113  neurons_[out].FeedForward();
114  // copy the values to the output buffer
115  outputs[out] = neurons_[out].output();
116  }
117  return true;
118 }
119 
120 // Sets a connection between two neurons
121 bool NeuralNet::SetConnection(int from, int to) {
122  // allocate the wgt
123  float *wts = AllocWgt(1);
124  if (wts == NULL) {
125  return false;
126  }
127  // register the connection
128  neurons_[to].AddFromConnection(neurons_ + from, wts, 1);
129  return true;
130 }
131 
132 // Create a fast readonly version of the net
134  fast_nodes_.resize(neuron_cnt_);
135  // build the node structures
136  int wts_cnt = 0;
137  for (int node_idx = 0; node_idx < neuron_cnt_; node_idx++) {
138  Node *node = &fast_nodes_[node_idx];
139  if (neurons_[node_idx].node_type() == Neuron::Input) {
140  // Input neurons have no fan-in
141  node->fan_in_cnt = 0;
142  node->inputs = NULL;
143  // Input bias is the normalization offset computed from
144  // training input stats
145  if (fabs(inputs_max_[node_idx] - inputs_min_[node_idx]) <
146  kMinInputRange) {
147  // if the range approaches zero, the stdev is not defined,
148  // this indicates that this input does not change.
149  // Set the bias to zero
150  node->bias = 0.0f;
151  } else {
152  node->bias = inputs_min_[node_idx] + (inputs_mean_[node_idx] *
153  (inputs_max_[node_idx] - inputs_min_[node_idx]));
154  }
155  } else {
156  node->bias = neurons_[node_idx].bias();
157  node->fan_in_cnt = neurons_[node_idx].fan_in_cnt();
158  // allocate memory for fan-in nodes
159  node->inputs = new WeightedNode[node->fan_in_cnt];
160  for (int fan_in = 0; fan_in < node->fan_in_cnt; fan_in++) {
161  // identify fan-in neuron
162  const int id = neurons_[node_idx].fan_in(fan_in)->id();
163  // Feedback connections are not allowed and should never happen
164  if (id >= node_idx) {
165  return false;
166  }
167  // add the the fan-in neuron and its wgt
168  node->inputs[fan_in].input_node = &fast_nodes_[id];
169  float wgt_val = neurons_[node_idx].fan_in_wts(fan_in);
170  // for input neurons normalize the wgt by the input scaling
171  // values to save time during feedforward
172  if (neurons_[node_idx].fan_in(fan_in)->node_type() == Neuron::Input) {
173  // if the range approaches zero, the stdev is not defined,
174  // this indicates that this input does not change.
175  // Set the weight to zero
176  if (fabs(inputs_max_[id] - inputs_min_[id]) < kMinInputRange) {
177  wgt_val = 0.0f;
178  } else {
179  wgt_val /= ((inputs_max_[id] - inputs_min_[id]) *
180  inputs_std_dev_[id]);
181  }
182  }
183  node->inputs[fan_in].input_weight = wgt_val;
184  }
185  // incr wgt count to validate against at the end
186  wts_cnt += node->fan_in_cnt;
187  }
188  }
189  // sanity check
190  return wts_cnt_ == wts_cnt;
191 }
192 
193 // returns a pointer to the requested set of weights
194 // Allocates in chunks
195 float * NeuralNet::AllocWgt(int wgt_cnt) {
196  // see if need to allocate a new chunk of wts
197  if (wts_vec_.size() == 0 || (alloc_wgt_cnt_ + wgt_cnt) > kWgtChunkSize) {
198  // add the new chunck to the wts_chunks vector
199  wts_vec_.push_back(new vector<float> (kWgtChunkSize));
200  alloc_wgt_cnt_ = 0;
201  }
202  float *ret_ptr = &((*wts_vec_.back())[alloc_wgt_cnt_]);
203  // incr usage counts
204  alloc_wgt_cnt_ += wgt_cnt;
205  wts_cnt_ += wgt_cnt;
206  return ret_ptr;
207 }
208 
209 // create a new net object using an input file as a source
210 NeuralNet *NeuralNet::FromFile(const string file_name) {
211  // open the file
212  InputFileBuffer input_buff(file_name);
213  // create a new net object using input buffer
214  NeuralNet *net_obj = FromInputBuffer(&input_buff);
215  return net_obj;
216 }
217 
218 // create a net object from an input buffer
220  // create a new net object
221  NeuralNet *net_obj = new NeuralNet();
222  // load the net
223  if (!net_obj->ReadBinary(ib)) {
224  delete net_obj;
225  net_obj = NULL;
226  }
227  return net_obj;
228 }
229 
230 // Compute the output of a specific output node.
231 // This function is useful for application that are interested in a single
232 // output of the net and do not want to waste time on the rest
233 // This is the fast-read-only version of this function
234 template <typename Type> bool NeuralNet::FastGetNetOutput(const Type *inputs,
235  int output_id,
236  Type *output) {
237  // feed inputs in and offset them by the pre-computed bias
238  int node_idx = 0;
239  Node *node = &fast_nodes_[0];
240  for (node_idx = 0; node_idx < in_cnt_; node_idx++, node++) {
241  node->out = inputs[node_idx] - node->bias;
242  }
243 
244  // compute nodes' activations and outputs for hidden nodes if any
245  int hidden_node_cnt = neuron_cnt_ - out_cnt_;
246  for (;node_idx < hidden_node_cnt; node_idx++, node++) {
247  double activation = -node->bias;
248  for (int fan_in_idx = 0; fan_in_idx < node->fan_in_cnt; fan_in_idx++) {
249  activation += (node->inputs[fan_in_idx].input_weight *
250  node->inputs[fan_in_idx].input_node->out);
251  }
252  node->out = Neuron::Sigmoid(activation);
253  }
254 
255  // compute the output of the required output node
256  node += output_id;
257  double activation = -node->bias;
258  for (int fan_in_idx = 0; fan_in_idx < node->fan_in_cnt; fan_in_idx++) {
259  activation += (node->inputs[fan_in_idx].input_weight *
260  node->inputs[fan_in_idx].input_node->out);
261  }
262  (*output) = Neuron::Sigmoid(activation);
263  return true;
264 }
265 
266 // Performs a feedforward for general nets. Used mainly in training mode
267 // Templatized for float and double Types
268 template <typename Type> bool NeuralNet::GetNetOutput(const Type *inputs,
269  int output_id,
270  Type *output) {
271  // validate output id
272  if (output_id < 0 || output_id >= out_cnt_) {
273  return false;
274  }
275 
276  // call the fast version in case of readonly nets
277  if (read_only_) {
278  return FastGetNetOutput(inputs, output_id, output);
279  }
280 
281  // For the slow version, we'll just call FeedForward and return the
282  // appropriate output
283  vector<Type> outputs(out_cnt_);
284  if (!FeedForward(inputs, &outputs[0])) {
285  return false;
286  }
287  (*output) = outputs[output_id];
288 
289  return true;
290 }
291 
292 // Instantiate all supported templates now that the functions have been defined.
293 template bool NeuralNet::FeedForward(const float *inputs, float *outputs);
294 template bool NeuralNet::FeedForward(const double *inputs, double *outputs);
295 template bool NeuralNet::FastFeedForward(const float *inputs, float *outputs);
296 template bool NeuralNet::FastFeedForward(const double *inputs,
297  double *outputs);
298 template bool NeuralNet::GetNetOutput(const float *inputs, int output_id,
299  float *output);
300 template bool NeuralNet::GetNetOutput(const double *inputs, int output_id,
301  double *output);
302 template bool NeuralNet::FastGetNetOutput(const float *inputs, int output_id,
303  float *output);
304 template bool NeuralNet::FastGetNetOutput(const double *inputs, int output_id,
305  double *output);
306 template bool NeuralNet::ReadBinary(InputFileBuffer *input_buffer);
307 
308 }
bool SetConnection(int from, int to)
Definition: neural_net.cpp:121
static NeuralNet * FromFile(const string file_name)
Definition: neural_net.cpp:210
static NeuralNet * FromInputBuffer(InputFileBuffer *ib)
Definition: neural_net.cpp:219
WeightedNode * inputs
Definition: neural_net.h:65
int fan_in_cnt() const
Definition: neuron.h:111
bool FeedForward(const Type *inputs, Type *outputs)
Definition: neural_net.cpp:88
Neuron * fan_in(int idx) const
Definition: neuron.h:114
vector< float > inputs_max_
Definition: neural_net.h:96
float output() const
Definition: neuron.h:102
bool FastFeedForward(const Type *inputs, Type *outputs)
Definition: neural_net.cpp:61
float fan_in_wts(int idx) const
Definition: neuron.h:117
void AddFromConnection(Neuron *neuron_vec, float *wts_offset, int from_cnt)
Definition: neuron.cpp:83
void FeedForward()
Definition: neuron.cpp:48
bool FastGetNetOutput(const Type *inputs, int output_id, Type *output)
Definition: neural_net.cpp:234
vector< vector< float > * > wts_vec_
Definition: neural_net.h:92
static const int kWgtChunkSize
Definition: neural_net.h:85
bool GetNetOutput(const Type *inputs, int output_id, Type *output)
Definition: neural_net.cpp:268
vector< float > inputs_min_
Definition: neural_net.h:98
bool ReadBinary(ReadBuffType *input_buff)
Definition: neural_net.h:115
vector< float > inputs_std_dev_
Definition: neural_net.h:102
void set_output(float out_val)
Definition: neuron.h:105
static float Sigmoid(float activation)
Definition: neuron.cpp:94
float bias() const
Definition: neuron.h:123
int id() const
Definition: neuron.h:108
vector< float > inputs_mean_
Definition: neural_net.h:100
float * AllocWgt(int wgt_cnt)
Definition: neural_net.cpp:195
vector< Node > fast_nodes_
Definition: neural_net.h:105