ruby-fann 0.7.10 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/History.txt +6 -1
  2. data/License.txt +1 -1
  3. data/Manifest.txt +22 -1
  4. data/README.txt +0 -1
  5. data/Rakefile +0 -0
  6. data/config/hoe.rb +0 -0
  7. data/config/requirements.rb +0 -0
  8. data/ext/ruby_fann/MANIFEST +0 -0
  9. data/ext/ruby_fann/Makefile +36 -28
  10. data/ext/ruby_fann/doublefann.c +30 -0
  11. data/ext/ruby_fann/doublefann.h +33 -0
  12. data/ext/ruby_fann/extconf.rb +9 -5
  13. data/ext/ruby_fann/fann.c +1552 -0
  14. data/ext/ruby_fann/fann_activation.h +144 -0
  15. data/ext/ruby_fann/fann_augment.h +0 -0
  16. data/ext/ruby_fann/fann_cascade.c +1031 -0
  17. data/ext/ruby_fann/fann_cascade.h +503 -0
  18. data/ext/ruby_fann/fann_data.h +799 -0
  19. data/ext/ruby_fann/fann_error.c +204 -0
  20. data/ext/ruby_fann/fann_error.h +161 -0
  21. data/ext/ruby_fann/fann_internal.h +148 -0
  22. data/ext/ruby_fann/fann_io.c +762 -0
  23. data/ext/ruby_fann/fann_io.h +100 -0
  24. data/ext/ruby_fann/fann_train.c +962 -0
  25. data/ext/ruby_fann/fann_train.h +1203 -0
  26. data/ext/ruby_fann/fann_train_data.c +1231 -0
  27. data/ext/ruby_fann/neural_network.c +0 -0
  28. data/lib/ruby_fann/neurotica.rb +0 -0
  29. data/lib/ruby_fann/version.rb +3 -3
  30. data/lib/ruby_fann.rb +0 -0
  31. data/neurotica1.png +0 -0
  32. data/neurotica2.vrml +18 -18
  33. data/setup.rb +0 -0
  34. data/tasks/deployment.rake +0 -0
  35. data/tasks/environment.rake +0 -0
  36. data/tasks/website.rake +0 -0
  37. data/test/test.train +0 -0
  38. data/test/test_helper.rb +0 -0
  39. data/test/test_neurotica.rb +0 -0
  40. data/test/test_ruby_fann.rb +0 -0
  41. data/test/test_ruby_fann_functional.rb +0 -0
  42. data/verify.train +0 -0
  43. data/website/index.html +42 -92
  44. data/website/index.txt +0 -0
  45. data/website/javascripts/rounded_corners_lite.inc.js +0 -0
  46. data/website/stylesheets/screen.css +0 -0
  47. data/website/template.rhtml +0 -0
  48. data/xor.train +0 -0
  49. data/xor_cascade.net +2 -2
  50. data/xor_float.net +1 -1
  51. metadata +22 -6
  52. data/log/debug.log +0 -0
