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