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