HOG2
NN.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <math.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <cassert>
6 #include "NN.h"
7 
8 
9 /*
10  class NN
11  double[][][] weights;
12  double[][][] errors;
13  double[] hidden;
14  double[] output;
15  double rate;
16  */
17 
18 static const float VERSION = 1.0;
19 
20 using namespace std;
21 
22 NN::NN(int _inputs, int _hiddens, int _outputs, double learnrate)
23 :inputs(_inputs), hiddens(_hiddens), outputs(_outputs)
24 {
26  rate = learnrate;
28 }
29 
31 {
32  freeMemory();
33 }
34 
35 NN::NN(NN *nn)
36 {
37  inputs = nn->inputs;
38  hiddens = nn->hiddens;
39  outputs = nn->outputs;
40  rate = nn->rate;
42 
44 }
45 
46 NN::NN(char *f)
47 {
48  inputs = -1;
49  load(f);
50 }
51 
53 {
54  NN *nn = (NN*)fa;
55  inputs = nn->inputs;
56  hiddens = nn->hiddens;
57  outputs = nn->outputs;
58  rate = nn->rate;
61 }
62 
63 void NN::allocateMemory(const NN *nn)
64 {
65  hidden.resize(hiddens);
66  output.resize(outputs);
67 
68 
69  weights.resize(2);
70  updatedweights.resize(2);
71  errors.resize(2);// = new double**[2];
72 
73  weights[0].resize(hiddens);
74  updatedweights[0].resize(hiddens);
75  errors[0].resize(hiddens);
76  for (int x = 0; x < hiddens; x++)
77  {
78  weights[0][x].resize(inputs+1);
79  updatedweights[0][x].resize(inputs+1);
80  errors[0][x].resize(inputs+1);
81  }
82 
83  for (int x = 0; x < hiddens; x++)
84  {
85  for (int y = 0; y < inputs+1; y++)
86  {
87  if (nn)
88  {
89  weights[0][x][y] = nn->weights[0][x][y];
90  }
91  else {
92  weights[0][x][y] = ((double)2*random()/RAND_MAX-1)/3;
93  }
94  errors[0][x][y] = 0;
95  }
96  }
97  weights[1].resize(outputs);
98  updatedweights[1].resize(outputs);
99  errors[1].resize(outputs);// = new double*[outputs];
100  for (int x = 0; x < outputs; x++)
101  {
102  weights[1][x].resize(hiddens+1);
103  updatedweights[1][x].resize(hiddens+1);
104  errors[1][x].resize(hiddens+1);// = new double[hiddens+1];
105  }
106  for (int x = 0; x < outputs; x++)
107  {
108  for (int y = 0; y < hiddens+1; y++)
109  {
110  if (nn)
111  weights[1][x][y] = weights[1][x][y];
112  else
113  weights[1][x][y] = ((double)2*random()/RAND_MAX-1)/3;
114  errors[1][x][y] = 0;
115  }
116  }
117 }
118 
120 {
121 // for (int x = 0; x < outputs; x++)
122 // {
123 // delete [] weights[1][x];// = new double[hiddens+1];
124 // delete [] errors[1][x];// = new double[hiddens+1];
125 // }
126 // delete [] weights[1];// = new double*[outputs];
127 // delete [] errors[1];// = new double*[outputs];
128 //
129 // for (int x = 0; x < hiddens; x++)
130 // {
131 // delete weights[0][x];// = new double[inputs+1];
132 // delete errors[0][x];// = new double[inputs+1];
133 // }
134 // delete [] weights[0];// = (double**)new double[hiddens];
135 // delete [] errors[0];// = (double **)new double[hiddens];
136 //
137 // delete [] weights;// = new double**[2];
138 // delete [] errors;// = new double**[2];
139 //
140 // delete [] hidden;// = new double[hiddens];
141 // delete [] output;// = new double[outputs];
142 }
143 
144 void NN::load(const NN *nn)
145 {
146  if ((nn->inputs != inputs) || (nn->hiddens != hiddens) || (nn->outputs != outputs))
147  {
148  freeMemory();
150  allocateMemory(nn);
151  }
152  else {
153  for (int x = 0; x < hiddens; x++)
154  {
155  for (int y = 0; y < inputs+1; y++)
156  {
157  weights[0][x][y] = nn->weights[0][x][y];
158  errors[0][x][y] = 0;
159  }
160  }
161  for (int x = 0; x < outputs; x++)
162  {
163  for (int y = 0; y < hiddens+1; y++)
164  {
165  weights[1][x][y] = weights[1][x][y];
166  errors[1][x][y] = 0;
167  }
168  }
169  }
170 }
171 
172 bool NN::validSaveFile(char *fname)
173 {
174  FILE *f;
175  f = fopen(fname, "r");
176  if (f == 0)
177  {
178  return false;
179  }
180  int finput, fhidden, foutput;
181  float version;
182  int res = fscanf(f, "NN %f %d %d %d\n", &version, &finput, &fhidden, &foutput);
183  fclose(f);
184  if (res != 4)
185  {
186  return false;
187  }
188  if (version > VERSION)
189  {
190  return false;
191  }
192  return true;
193 }
194 
195 void NN::load(const char *fname)
196 {
197  FILE *f;
198  f = fopen(fname, "r");
199  if (f == 0)
200  {
201  fprintf(stderr, "Error: could not load file %s\n", fname);
202  return;
203  }
204  load(f);
205  fclose(f);
206 }
207 
208 void NN::load(FILE *f)
209 {
210  int finput, fhidden, foutput;
211  float version;
212  int res = fscanf(f, "NN %f %d %d %d\n", &version, &finput, &fhidden, &foutput);
213  if (res != 4)
214  {
215  printf("Error: unrecognized neural network file. Expected header 'NN <version> <inputs> <hidden> <outputs>'.");
216  exit(0);
217  }
218  if (version > VERSION)
219  {
220  printf("Error: loaded network is %1.2f, but code can only handle %1.2f.",
221  version, VERSION);
222  exit(0);
223  }
224  if ((finput != inputs) || (fhidden != hiddens) || (foutput != outputs))
225  {
226  if (inputs != -1)
227  freeMemory();
228  inputs = finput;
229  hiddens = fhidden;
230  outputs = foutput;
231  allocateMemory();
232  }
233 
234  for (int x = 0; x < hiddens; x++)
235  {
236  for (int y = 0; y < inputs+1; y++)
237  {
238  fscanf(f, "%lf", &weights[0][x][y]);
239  //fread(&weights[0][x][y], sizeof(double), 1, f);
240  errors[0][x][y] = 0;
241  }
242  }
243  for (int x = 0; x < outputs; x++)
244  {
245  for (int y = 0; y < hiddens+1; y++)
246  {
247  fscanf(f, "%lf ", &weights[1][x][y]);
248  //fread(&weights[1][x][y], sizeof(double), 1, f);
249  errors[1][x][y] = 0;
250  }
251  }
252 }
253 
254 void NN::save(const char *fname)
255 {
256  FILE *f;
257  f = fopen(fname, "w+");
258  if (f == 0)
259  {
260  fprintf(stderr, "Error: could not open file for saving.\n");
261  return;
262  }
263  save(f);
264  fclose(f);
265 }
266 
267 void NN::save(FILE *f)
268 {
269  fprintf(f, "NN %1.2f %d %d %d\n", VERSION, inputs, hiddens, outputs);
270  for (int x = 0; x < hiddens; x++)
271  {
272  for (int y = 0; y < inputs+1; y++)
273  {
274  //fwrite(&weights[0][x][y], sizeof(double), 1, f);
275  fprintf(f, "%lf ", weights[0][x][y]);
276  }
277  fprintf(f, "\n");
278  }
279  //printf("Done...with internal\n");
280  for (int x = 0; x < outputs; x++)
281  {
282  for (int y = 0; y < hiddens+1; y++)
283  {
284  //fwrite(&weights[1][x][y], sizeof(double), 1, f);
285  fprintf(f, "%lf ", weights[1][x][y]);
286  }
287  fprintf(f, "\n");
288  }
289  //printf("Done...with external\n");
290 }
291 
292 double NN::g(double a)
293 {
294  return (1/(1+exp(-a)));
295 }
296 
297 double NN::dg(double a)
298 {
299  double g_a = a;
300  return g_a*(1-g_a);
301 }
302 
303 double NN::outputerr(const std::vector<double> &out, const std::vector<double> &expected, int which)
304 {
305  double err = (expected[which]-out[which]);
307  err *= dg(out[which]);
308 
309  return err;
310 }
311 
312 double NN::internalerr(const std::vector<double> &out, const std::vector<double> &expected, int which)
313 {
314  double answer = 0;
315 
316  for (int x = 0; x < outputs; x++) // weights[1].length
317  answer+=weights[1][x][which]*outputerr(out, expected, x);
318  answer *= dg(hidden[which]);
319 
320  return answer;
321 }
322 
323 double NN::internalinputerr(const std::vector<double> &out, const std::vector<double> &expected, int which)
324 {
325  double answer = 0;
326 
327  for (int x = 0; x < outputs; x++)
328  answer+=hidden[which]*outputerr(out, expected, x)*dg(weights[1][x][which]);
329 
330  return answer;
331 }
332 
333 double NN::error(const std::vector<double> &target)
334 {
335  double answer = 0, t;
336  for (int x = 0; x < outputs; x++) // output.length
337  {
338  t = (output[x]-target[x]);
339  answer += t*t;
340  }
341  return answer;
342 }
343 
344 double NN::train(std::vector<double> &input, std::vector<double> &target)
345 {
346  test(input);
347 
348  // calulate error in output layer
349  for (int x = 0; x < outputs; x++) // weights[1].length
350  {
351  double xoutputerror = rate*outputerr(output, target, x);
352  errors[1][x][0] = xoutputerror;
353  updatedweights[1][x][0] = weights[1][x][0] + errors[1][x][0];
354  for (int y = 0; y < hiddens; y++)
355  {
356  errors[1][x][y+1] = hidden[y]*xoutputerror;
357  updatedweights[1][x][y+1] = weights[1][x][y+1]+errors[1][x][y+1];
358  }
359  }
360 
361  // calulate error in hidden layer
362  for (int x = 0; x < hiddens; x++) // weights[0].length
363  {
364  double xinternalerror = rate*internalerr(output, target, x);
365  errors[0][x][0] = xinternalerror;
366  updatedweights[0][x][0] = weights[0][x][0]+errors[0][x][0];
367  for (int y = 0; y < inputs; y++)
368  {
369  errors[0][x][y+1] = input[y]*xinternalerror;
370  updatedweights[0][x][y+1] = weights[0][x][y+1]+errors[0][x][y+1];
371  }
372  }
373  updatedweights.swap(weights);
374  return error(target);
375 }
376 
377 double NN::train(std::vector<unsigned int> &input, std::vector<double> &target)
378 {
379  assert(!"Code needs updating");
380  test(input);
381 
382  // calulate error in output layer
383  for (int x = 0; x < outputs; x++) // weights[1].length
384  {
385  double xoutputerror = rate*outputerr(output, target, x);
386  errors[1][x][0] = xoutputerror;
387  weights[1][x][0] += errors[1][x][0];
388  for (int y = 0; y < hiddens; y++) // weights[1][x].length-1
389  {
390  errors[1][x][y+1] = hidden[y]*xoutputerror;
391  weights[1][x][y+1] += errors[1][x][y+1];
392  }
393  }
394 
395  // calulate error in hidden layer
396  for (int x = 0; x < hiddens; x++) // weights[0].length
397  {
398  double xinternalerror = rate*internalerr(output, target, x);
399  errors[0][x][0] = xinternalerror;
400  weights[0][x][0] += errors[0][x][0];
401  for (unsigned int y = 0; y < input.size(); y++) //w[0][x].length-1
402  {
403  errors[0][x][input[y]+1] = (1)*xinternalerror;
404  weights[0][x][input[y]+1] += errors[0][x][input[y]+1];
405  }
406  }
407  return error(target);
408 }
409 
410 /*
411  * Given the target output, find input that would maximize this classification
412  */
413 double NN::GetInput(std::vector<double> &input, const std::vector<double> &target)
414 {
415  test(input);
416 
417  // calulate error in hidden layer
418  for (int x = 0; x < hiddens; x++) // weights[0].length
419  {
420  double xinternalerror = internalinputerr(output, target, x);
421  for (int y = 0; y < inputs; y++)
422  {
423  input[y] += weights[0][x][y+1]*xinternalerror;
424  }
425  }
426  return error(target);
427 }
428 
429 double *NN::test(const std::vector<double> &input)
430 {
431  // calculate the input value for the node
432  for (int y = 0; y < hiddens; y++)
433  hidden[y] = weights[0][y][0]*(1);
434 
435  for (int x = 0; x < inputs; x++) //input.length
436  if (input[x] != 0)
437  for (int y = 0; y < hiddens; y++) // hidden.length
438  hidden[y] += weights[0][y][x+1]*input[x];
439 
440  // pass value through activation function
441  for (int y = 0; y < hiddens; y++)
442  hidden[y] = g(hidden[y]);
443 
444  for (int y = 0; y < outputs; y++) // output.length
445  {
446  // calculate the input value for the node
447  output[y] = weights[1][y][0]*(1);
448  for (int x = 0; x < hiddens; x++) // hidden.length
449  output[y] += weights[1][y][x+1]*hidden[x];
450 
452  output[y] = g(output[y]);
453  else if (outputActivation == kStep)
454  {
455  if (output[y] > .5)
456  output[y] = 1.0;
457  else
458  output[y] = 0.0;
459  }
460  else // kLinear
461  output[y] = output[y];
462  }
463  return &output[0];
464 }
465 
466 double *NN::test(const std::vector<unsigned int> &input)
467 {
468  // calculate the input value for the node
469  for (int y = 0; y < hiddens; y++)
470  hidden[y] = weights[0][y][0]*(1);
471 
472  for (unsigned int x = 0; x < input.size(); x++) //input.length
473  for (int y = 0; y < hiddens; y++) // hidden.length
474  hidden[y] += weights[0][y][input[x]+1]*(1);
475 
476  // pass value through activation function
477  for (int y = 0; y < hiddens; y++)
478  hidden[y] = g(hidden[y]);
479 
480  for (int y = 0; y < outputs; y++) // output.length
481  {
482  // calculate the input value for the node
483  output[y] = weights[1][y][0]*(1);
484  for (int x = 0; x < hiddens; x++) // hidden.length
485  output[y] += weights[1][y][x+1]*hidden[x];
486 
488  output[y] = g(output[y]);
489  else if (outputActivation == kStep)
490  {
491  if (output[y] > .5)
492  output[y] = 1.0;
493  else
494  output[y] = 0.0;
495  }
496  else // kLinear
497  output[y] = output[y];
498  }
499  return &output[0];
500 }
501 
502 void NN::Print()
503 {
504  cout << "Neural network weights:" << endl;
505  for (int x = 0; x < outputs; x++) // weights[1].length
506  {
507  cout << "Input weights to output " << x << ":";
508  for (int y = 0; y < hiddens+1; y++)
509  cout << " " << weights[1][x][y];
510  cout << endl;
511  }
512  for (int x = 0; x < outputs; x++)
513  {
514  cout << "Input weights to hidden node " << x << ":";
515  for (int y = 0; y < hiddens+1; y++)
516  cout << " " << weights[0][x][y];
517  cout << endl;
518  }
519 }
520 
521 
NN::errors
std::vector< std::vector< std::vector< double > > > errors
Definition: NN.h:38
NN::test
double * test(const std::vector< double > &input)
Definition: NN.cpp:429
NN::internalinputerr
double internalinputerr(const std::vector< double > &output, const std::vector< double > &expected, int which)
Definition: NN.cpp:323
NN::error
double error(const std::vector< double > &outputs)
Definition: NN.cpp:333
NN::validSaveFile
static bool validSaveFile(char *fname)
Definition: NN.cpp:172
NN::inputs
int inputs
Definition: NN.h:41
NN::load
void load(const char *)
Definition: NN.cpp:195
NN::GetInput
double GetInput(std::vector< double > &input, const std::vector< double > &target)
Definition: NN.cpp:413
NN
Definition: NN.h:7
NN::train
double train(std::vector< double > &input, std::vector< double > &target)
Definition: NN.cpp:344
NN::dg
double dg(double a)
Definition: NN.cpp:297
NN::hiddens
int hiddens
Definition: NN.h:41
FunctionApproximator::rate
double rate
Definition: FunctionApproximator.h:61
kExponential
@ kExponential
Definition: FunctionApproximator.h:22
NN::outputerr
double outputerr(const std::vector< double > &output, const std::vector< double > &expected, int which)
Definition: NN.cpp:303
FunctionApproximator
Definition: FunctionApproximator.h:25
NN::save
void save(const char *)
Definition: NN.cpp:254
NN::~NN
~NN()
Definition: NN.cpp:30
NN::outputs
int outputs
Definition: NN.h:41
kStep
@ kStep
Definition: FunctionApproximator.h:21
NN::freeMemory
void freeMemory()
Definition: NN.cpp:119
NN::output
std::vector< double > output
Definition: NN.h:40
std
Definition: CanonicalGraphEnvironment.h:26
NN::updatedweights
std::vector< std::vector< std::vector< double > > > updatedweights
Definition: NN.h:37
NN::allocateMemory
void allocateMemory(const NN *nn=0)
Definition: NN.cpp:63
VERSION
static const float VERSION
Definition: NN.cpp:18
NN::Print
void Print()
Definition: NN.cpp:502
NN::internalerr
double internalerr(const std::vector< double > &output, const std::vector< double > &expected, int which)
Definition: NN.cpp:312
FunctionApproximator::outputActivation
tActivation outputActivation
Definition: FunctionApproximator.h:62
NN::g
double g(double a)
Definition: NN.cpp:292
NN::hidden
std::vector< double > hidden
Definition: NN.h:39
NN::NN
NN(int inputs, int hiddens, int outputs, double learnrate)
Definition: NN.cpp:22
NN.h
NN::weights
std::vector< std::vector< std::vector< double > > > weights
Definition: NN.h:36