growing_neurons.cpp
1// OpenNN: Open Neural Networks Library
2// www.opennn.net
3//
4// G R O W I N G N E U R O N S C L A S S
5//
6// Artificial Intelligence Techniques SL
7// artelnics@artelnics.com
8
9#include "growing_neurons.h"
10
11namespace OpenNN
12{
13
15
18{
20}
21
22
25
26GrowingNeurons::GrowingNeurons(TrainingStrategy* new_training_strategy_pointer)
27 : NeuronsSelection(new_training_strategy_pointer)
28{
30}
31
32
34
36{
37}
38
39
41
42const Index& GrowingNeurons::get_step() const
43{
44 return neurons_increment;
45}
46
47
49
51{
53}
54
55
57
59{
61
62 maximum_neurons = 10;
63
64 trials_number = 3;
65
67
69
70 maximum_time = type(3600);
71}
72
73
77
78void GrowingNeurons::set_neurons_increment(const Index& new_neurons_increment)
79{
80#ifdef OPENNN_DEBUG
81
82 if(new_neurons_increment <= 0)
83 {
84 ostringstream buffer;
85
86 buffer << "OpenNN Exception: GrowingNeurons class.\n"
87 << "void set_neurons_increment(const Index&) method.\n"
88 << "New_step(" << new_neurons_increment << ") must be greater than 0.\n";
89
90 throw logic_error(buffer.str());
91 }
92
93#endif
94
95 neurons_increment = new_neurons_increment;
96}
97
98
101
102void GrowingNeurons::set_maximum_selection_failures(const Index& new_maximum_selection_failures)
103{
104#ifdef OPENNN_DEBUG
105
106 if(new_maximum_selection_failures <= 0)
107 {
108 ostringstream buffer;
109
110 buffer << "OpenNN Exception: GrowingNeurons class.\n"
111 << "void set_maximum_selection_failures(const Index&) method.\n"
112 << "Maximum selection failures must be greater than 0.\n";
113
114 throw logic_error(buffer.str());
115 }
116
117#endif
118
119 maximum_selection_failures = new_maximum_selection_failures;
120}
121
122
124
126{
127 #ifdef OPENNN_DEBUG
128
130 {
131 ostringstream buffer;
132
133 buffer << "OpenNN Exception: growing_neurons class.\n"
134 << "TrainingStrategy* training_strategy_pointer const method.\n"
135 << "training_strategy_pointer is nullptr.\n";
136
137 throw logic_error(buffer.str());
138 }
139
140 #endif
141
142 NeuronsSelectionResults neurons_selection_results(maximum_epochs_number);
143
144 if(display) cout << "Performing growing neurons selection..." << endl;
145
146 // Neural network
147
149
150 const Index trainable_layers_number = neural_network->get_trainable_layers_number();
151
152 const Tensor<Layer*, 1> trainable_layers_pointers = neural_network->get_trainable_layers_pointers();
153
154 Index neurons_number;
155
156 // Loss index
157
158 type previous_selection_error = numeric_limits<type>::max();
159
160 // Optimization algorithm
161
162 Index selection_failures = 0;
163
164 bool end = false;
165
166 time_t beginning_time, current_time;
167
168 type elapsed_time = type(0);
169
170 TrainingResults training_results;
171
173
174 time(&beginning_time);
175
176 // Main loop
177
178 for(Index epoch = 0; epoch < maximum_epochs_number; epoch++)
179 {
180 if(display == 0) cout << endl << "Neurons selection epoch: " << epoch << endl;
181
182 // Neural network
183
184 neurons_number = minimum_neurons + epoch*neurons_increment;
185
186 trainable_layers_pointers(trainable_layers_number-2)->set_neurons_number(neurons_number);
187
188 trainable_layers_pointers(trainable_layers_number-1)->set_inputs_number(neurons_number);
189
190 neurons_selection_results.neurons_number_history(epoch) = neurons_number;
191
192 // Loss index
193
194 if(display) cout << "Neurons number: " << neurons_number << endl;
195
196 type minimum_training_error = numeric_limits<type>::max();
197 type minimum_selection_error = numeric_limits<type>::max();
198
199 for(Index trial = 0; trial < trials_number; trial++)
200 {
201 neural_network->set_parameters_random();
202
203 training_results = training_strategy_pointer->perform_training();
204
205 if(display)
206 {
207 cout << "Trial: " << trial+1 << endl;
208 cout << "Training error: " << training_results.get_training_error() << endl;
209 cout << "Selection error: " << training_results.get_selection_error() << endl;
210 }
211
212 if(training_results.get_selection_error() < minimum_selection_error)
213 {
214 minimum_training_error = training_results.get_training_error();
215 minimum_selection_error = training_results.get_selection_error();
216
217 neurons_selection_results.training_error_history(epoch) = minimum_training_error;
218 neurons_selection_results.selection_error_history(epoch) = minimum_selection_error;
219 }
220
221 if(minimum_selection_error < neurons_selection_results.optimum_selection_error)
222 {
223 neurons_selection_results.optimal_neurons_number = neurons_number;
224 neurons_selection_results.optimal_parameters = neural_network->get_parameters();
225
226 neurons_selection_results.optimum_training_error = minimum_training_error;
227 neurons_selection_results.optimum_selection_error = minimum_selection_error;
228 }
229 }
230
231 if(display)
232 {
233 cout << "Neurons number: " << neurons_number << endl;
234 cout << "Training error: " << training_results.get_training_error() << endl;
235 cout << "Selection error: " << training_results.get_selection_error() << endl;
236
237 cout << "Elapsed time: " << write_time(elapsed_time) << endl;
238 }
239
240 if(neurons_selection_results.optimum_selection_error > previous_selection_error) selection_failures++;
241
242 previous_selection_error = neurons_selection_results.optimum_selection_error;
243
244 time(&current_time);
245
246 elapsed_time = static_cast<type>(difftime(current_time, beginning_time));
247
248 // Stopping criteria
249
250 if(elapsed_time >= maximum_time)
251 {
252 end = true;
253
254 if(display) cout << "Epoch " << epoch << endl << "Maximum time reached: " << write_time(elapsed_time) << endl;
255
256 neurons_selection_results.stopping_condition = GrowingNeurons::StoppingCondition::MaximumTime;
257 }
258
259 if(training_results.get_selection_error() <= selection_error_goal)
260 {
261 end = true;
262
263 if(display) cout << "Epoch " << epoch << endl << "Selection error goal reached: " << training_results.get_selection_error() << endl;
264
265 neurons_selection_results.stopping_condition = GrowingNeurons::StoppingCondition::SelectionErrorGoal;
266 }
267
268 if(epoch >= maximum_epochs_number)
269 {
270 end = true;
271
272 if(display) cout << "Epoch " << epoch << endl << "Maximum number of epochs reached: " << epoch << endl;
273
274 neurons_selection_results.stopping_condition = GrowingNeurons::StoppingCondition::MaximumEpochs;
275 }
276
277 if(selection_failures >= maximum_selection_failures)
278 {
279 end = true;
280
281 if(display) cout << "Epoch " << epoch << endl << "Maximum selection failures reached: " << selection_failures << endl;
282
283 neurons_selection_results.stopping_condition = GrowingNeurons::StoppingCondition::MaximumSelectionFailures;
284 }
285
286 if(neurons_number >= maximum_neurons)
287 {
288 end = true;
289
290 if(display) cout << "Epoch " << epoch << endl << "Maximum number of neurons reached: " << neurons_number << endl;
291
292 neurons_selection_results.stopping_condition = GrowingNeurons::StoppingCondition::MaximumNeurons;
293 }
294
295 if(end)
296 {
297 neurons_selection_results.resize_history(epoch+1);
298
299 neurons_selection_results.elapsed_time = write_time(elapsed_time);
300
301 break;
302 }
303 }
304
305 // Save neural network
306
307 trainable_layers_pointers[trainable_layers_number-1]->set_inputs_number(neurons_selection_results.optimal_neurons_number);
308 trainable_layers_pointers[trainable_layers_number-2]->set_neurons_number(neurons_selection_results.optimal_neurons_number);
309
310 neural_network->set_parameters(neurons_selection_results.optimal_parameters);
311
312 if(display) neurons_selection_results.print();
313
314 return neurons_selection_results;
315}
316
317
319
320Tensor<string, 2> GrowingNeurons::to_string_matrix() const
321{
322 ostringstream buffer;
323
324 Tensor<string, 1> labels(8);
325 Tensor<string, 1> values(8);
326
327 // Minimum neurons number
328
329 labels(0) = "Minimum neurons";
330
331 buffer.str("");
332 buffer << minimum_neurons;
333
334 values(0) = buffer.str();
335
336 // Maximum order
337
338 labels(1) = "Maximum neurons";
339
340 buffer.str("");
341 buffer << maximum_neurons;
342
343 values(1) = buffer.str();
344
345 // Step
346
347 labels(2) = "Step";
348
349 buffer.str("");
350 buffer << neurons_increment;
351
352 values(2) = buffer.str();
353
354 // Trials number
355
356 labels(3) = "Trials number";
357
358 buffer.str("");
359 buffer << trials_number;
360
361 values(3) = buffer.str();
362
363 // Selection loss goal
364
365 labels(4) = "Selection loss goal";
366
367 buffer.str("");
368 buffer << selection_error_goal;
369
370 values(4) = buffer.str();
371
372 // Maximum selection failures
373
374 labels(5) = "Maximum selection failures";
375
376 buffer.str("");
378
379 values(5) = buffer.str();
380
381 // Maximum iterations number
382
383 labels(6) = "Maximum iterations number";
384
385 buffer.str("");
386 buffer << maximum_epochs_number;
387
388 values(6) = buffer.str();
389
390 // Maximum time
391
392 labels(7) = "Maximum time";
393
394 buffer.str("");
395 buffer << maximum_time;
396
397 values(7) = buffer.str();
398
399 const Index rows_number = labels.size();
400 const Index columns_number = 2;
401
402 Tensor<string, 2> string_matrix(rows_number, columns_number);
403
404 string_matrix.chip(0, 1) = labels;
405 string_matrix.chip(1, 1) = values;
406
407 return string_matrix;
408}
409
410
414
416{
417 ostringstream buffer;
418
419 file_stream.OpenElement("GrowingNeurons");
420
421 // Minimum order
422
423 file_stream.OpenElement("MinimumNeurons");
424
425 buffer.str("");
426 buffer << minimum_neurons;
427
428 file_stream.PushText(buffer.str().c_str());
429
430 file_stream.CloseElement();
431
432 // Maximum order
433
434 file_stream.OpenElement("MaximumNeurons");
435
436 buffer.str("");
437 buffer << maximum_neurons;
438
439 file_stream.PushText(buffer.str().c_str());
440
441 file_stream.CloseElement();
442
443 // Step
444
445 file_stream.OpenElement("Step");
446
447 buffer.str("");
448 buffer << neurons_increment;
449
450 file_stream.PushText(buffer.str().c_str());
451
452 file_stream.CloseElement();
453
454 // Trials number
455
456 file_stream.OpenElement("TrialsNumber");
457
458 buffer.str("");
459 buffer << trials_number;
460
461 file_stream.PushText(buffer.str().c_str());
462
463 file_stream.CloseElement();
464
465 // Selection error goal
466
467 file_stream.OpenElement("SelectionErrorGoal");
468
469 buffer.str("");
470 buffer << selection_error_goal;
471
472 file_stream.PushText(buffer.str().c_str());
473
474 file_stream.CloseElement();
475
476 // Maximum selection failures
477
478 file_stream.OpenElement("MaximumSelectionFailures");
479
480 buffer.str("");
482
483 file_stream.PushText(buffer.str().c_str());
484
485 file_stream.CloseElement();
486
487 // Maximum time
488
489 file_stream.OpenElement("MaximumTime");
490
491 buffer.str("");
492 buffer << maximum_time;
493
494 file_stream.PushText(buffer.str().c_str());
495
496 file_stream.CloseElement();
497
498 file_stream.CloseElement();
499}
500
501
504
506{
507 const tinyxml2::XMLElement* root_element = document.FirstChildElement("GrowingNeurons");
508
509 if(!root_element)
510 {
511 ostringstream buffer;
512
513 buffer << "OpenNN Exception: GrowingNeurons class.\n"
514 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
515 << "GrowingNeurons element is nullptr.\n";
516
517 throw logic_error(buffer.str());
518 }
519
520 // Minimum neurons
521 {
522 const tinyxml2::XMLElement* element = root_element->FirstChildElement("MinimumNeurons");
523
524 if(element)
525 {
526 const Index new_minimum_neurons = static_cast<Index>(atoi(element->GetText()));
527
528 try
529 {
530 minimum_neurons = new_minimum_neurons;
531 }
532 catch(const logic_error& e)
533 {
534 cerr << e.what() << endl;
535 }
536 }
537 }
538
539 // Maximum neurons
540 {
541 const tinyxml2::XMLElement* element = root_element->FirstChildElement("MaximumNeurons");
542
543 if(element)
544 {
545 const Index new_maximum_neurons = static_cast<Index>(atoi(element->GetText()));
546
547 try
548 {
549 maximum_neurons = new_maximum_neurons;
550 }
551 catch(const logic_error& e)
552 {
553 cerr << e.what() << endl;
554 }
555 }
556 }
557
558 // Step
559 {
560 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Step");
561
562 if(element)
563 {
564 const Index new_step = static_cast<Index>(atoi(element->GetText()));
565
566 try
567 {
568 set_neurons_increment(new_step);
569 }
570 catch(const logic_error& e)
571 {
572 cerr << e.what() << endl;
573 }
574 }
575 }
576
577 // Trials number
578 {
579 const tinyxml2::XMLElement* element = root_element->FirstChildElement("TrialsNumber");
580
581 if(element)
582 {
583 const Index new_trials_number = static_cast<Index>(atoi(element->GetText()));
584
585 try
586 {
587 set_trials_number(new_trials_number);
588 }
589 catch(const logic_error& e)
590 {
591 cerr << e.what() << endl;
592 }
593 }
594 }
595
596 // Selection error goal
597 {
598 const tinyxml2::XMLElement* element = root_element->FirstChildElement("SelectionErrorGoal");
599
600 if(element)
601 {
602 const type new_selection_error_goal = static_cast<type>(atof(element->GetText()));
603
604 try
605 {
606 set_selection_error_goal(new_selection_error_goal);
607 }
608 catch(const logic_error& e)
609 {
610 cerr << e.what() << endl;
611 }
612 }
613 }
614
615 // Maximum selection failures
616 {
617 const tinyxml2::XMLElement* element = root_element->FirstChildElement("MaximumSelectionFailures");
618
619 if(element)
620 {
621 const Index new_maximum_selection_failures = static_cast<Index>(atoi(element->GetText()));
622
623 try
624 {
625 set_maximum_selection_failures(new_maximum_selection_failures);
626 }
627 catch(const logic_error& e)
628 {
629 cerr << e.what() << endl;
630 }
631 }
632 }
633
634 // Maximum time
635 {
636 const tinyxml2::XMLElement* element = root_element->FirstChildElement("MaximumTime");
637
638 if(element)
639 {
640 const type new_maximum_time = type(atoi(element->GetText()));
641
642 try
643 {
644 set_maximum_time(new_maximum_time);
645 }
646 catch(const logic_error& e)
647 {
648 cerr << e.what() << endl;
649 }
650 }
651 }
652}
653
654
657
658void GrowingNeurons::save(const string& file_name) const
659{
660 FILE * file = fopen(file_name.c_str(), "w");
661
662 tinyxml2::XMLPrinter printer(file);
663
664 write_XML(printer);
665
666 fclose(file);
667}
668
669
672
673void GrowingNeurons::load(const string& file_name)
674{
675 set_default();
676
677 tinyxml2::XMLDocument document;
678
679 if(document.LoadFile(file_name.c_str()))
680 {
681 ostringstream buffer;
682
683 buffer << "OpenNN Exception: GrowingNeurons class.\n"
684 << "void load(const string&) method.\n"
685 << "Cannot load XML file " << file_name << ".\n";
686
687 throw logic_error(buffer.str());
688 }
689
690 from_XML(document);
691}
692
693}
694
695// OpenNN: Open Neural Networks Library.
696// Copyright(C) 2005-2021 Artificial Intelligence Techniques, SL.
697//
698// This library is free software; you can redistribute it and/or
699// modify it under the terms of the GNU Lesser General Public
700// License as published by the Free Software Foundation; either
701// version 2.1 of the License, or any later version.
702//
703// This library is distributed in the hope that it will be useful,
704// but WITHOUT ANY WARRANTY; without even the implied warranty of
705// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
706// Lesser General Public License for more details.
707
708// You should have received a copy of the GNU Lesser General Public
709// License along with this library; if not, write to the Free Software
710// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
void set_maximum_selection_failures(const Index &)
virtual ~GrowingNeurons()
Destructor.
void from_XML(const tinyxml2::XMLDocument &)
void set_default()
Sets the members of the model selection object to their default values:
void load(const string &)
GrowingNeurons()
Default constructor.
NeuronsSelectionResults perform_neurons_selection()
Perform neurons selection with the growing neurons method.
Tensor< string, 2 > to_string_matrix() const
Writes as matrix of strings the most representative atributes.
Index neurons_increment
Number of neurons added at each iteration.
void save(const string &) const
void set_neurons_increment(const Index &)
const Index & get_step() const
Returns the number of the hidden perceptrons pointed in each iteration of the growing neurons algorit...
void write_XML(tinyxml2::XMLPrinter &) const
const Index & get_maximum_selection_failures() const
Returns the maximum number of selection failures in the model neurons selection algorithm.
Index maximum_selection_failures
Maximum number of epochs at which the selection error increases.
Tensor< Layer *, 1 > get_trainable_layers_pointers() const
Returns a pointer to the trainable layers object composing this neural network object.
void set_parameters(Tensor< type, 1 > &)
Tensor< type, 1 > get_parameters() const
This abstract class represents the concept of neurons selection algorithm for a ModelSelection[1].
Index minimum_neurons
Minimum number of hidden neurons.
TrainingStrategy * training_strategy_pointer
Pointer to a training strategy object.
void set_selection_error_goal(const type &)
Index maximum_neurons
Maximum number of hidden neurons.
Index trials_number
Number of trials for each neural network.
bool display
Display messages to screen.
type selection_error_goal
Goal value for the selection error. It is used as a stopping criterion.
void set_maximum_time(const type &)
const string write_time(const type &) const
Writes the time from seconds in format HH:mm:ss.
type maximum_time
Maximum selection algorithm time. It is used as a stopping criterion.
Index maximum_epochs_number
Maximum number of epochs to perform neurons selection. It is used as a stopping criterion.
void set_trials_number(const Index &)
This class represents the concept of training strategy for a neural network in OpenNN.
TrainingResults perform_training()
NeuralNetwork * get_neural_network_pointer() const
Returns a pointer to the NeuralNetwork class.
void set_display(const bool &)
void PushText(const char *text, bool cdata=false)
Add a text node.
Definition: tinyxml2.cpp:2878
virtual void CloseElement(bool compactMode=false)
If streaming, close the Element.
Definition: tinyxml2.cpp:2834
This structure contains the results from the neurons selection.
type optimum_training_error
Value of loss for the neural network with minimum selection error.
Tensor< type, 1 > selection_error_history
Selection loss of the different neural networks.
Index optimal_neurons_number
Neurons of the neural network with minimum selection error.
Tensor< type, 1 > optimal_parameters
Vector of parameters for the neural network with minimum selection error.
type optimum_selection_error
Value of minimum selection error.
Tensor< type, 1 > training_error_history
Performance of the different neural networks.
NeuronsSelection::StoppingCondition stopping_condition
Stopping condition of the algorithm.
string elapsed_time
Elapsed time during the loss of the algortihm.
Tensor< Index, 1 > neurons_number_history
Neurons of the diferent neural networks.
This structure contains the optimization algorithm results.