@@ -0,0 +1,1031 @@
1
+ /*
2
+ Fast Artificial Neural Network Library (fann)
3
+ Copyright (C) 2003 Steffen Nissen (lukesky@diku.dk)
4
+
5
+ This library is free software; you can redistribute it and/or
6
+ modify it under the terms of the GNU Lesser General Public
7
+ License as published by the Free Software Foundation; either
8
+ version 2.1 of the License, or (at your option) any later version.
9
+
10
+ This library is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ Lesser General Public License for more details.
14
+
15
+ You should have received a copy of the GNU Lesser General Public
16
+ License along with this library; if not, write to the Free Software
17
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
+ */
19
+
20
+ #include "config.h"
21
+ #include "fann.h"
22
+ #include "string.h"
23
+
24
+ #ifndef FIXEDFANN
25
+
26
+ /* #define CASCADE_DEBUG */
27
+ /* #define CASCADE_DEBUG_FULL */
28
+
29
+ void fann_print_connections_raw(struct fann *ann)
30
+ {
31
+ unsigned int i;
32
+
33
+ for(i = 0; i < ann->total_connections_allocated; i++)
34
+ {
35
+ if(i == ann->total_connections)
36
+ {
37
+ printf("* ");
38
+ }
39
+ printf("%f ", ann->weights[i]);
40
+ }
41
+ printf("\n\n");
42
+ }
43
+
44
+ /* Cascade training directly on the training data.
45
+ The connected_neurons pointers are not valid during training,
46
+ but they will be again after training.
47
+ */
48
+ FANN_EXTERNAL void FANN_API fann_cascadetrain_on_data(struct fann *ann, struct fann_train_data *data,
49
+ unsigned int max_neurons,
50
+ unsigned int neurons_between_reports,
51
+ float desired_error)
52
+ {
53
+ float error;
54
+ unsigned int i;
55
+ unsigned int total_epochs = 0;
56
+ int desired_error_reached;
57
+
58
+ if(neurons_between_reports && ann->callback == NULL)
59
+ {
60
+ printf("Max neurons %3d. Desired error: %.6f\n", max_neurons, desired_error);
61
+ }
62
+
63
+ for(i = 1; i <= max_neurons; i++)
64
+ {
65
+ /* train output neurons */
66
+ total_epochs += fann_train_outputs(ann, data, desired_error);
67
+ error = fann_get_MSE(ann);
68
+ desired_error_reached = fann_desired_error_reached(ann, desired_error);
69
+
70
+ /* print current error */
71
+ if(neurons_between_reports &&
72
+ (i % neurons_between_reports == 0
73
+ || i == max_neurons || i == 1 || desired_error_reached == 0))
74
+ {
75
+ if(ann->callback == NULL)
76
+ {
77
+ printf
78
+ ("Neurons %3d. Current error: %.6f. Total error:%8.4f. Epochs %5d. Bit fail %3d",
79
+ i, error, ann->MSE_value, total_epochs, ann->num_bit_fail);
80
+ if((ann->last_layer-2) != ann->first_layer)
81
+ {
82
+ printf(". candidate steepness %.2f. function %s",
83
+ (ann->last_layer-2)->first_neuron->activation_steepness,
84
+ FANN_ACTIVATIONFUNC_NAMES[(ann->last_layer-2)->first_neuron->activation_function]);
85
+ }
86
+ printf("\n");
87
+ }
88
+ else if((*ann->callback) (ann, data, max_neurons,
89
+ neurons_between_reports, desired_error, total_epochs) == -1)
90
+ {
91
+ /* you can break the training by returning -1 */
92
+ break;
93
+ }
94
+ }
95
+
96
+ if(desired_error_reached == 0)
97
+ break;
98
+
99
+ if(fann_initialize_candidates(ann) == -1)
100
+ {
101
+ /* Unable to initialize room for candidates */
102
+ break;
103
+ }
104
+
105
+ /* train new candidates */
106
+ total_epochs += fann_train_candidates(ann, data);
107
+
108
+ /* this installs the best candidate */
109
+ fann_install_candidate(ann);
110
+ }
111
+
112
+ /* Train outputs one last time but without any desired error */
113
+ total_epochs += fann_train_outputs(ann, data, 0.0);
114
+
115
+ if(neurons_between_reports && ann->callback == NULL)
116
+ {
117
+ printf("Train outputs Current error: %.6f. Epochs %6d\n", fann_get_MSE(ann),
118
+ total_epochs);
119
+ }
120
+
121
+ /* Set pointers in connected_neurons
122
+ * This is ONLY done in the end of cascade training,
123
+ * since there is no need for them during training.
124
+ */
125
+ fann_set_shortcut_connections(ann);
126
+ }
127
+
128
+ FANN_EXTERNAL void FANN_API fann_cascadetrain_on_file(struct fann *ann, const char *filename,
129
+ unsigned int max_neurons,
130
+ unsigned int neurons_between_reports,
131
+ float desired_error)
132
+ {
133
+ struct fann_train_data *data = fann_read_train_from_file(filename);
134
+
135
+ if(data == NULL)
136
+ {
137
+ return;
138
+ }
139
+ fann_cascadetrain_on_data(ann, data, max_neurons, neurons_between_reports, desired_error);
140
+ fann_destroy_train(data);
141
+ }
142
+
143
+ int fann_train_outputs(struct fann *ann, struct fann_train_data *data, float desired_error)
144
+ {
145
+ float error, initial_error, error_improvement;
146
+ float target_improvement = 0.0;
147
+ float backslide_improvement = -1.0e20f;
148
+ unsigned int i;
149
+ unsigned int max_epochs = ann->cascade_max_out_epochs;
150
+ unsigned int stagnation = max_epochs;
151
+
152
+ /* TODO should perhaps not clear all arrays */
153
+ fann_clear_train_arrays(ann);
154
+
155
+ /* run an initial epoch to set the initital error */
156
+ initial_error = fann_train_outputs_epoch(ann, data);
157
+
158
+ if(fann_desired_error_reached(ann, desired_error) == 0)
159
+ return 1;
160
+
161
+ for(i = 1; i < max_epochs; i++)
162
+ {
163
+ error = fann_train_outputs_epoch(ann, data);
164
+
165
+ /*printf("Epoch %6d. Current error: %.6f. Bit fail %d.\n", i, error, ann->num_bit_fail); */
166
+
167
+ if(fann_desired_error_reached(ann, desired_error) == 0)
168
+ {
169
+ #ifdef CASCADE_DEBUG
170
+ printf("Error %f < %f\n", error, desired_error);
171
+ #endif
172
+ return i + 1;
173
+ }
174
+
175
+ /* Improvement since start of train */
176
+ error_improvement = initial_error - error;
177
+
178
+ /* After any significant change, set a new goal and
179
+ * allow a new quota of epochs to reach it */
180
+ if((error_improvement > target_improvement) || (error_improvement < backslide_improvement))
181
+ {
182
+ /*printf("error_improvement=%f, target_improvement=%f, backslide_improvement=%f, stagnation=%d\n", error_improvement, target_improvement, backslide_improvement, stagnation); */
183
+
184
+ target_improvement = error_improvement * (1.0f + ann->cascade_output_change_fraction);
185
+ backslide_improvement = error_improvement * (1.0f - ann->cascade_output_change_fraction);
186
+ stagnation = i + ann->cascade_output_stagnation_epochs;
187
+ }
188
+
189
+ /* No improvement in allotted period, so quit */
190
+ if(i >= stagnation)
191
+ {
192
+ return i + 1;
193
+ }
194
+ }
195
+
196
+ return max_epochs;
197
+ }
198
+
199
+ float fann_train_outputs_epoch(struct fann *ann, struct fann_train_data *data)
200
+ {
201
+ unsigned int i;
202
+
203
+ fann_reset_MSE(ann);
204
+
205
+ for(i = 0; i < data->num_data; i++)
206
+ {
207
+ fann_run(ann, data->input[i]);
208
+ fann_compute_MSE(ann, data->output[i]);
209
+ fann_update_slopes_batch(ann, ann->last_layer - 1, ann->last_layer - 1);
210
+ }
211
+
212
+ switch (ann->training_algorithm)
213
+ {
214
+ case FANN_TRAIN_RPROP:
215
+ fann_update_weights_irpropm(ann, (ann->last_layer - 1)->first_neuron->first_con,
216
+ ann->total_connections);
217
+ break;
218
+ case FANN_TRAIN_QUICKPROP:
219
+ fann_update_weights_quickprop(ann, data->num_data,
220
+ (ann->last_layer - 1)->first_neuron->first_con,
221
+ ann->total_connections);
222
+ break;
223
+ case FANN_TRAIN_BATCH:
224
+ case FANN_TRAIN_INCREMENTAL:
225
+ fann_error((struct fann_error *) ann, FANN_E_CANT_USE_TRAIN_ALG);
226
+ }
227
+
228
+ return fann_get_MSE(ann);
229
+ }
230
+
231
+ int fann_reallocate_connections(struct fann *ann, unsigned int total_connections)
232
+ {
233
+ /* The connections are allocated, but the pointers inside are
234
+ * first moved in the end of the cascade training session.
235
+ */
236
+
237
+ #ifdef CASCADE_DEBUG
238
+ printf("realloc from %d to %d\n", ann->total_connections_allocated, total_connections);
239
+ #endif
240
+ ann->connections =
241
+ (struct fann_neuron **) realloc(ann->connections,
242
+ total_connections * sizeof(struct fann_neuron *));
243
+ if(ann->connections == NULL)
244
+ {
245
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
246
+ return -1;
247
+ }
248
+
249
+ ann->weights = (fann_type *) realloc(ann->weights, total_connections * sizeof(fann_type));
250
+ if(ann->weights == NULL)
251
+ {
252
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
253
+ return -1;
254
+ }
255
+
256
+ ann->train_slopes =
257
+ (fann_type *) realloc(ann->train_slopes, total_connections * sizeof(fann_type));
258
+ if(ann->train_slopes == NULL)
259
+ {
260
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
261
+ return -1;
262
+ }
263
+
264
+ ann->prev_steps = (fann_type *) realloc(ann->prev_steps, total_connections * sizeof(fann_type));
265
+ if(ann->prev_steps == NULL)
266
+ {
267
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
268
+ return -1;
269
+ }
270
+
271
+ ann->prev_train_slopes =
272
+ (fann_type *) realloc(ann->prev_train_slopes, total_connections * sizeof(fann_type));
273
+ if(ann->prev_train_slopes == NULL)
274
+ {
275
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
276
+ return -1;
277
+ }
278
+
279
+ ann->total_connections_allocated = total_connections;
280
+
281
+ return 0;
282
+ }
283
+
284
+ int fann_reallocate_neurons(struct fann *ann, unsigned int total_neurons)
285
+ {
286
+ struct fann_layer *layer_it;
287
+ struct fann_neuron *neurons;
288
+ unsigned int num_neurons = 0;
289
+ unsigned int num_neurons_so_far = 0;
290
+
291
+ neurons =
292
+ (struct fann_neuron *) realloc(ann->first_layer->first_neuron,
293
+ total_neurons * sizeof(struct fann_neuron));
294
+ ann->total_neurons_allocated = total_neurons;
295
+
296
+ if(neurons == NULL)
297
+ {
298
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
299
+ return -1;
300
+ }
301
+
302
+ /* Also allocate room for more train_errors */
303
+ ann->train_errors = (fann_type *) realloc(ann->train_errors, total_neurons * sizeof(fann_type));
304
+ if(ann->train_errors == NULL)
305
+ {
306
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
307
+ return -1;
308
+ }
309
+
310
+ if(neurons != ann->first_layer->first_neuron)
311
+ {
312
+ /* Then the memory has moved, also move the pointers */
313
+
314
+ #ifdef CASCADE_DEBUG_FULL
315
+ printf("Moving neuron pointers\n");
316
+ #endif
317
+
318
+ /* Move pointers from layers to neurons */
319
+ for(layer_it = ann->first_layer; layer_it != ann->last_layer; layer_it++)
320
+ {
321
+ num_neurons = layer_it->last_neuron - layer_it->first_neuron;
322
+ layer_it->first_neuron = neurons + num_neurons_so_far;
323
+ layer_it->last_neuron = layer_it->first_neuron + num_neurons;
324
+ num_neurons_so_far += num_neurons;
325
+ }
326
+ }
327
+
328
+ return 0;
329
+ }
330
+
331
+ void initialize_candidate_weights(struct fann *ann, unsigned int first_con, unsigned int last_con, float scale_factor)
332
+ {
333
+ fann_type prev_step;
334
+ unsigned int i = 0;
335
+ unsigned int bias_weight = first_con + (ann->first_layer->last_neuron - ann->first_layer->first_neuron) - 1;
336
+
337
+ if(ann->training_algorithm == FANN_TRAIN_RPROP)
338
+ prev_step = ann->rprop_delta_zero;
339
+ else
340
+ prev_step = 0;
341
+
342
+ for(i = first_con; i < last_con; i++)
343
+ {
344
+ if(i == bias_weight)
345
+ ann->weights[i] = fann_rand(-scale_factor, scale_factor);
346
+ else
347
+ ann->weights[i] = fann_rand(0,scale_factor);
348
+
349
+ ann->train_slopes[i] = 0;
350
+ ann->prev_steps[i] = prev_step;
351
+ ann->prev_train_slopes[i] = 0;
352
+ }
353
+ }
354
+
355
+ int fann_initialize_candidates(struct fann *ann)
356
+ {
357
+ /* The candidates are allocated after the normal neurons and connections,
358
+ * but there is an empty place between the real neurons and the candidate neurons,
359
+ * so that it will be possible to make room when the chosen candidate are copied in
360
+ * on the desired place.
361
+ */
362
+ unsigned int neurons_to_allocate, connections_to_allocate;
363
+ unsigned int num_candidates = fann_get_cascade_num_candidates(ann);
364
+ unsigned int num_neurons = ann->total_neurons + num_candidates + 1;
365
+ unsigned int num_hidden_neurons = ann->total_neurons - ann->num_input - ann->num_output;
366
+ unsigned int candidate_connections_in = ann->total_neurons - ann->num_output;
367
+ unsigned int candidate_connections_out = ann->num_output;
368
+
369
+ /* the number of connections going into a and out of a candidate is
370
+ * ann->total_neurons */
371
+ unsigned int num_connections =
372
+ ann->total_connections + (ann->total_neurons * (num_candidates + 1));
373
+ unsigned int first_candidate_connection = ann->total_connections + ann->total_neurons;
374
+ unsigned int first_candidate_neuron = ann->total_neurons + 1;
375
+ unsigned int connection_it, i, j, k, candidate_index;
376
+ struct fann_neuron *neurons;
377
+ float scale_factor;
378
+
379
+ /* First make sure that there is enough room, and if not then allocate a
380
+ * bit more so that we do not need to allocate more room each time.
381
+ */
382
+ if(num_neurons > ann->total_neurons_allocated)
383
+ {
384
+ /* Then we need to allocate more neurons
385
+ * Allocate half as many neurons as already exist (at least ten)
386
+ */
387
+ neurons_to_allocate = num_neurons + num_neurons / 2;
388
+ if(neurons_to_allocate < num_neurons + 10)
389
+ {
390
+ neurons_to_allocate = num_neurons + 10;
391
+ }
392
+
393
+ if(fann_reallocate_neurons(ann, neurons_to_allocate) == -1)
394
+ {
395
+ return -1;
396
+ }
397
+ }
398
+
399
+ if(num_connections > ann->total_connections_allocated)
400
+ {
401
+ /* Then we need to allocate more connections
402
+ * Allocate half as many connections as already exist
403
+ * (at least enough for ten neurons)
404
+ */
405
+ connections_to_allocate = num_connections + num_connections / 2;
406
+ if(connections_to_allocate < num_connections + ann->total_neurons * 10)
407
+ {
408
+ connections_to_allocate = num_connections + ann->total_neurons * 10;
409
+ }
410
+
411
+ if(fann_reallocate_connections(ann, connections_to_allocate) == -1)
412
+ {
413
+ return -1;
414
+ }
415
+ }
416
+
417
+ /* Some test code to do semi Widrow + Nguyen initialization */
418
+ scale_factor = (float) 2.0f*(pow((double) (0.7f * (double) num_hidden_neurons),
419
+ (double) (1.0f / (double) ann->num_input)));
420
+ if(scale_factor > 8)
421
+ scale_factor = 8;
422
+ else if(scale_factor < 0.5)
423
+ scale_factor = 0.5;
424
+
425
+ /* Set the neurons.
426
+ */
427
+ connection_it = first_candidate_connection;
428
+ neurons = ann->first_layer->first_neuron;
429
+ candidate_index = first_candidate_neuron;
430
+
431
+ for(i = 0; i < ann->cascade_activation_functions_count; i++)
432
+ {
433
+ for(j = 0; j < ann->cascade_activation_steepnesses_count; j++)
434
+ {
435
+ for(k = 0; k < ann->cascade_num_candidate_groups; k++)
436
+ {
437
+ /* TODO candidates should actually be created both in
438
+ * the last layer before the output layer, and in a new layer.
439
+ */
440
+ neurons[candidate_index].value = 0;
441
+ neurons[candidate_index].sum = 0;
442
+
443
+ neurons[candidate_index].activation_function =
444
+ ann->cascade_activation_functions[i];
445
+ neurons[candidate_index].activation_steepness =
446
+ ann->cascade_activation_steepnesses[j];
447
+
448
+ neurons[candidate_index].first_con = connection_it;
449
+ connection_it += candidate_connections_in;
450
+ neurons[candidate_index].last_con = connection_it;
451
+ /* We have no specific pointers to the output weights, but they are
452
+ * available after last_con */
453
+ connection_it += candidate_connections_out;
454
+ ann->train_errors[candidate_index] = 0;
455
+ initialize_candidate_weights(ann, neurons[candidate_index].first_con, neurons[candidate_index].last_con+candidate_connections_out, scale_factor);
456
+ candidate_index++;
457
+ }
458
+ }
459
+ }
460
+
461
+
462
+ /* Now randomize the weights and zero out the arrays that needs zeroing out.
463
+ */
464
+ /*
465
+ #ifdef CASCADE_DEBUG_FULL
466
+ printf("random cand weight [%d ... %d]\n", first_candidate_connection, num_connections - 1);
467
+ #endif
468
+
469
+ for(i = first_candidate_connection; i < num_connections; i++)
470
+ {
471
+
472
+ //ann->weights[i] = fann_random_weight();
473
+ ann->weights[i] = fann_rand(-2.0,2.0);
474
+ ann->train_slopes[i] = 0;
475
+ ann->prev_steps[i] = 0;
476
+ ann->prev_train_slopes[i] = initial_slope;
477
+ }
478
+ */
479
+
480
+ return 0;
481
+ }
482
+
483
+ int fann_train_candidates(struct fann *ann, struct fann_train_data *data)
484
+ {
485
+ fann_type best_cand_score = 0.0;
486
+ fann_type target_cand_score = 0.0;
487
+ fann_type backslide_cand_score = -1.0e20f;
488
+ unsigned int i;
489
+ unsigned int max_epochs = ann->cascade_max_cand_epochs;
490
+ unsigned int stagnation = max_epochs;
491
+
492
+ if(ann->cascade_candidate_scores == NULL)
493
+ {
494
+ ann->cascade_candidate_scores =
495
+ (fann_type *) malloc(fann_get_cascade_num_candidates(ann) * sizeof(fann_type));
496
+ if(ann->cascade_candidate_scores == NULL)
497
+ {
498
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
499
+ return 0;
500
+ }
501
+ }
502
+
503
+ for(i = 0; i < max_epochs; i++)
504
+ {
505
+ best_cand_score = fann_train_candidates_epoch(ann, data);
506
+
507
+ if(best_cand_score / ann->MSE_value > ann->cascade_candidate_limit)
508
+ {
509
+ #ifdef CASCADE_DEBUG
510
+ printf("above candidate limit %f/%f > %f", best_cand_score, ann->MSE_value,
511
+ ann->cascade_candidate_limit);
512
+ #endif
513
+ return i + 1;
514
+ }
515
+
516
+ if((best_cand_score > target_cand_score) || (best_cand_score < backslide_cand_score))
517
+ {
518
+ #ifdef CASCADE_DEBUG_FULL
519
+ printf("Best candidate score %f, real score: %f\n", ann->MSE_value - best_cand_score,
520
+ best_cand_score);
521
+ /* printf("best_cand_score=%f, target_cand_score=%f, backslide_cand_score=%f, stagnation=%d\n", best_cand_score, target_cand_score, backslide_cand_score, stagnation); */
522
+ #endif
523
+
524
+ target_cand_score = best_cand_score * (1.0f + ann->cascade_candidate_change_fraction);
525
+ backslide_cand_score = best_cand_score * (1.0f - ann->cascade_candidate_change_fraction);
526
+ stagnation = i + ann->cascade_candidate_stagnation_epochs;
527
+ }
528
+
529
+ /* No improvement in allotted period, so quit */
530
+ if(i >= stagnation)
531
+ {
532
+ #ifdef CASCADE_DEBUG
533
+ printf("Stagnation with %d epochs, best candidate score %f, real score: %f\n", i + 1,
534
+ ann->MSE_value - best_cand_score, best_cand_score);
535
+ #endif
536
+ return i + 1;
537
+ }
538
+ }
539
+
540
+ #ifdef CASCADE_DEBUG
541
+ printf("Max epochs %d reached, best candidate score %f, real score: %f\n", max_epochs,
542
+ ann->MSE_value - best_cand_score, best_cand_score);
543
+ #endif
544
+ return max_epochs;
545
+ }
546
+
547
+ void fann_update_candidate_slopes(struct fann *ann)
548
+ {
549
+ struct fann_neuron *neurons = ann->first_layer->first_neuron;
550
+ struct fann_neuron *first_cand = neurons + ann->total_neurons + 1;
551
+ struct fann_neuron *last_cand = first_cand + fann_get_cascade_num_candidates(ann);
552
+ struct fann_neuron *cand_it;
553
+ unsigned int i, j, num_connections;
554
+ unsigned int num_output = ann->num_output;
555
+ fann_type max_sum, cand_sum, activation, derived, error_value, diff, cand_score;
556
+ fann_type *weights, *cand_out_weights, *cand_slopes, *cand_out_slopes;
557
+ fann_type *output_train_errors = ann->train_errors + (ann->total_neurons - ann->num_output);
558
+
559
+ for(cand_it = first_cand; cand_it < last_cand; cand_it++)
560
+ {
561
+ cand_score = ann->cascade_candidate_scores[cand_it - first_cand];
562
+ error_value = 0.0;
563
+
564
+ /* code more or less stolen from fann_run to fast forward pass
565
+ */
566
+ cand_sum = 0.0;
567
+ num_connections = cand_it->last_con - cand_it->first_con;
568
+ weights = ann->weights + cand_it->first_con;
569
+
570
+ /* unrolled loop start */
571
+ i = num_connections & 3; /* same as modulo 4 */
572
+ switch (i)
573
+ {
574
+ case 3:
575
+ cand_sum += weights[2] * neurons[2].value;
576
+ case 2:
577
+ cand_sum += weights[1] * neurons[1].value;
578
+ case 1:
579
+ cand_sum += weights[0] * neurons[0].value;
580
+ case 0:
581
+ break;
582
+ }
583
+
584
+ for(; i != num_connections; i += 4)
585
+ {
586
+ cand_sum +=
587
+ weights[i] * neurons[i].value +
588
+ weights[i + 1] * neurons[i + 1].value +
589
+ weights[i + 2] * neurons[i + 2].value + weights[i + 3] * neurons[i + 3].value;
590
+ }
591
+ /*
592
+ * for(i = 0; i < num_connections; i++){
593
+ * cand_sum += weights[i] * neurons[i].value;
594
+ * }
595
+ */
596
+ /* unrolled loop end */
597
+
598
+ max_sum = 150/cand_it->activation_steepness;
599
+ if(cand_sum > max_sum)
600
+ cand_sum = max_sum;
601
+ else if(cand_sum < -max_sum)
602
+ cand_sum = -max_sum;
603
+
604
+ activation =
605
+ fann_activation(ann, cand_it->activation_function, cand_it->activation_steepness,
606
+ cand_sum);
607
+ /* printf("%f = sigmoid(%f);\n", activation, cand_sum); */
608
+
609
+ cand_it->sum = cand_sum;
610
+ cand_it->value = activation;
611
+
612
+ derived = fann_activation_derived(cand_it->activation_function,
613
+ cand_it->activation_steepness, activation, cand_sum);
614
+
615
+ /* The output weights is located right after the input weights in
616
+ * the weight array.
617
+ */
618
+ cand_out_weights = weights + num_connections;
619
+
620
+ cand_out_slopes = ann->train_slopes + cand_it->first_con + num_connections;
621
+ for(j = 0; j < num_output; j++)
622
+ {
623
+ diff = (activation * cand_out_weights[j]) - output_train_errors[j];
624
+ #ifdef CASCADE_DEBUG_FULL
625
+ /* printf("diff = %f = (%f * %f) - %f;\n", diff, activation, cand_out_weights[j], output_train_errors[j]); */
626
+ #endif
627
+ cand_out_slopes[j] -= 2.0f * diff * activation;
628
+ #ifdef CASCADE_DEBUG_FULL
629
+ /* printf("cand_out_slopes[%d] <= %f += %f * %f;\n", j, cand_out_slopes[j], diff, activation); */
630
+ #endif
631
+ error_value += diff * cand_out_weights[j];
632
+ cand_score -= (diff * diff);
633
+ #ifdef CASCADE_DEBUG_FULL
634
+ /* printf("cand_score[%d][%d] = %f -= (%f * %f)\n", cand_it - first_cand, j, cand_score, diff, diff); */
635
+
636
+ printf("cand[%d]: error=%f, activation=%f, diff=%f, slope=%f\n", cand_it - first_cand,
637
+ output_train_errors[j], (activation * cand_out_weights[j]), diff,
638
+ -2.0 * diff * activation);
639
+ #endif
640
+ }
641
+
642
+ ann->cascade_candidate_scores[cand_it - first_cand] = cand_score;
643
+ error_value *= derived;
644
+
645
+ cand_slopes = ann->train_slopes + cand_it->first_con;
646
+ for(i = 0; i < num_connections; i++)
647
+ {
648
+ cand_slopes[i] -= error_value * neurons[i].value;
649
+ }
650
+ }
651
+ }
652
+
653
+ void fann_update_candidate_weights(struct fann *ann, unsigned int num_data)
654
+ {
655
+ struct fann_neuron *first_cand = (ann->last_layer - 1)->last_neuron + 1; /* there is an empty neuron between the actual neurons and the candidate neuron */
656
+ struct fann_neuron *last_cand = first_cand + fann_get_cascade_num_candidates(ann) - 1;
657
+
658
+ switch (ann->training_algorithm)
659
+ {
660
+ case FANN_TRAIN_RPROP:
661
+ fann_update_weights_irpropm(ann, first_cand->first_con,
662
+ last_cand->last_con + ann->num_output);
663
+ break;
664
+ case FANN_TRAIN_QUICKPROP:
665
+ fann_update_weights_quickprop(ann, num_data, first_cand->first_con,
666
+ last_cand->last_con + ann->num_output);
667
+ break;
668
+ case FANN_TRAIN_BATCH:
669
+ case FANN_TRAIN_INCREMENTAL:
670
+ fann_error((struct fann_error *) ann, FANN_E_CANT_USE_TRAIN_ALG);
671
+ break;
672
+ }
673
+ }
674
+
675
+ fann_type fann_train_candidates_epoch(struct fann *ann, struct fann_train_data *data)
676
+ {
677
+ unsigned int i, j;
678
+ unsigned int best_candidate;
679
+ fann_type best_score;
680
+ unsigned int num_cand = fann_get_cascade_num_candidates(ann);
681
+ fann_type *output_train_errors = ann->train_errors + (ann->total_neurons - ann->num_output);
682
+ struct fann_neuron *output_neurons = (ann->last_layer - 1)->first_neuron;
683
+
684
+ for(i = 0; i < num_cand; i++)
685
+ {
686
+ /* The ann->MSE_value is actually the sum squared error */
687
+ ann->cascade_candidate_scores[i] = ann->MSE_value;
688
+ }
689
+ /*printf("start score: %f\n", ann->MSE_value); */
690
+
691
+ for(i = 0; i < data->num_data; i++)
692
+ {
693
+ fann_run(ann, data->input[i]);
694
+
695
+ for(j = 0; j < ann->num_output; j++)
696
+ {
697
+ /* TODO only debug, but the error is in opposite direction, this might be usefull info */
698
+ /* if(output_train_errors[j] != (ann->output[j] - data->output[i][j])){
699
+ * printf("difference in calculated error at %f != %f; %f = %f - %f;\n", output_train_errors[j], (ann->output[j] - data->output[i][j]), output_train_errors[j], ann->output[j], data->output[i][j]);
700
+ * } */
701
+
702
+ /*
703
+ * output_train_errors[j] = (data->output[i][j] - ann->output[j])/2;
704
+ * output_train_errors[j] = ann->output[j] - data->output[i][j];
705
+ */
706
+
707
+ output_train_errors[j] = (data->output[i][j] - ann->output[j]);
708
+
709
+ switch (output_neurons[j].activation_function)
710
+ {
711
+ case FANN_LINEAR_PIECE_SYMMETRIC:
712
+ case FANN_SIGMOID_SYMMETRIC:
713
+ case FANN_SIGMOID_SYMMETRIC_STEPWISE:
714
+ case FANN_THRESHOLD_SYMMETRIC:
715
+ case FANN_ELLIOT_SYMMETRIC:
716
+ case FANN_GAUSSIAN_SYMMETRIC:
717
+ case FANN_SIN_SYMMETRIC:
718
+ case FANN_COS_SYMMETRIC:
719
+ output_train_errors[j] /= 2.0;
720
+ break;
721
+ case FANN_LINEAR:
722
+ case FANN_THRESHOLD:
723
+ case FANN_SIGMOID:
724
+ case FANN_SIGMOID_STEPWISE:
725
+ case FANN_GAUSSIAN:
726
+ case FANN_GAUSSIAN_STEPWISE:
727
+ case FANN_ELLIOT:
728
+ case FANN_LINEAR_PIECE:
729
+ case FANN_SIN:
730
+ case FANN_COS:
731
+ break;
732
+ }
733
+ }
734
+
735
+ fann_update_candidate_slopes(ann);
736
+ }
737
+
738
+ fann_update_candidate_weights(ann, data->num_data);
739
+
740
+ /* find the best candidate score */
741
+ best_candidate = 0;
742
+ best_score = ann->cascade_candidate_scores[best_candidate];
743
+ for(i = 1; i < num_cand; i++)
744
+ {
745
+ /*struct fann_neuron *cand = ann->first_layer->first_neuron + ann->total_neurons + 1 + i;
746
+ * printf("candidate[%d] = activation: %s, steepness: %f, score: %f\n",
747
+ * i, FANN_ACTIVATIONFUNC_NAMES[cand->activation_function],
748
+ * cand->activation_steepness, ann->cascade_candidate_scores[i]); */
749
+
750
+ if(ann->cascade_candidate_scores[i] > best_score)
751
+ {
752
+ best_candidate = i;
753
+ best_score = ann->cascade_candidate_scores[best_candidate];
754
+ }
755
+ }
756
+
757
+ ann->cascade_best_candidate = ann->total_neurons + best_candidate + 1;
758
+ #ifdef CASCADE_DEBUG_FULL
759
+ printf("Best candidate[%d]: with score %f, real score: %f\n", best_candidate,
760
+ ann->MSE_value - best_score, best_score);
761
+ #endif
762
+
763
+ return best_score;
764
+ }
765
+
766
+ /* add a layer ad the position pointed to by *layer */
767
+ struct fann_layer *fann_add_layer(struct fann *ann, struct fann_layer *layer)
768
+ {
769
+ int layer_pos = layer - ann->first_layer;
770
+ int num_layers = ann->last_layer - ann->first_layer + 1;
771
+ int i;
772
+
773
+ /* allocate the layer */
774
+ struct fann_layer *layers =
775
+ (struct fann_layer *) realloc(ann->first_layer, num_layers * sizeof(struct fann_layer));
776
+ if(layers == NULL)
777
+ {
778
+ fann_error((struct fann_error *) ann, FANN_E_CANT_ALLOCATE_MEM);
779
+ return NULL;
780
+ }
781
+
782
+ /* copy layers so that the free space is at the right location */
783
+ for(i = num_layers - 1; i >= layer_pos; i--)
784
+ {
785
+ layers[i] = layers[i - 1];
786
+ }
787
+
788
+ /* the newly allocated layer is empty */
789
+ layers[layer_pos].first_neuron = layers[layer_pos + 1].first_neuron;
790
+ layers[layer_pos].last_neuron = layers[layer_pos + 1].first_neuron;
791
+
792
+ /* Set the ann pointers correctly */
793
+ ann->first_layer = layers;
794
+ ann->last_layer = layers + num_layers;
795
+
796
+ #ifdef CASCADE_DEBUG_FULL
797
+ printf("add layer at pos %d\n", layer_pos);
798
+ #endif
799
+
800
+ return layers + layer_pos;
801
+ }
802
+
803
+ void fann_set_shortcut_connections(struct fann *ann)
804
+ {
805
+ struct fann_layer *layer_it;
806
+ struct fann_neuron *neuron_it, **neuron_pointers, *neurons;
807
+ unsigned int num_connections = 0, i;
808
+
809
+ neuron_pointers = ann->connections;
810
+ neurons = ann->first_layer->first_neuron;
811
+
812
+ for(layer_it = ann->first_layer + 1; layer_it != ann->last_layer; layer_it++)
813
+ {
814
+ for(neuron_it = layer_it->first_neuron; neuron_it != layer_it->last_neuron; neuron_it++)
815
+ {
816
+
817
+ neuron_pointers += num_connections;
818
+ num_connections = neuron_it->last_con - neuron_it->first_con;
819
+
820
+ for(i = 0; i != num_connections; i++)
821
+ {
822
+ neuron_pointers[i] = neurons + i;
823
+ }
824
+ }
825
+ }
826
+ }
827
+
828
+ void fann_add_candidate_neuron(struct fann *ann, struct fann_layer *layer)
829
+ {
830
+ unsigned int num_connections_in = layer->first_neuron - ann->first_layer->first_neuron;
831
+ unsigned int num_connections_out =
832
+ (ann->last_layer - 1)->last_neuron - (layer + 1)->first_neuron;
833
+ unsigned int num_connections_move = num_connections_out + num_connections_in;
834
+
835
+ unsigned int candidate_con, candidate_output_weight;
836
+ int i;
837
+
838
+ struct fann_layer *layer_it;
839
+ struct fann_neuron *neuron_it, *neuron_place, *candidate;
840
+
841
+ /* We know that there is enough room for the new neuron
842
+ * (the candidates are in the same arrays), so move
843
+ * the last neurons to make room for this neuron.
844
+ */
845
+
846
+ /* first move the pointers to neurons in the layer structs */
847
+ for(layer_it = ann->last_layer - 1; layer_it != layer; layer_it--)
848
+ {
849
+ #ifdef CASCADE_DEBUG_FULL
850
+ printf("move neuron pointers in layer %d, first(%d -> %d), last(%d -> %d)\n",
851
+ layer_it - ann->first_layer,
852
+ layer_it->first_neuron - ann->first_layer->first_neuron,
853
+ layer_it->first_neuron - ann->first_layer->first_neuron + 1,
854
+ layer_it->last_neuron - ann->first_layer->first_neuron,
855
+ layer_it->last_neuron - ann->first_layer->first_neuron + 1);
856
+ #endif
857
+ layer_it->first_neuron++;
858
+ layer_it->last_neuron++;
859
+ }
860
+
861
+ /* also move the last neuron in the layer that needs the neuron added */
862
+ layer->last_neuron++;
863
+
864
+ /* this is the place that should hold the new neuron */
865
+ neuron_place = layer->last_neuron - 1;
866
+
867
+ #ifdef CASCADE_DEBUG_FULL
868
+ printf("num_connections_in=%d, num_connections_out=%d\n", num_connections_in,
869
+ num_connections_out);
870
+ #endif
871
+
872
+ candidate = ann->first_layer->first_neuron + ann->cascade_best_candidate;
873
+
874
+ /* the output weights for the candidates are located after the input weights */
875
+ candidate_output_weight = candidate->last_con;
876
+
877
+ /* move the actual output neurons and the indexes to the connection arrays */
878
+ for(neuron_it = (ann->last_layer - 1)->last_neuron - 1; neuron_it != neuron_place; neuron_it--)
879
+ {
880
+ #ifdef CASCADE_DEBUG_FULL
881
+ printf("move neuron %d -> %d\n", neuron_it - ann->first_layer->first_neuron - 1,
882
+ neuron_it - ann->first_layer->first_neuron);
883
+ #endif
884
+ *neuron_it = *(neuron_it - 1);
885
+
886
+ /* move the weights */
887
+ #ifdef CASCADE_DEBUG_FULL
888
+ printf("move weight[%d ... %d] -> weight[%d ... %d]\n", neuron_it->first_con,
889
+ neuron_it->last_con - 1, neuron_it->first_con + num_connections_move - 1,
890
+ neuron_it->last_con + num_connections_move - 2);
891
+ #endif
892
+ for(i = neuron_it->last_con - 1; i >= (int)neuron_it->first_con; i--)
893
+ {
894
+ #ifdef CASCADE_DEBUG_FULL
895
+ printf("move weight[%d] = weight[%d]\n", i + num_connections_move - 1, i);
896
+ #endif
897
+ ann->weights[i + num_connections_move - 1] = ann->weights[i];
898
+ }
899
+
900
+ /* move the indexes to weights */
901
+ neuron_it->last_con += num_connections_move;
902
+ num_connections_move--;
903
+ neuron_it->first_con += num_connections_move;
904
+
905
+ /* set the new weight to the newly allocated neuron */
906
+ ann->weights[neuron_it->last_con - 1] =
907
+ (ann->weights[candidate_output_weight]) * ann->cascade_weight_multiplier;
908
+ candidate_output_weight++;
909
+ }
910
+
911
+ /* Now inititalize the actual neuron */
912
+ neuron_place->value = 0;
913
+ neuron_place->sum = 0;
914
+ neuron_place->activation_function = candidate->activation_function;
915
+ neuron_place->activation_steepness = candidate->activation_steepness;
916
+ neuron_place->last_con = (neuron_place + 1)->first_con;
917
+ neuron_place->first_con = neuron_place->last_con - num_connections_in;
918
+ #ifdef CASCADE_DEBUG_FULL
919
+ printf("neuron[%d] = weights[%d ... %d] activation: %s, steepness: %f\n",
920
+ neuron_place - ann->first_layer->first_neuron, neuron_place->first_con,
921
+ neuron_place->last_con - 1, FANN_ACTIVATIONFUNC_NAMES[neuron_place->activation_function],
922
+ neuron_place->activation_steepness);/* TODO remove */
923
+ #endif
924
+
925
+ candidate_con = candidate->first_con;
926
+ /* initialize the input weights at random */
927
+ #ifdef CASCADE_DEBUG_FULL
928
+ printf("move cand weights[%d ... %d] -> [%d ... %d]\n", candidate_con,
929
+ candidate_con + num_connections_in - 1, neuron_place->first_con,
930
+ neuron_place->last_con - 1);
931
+ #endif
932
+
933
+ for(i = 0; i < (int)num_connections_in; i++)
934
+ {
935
+ ann->weights[i + neuron_place->first_con] = ann->weights[i + candidate_con];
936
+ #ifdef CASCADE_DEBUG_FULL
937
+ printf("move weights[%d] -> weights[%d] (%f)\n", i + candidate_con,
938
+ i + neuron_place->first_con, ann->weights[i + neuron_place->first_con]);
939
+ #endif
940
+ }
941
+
942
+ /* Change some of main variables */
943
+ ann->total_neurons++;
944
+ ann->total_connections += num_connections_in + num_connections_out;
945
+
946
+ return;
947
+ }
948
+
949
+ void fann_install_candidate(struct fann *ann)
950
+ {
951
+ struct fann_layer *layer;
952
+
953
+ layer = fann_add_layer(ann, ann->last_layer - 1);
954
+ fann_add_candidate_neuron(ann, layer);
955
+ return;
956
+ }
957
+
958
+ #endif /* FIXEDFANN */
959
+
960
+ FANN_EXTERNAL unsigned int FANN_API fann_get_cascade_num_candidates(struct fann *ann)
961
+ {
962
+ return ann->cascade_activation_functions_count *
963
+ ann->cascade_activation_steepnesses_count *
964
+ ann->cascade_num_candidate_groups;
965
+ }
966
+
967
+ FANN_GET_SET(float, cascade_output_change_fraction)
968
+ FANN_GET_SET(unsigned int, cascade_output_stagnation_epochs)
969
+ FANN_GET_SET(float, cascade_candidate_change_fraction)
970
+ FANN_GET_SET(unsigned int, cascade_candidate_stagnation_epochs)
971
+ FANN_GET_SET(unsigned int, cascade_num_candidate_groups)
972
+ FANN_GET_SET(fann_type, cascade_weight_multiplier)
973
+ FANN_GET_SET(fann_type, cascade_candidate_limit)
974
+ FANN_GET_SET(unsigned int, cascade_max_out_epochs)
975
+ FANN_GET_SET(unsigned int, cascade_max_cand_epochs)
976
+
977
+ FANN_GET(unsigned int, cascade_activation_functions_count)
978
+ FANN_GET(enum fann_activationfunc_enum *, cascade_activation_functions)
979
+
980
+ FANN_EXTERNAL void FANN_API fann_set_cascade_activation_functions(struct fann *ann,
981
+ enum fann_activationfunc_enum *
982
+ cascade_activation_functions,
983
+ unsigned int
984
+ cascade_activation_functions_count)
985
+ {
986
+ if(ann->cascade_activation_functions_count != cascade_activation_functions_count)
987
+ {
988
+ ann->cascade_activation_functions_count = cascade_activation_functions_count;
989
+
990
+ /* reallocate mem */
991
+ ann->cascade_activation_functions =
992
+ (enum fann_activationfunc_enum *)realloc(ann->cascade_activation_functions,
993
+ ann->cascade_activation_functions_count * sizeof(enum fann_activationfunc_enum));
994
+ if(ann->cascade_activation_functions == NULL)
995
+ {
996
+ fann_error((struct fann_error*)ann, FANN_E_CANT_ALLOCATE_MEM);
997
+ return;
998
+ }
999
+ }
1000
+
1001
+ memmove(ann->cascade_activation_functions, cascade_activation_functions,
1002
+ ann->cascade_activation_functions_count * sizeof(enum fann_activationfunc_enum));
1003
+ }
1004
+
1005
+ FANN_GET(unsigned int, cascade_activation_steepnesses_count)
1006
+ FANN_GET(fann_type *, cascade_activation_steepnesses)
1007
+
1008
+ FANN_EXTERNAL void FANN_API fann_set_cascade_activation_steepnesses(struct fann *ann,
1009
+ fann_type *
1010
+ cascade_activation_steepnesses,
1011
+ unsigned int
1012
+ cascade_activation_steepnesses_count)
1013
+ {
1014
+ if(ann->cascade_activation_steepnesses_count != cascade_activation_steepnesses_count)
1015
+ {
1016
+ ann->cascade_activation_steepnesses_count = cascade_activation_steepnesses_count;
1017
+
1018
+ /* reallocate mem */
1019
+ ann->cascade_activation_steepnesses =
1020
+ (fann_type *)realloc(ann->cascade_activation_steepnesses,
1021
+ ann->cascade_activation_steepnesses_count * sizeof(fann_type));
1022
+ if(ann->cascade_activation_steepnesses == NULL)
1023
+ {
1024
+ fann_error((struct fann_error*)ann, FANN_E_CANT_ALLOCATE_MEM);
1025
+ return;
1026
+ }
1027
+ }
1028
+
1029
+ memmove(ann->cascade_activation_steepnesses, cascade_activation_steepnesses,
1030
+ ann->cascade_activation_steepnesses_count * sizeof(fann_type));
1031
+ }