neural_network.cpp
1// OpenNN: Open Neural Networks Library
2// www.opennn.net
3//
4// N E U R A L N E T W O R K C L A S S
5//
6// Artificial Intelligence Techniques SL
7// artelnics@artelnics.com
8
9#include "neural_network.h"
10
11namespace OpenNN
12{
13
18
20{
21 set();
22}
23
24
31
32NeuralNetwork::NeuralNetwork(const NeuralNetwork::ProjectType& model_type, const Tensor<Index, 1>& architecture)
33{
34 set(model_type, architecture);
35}
36
37
38NeuralNetwork::NeuralNetwork(const NeuralNetwork::ProjectType& model_type, const initializer_list<Index>& architecture_list)
39{
40 Tensor<Index, 1> architecture(architecture_list.size());
41 architecture.setValues(architecture_list);
42
43 set(model_type, architecture);
44}
45
46
50
51NeuralNetwork::NeuralNetwork(const Tensor<Index, 1>& new_inputs_dimensions,
52 const Index& new_blocks_number,
53 const Tensor<Index, 1>& new_filters_dimensions,
54 const Index& new_outputs_number)
55{
56 set(new_inputs_dimensions, new_blocks_number, new_filters_dimensions, new_outputs_number);
57}
58
59
64
65NeuralNetwork::NeuralNetwork(const string& file_name)
66{
67 load(file_name);
68}
69
70
74
76{
77 from_XML(document);
78}
79
80
84
85NeuralNetwork::NeuralNetwork(const Tensor<Layer*, 1>& new_layers_pointers)
86{
87 set();
88
89 layers_pointers = new_layers_pointers;
90}
91
92
94
96{
97 delete_layers();
98}
99
100
101void NeuralNetwork::delete_layers()
102{
103 const Index layers_number = get_layers_number();
104
105 for(Index i = 0; i < layers_number; i++)
106 {
107 delete layers_pointers[i];
108
109 layers_pointers[i] = nullptr;
110 }
111
112 layers_pointers.resize(0);
113}
114
115
118
119void NeuralNetwork::add_layer(Layer* layer_pointer)
120{
122 {
123 ostringstream buffer;
124
125 buffer << "OpenNN Exception: NeuralNetwork class.\n"
126 << "NeuralNetwork::add_layer() method.\n"
127 << "No layers can be added after a bounding layer.\n";
128
129 print();
130
131 throw logic_error(buffer.str());
132 }
133
135 {
136 ostringstream buffer;
137
138 buffer << "OpenNN Exception: NeuralNetwork class.\n"
139 << "NeuralNetwork::add_layer() method.\n"
140 << "No layers can be added after a probabilistic layer.\n";
141
142 throw logic_error(buffer.str());
143 }
144
145 if(layer_pointer->get_type_string() == "Pooling")
146 {
147 ostringstream buffer;
148
149 buffer << "OpenNN Exception: NeuralNetwork class.\n"
150 << "NeuralNetwork::add_layer() method.\n"
151 << "Pooling Layer is not available yet. It will be included in future versions.\n";
152
153 throw logic_error(buffer.str());
154 }
155
156 if(layer_pointer->get_type_string() == "Convolutional")
157 {
158 ostringstream buffer;
159
160 buffer << "OpenNN Exception: NeuralNetwork class.\n"
161 << "NeuralNetwork::add_layer() method.\n"
162 << "Convolutional Layer is not available yet. It will be included in future versions.\n";
163
164 throw logic_error(buffer.str());
165 }
166
167 const Layer::Type layer_type = layer_pointer->get_type();
168
169 if(check_layer_type(layer_type))
170 {
171 const Index old_layers_number = get_layers_number();
172
173 Tensor<Layer*, 1> old_layers_pointers = get_layers_pointers();
174
175 layers_pointers.resize(old_layers_number+1);
176
177 for(Index i = 0; i < old_layers_number; i++) layers_pointers(i) = old_layers_pointers(i);
178
179 layers_pointers(old_layers_number) = layer_pointer;
180 }
181 else
182 {
183 ostringstream buffer;
184
185 buffer << "OpenNN Exception: NeuralNetwork class.\n"
186 << "void add_layer(const Layer*) method.\n"
187 << "Layer type " << layer_pointer->get_type_string() << " cannot be added in position " << layers_pointers.size()
188 << " in the neural network architecture.\n";
189
190 throw logic_error(buffer.str());
191 }
192}
193
194
198
200{
201 const Index layers_number = layers_pointers.size();
202
203 if(layers_number > 1 && (layer_type == Layer::Type::Recurrent || layer_type == Layer::Type::LongShortTermMemory))
204 {
205 return false;
206 }
207 else if(layers_number == 1 && (layer_type == Layer::Type::Recurrent || layer_type == Layer::Type::LongShortTermMemory))
208 {
209 const Layer::Type first_layer_type = layers_pointers[0]->get_type();
210
211 if(first_layer_type != Layer::Type::Scaling) return false;
212 }
213
214 return true;
215}
216
217
220
222{
223 const Index layers_number = get_layers_number();
224
225 for(Index i = 0; i < layers_number; i++)
226 {
227 if(layers_pointers[i]->get_type() == Layer::Type::Scaling) return true;
228 }
229
230 return false;
231}
232
233
236
238{
239 const Index layers_number = get_layers_number();
240
241 for(Index i = 0; i < layers_number; i++)
242 {
243 if(layers_pointers[i]->get_type() == Layer::Type::LongShortTermMemory) return true;
244 }
245
246 return false;
247}
248
249
252
254{
255 const Index layers_number = get_layers_number();
256
257 for(Index i = 0; i < layers_number; i++)
258 {
259 if(layers_pointers[i]->get_type() == Layer::Type::Convolutional) return true;
260 }
261
262 return false;
263}
264
265
268
270{
271 const Index layers_number = get_layers_number();
272
273 for(Index i = 0; i < layers_number; i++)
274 {
275 if(layers_pointers[i]->get_type() == Layer::Type::Recurrent) return true;
276 }
277
278 return false;
279}
280
281
284
286{
287 const Index layers_number = get_layers_number();
288
289 for(Index i = 0; i < layers_number; i++)
290 {
291 if(layers_pointers[i]->get_type() == Layer::Type::Unscaling) return true;
292 }
293
294 return false;
295}
296
297
300
302{
303 const Index layers_number = get_layers_number();
304
305 for(Index i = 0; i < layers_number; i++)
306 {
307 if(layers_pointers[i]->get_type() == Layer::Type::Bounding) return true;
308 }
309
310 return false;
311}
312
313
316
318{
319 const Index layers_number = get_layers_number();
320
321 for(Index i = 0; i < layers_number; i++)
322 {
323 if(layers_pointers[i]->get_type() == Layer::Type::Probabilistic) return true;
324 }
325
326 return false;
327}
328
329
332
334{
335 if(layers_pointers.dimension(0) == 0) return true;
336
337 return false;
338}
339
340
342
343const Tensor<string, 1>& NeuralNetwork::get_inputs_names() const
344{
345 return inputs_names;
346}
347
348
351
352string NeuralNetwork::get_input_name(const Index& index) const
353{
354 return inputs_names[index];
355}
356
357
360
361Index NeuralNetwork::get_input_index(const string& name) const
362{
363 for(Index i = 0; i < inputs_names.size(); i++)
364 {
365 if(inputs_names(i) == name) return i;
366 }
367
368 return 0;
369}
370
371
373
374const Tensor<string, 1>& NeuralNetwork::get_outputs_names() const
375{
376 return outputs_names;
377}
378
379
382
383string NeuralNetwork::get_output_name(const Index& index) const
384{
385 return outputs_names[index];
386}
387
388
391
392Index NeuralNetwork::get_output_index(const string& name) const
393{
394 for(Index i = 0; i < outputs_names.size(); i++)
395 {
396 if(outputs_names(i) == name) return i;
397 }
398
399 return 0;
400}
401
402
404
405Tensor<Layer*, 1> NeuralNetwork::get_layers_pointers() const
406{
407 return layers_pointers;
408}
409
410
411Layer* NeuralNetwork::get_layer_pointer(const Index& layer_index) const
412{
413 return layers_pointers(layer_index);
414}
415
416
418
420{
421 const Index layers_number = get_layers_number();
422
423 const Index trainable_layers_number = get_trainable_layers_number();
424
425 Tensor<Layer*, 1> trainable_layers_pointers(trainable_layers_number);
426
427 Index index = 0;
428
429 for(Index i = 0; i < layers_number; i++)
430 {
431 if(layers_pointers[i]->get_type() != Layer::Type::Scaling
432 && layers_pointers[i]->get_type() != Layer::Type::Unscaling
433 && layers_pointers[i]->get_type() != Layer::Type::Bounding)
434 {
435 trainable_layers_pointers[index] = layers_pointers[i];
436 index++;
437 }
438 }
439
440 return trainable_layers_pointers;
441}
442
443
445
447{
448 const Index layers_number = get_layers_number();
449
450 const Index trainable_layers_number = get_trainable_layers_number();
451
452 Tensor<Index, 1> trainable_layers_indices(trainable_layers_number);
453
454 Index trainable_layer_index = 0;
455
456 for(Index i = 0; i < layers_number; i++)
457 {
458 if(layers_pointers[i]->get_type() != Layer::Type::Scaling
459 && layers_pointers[i]->get_type() != Layer::Type::Unscaling
460 && layers_pointers[i]->get_type() != Layer::Type::Bounding)
461 {
462 trainable_layers_indices[trainable_layer_index] = i;
463 trainable_layer_index++;
464 }
465 }
466
467 return trainable_layers_indices;
468}
469
470
472
474{
475 const Index layers_number = get_layers_number();
476
477 for(Index i = 0; i < layers_number; i++)
478 {
479 if(layers_pointers[i]->get_type() == Layer::Type::Scaling)
480 {
481 return dynamic_cast<ScalingLayer*>(layers_pointers[i]);
482 }
483 }
484
485 ostringstream buffer;
486
487 buffer << "OpenNN Exception: NeuralNetwork class.\n"
488 << "ScalingLayer* get_scaling_layer_pointer() const method.\n"
489 << "No scaling layer in neural network.\n";
490
491 throw logic_error(buffer.str());
492}
493
494
496
498{
499 const Index layers_number = get_layers_number();
500
501 for(Index i = 0; i < layers_number; i++)
502 {
503 if(layers_pointers[i]->get_type() == Layer::Type::Unscaling)
504 {
505 return dynamic_cast<UnscalingLayer*>(layers_pointers[i]);
506 }
507 }
508
509 ostringstream buffer;
510
511 buffer << "OpenNN Exception: NeuralNetwork class.\n"
512 << "UnscalingLayer* get_unscaling_layer_pointer() const method.\n"
513 << "No unscaling layer in neural network.\n";
514
515 throw logic_error(buffer.str());
516}
517
518
520
522{
523 const Index layers_number = get_layers_number();
524
525 for(Index i = 0; i < layers_number; i++)
526 {
527 if(layers_pointers[i]->get_type() == Layer::Type::Bounding)
528 {
529 return dynamic_cast<BoundingLayer*>(layers_pointers[i]);
530 }
531 }
532
533 ostringstream buffer;
534
535 buffer << "OpenNN Exception: NeuralNetwork class.\n"
536 << "BoundingLayer* get_bounding_layer_pointer() const method.\n"
537 << "No bounding layer in neural network.\n";
538
539 throw logic_error(buffer.str());
540}
541
542
544
546{
547 const Index layers_number = get_layers_number();
548
549 for(Index i = 0; i < layers_number; i++)
550 {
551 if(layers_pointers[i]->get_type() == Layer::Type::Probabilistic)
552 {
553 return dynamic_cast<ProbabilisticLayer*>(layers_pointers[i]);
554 }
555 }
556
557 ostringstream buffer;
558
559 buffer << "OpenNN Exception: NeuralNetwork class.\n"
560 << "ProbabilisticLayer* get_probabilistic_layer_pointer() const method.\n"
561 << "No probabilistic layer in neural network.\n";
562
563 throw logic_error(buffer.str());
564}
565
567
569{
570 const Index layers_number = get_layers_number();
571
572 for(Index i = 0; i < layers_number; i++)
573 {
574 if(layers_pointers[i]->get_type() == Layer::Type::LongShortTermMemory)
575 {
576 return dynamic_cast<LongShortTermMemoryLayer*>(layers_pointers[i]);
577 }
578 }
579
580 ostringstream buffer;
581
582 buffer << "OpenNN Exception: NeuralNetwork class.\n"
583 << "LongShortTermMemoryLayer* get_long_short_term_memory_layer_pointer() const method.\n"
584 << "No long-short term memory layer in neural network.\n";
585
586 throw logic_error(buffer.str());
587}
588
589
591
593{
594 const Index layers_number = get_layers_number();
595
596 for(Index i = 0; i < layers_number; i++)
597 {
598 if(layers_pointers[i]->get_type() == Layer::Type::Recurrent)
599 {
600 return dynamic_cast<RecurrentLayer*>(layers_pointers[i]);
601 }
602 }
603
604 ostringstream buffer;
605
606 buffer << "OpenNN Exception: NeuralNetwork class.\n"
607 << "RecurrentLayer* get_recurrent_layer_pointer() const method.\n"
608 << "No recurrent layer in neural network.\n";
609
610 throw logic_error(buffer.str());
611}
612
613
616
617const bool& NeuralNetwork::get_display() const
618{
619 return display;
620}
621
622
625
627{
628 inputs_names.resize(0);
629
630 outputs_names.resize(0);
631
632 delete_layers();
633
634 set_default();
635}
636
637
641
642void NeuralNetwork::set(const NeuralNetwork::ProjectType& model_type, const Tensor<Index, 1>& architecture)
643{
644 delete_layers();
645
646 if(architecture.size() <= 1) return;
647
648 const Index size = architecture.size();
649
650 const Index inputs_number = architecture[0];
651 const Index outputs_number = architecture[size-1];
652
653 inputs_names.resize(inputs_number);
654
655 ScalingLayer* scaling_layer_pointer = new ScalingLayer(inputs_number);
656
657 this->add_layer(scaling_layer_pointer);
658
659 if(model_type == ProjectType::Approximation)
660 {
661 for(Index i = 0; i < size-1; i++)
662 {
663 PerceptronLayer* perceptron_layer_pointer = new PerceptronLayer(architecture[i], architecture[i+1]);
664 perceptron_layer_pointer->set_name("perceptron_layer_" + to_string(i+1));
665
666 this->add_layer(perceptron_layer_pointer);
667
668 if(i == size-2) perceptron_layer_pointer->set_activation_function(PerceptronLayer::ActivationFunction::Linear);
669 }
670
671 UnscalingLayer* unscaling_layer_pointer = new UnscalingLayer(outputs_number);
672
673 this->add_layer(unscaling_layer_pointer);
674
675 BoundingLayer* bounding_layer_pointer = new BoundingLayer(outputs_number);
676
677 this->add_layer(bounding_layer_pointer);
678 }
679 else if(model_type == ProjectType::Classification)
680 {
681 for(Index i = 0; i < size-2; i++)
682 {
683 PerceptronLayer* perceptron_layer_pointer = new PerceptronLayer(architecture[i], architecture[i+1]);
684
685 perceptron_layer_pointer->set_name("perceptron_layer_" + to_string(i+1));
686
687 this->add_layer(perceptron_layer_pointer);
688 }
689
690 ProbabilisticLayer* probabilistic_layer_pointer = new ProbabilisticLayer(architecture[size-2], architecture[size-1]);
691
692 this->add_layer(probabilistic_layer_pointer);
693 }
694 else if(model_type == ProjectType::Forecasting)
695 {
696 LongShortTermMemoryLayer* long_short_term_memory_layer_pointer = new LongShortTermMemoryLayer(architecture[0], architecture[1]);
697// RecurrentLayer* long_short_term_memory_layer_pointer = new RecurrentLayer(architecture[0], architecture[1]);
698
699 this->add_layer(long_short_term_memory_layer_pointer);
700
701 for(Index i = 1; i < size-1; i++)
702 {
703 PerceptronLayer* perceptron_layer_pointer = new PerceptronLayer(architecture[i], architecture[i+1]);
704
705 perceptron_layer_pointer->set_name("perceptron_layer_" + to_string(i));
706
707 this->add_layer(perceptron_layer_pointer);
708
709 if(i == size-2) perceptron_layer_pointer->set_activation_function(PerceptronLayer::ActivationFunction::Linear);
710 }
711
712 UnscalingLayer* unscaling_layer_pointer = new UnscalingLayer(architecture[size-1]);
713
714 this->add_layer(unscaling_layer_pointer);
715
716 BoundingLayer* bounding_layer_pointer = new BoundingLayer(outputs_number);
717
718 this->add_layer(bounding_layer_pointer);
719 }
720
721 outputs_names.resize(outputs_number);
722
723 set_default();
724}
725
726
727void NeuralNetwork::set(const NeuralNetwork::ProjectType& model_type, const initializer_list<Index>& architecture_list)
728{
729 Tensor<Index, 1> architecture(architecture_list.size());
730 architecture.setValues(architecture_list);
731
732 set(model_type, architecture);
733}
734
735
742
743void NeuralNetwork::set(const Tensor<Index, 1>& input_variables_dimensions,
744 const Index& blocks_number,
745 const Tensor<Index, 1>& filters_dimensions,
746 const Index& outputs_number)
747{
748 delete_layers();
749
750 ScalingLayer* scaling_layer = new ScalingLayer(input_variables_dimensions);
751 this->add_layer(scaling_layer);
752
753 Tensor<Index, 1> outputs_dimensions = scaling_layer->get_outputs_dimensions();
754
755 for(Index i = 0; i < blocks_number; i++)
756 {
757 ConvolutionalLayer* convolutional_layer = new ConvolutionalLayer(outputs_dimensions, filters_dimensions);
758 add_layer(convolutional_layer);
759
760 outputs_dimensions = convolutional_layer->get_outputs_dimensions();
761
762 // Pooling layer 1
763
764 PoolingLayer* pooling_layer_1 = new PoolingLayer(outputs_dimensions);
765 add_layer(pooling_layer_1);
766
767 outputs_dimensions = pooling_layer_1->get_outputs_dimensions();
768 }
769
770 const Tensor<Index, 0> outputs_dimensions_sum = outputs_dimensions.sum();
771
772 PerceptronLayer* perceptron_layer = new PerceptronLayer(outputs_dimensions_sum(0), 18);
773 add_layer(perceptron_layer);
774
775 const Index perceptron_layer_outputs = perceptron_layer->get_neurons_number();
776
777 ProbabilisticLayer* probabilistic_layer = new ProbabilisticLayer(perceptron_layer_outputs, outputs_number);
778 add_layer(probabilistic_layer);
779}
780
781
784
785void NeuralNetwork::set(const string& file_name)
786{
787 delete_layers();
788
789 load(file_name);
790}
791
792
795
796void NeuralNetwork::set_inputs_names(const Tensor<string, 1>& new_inputs_names)
797{
798 inputs_names = new_inputs_names;
799}
800
801
804
805void NeuralNetwork::set_outputs_names(const Tensor<string, 1>& new_outputs_names)
806{
807 outputs_names = new_outputs_names;
808}
809
810
813
814void NeuralNetwork::set_inputs_number(const Index& new_inputs_number)
815{
816#ifdef OPENNN_DEBUG
817
818 if(new_inputs_number == 0)
819 {
820 ostringstream buffer;
821
822 buffer << "OpenNN Exception: NeuralNetwork class.\n"
823 << "void set_inputs_number(const Index&) method.\n"
824 << "The number of inputs (" << new_inputs_number << ") must be greater than 0.\n";
825
826 throw logic_error(buffer.str());
827 }
828
829#endif
830
831 inputs_names.resize(new_inputs_number);
832
834 {
835 ScalingLayer* scaling_layer_pointer = get_scaling_layer_pointer();
836
837 scaling_layer_pointer->set_inputs_number(new_inputs_number);
838 }
839
840 const Index trainable_layers_number = get_trainable_layers_number();
841 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
842
843 if(trainable_layers_number > 0)
844 {
845 trainable_layers_pointers[0]->set_inputs_number(new_inputs_number);
846 }
847}
848
849
852
853void NeuralNetwork::set_inputs_number(const Tensor<bool, 1>& inputs)
854{
855 if(layers_pointers.dimension(0) == 0) return;
856
857 Index new_inputs_number = 0;
858
859 for(Index i = 0; i < inputs.dimension(0); i++)
860 {
861 if(inputs(i)) new_inputs_number++;
862 }
863
864 set_inputs_number(new_inputs_number);
865}
866
867
869
871{
872 display = true;
873}
874
875
876void NeuralNetwork::set_threads_number(const int& new_threads_number)
877{
878 const Index layers_number = get_layers_number();
879
880 for(Index i = 0; i < layers_number; i++)
881 {
882 layers_pointers(i)->set_threads_number(new_threads_number);
883 }
884}
885
886
887void NeuralNetwork::set_layers_pointers(Tensor<Layer*, 1>& new_layers_pointers)
888{
889 layers_pointers = new_layers_pointers;
890}
891
892
893PerceptronLayer* NeuralNetwork::get_first_perceptron_layer_pointer() const
894{
895 const Index layers_number = get_layers_number();
896
897 for(Index i = 0; i < layers_number; i++)
898 {
899 if(layers_pointers(i)->get_type() == Layer::Type::Perceptron)
900 {
901 return static_cast<PerceptronLayer*>(layers_pointers[i]);
902 }
903 }
904
905 return nullptr;
906}
907
908
910
912{
913 if(layers_pointers.dimension(0) != 0)
914 {
915 return layers_pointers(0)->get_inputs_number();
916 }
917
918 return 0;
919}
920
921
922Index NeuralNetwork::get_outputs_number() const
923{
924 if(layers_pointers.size() > 0)
925 {
926 Layer* last_layer = layers_pointers[layers_pointers.size()-1];
927
928 return last_layer->get_neurons_number();
929 }
930
931 return 0;
932}
933
934
935Tensor<Index, 1> NeuralNetwork::get_trainable_layers_neurons_numbers() const
936{
937 const Index trainable_layers_number = get_trainable_layers_number();
938
939 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
940
941 Index count = 0;
942
943 for(Index i = 0; i < layers_pointers.size(); i++)
944 {
945 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
946 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
947 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
948 {
949 layers_neurons_number(count) = layers_pointers[i]->get_neurons_number();
950
951 count++;
952 }
953
954 }
955
956 return layers_neurons_number;
957}
958
959
960Tensor<Index, 1> NeuralNetwork::get_trainable_layers_inputs_numbers() const
961{
962 const Index trainable_layers_number = get_trainable_layers_number();
963
964 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
965
966 Index count = 0;
967
968 for(Index i = 0; i < layers_pointers.size(); i++)
969 {
970 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
971 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
972 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
973 {
974 layers_neurons_number(count) = layers_pointers[i]->get_inputs_number();
975
976 count++;
977 }
978 }
979
980 return layers_neurons_number;
981}
982
983
984Tensor<Index, 1> NeuralNetwork::get_trainable_layers_synaptic_weight_numbers() const
985{
986 const Index trainable_layers_number = get_trainable_layers_number();
987
988 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
989
990 Index count = 0;
991
992 for(Index i = 0; i < layers_pointers.size(); i++)
993 {
994 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
995 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
996 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
997 {
998 layers_neurons_number(count) = layers_pointers[i]->get_synaptic_weights_number();
999
1000 count++;
1001 }
1002 }
1003
1004 return layers_neurons_number;
1005}
1006
1007
1018
1019Tensor<Index, 1> NeuralNetwork::get_architecture() const
1020{
1021 const Index layers_number = get_layers_number();
1022
1023 Tensor<Index, 1> architecture(layers_number);
1024
1025 const Index inputs_number = get_inputs_number();
1026
1027 if(inputs_number == 0) return architecture;
1028
1029 if(layers_number > 0)
1030 {
1031 for(Index i = 0; i < layers_number; i++)
1032 {
1033 architecture(i) = layers_pointers(i)->get_neurons_number();
1034 }
1035 }
1036
1037 return architecture;
1038}
1039
1040
1043
1045{
1046 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1047
1048 Index parameters_number = 0;
1049
1050 for(Index i = 0; i < trainable_layers_pointers.size(); i++)
1051 {
1052 parameters_number += trainable_layers_pointers[i]->get_parameters_number();
1053 }
1054
1055 return parameters_number;
1056}
1057
1058
1061
1062Tensor<type, 1> NeuralNetwork::get_parameters() const
1063{
1064 const Index parameters_number = get_parameters_number();
1065
1066 Tensor<type, 1> parameters(parameters_number);
1067
1068 const Index trainable_layers_number = get_trainable_layers_number();
1069
1070 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1071
1072 Index position = 0;
1073
1074 for(Index i = 0; i < trainable_layers_number; i++)
1075 {
1076 const Tensor<type, 1> layer_parameters = trainable_layers_pointers(i)->get_parameters();
1077
1078 for(Index j = 0; j < layer_parameters.size(); j++)
1079 {
1080 parameters(j + position) = layer_parameters(j);
1081 }
1082
1083 position += layer_parameters.size();
1084 }
1085
1086 return parameters;
1087}
1088
1089
1090Tensor<Index, 1> NeuralNetwork::get_trainable_layers_parameters_numbers() const
1091{
1092 const Index trainable_layers_number = get_trainable_layers_number();
1093
1094 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1095
1096 Tensor<Index, 1> trainable_layers_parameters_number(trainable_layers_number);
1097
1098 for(Index i = 0; i < trainable_layers_number; i++)
1099 {
1100 trainable_layers_parameters_number[i] = trainable_layers_pointers[i]->get_parameters_number();
1101 }
1102
1103 return trainable_layers_parameters_number;
1104}
1105
1106
1107Tensor<Tensor<type, 1>, 1> NeuralNetwork::get_trainable_layers_parameters(const Tensor<type, 1>& parameters) const
1108{
1109 const Index trainable_layers_number = get_trainable_layers_number();
1110
1111 const Tensor<Index, 1> trainable_layers_parameters_number = get_trainable_layers_parameters_numbers();
1112
1113 Tensor<Tensor<type, 1>, 1> trainable_layers_parameters(trainable_layers_number);
1114
1115 Index index = 0;
1116
1117 for(Index i = 0; i < trainable_layers_number; i++)
1118 {
1119
1120 trainable_layers_parameters(i).resize(trainable_layers_parameters_number(i));
1121
1122 trainable_layers_parameters(i) = parameters.slice(Eigen::array<Eigen::Index, 1>({index}), Eigen::array<Eigen::Index, 1>({trainable_layers_parameters_number(i)}));
1123
1124 index += trainable_layers_parameters_number(i);
1125
1126 }
1127
1128 return trainable_layers_parameters;
1129}
1130
1131
1134
1135void NeuralNetwork::set_parameters(Tensor<type, 1>& new_parameters)
1136{
1137#ifdef OPENNN_DEBUG
1138
1139 const Index size = new_parameters.size();
1140
1141 const Index parameters_number = get_parameters_number();
1142
1143 if(size < parameters_number)
1144 {
1145 ostringstream buffer;
1146
1147 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1148 << "void set_parameters(const Tensor<type, 1>&) method.\n"
1149 << "Size (" << size << ") must be grater or equal to number of parameters (" << parameters_number << ").\n";
1150
1151 throw logic_error(buffer.str());
1152 }
1153
1154#endif
1155
1156 const Index trainable_layers_number = get_trainable_layers_number();
1157
1158 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1159
1160 const Tensor<Index, 1> trainable_layers_parameters_numbers = get_trainable_layers_parameters_numbers();
1161
1162 Index index = 0;
1163
1164 for(Index i = 0; i < trainable_layers_number; i++)
1165 {
1166 trainable_layers_pointers(i)->set_parameters(new_parameters, index);
1167
1168 index += trainable_layers_parameters_numbers(i);
1169 }
1170}
1171
1172
1177
1178void NeuralNetwork::set_display(const bool& new_display)
1179{
1180 display = new_display;
1181}
1182
1183
1186
1188{
1189 return layers_pointers.size();
1190}
1191
1192
1193Tensor<Index, 1> NeuralNetwork::get_layers_neurons_numbers() const
1194{
1195 Tensor<Index, 1> layers_neurons_number(layers_pointers.size());
1196
1197 for(Index i = 0; i < layers_pointers.size(); i++)
1198 {
1199 layers_neurons_number(i) = layers_pointers[i]->get_neurons_number();
1200 }
1201
1202 return layers_neurons_number;
1203}
1204
1205
1206Index NeuralNetwork::get_trainable_layers_number() const
1207{
1208 const Index layers_number = get_layers_number();
1209
1210 Index count = 0;
1211
1212 for(Index i = 0; i < layers_number; i++)
1213 {
1214 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
1215 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
1216 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
1217 {
1218 count++;
1219 }
1220 }
1221
1222 return count;
1223}
1224
1225
1226Index NeuralNetwork::get_perceptron_layers_number() const
1227{
1228 const Index layers_number = get_layers_number();
1229
1230 Index count = 0;
1231
1232 for(Index i = 0; i < layers_number; i++)
1233 {
1234 if(layers_pointers(i)->get_type() == Layer::Type::Perceptron)
1235 {
1236 count++;
1237 }
1238 }
1239
1240 return count;
1241}
1242
1243
1244Index NeuralNetwork::get_probabilistic_layers_number() const
1245{
1246 const Index layers_number = get_layers_number();
1247
1248 Index count = 0;
1249
1250 for(Index i = 0; i < layers_number; i++)
1251 {
1252 if(layers_pointers(i)->get_type() == Layer::Type::Probabilistic)
1253 {
1254 count++;
1255 }
1256 }
1257
1258 return count;
1259}
1260
1261
1262Index NeuralNetwork::get_long_short_term_memory_layers_number() const
1263{
1264 const Index layers_number = get_layers_number();
1265
1266 Index count = 0;
1267
1268 for(Index i = 0; i < layers_number; i++)
1269 {
1270 if(layers_pointers(i)->get_type() == Layer::Type::LongShortTermMemory)
1271 {
1272 count++;
1273 }
1274 }
1275
1276 return count;
1277}
1278
1279Index NeuralNetwork::get_recurrent_layers_number() const
1280{
1281 const Index layers_number = get_layers_number();
1282
1283 Index count = 0;
1284
1285 for(Index i = 0; i < layers_number; i++)
1286 {
1287 if(layers_pointers(i)->get_type() == Layer::Type::Recurrent)
1288 {
1289 count++;
1290 }
1291 }
1292
1293 return count;
1294}
1295
1297
1299{
1300 const Index trainable_layers_number = get_trainable_layers_number();
1301
1302 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1303
1304 for(Index i = 0; i < trainable_layers_number; i++)
1305 {
1306 trainable_layers_pointers[i]->set_parameters_constant(value);
1307 }
1308}
1309
1310
1315
1317{
1318 const Index trainable_layers_number = get_trainable_layers_number();
1319
1320 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1321
1322 for(Index i = 0; i < trainable_layers_number; i++)
1323 {
1324 trainable_layers_pointers[i]->set_parameters_random();
1325 }
1326}
1327
1328
1330
1332{
1333 const Tensor<type, 1> parameters = get_parameters();
1334
1335 const Tensor<type, 0> parameters_norm = parameters.square().sum().sqrt();
1336
1337 return parameters_norm(0);
1338}
1339
1340
1343
1344void NeuralNetwork::perturbate_parameters(const type& perturbation)
1345{
1346#ifdef OPENNN_DEBUG
1347
1348 if(perturbation < 0)
1349 {
1350 ostringstream buffer;
1351
1352 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1353 << "void perturbate_parameters(const type&) method.\n"
1354 << "Perturbation must be equal or greater than 0.\n";
1355
1356 throw logic_error(buffer.str());
1357 }
1358
1359#endif
1360
1361 Tensor<type, 1> parameters = get_parameters();
1362
1363 parameters = parameters + perturbation;
1364
1365 set_parameters(parameters);
1366}
1367
1368
1372
1374 NeuralNetworkForwardPropagation& forward_propagation) const
1375{
1376 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1377
1378 const Index trainable_layers_number = trainable_layers_pointers.size();
1379
1380 if(trainable_layers_pointers(0)->get_type() == Layer::Type::Convolutional)
1381 {
1382 trainable_layers_pointers(0)->forward_propagate(batch.inputs_4d, forward_propagation.layers(0));
1383 }
1384 else
1385 {
1386 trainable_layers_pointers(0)->forward_propagate(batch.inputs_2d, forward_propagation.layers(0));
1387 }
1388
1389 for(Index i = 1; i < trainable_layers_number; i++)
1390 {
1391 switch(trainable_layers_pointers(i-1)->get_type())
1392 {
1393 case Layer::Type::Perceptron:
1394
1395 trainable_layers_pointers(i)
1396 ->forward_propagate(static_cast<PerceptronLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1397 forward_propagation.layers(i));
1398 break;
1399
1400 case Layer::Type::Probabilistic:
1401
1402 trainable_layers_pointers(i)
1403 ->forward_propagate(static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1404 forward_propagation.layers(i));
1405 break;
1406
1407 case Layer::Type::Recurrent:
1408
1409 trainable_layers_pointers(i)
1410 ->forward_propagate(static_cast<RecurrentLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1411 forward_propagation.layers(i));
1412
1413 break;
1414
1415 case Layer::Type::LongShortTermMemory:
1416
1417 trainable_layers_pointers(i)
1418 ->forward_propagate(static_cast<LongShortTermMemoryLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1419 forward_propagation.layers(i));
1420 break;
1421
1422 case Layer::Type::Pooling:
1423
1424 break;
1425
1426 case Layer::Type::Convolutional:
1427
1428 break;
1429
1430 default: break;
1431 }
1432 }
1433}
1434
1435
1440
1442 Tensor<type, 1>& parameters,
1443 NeuralNetworkForwardPropagation& forward_propagation) const
1444{
1445 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1446
1447 const Index trainable_layers_number = trainable_layers_pointers.size();
1448
1449 const Index parameters_number = trainable_layers_pointers(0)->get_parameters_number();
1450
1451 const TensorMap<Tensor<type, 1>> potential_parameters(parameters.data(), parameters_number);
1452
1453 if(trainable_layers_pointers(0)->get_type() == Layer::Type::Convolutional)
1454 {
1455 trainable_layers_pointers(0)->forward_propagate(batch.inputs_4d, potential_parameters, forward_propagation.layers(0));
1456 }
1457 else
1458 {
1459 trainable_layers_pointers(0)->forward_propagate(batch.inputs_2d, potential_parameters, forward_propagation.layers(0));
1460 }
1461
1462 Index index = parameters_number;
1463
1464 for(Index i = 1; i < trainable_layers_number; i++)
1465 {
1466 const Index parameters_number = trainable_layers_pointers(i)->get_parameters_number();
1467
1468 const TensorMap<Tensor<type, 1>> potential_parameters(parameters.data() + index, parameters_number);
1469
1470 switch(trainable_layers_pointers(i-1)->get_type())
1471 {
1472 case Layer::Type::Perceptron:
1473 {
1474 trainable_layers_pointers(i)
1475 ->forward_propagate(static_cast<PerceptronLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1476 potential_parameters,
1477 forward_propagation.layers(i));
1478 }
1479 break;
1480
1481 case Layer::Type::Probabilistic:
1482 {
1483 trainable_layers_pointers(i)
1484 ->forward_propagate(static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1485 potential_parameters,
1486 forward_propagation.layers(i));
1487 }
1488 break;
1489
1490 case Layer::Type::Recurrent:
1491 {
1492 trainable_layers_pointers(i)
1493 ->forward_propagate(static_cast<RecurrentLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1494 potential_parameters,
1495 forward_propagation.layers(i));
1496 }
1497 break;
1498
1499 case Layer::Type::LongShortTermMemory:
1500 {
1501 trainable_layers_pointers(i)
1502 ->forward_propagate(static_cast<LongShortTermMemoryLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1503 potential_parameters,
1504 forward_propagation.layers(i));
1505 }
1506 break;
1507
1508 case Layer::Type::Convolutional:
1509 {
1510 //trainable_layers_pointers(i)->forward_propagate(static_cast<ConvolutionalLayer::ConvolutionalLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1511 // potential_parameters,
1512 // forward_propagation.layers(i));
1513 }
1514 break;
1515
1516 default: break;
1517
1518 }
1519
1520 index += parameters_number;
1521 }
1522}
1523
1524
1536
1537Tensor<type, 2> NeuralNetwork::calculate_outputs(const Tensor<type, 2>& inputs)
1538{
1539#ifdef OPENNN_DEBUG
1540
1541 const Index inputs_dimensions_number = inputs.rank();
1542
1543 if(inputs_dimensions_number != 2 && inputs_dimensions_number != 4)
1544 {
1545 ostringstream buffer;
1546
1547 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1548 << "Tensor<type, 2> calculate_outputs(const Tensor<type, 2>&) const method.\n"
1549 << "Inputs dimensions number (" << inputs_dimensions_number << ") must be 2 or 4.\n";
1550
1551 throw logic_error(buffer.str());
1552 }
1553
1554#endif
1555
1556 Tensor<type, 2> outputs;
1557
1558 const Index layers_number = get_layers_number();
1559
1560 if(layers_number == 0) return inputs;
1561
1562 outputs = layers_pointers(0)->calculate_outputs(inputs);
1563
1564 for(Index i = 1; i < layers_number; i++)
1565 {
1566 outputs = layers_pointers(i)->calculate_outputs(outputs);
1567 }
1568
1569 return outputs;
1570}
1571
1572
1573Tensor<type, 2> NeuralNetwork::calculate_outputs(const Tensor<type, 4>& inputs)
1574{
1575#ifdef OPENNN_DEBUG
1576
1577 const Index inputs_dimensions_number = inputs.rank();
1578
1579 if(inputs_dimensions_number != 2 && inputs_dimensions_number != 4)
1580 {
1581 ostringstream buffer;
1582
1583 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1584 << "Tensor<type, 2> calculate_outputs(const Tensor<type, 2>&) const method.\n"
1585 << "Inputs dimensions number (" << inputs_dimensions_number << ") must be 2 or 4.\n";
1586
1587 throw logic_error(buffer.str());
1588 }
1589
1590#endif
1591
1592 Tensor<type, 4> outputs_4d;
1593 Tensor<type, 2> outputs, inputs_2d;
1594
1595 const Index layers_number = get_layers_number();
1596
1597 if(layers_number == 0) return inputs_2d;
1598
1599 // First layer output
1600
1601 if(layers_pointers(1)->get_type() == Layer::Type::Convolutional)
1602 {
1603 outputs_4d = layers_pointers(0)->calculate_outputs_4D(inputs);
1604 }
1605 else
1606 {
1607 outputs = layers_pointers(0)->calculate_outputs_from4D(inputs);
1608 }
1609
1610 for(Index i = 1; i < layers_number; i++)
1611 {
1612 if(layers_pointers(i + 1)->get_type() == Layer::Type::Convolutional)
1613 {
1614 outputs_4d = layers_pointers(i)->calculate_outputs_4D(outputs_4d);
1615 }
1616 else
1617 {
1618 if(layers_pointers(i)->get_type() != Layer::Type::Convolutional && layers_pointers(i)->get_type() != Layer::Type::Pooling)
1619 {
1620 outputs = layers_pointers(i)->calculate_outputs(outputs);
1621 }
1622 else
1623 {
1624 outputs = layers_pointers(i)->calculate_outputs_from4D(outputs_4d);
1625 }
1626 }
1627 }
1628
1629 return outputs;
1630}
1631
1632
1639
1640Tensor<type, 2> NeuralNetwork::calculate_directional_inputs(const Index& direction,
1641 const Tensor<type, 1>& point,
1642 const type& minimum,
1643 const type& maximum,
1644 const Index& points_number) const
1645{
1646 const Index inputs_number = get_inputs_number();
1647
1648 Tensor<type, 2> directional_inputs(points_number, inputs_number);
1649
1650 Tensor<type, 1> inputs(inputs_number);
1651
1652 inputs = point;
1653
1654 for(Index i = 0; i < points_number; i++)
1655 {
1656 inputs(direction) = minimum + (maximum - minimum)*static_cast<type>(i)/static_cast<type>(points_number-1);
1657
1658 for(Index j = 0; j < inputs_number; j++)
1659 {
1660 directional_inputs(i,j) = inputs(j);
1661 }
1662 }
1663
1664 return directional_inputs;
1665}
1666
1667
1670
1671Tensor<string, 2> NeuralNetwork::get_information() const
1672{
1673 const Index trainable_layers_number = get_trainable_layers_number();
1674
1675 Tensor<string, 2> information(trainable_layers_number, 3);
1676
1677 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1678
1679 for(Index i = 0; i < trainable_layers_number; i++)
1680 {
1681 information(i,0) = to_string(trainable_layers_pointers(i)->get_inputs_number());
1682 information(i,1) = to_string(trainable_layers_pointers(i)->get_neurons_number());
1683
1684 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1685
1686 if(layer_type == "Perceptron")
1687 {
1688 PerceptronLayer* perceptron_layer = static_cast<PerceptronLayer*>(trainable_layers_pointers(i));
1689
1690 information(i,2) = perceptron_layer->write_activation_function();
1691 }
1692 else
1693 {
1694
1695 }
1696 }
1697
1698 return information;
1699}
1700
1701
1703
1705{
1706 const Index trainable_layers_number = get_trainable_layers_number();
1707
1708 const Index perceptron_layers_number = get_perceptron_layers_number();
1709
1710 Tensor<string, 2> information(perceptron_layers_number, 3);
1711
1712 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1713
1714 Index perceptron_layer_index = 0;
1715
1716 for(Index i = 0; i < trainable_layers_number; i++)
1717 {
1718 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1719
1720 if(layer_type == "Perceptron")
1721 {
1722 information(perceptron_layer_index,0) = to_string(trainable_layers_pointers(i)->get_inputs_number());
1723 information(perceptron_layer_index,1) = to_string(trainable_layers_pointers(i)->get_neurons_number());
1724
1725 const PerceptronLayer* perceptron_layer = static_cast<PerceptronLayer*>(trainable_layers_pointers(i));
1726
1727 information(perceptron_layer_index, 2) = perceptron_layer->write_activation_function();
1728
1729 perceptron_layer_index++;
1730 }
1731 }
1732
1733 return information;
1734}
1735
1736
1738
1740{
1741 const Index trainable_layers_number = get_trainable_layers_number();
1742
1743 const Index probabilistic_layers_number = get_probabilistic_layers_number();
1744
1745 Tensor<string, 2> information(probabilistic_layers_number, 3);
1746
1747 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1748
1749 Index probabilistic_layer_index = 0;
1750
1751 for(Index i = 0; i < trainable_layers_number; i++)
1752 {
1753 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1754
1755 if(layer_type == "Probabilistic")
1756 {
1757 information(probabilistic_layer_index,0) = to_string(trainable_layers_pointers(i)->get_inputs_number());
1758 information(probabilistic_layer_index,1) = to_string(trainable_layers_pointers(i)->get_neurons_number());
1759
1760 ProbabilisticLayer* probabilistic_layer = static_cast<ProbabilisticLayer*>(trainable_layers_pointers(i));
1761
1762 information(probabilistic_layer_index,2) = probabilistic_layer->write_activation_function();
1763
1764 probabilistic_layer_index++;
1765 }
1766 }
1767
1768 return information;
1769}
1770
1771
1774
1776{
1777 ostringstream buffer;
1778
1779 file_stream.OpenElement("NeuralNetwork");
1780
1781 // Inputs
1782
1783 file_stream.OpenElement("Inputs");
1784
1785 // Inputs number
1786
1787 file_stream.OpenElement("InputsNumber");
1788
1789 buffer.str("");
1790 buffer << get_inputs_number();
1791
1792 file_stream.PushText(buffer.str().c_str());
1793
1794 file_stream.CloseElement();
1795
1796 // Inputs names
1797
1798 for(Index i = 0; i < inputs_names.size(); i++)
1799 {
1800 file_stream.OpenElement("Input");
1801
1802 file_stream.PushAttribute("Index", to_string(i+1).c_str());
1803
1804 file_stream.PushText(inputs_names[i].c_str());
1805
1806 file_stream.CloseElement();
1807 }
1808
1809 // Inputs (end tag)
1810
1811 file_stream.CloseElement();
1812
1813 // Layers
1814
1815 file_stream.OpenElement("Layers");
1816
1817 // Layers number
1818
1819 file_stream.OpenElement("LayersTypes");
1820
1821 buffer.str("");
1822
1823 for(Index i = 0; i < layers_pointers.size(); i++)
1824 {
1825 buffer << layers_pointers[i]->get_type_string();
1826 if(i != (layers_pointers.size()-1)) buffer << " ";
1827 }
1828
1829 file_stream.PushText(buffer.str().c_str());
1830
1831 file_stream.CloseElement();
1832
1833 // Layers information
1834
1835 for(Index i = 0; i < layers_pointers.size(); i++)
1836 {
1837 layers_pointers[i]->write_XML(file_stream);
1838 }
1839
1840 // Layers (end tag)
1841
1842 file_stream.CloseElement();
1843
1844 // Ouputs
1845
1846 file_stream.OpenElement("Outputs");
1847
1848 // Outputs number
1849
1850 const Index outputs_number = outputs_names.size();
1851
1852 file_stream.OpenElement("OutputsNumber");
1853
1854 buffer.str("");
1855 buffer << outputs_number;
1856
1857 file_stream.PushText(buffer.str().c_str());
1858
1859 file_stream.CloseElement();
1860
1861 // Outputs names
1862
1863 for(Index i = 0; i < outputs_number; i++)
1864 {
1865 file_stream.OpenElement("Output");
1866
1867 file_stream.PushAttribute("Index", to_string(i+1).c_str());
1868
1869 file_stream.PushText(outputs_names[i].c_str());
1870
1871 file_stream.CloseElement();
1872 }
1873
1874 //Outputs (end tag)
1875
1876 file_stream.CloseElement();
1877
1878 // Neural network (end tag)
1879
1880 file_stream.CloseElement();
1881}
1882
1883
1886
1888{
1889 ostringstream buffer;
1890
1891 const tinyxml2::XMLElement* root_element = document.FirstChildElement("NeuralNetwork");
1892
1893 if(!root_element)
1894 {
1895 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1896 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
1897 << "Neural network element is nullptr.\n";
1898
1899 throw logic_error(buffer.str());
1900 }
1901
1902 // Inputs
1903 {
1904 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Inputs");
1905
1906 if(element)
1907 {
1908 tinyxml2::XMLDocument inputs_document;
1909 tinyxml2::XMLNode* element_clone;
1910
1911 element_clone = element->DeepClone(&inputs_document);
1912
1913 inputs_document.InsertFirstChild(element_clone);
1914
1915 inputs_from_XML(inputs_document);
1916 }
1917 }
1918
1919 // Layers
1920 {
1921 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Layers");
1922
1923 if(element)
1924 {
1925 tinyxml2::XMLDocument layers_document;
1926 tinyxml2::XMLNode* element_clone;
1927
1928 element_clone = element->DeepClone(&layers_document);
1929
1930 layers_document.InsertFirstChild(element_clone);
1931
1932 layers_from_XML(layers_document);
1933 }
1934 }
1935
1936 // Outputs
1937 {
1938 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Outputs");
1939
1940 if(element)
1941 {
1942
1943 tinyxml2::XMLDocument outputs_document;
1944 tinyxml2::XMLNode* element_clone;
1945
1946 element_clone = element->DeepClone(&outputs_document);
1947
1948 outputs_document.InsertFirstChild(element_clone);
1949
1950 outputs_from_XML(outputs_document);
1951
1952 }
1953 }
1954
1955 // Display
1956 {
1957 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Display");
1958
1959 if(element)
1960 {
1961 const string new_display_string = element->GetText();
1962
1963 try
1964 {
1965 set_display(new_display_string != "0");
1966 }
1967 catch(const logic_error& e)
1968 {
1969 cerr << e.what() << endl;
1970 }
1971 }
1972 }
1973}
1974
1975
1976void NeuralNetwork::inputs_from_XML(const tinyxml2::XMLDocument& document)
1977{
1978 ostringstream buffer;
1979
1980 const tinyxml2::XMLElement* root_element = document.FirstChildElement("Inputs");
1981
1982 if(!root_element)
1983 {
1984 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1985 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
1986 << "Inputs element is nullptr.\n";
1987
1988 throw logic_error(buffer.str());
1989 }
1990
1991 // Inputs number
1992
1993 const tinyxml2::XMLElement* inputs_number_element = root_element->FirstChildElement("InputsNumber");
1994
1995 if(!inputs_number_element)
1996 {
1997 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1998 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
1999 << "Inputs number element is nullptr.\n";
2000
2001 throw logic_error(buffer.str());
2002 }
2003
2004 Index new_inputs_number = 0;
2005
2006 if(inputs_number_element->GetText())
2007 {
2008 new_inputs_number = static_cast<Index>(atoi(inputs_number_element->GetText()));
2009
2010 set_inputs_number(new_inputs_number);
2011 }
2012
2013 // Inputs names
2014
2015 const tinyxml2::XMLElement* start_element = inputs_number_element;
2016
2017 if(new_inputs_number > 0)
2018 {
2019 for(Index i = 0; i < new_inputs_number; i++)
2020 {
2021 const tinyxml2::XMLElement* input_element = start_element->NextSiblingElement("Input");
2022 start_element = input_element;
2023
2024 if(input_element->Attribute("Index") != to_string(i+1))
2025 {
2026 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2027 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2028 << "Input index number (" << i+1 << ") does not match (" << input_element->Attribute("Item") << ").\n";
2029
2030 throw logic_error(buffer.str());
2031 }
2032
2033 if(!input_element->GetText())
2034 {
2035 inputs_names(i) = "";
2036 }
2037 else
2038 {
2039 inputs_names(i) = input_element->GetText();
2040 }
2041 }
2042 }
2043}
2044
2045
2046void NeuralNetwork::layers_from_XML(const tinyxml2::XMLDocument& document)
2047{
2048 ostringstream buffer;
2049
2050 const tinyxml2::XMLElement* root_element = document.FirstChildElement("Layers");
2051
2052 if(!root_element)
2053 {
2054 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2055 << "void layers_from_XML(const tinyxml2::XMLDocument&) method.\n"
2056 << "Layers element is nullptr.\n";
2057
2058 throw logic_error(buffer.str());
2059 }
2060
2061 // Layers types
2062
2063 const tinyxml2::XMLElement* layers_types_element = root_element->FirstChildElement("LayersTypes");
2064
2065 if(!layers_types_element)
2066 {
2067 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2068 << "void layers_from_XML(const tinyxml2::XMLDocument&) method.\n"
2069 << "Layers types element is nullptr.\n";
2070
2071 throw logic_error(buffer.str());
2072 }
2073
2074 Tensor<string, 1> layers_types;
2075
2076 if(layers_types_element->GetText())
2077 {
2078 layers_types = get_tokens(layers_types_element->GetText(), ' ');
2079 }
2080
2081 // Add layers
2082
2083 const tinyxml2::XMLElement* start_element = layers_types_element;
2084
2085 for(Index i = 0; i < layers_types.size(); i++)
2086 {
2087 if(layers_types(i) == "Scaling")
2088 {
2089 ScalingLayer* scaling_layer = new ScalingLayer();
2090
2091 const tinyxml2::XMLElement* scaling_element = start_element->NextSiblingElement("ScalingLayer");
2092 start_element = scaling_element;
2093
2094 if(scaling_element)
2095 {
2096 tinyxml2::XMLDocument scaling_document;
2097 tinyxml2::XMLNode* element_clone;
2098
2099 element_clone = scaling_element->DeepClone(&scaling_document);
2100
2101 scaling_document.InsertFirstChild(element_clone);
2102
2103 scaling_layer->from_XML(scaling_document);
2104 }
2105
2106 add_layer(scaling_layer);
2107 }
2108 else if(layers_types(i) == "Convolutional")
2109 {
2110 ConvolutionalLayer* convolutional_layer = new ConvolutionalLayer();
2111
2112 const tinyxml2::XMLElement* convolutional_element = start_element->NextSiblingElement("ConvolutionalLayer");
2113 start_element = convolutional_element;
2114
2115 if(convolutional_element)
2116 {
2117 tinyxml2::XMLDocument convolutional_document;
2118 tinyxml2::XMLNode* element_clone;
2119
2120 element_clone = convolutional_element->DeepClone(&convolutional_document);
2121
2122 convolutional_document.InsertFirstChild(element_clone);
2123
2124 convolutional_layer->from_XML(convolutional_document);
2125 }
2126
2127 add_layer(convolutional_layer);
2128 }
2129 else if(layers_types(i) == "Perceptron")
2130 {
2131 PerceptronLayer* perceptron_layer = new PerceptronLayer();
2132
2133 const tinyxml2::XMLElement* perceptron_element = start_element->NextSiblingElement("PerceptronLayer");
2134 start_element = perceptron_element;
2135
2136 if(perceptron_element)
2137 {
2138 tinyxml2::XMLDocument perceptron_document;
2139 tinyxml2::XMLNode* element_clone;
2140
2141 element_clone = perceptron_element->DeepClone(&perceptron_document);
2142
2143 perceptron_document.InsertFirstChild(element_clone);
2144
2145 perceptron_layer->from_XML(perceptron_document);
2146 }
2147
2148 add_layer(perceptron_layer);
2149 }
2150 else if(layers_types(i) == "Pooling")
2151 {
2152 PoolingLayer* pooling_layer = new PoolingLayer();
2153
2154 const tinyxml2::XMLElement* pooling_element = start_element->NextSiblingElement("PoolingLayer");
2155 start_element = pooling_element;
2156
2157 if(pooling_element)
2158 {
2159 tinyxml2::XMLDocument pooling_document;
2160 tinyxml2::XMLNode* element_clone;
2161
2162 element_clone = pooling_element->DeepClone(&pooling_document);
2163
2164 pooling_document.InsertFirstChild(element_clone);
2165
2166 pooling_layer->from_XML(pooling_document);
2167 }
2168
2169 add_layer(pooling_layer);
2170 }
2171 else if(layers_types(i) == "Probabilistic")
2172 {
2173 ProbabilisticLayer* probabilistic_layer = new ProbabilisticLayer();
2174
2175 const tinyxml2::XMLElement* probabilistic_element = start_element->NextSiblingElement("ProbabilisticLayer");
2176 start_element = probabilistic_element;
2177
2178 if(probabilistic_element)
2179 {
2180 tinyxml2::XMLDocument probabilistic_document;
2181 tinyxml2::XMLNode* element_clone;
2182
2183 element_clone = probabilistic_element->DeepClone(&probabilistic_document);
2184
2185 probabilistic_document.InsertFirstChild(element_clone);
2186 probabilistic_layer->from_XML(probabilistic_document);
2187 }
2188
2189 add_layer(probabilistic_layer);
2190 }
2191 else if(layers_types(i) == "LongShortTermMemory")
2192 {
2193 LongShortTermMemoryLayer* long_short_term_memory_layer = new LongShortTermMemoryLayer();
2194
2195 const tinyxml2::XMLElement* long_short_term_memory_element = start_element->NextSiblingElement("LongShortTermMemoryLayer");
2196 start_element = long_short_term_memory_element;
2197
2198 if(long_short_term_memory_element)
2199 {
2200 tinyxml2::XMLDocument long_short_term_memory_document;
2201 tinyxml2::XMLNode* element_clone;
2202
2203 element_clone = long_short_term_memory_element->DeepClone(&long_short_term_memory_document);
2204
2205 long_short_term_memory_document.InsertFirstChild(element_clone);
2206
2207 long_short_term_memory_layer->from_XML(long_short_term_memory_document);
2208 }
2209
2210 add_layer(long_short_term_memory_layer);
2211 }
2212 else if(layers_types(i) == "Recurrent")
2213 {
2214 RecurrentLayer* recurrent_layer = new RecurrentLayer();
2215
2216 const tinyxml2::XMLElement* recurrent_element = start_element->NextSiblingElement("RecurrentLayer");
2217 start_element = recurrent_element;
2218
2219 if(recurrent_element)
2220 {
2221 tinyxml2::XMLDocument recurrent_document;
2222 tinyxml2::XMLNode* element_clone;
2223
2224 element_clone = recurrent_element->DeepClone(&recurrent_document);
2225
2226 recurrent_document.InsertFirstChild(element_clone);
2227
2228 recurrent_layer->from_XML(recurrent_document);
2229 }
2230
2231 add_layer(recurrent_layer);
2232 }
2233 else if(layers_types(i) == "Unscaling")
2234 {
2235 UnscalingLayer* unscaling_layer = new UnscalingLayer();
2236
2237 const tinyxml2::XMLElement* unscaling_element = start_element->NextSiblingElement("UnscalingLayer");
2238 start_element = unscaling_element;
2239
2240 if(unscaling_element)
2241 {
2242 tinyxml2::XMLDocument unscaling_document;
2243 tinyxml2::XMLNode* element_clone;
2244
2245 element_clone = unscaling_element->DeepClone(&unscaling_document);
2246
2247 unscaling_document.InsertFirstChild(element_clone);
2248
2249 unscaling_layer->from_XML(unscaling_document);
2250 }
2251
2252 add_layer(unscaling_layer);
2253 }
2254 else if(layers_types(i) == "Bounding")
2255 {
2256 BoundingLayer* bounding_layer = new BoundingLayer();
2257
2258 const tinyxml2::XMLElement* bounding_element = start_element->NextSiblingElement("BoundingLayer");
2259
2260 start_element = bounding_element;
2261
2262 if(bounding_element)
2263 {
2264 tinyxml2::XMLDocument bounding_document;
2265 tinyxml2::XMLNode* element_clone;
2266
2267 element_clone = bounding_element->DeepClone(&bounding_document);
2268
2269 bounding_document.InsertFirstChild(element_clone);
2270
2271 bounding_layer->from_XML(bounding_document);
2272 }
2273
2274 add_layer(bounding_layer);
2275 }
2276 }
2277}
2278
2279
2280void NeuralNetwork::outputs_from_XML(const tinyxml2::XMLDocument& document)
2281{
2282 ostringstream buffer;
2283
2284 const tinyxml2::XMLElement* root_element = document.FirstChildElement("Outputs");
2285
2286 if(!root_element)
2287 {
2288 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2289 << "void outputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2290 << "Outputs element is nullptr.\n";
2291
2292 throw logic_error(buffer.str());
2293 }
2294
2295 // Outputs number
2296
2297 const tinyxml2::XMLElement* outputs_number_element = root_element->FirstChildElement("OutputsNumber");
2298
2299 if(!outputs_number_element)
2300 {
2301 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2302 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2303 << "Outputs number element is nullptr.\n";
2304
2305 throw logic_error(buffer.str());
2306 }
2307
2308 Index new_outputs_number = 0;
2309
2310 if(outputs_number_element->GetText())
2311 {
2312 new_outputs_number = static_cast<Index>(atoi(outputs_number_element->GetText()));
2313 }
2314
2315 // Outputs names
2316
2317 const tinyxml2::XMLElement* start_element = outputs_number_element;
2318
2319 if(new_outputs_number > 0)
2320 {
2321 outputs_names.resize(new_outputs_number);
2322
2323 for(Index i = 0; i < new_outputs_number; i++)
2324 {
2325 const tinyxml2::XMLElement* output_element = start_element->NextSiblingElement("Output");
2326 start_element = output_element;
2327
2328 if(output_element->Attribute("Index") != to_string(i+1))
2329 {
2330 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2331 << "void outputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2332 << "Output index number (" << i+1 << ") does not match (" << output_element->Attribute("Item") << ").\n";
2333
2334 throw logic_error(buffer.str());
2335 }
2336
2337 if(!output_element->GetText())
2338 {
2339 outputs_names(i) = "";
2340 }
2341 else
2342 {
2343 outputs_names(i) = output_element->GetText();
2344 }
2345 }
2346 }
2347}
2348
2349
2351
2353{
2354 cout << "Neural network" << endl;
2355
2356 const Index layers_number = get_layers_number();
2357
2358 cout << "Layers number: " << layers_number << endl;
2359
2360 for(Index i = 0; i < layers_number; i++)
2361 {
2362 cout << "Layer " << i+1 << ": " << layers_pointers[i]->get_neurons_number()
2363 << " " << layers_pointers[i]->get_type_string() << " neurons" << endl;
2364 }
2365}
2366
2367
2370
2371void NeuralNetwork::save(const string& file_name) const
2372{
2373 FILE * file = fopen(file_name.c_str(), "w");
2374
2375 tinyxml2::XMLPrinter printer(file);
2376
2377 write_XML(printer);
2378
2379 fclose(file);
2380}
2381
2382
2385
2386void NeuralNetwork::save_parameters(const string& file_name) const
2387{
2388 ofstream file(file_name.c_str());
2389
2390 if(!file.is_open())
2391 {
2392 ostringstream buffer;
2393
2394 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2395 << "void save_parameters(const string&) const method.\n"
2396 << "Cannot open parameters data file.\n";
2397
2398 throw logic_error(buffer.str());
2399 }
2400
2401 const Tensor<type, 1> parameters = get_parameters();
2402
2403 file << parameters << endl;
2404
2405 // Close file
2406
2407 file.close();
2408}
2409
2410
2414
2415void NeuralNetwork::load(const string& file_name)
2416{
2417 set_default();
2418
2419 tinyxml2::XMLDocument document;
2420
2421 if(document.LoadFile(file_name.c_str()))
2422 {
2423 ostringstream buffer;
2424
2425 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2426 << "void load(const string&) method.\n"
2427 << "Cannot load XML file " << file_name << ".\n";
2428
2429 throw logic_error(buffer.str());
2430
2431 }
2432
2433 from_XML(document);
2434}
2435
2436
2440
2441void NeuralNetwork::load_parameters_binary(const string& file_name)
2442{
2443 ifstream file;
2444
2445 file.open(file_name.c_str(), ios::binary);
2446
2447 if(!file.is_open())
2448 {
2449 ostringstream buffer;
2450
2451 buffer << "OpenNN Exception: NeuralNetwork template.\n"
2452 << "void load_parameters_binary(const string&) method.\n"
2453 << "Cannot open binary file: " << file_name << "\n";
2454
2455 throw logic_error(buffer.str());
2456 }
2457
2458 streamsize size = sizeof(double);
2459
2460 const Index parameters_number = get_parameters_number();
2461
2462 Tensor<type, 1> new_parameters(parameters_number);
2463
2464 type value;
2465
2466 for(Index i = 0; i < parameters_number; i++)
2467 {
2468 file.read(reinterpret_cast<char*>(&value), size);
2469
2470 new_parameters(i) = value;
2471 }
2472
2473 set_parameters(new_parameters);
2474}
2475
2476
2478
2480{
2481 const Index layers_number = get_layers_number();
2482
2483 const Tensor<Layer*, 1> layers_pointers = get_layers_pointers();
2484 const Tensor<string, 1> layers_names = get_layers_names();
2485
2486 ostringstream buffer;
2487
2488 buffer <<"// Artificial Intelligence Techniques SL\t"<<endl;
2489 buffer <<"// artelnics@artelnics.com\t"<<endl;
2490 buffer <<"// "<<endl;
2491 buffer <<"// Your model has been exported to this file." <<endl;
2492 buffer <<"// You can manage it with the 'neural network' method.\t"<<endl;
2493 buffer <<"// Example:"<<endl;
2494 buffer <<"// "<<endl;
2495 buffer <<"// \tvector<float> sample(n);\t"<<endl;
2496 buffer <<"// \tsample[0] = 1;\t"<<endl;
2497 buffer <<"// \tsample[1] = 2;\t"<<endl;
2498 buffer <<"// \tsample[n] = 10;\t"<<endl;
2499 buffer <<"// \tvector<float> outputs = neural_network(sample);"<<endl;
2500 buffer <<"// "<<endl;
2501 buffer <<"// Notice that only one sample is allowed as input. DataSetBatch of inputs are not yet implement,\t"<<endl;
2502 buffer <<"// however you can loop through neural network function in order to get multiple outputs.\t"<<endl;
2503 buffer <<""<<endl;
2504
2505 buffer << "#include <vector>\n" << endl;
2506
2507 buffer << "using namespace std;\n" << endl;
2508
2510 {
2511 LongShortTermMemoryLayer* long_short_term_memory_pointer = get_long_short_term_memory_layer_pointer();
2512 Index timestep = long_short_term_memory_pointer->get_timesteps();
2513 Index neurons_number = long_short_term_memory_pointer->get_neurons_number();
2514
2515 buffer << "class LSTMNetwork\n";
2516 buffer << "{\n" << endl;
2517 buffer << "public:\n" << endl;
2518 buffer << " LSTMNetwork()\n";
2519 buffer << " {\n";
2520 buffer << " hidden_states.resize(" << neurons_number << ");\n";
2521 buffer << " cell_states.resize(" << neurons_number << ");\n";
2522 buffer << " }\n" << endl;
2523 buffer << " vector<vector<float>> neural_network_batch(const vector<vector<float>>& inputs)\n";
2524 buffer << " {\n";
2525 buffer << " vector<vector<float>> outputs(inputs.size());\n" << endl;
2526 buffer << " for(size_t i = 0; i < inputs.size(); i++)\n";
2527 buffer << " {\n";
2528 buffer << " if(i % " << timestep << " == 0)\n";
2529 buffer << " {\n";
2530 buffer << " fill(hidden_states.begin(), hidden_states.end(), 0.0);\n";
2531 buffer << " fill(cell_states.begin(), cell_states.end(), 0.0);\n";
2532 buffer << " }\n" << endl;
2533 buffer << " outputs[i] = neural_network(inputs[i]);\n";
2534 buffer << " }\n" << endl;
2535 buffer << " return outputs;\n";
2536 buffer << " }\n" << endl << endl;
2537 buffer << "private:\n" << endl;
2538 buffer << " vector<float> hidden_states;\n";
2539 buffer << " vector<float> cell_states;\n" << endl << endl;
2540 }
2541
2542 for(Index i = 0; i < layers_number; i++)
2543 {
2544 buffer << layers_pointers[i]->write_expression_c() << endl;
2545 }
2546
2547 buffer << "vector<float> neural_network(const vector<float>& inputs)\n{" << endl;
2548
2549 buffer << "\tvector<float> outputs;\n" << endl;
2550
2551 if(layers_number > 0)
2552 {
2553 buffer << "\toutputs = " << layers_names[0] << "(inputs);\n";
2554 }
2555
2556 for(Index i = 1; i < layers_number; i++)
2557 {
2558 buffer << "\toutputs = " << layers_names[i] << "(outputs);\n";
2559 }
2560
2561 buffer << "\n\treturn outputs;\n}" << endl;
2562
2563 if(has_long_short_term_memory_layer()) buffer << "\n};\n" << endl;
2564
2565 buffer << "int main(){return 0;}" << endl;
2566
2567 string expression = buffer.str();
2568
2569 replace(expression, "+-", "-");
2570 replace(expression, "-+", "-");
2571 replace(expression, "--", "+");
2572
2573 return expression;
2574}
2575
2576
2577string NeuralNetwork::write_expression() const
2578{
2579 const Index layers_number = get_layers_number();
2580
2581 const Tensor<Layer*, 1> layers_pointers = get_layers_pointers();
2582 const Tensor<string, 1> layers_names = get_layers_names();
2583
2584 Tensor<string, 1> outputs_names_vector;
2585 Tensor<string, 1> inputs_names_vector;
2586 inputs_names_vector = inputs_names;
2587
2588 Index layer_neurons_number;
2589
2590 ostringstream buffer;
2591
2592 for(Index i = 0; i < layers_number; i++)
2593 {
2594 if(i == layers_number-1)
2595 {
2596 outputs_names_vector = outputs_names;
2597 buffer << layers_pointers[i]->write_expression(inputs_names_vector, outputs_names_vector) << endl;
2598 }
2599 else
2600 {
2601 layer_neurons_number = layers_pointers[i]->get_neurons_number();
2602 outputs_names_vector.resize(layer_neurons_number);
2603
2604 for(Index j = 0; j < layer_neurons_number; j++)
2605 {
2606 if(layers_names(i) == "scaling_layer")
2607 {
2608 outputs_names_vector(j) = "scaled_" + inputs_names(j);
2609 }
2610 else
2611 {
2612 outputs_names_vector(j) = layers_names(i) + "_output_" + to_string(j);
2613 }
2614 }
2615 buffer << layers_pointers[i]->write_expression(inputs_names_vector, outputs_names_vector) << endl;
2616
2617 inputs_names_vector = outputs_names_vector;
2618 }
2619 }
2620
2621 string expression = buffer.str();
2622
2623 replace(expression, "+-", "-");
2624
2625 return expression;
2626}
2627
2628
2631{
2632 const Index layers_number = get_layers_number();
2633
2634 const Tensor<Layer*, 1> layers_pointers = get_layers_pointers();
2635 const Tensor<string, 1> layers_names = get_layers_names();
2636
2637 ostringstream buffer;
2638
2639 buffer <<"'''"<<endl;
2640 buffer <<"Artificial Intelligence Techniques SL\t"<<endl;
2641 buffer <<"artelnics@artelnics.com\t"<<endl;
2642 buffer <<""<<endl;
2643 buffer <<"Your model has been exported to this python file." <<endl;
2644 buffer <<"You can manage it with the 'NeuralNetwork' class.\t"<<endl;
2645 buffer <<"Example:"<<endl;
2646 buffer <<""<<endl;
2647 buffer <<"\tmodel = NeuralNetwork()\t"<<endl;
2648 buffer <<"\tsample = [input_1, input_2, input_3, input_4, ...] \t"<<endl;
2649 buffer <<"\toutputs = model.calculate_output(sample)"<<endl;
2650 buffer <<""<<endl;
2651 buffer <<"\tInputs Names: \t"<<endl;
2652
2653 const Tensor<string, 1> inputs = get_inputs_names();
2654
2655 for(int i = 0; i < inputs.dimension(0); i++)
2656 {
2657 if(inputs[i] == "")
2658 {
2659 buffer <<"\t" << to_string(1+i) + " )" << "input_"+ to_string(1+i) << endl;
2660 }
2661 else
2662 {
2663 buffer <<"\t" << to_string(1+i) + " )" << inputs[i] << endl;
2664 }
2665 }
2666
2667 buffer <<""<<endl;
2668 buffer <<"You can predict with a batch of samples using calculate_batch_output method\t" <<endl;
2669 buffer <<"IMPORTANT: input batch must be <class 'numpy.ndarray'> type\t" <<endl;
2670 buffer <<"Example_1:\t" <<endl;
2671 buffer <<"\tmodel = NeuralNetwork()\t"<<endl;
2672 buffer <<"\tinput_batch = np.array([[1, 2], [4, 5]], np.int32)\t" <<endl;
2673 buffer <<"\toutputs = model.calculate_batch_output(input_batch)"<<endl;
2674 buffer <<"Example_2:\t" <<endl;
2675 buffer <<"\tinput_batch = pd.DataFrame( {'col1': [1, 2], 'col2': [3, 4]})\t" <<endl;
2676 buffer <<"\toutputs = model.calculate_batch_output(input_batch.values)"<<endl;
2677 buffer <<"'''"<<endl;
2678 buffer <<""<<endl;
2679 buffer << "import numpy as np\n" << endl;
2680 buffer << "class NeuralNetwork:\n " << endl;
2681 buffer << "\tdef __init__(self):\n " << endl;
2682
2684 {
2685 buffer << "\t\tself.timestep = "+to_string(get_recurrent_layer_pointer()->get_timesteps())+"\n " << endl;
2686 buffer << "\t\tself.hidden_states = " + to_string(get_recurrent_layer_pointer()->get_neurons_number()) + "*[0]\n " << endl;
2687 }
2688
2690 {
2691 buffer << "\t\tself.timestep = "+to_string(get_long_short_term_memory_layer_pointer()->get_timesteps())+"\n " << endl;
2692 buffer << "\t\tself.hidden_states = " + to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number()) + "*[0]\n " << endl;
2693 buffer << "\t\tself.cell_states = " + to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number()) + "*[0]\n " << endl;
2694 }
2695
2696 buffer << "\t\tself.parameters_number = " + to_string(get_parameters_number()) + "\n " << endl;
2697
2698 for(Index i = 0; i < layers_number; i++)
2699 {
2700 buffer << layers_pointers[i]->write_expression_python() << endl;
2701 }
2702
2703 buffer << "\tdef calculate_output(self, inputs):\n" << endl;
2704
2705 buffer << "\t\toutput_" + layers_pointers[0]->get_name() + " = self." +layers_pointers[0]->get_name() + "(inputs)\n" << endl;
2706
2707 for(Index i = 1; i < layers_number; i++)
2708 {
2709 buffer << "\t\toutput_" + layers_pointers[i]->get_name() + " = self." +layers_pointers[i]->get_name() + "(output_"+layers_pointers[i-1]->get_name() + ")\n" << endl;
2710 }
2711
2712 buffer << "\t\treturn output_" + layers_pointers[layers_number-1]->get_name()<<endl;
2713
2714 buffer << "\n\n\tdef calculate_batch_output(self, input_batch):\n" << endl;
2715
2716 buffer << "\t\toutput = []\n" << endl;
2717
2718 buffer << "\t\tfor i in range(input_batch.shape[0]):\n" << endl;
2719
2721 {
2722 buffer << "\t\t\tif(i%self.timestep==0):\n" << endl;
2723
2724 buffer << "\t\t\t\tself.hidden_states = "+to_string(get_recurrent_layer_pointer()->get_neurons_number())+"*[0]\n" << endl;
2725 }
2726
2728 {
2729 buffer << "\t\t\tif(i%self.timestep==0):\n" << endl;
2730
2731 buffer << "\t\t\t\tself.hidden_states = "+to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number())+"*[0]\n" << endl;
2732
2733 buffer << "\t\t\t\tself.cell_states = "+to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number())+"*[0]\n" << endl;
2734 }
2735
2736
2737 buffer << "\t\t\tinputs = list(input_batch[i])\n" << endl;
2738
2739 buffer << "\t\t\toutput_" + layers_pointers[0]->get_name() + " = self." +layers_pointers[0]->get_name() + "(inputs)\n" << endl;
2740
2741 for(Index i = 1; i < layers_number; i++)
2742 {
2743 buffer << "\t\t\toutput_" + layers_pointers[i]->get_name() + " = self." +layers_pointers[i]->get_name() + "(output_"+layers_pointers[i-1]->get_name() + ")\n" << endl;
2744 }
2745
2746 buffer << "\t\t\toutput = np.append(output,output_" + layers_pointers[layers_number-1]->get_name()+ ", axis=0)\n"<< endl;
2747
2748 buffer << "\t\treturn output"<<endl;
2749
2750 string expression = buffer.str();
2751
2752 replace(expression, "+-", "-");
2753 replace(expression, "-+", "-");
2754 replace(expression, "--", "+");
2755
2756 return expression;
2757}
2758
2759
2762
2763void NeuralNetwork::save_expression_c(const string& file_name)
2764{
2765 ofstream file(file_name.c_str());
2766
2767 if(!file.is_open())
2768 {
2769 ostringstream buffer;
2770
2771 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2772 << "void save_expression(const string&) method.\n"
2773 << "Cannot open expression text file.\n";
2774
2775 throw logic_error(buffer.str());
2776 }
2777
2778 file << write_expression_c();
2779
2780 file.close();
2781}
2782
2783
2786
2787void NeuralNetwork::save_expression_python(const string& file_name)
2788{
2789 ofstream file(file_name.c_str());
2790
2791 if(!file.is_open())
2792 {
2793 ostringstream buffer;
2794
2795 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2796 << "void save_expression_python(const string&) method.\n"
2797 << "Cannot open expression text file.\n";
2798
2799 throw logic_error(buffer.str());
2800 }
2801
2802 file << write_expression_python();
2803
2804 file.close();
2805}
2806
2807
2811
2812void NeuralNetwork::save_outputs(const Tensor<type, 2>& inputs, const string & file_name)
2813{
2814 const Tensor<type, 2> outputs = calculate_outputs(inputs);
2815
2816 ofstream file(file_name.c_str());
2817
2818 if(!file.is_open())
2819 {
2820 ostringstream buffer;
2821
2822 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2823 << "void save_expression_python(const string&) method.\n"
2824 << "Cannot open expression text file.\n";
2825
2826 throw logic_error(buffer.str());
2827 }
2828
2829 const Tensor<string, 1> outputs_names = get_outputs_names();
2830
2831 const Index outputs_number = get_outputs_number();
2832 const Index samples_number = inputs.dimension(0);
2833
2834 for(Index i = 0; i < outputs_number; i++)
2835 {
2836 file << outputs_names[i];
2837
2838 if(i != outputs_names.size()-1) file << ";";
2839 }
2840
2841 file << "\n";
2842
2843 for(Index i = 0; i < samples_number; i++)
2844 {
2845 for(Index j = 0; j < outputs_number; j++)
2846 {
2847 file << outputs(i,j);
2848
2849 if(j != outputs_number-1) file << ";";
2850 }
2851
2852 file << "\n";
2853 }
2854
2855 file.close();
2856}
2857
2858
2859Tensor<string, 1> NeuralNetwork::get_layers_names() const
2860{
2861 const Index layers_number = get_layers_number();
2862
2863 Tensor<string, 1> layers_names(layers_number);
2864
2865 for(Index i = 0; i < layers_number; i++)
2866 {
2867 layers_names[i] = layers_pointers[i]->get_name();
2868 }
2869
2870 return layers_names;
2871}
2872
2873
2874Layer* NeuralNetwork::get_last_trainable_layer_pointer() const
2875{
2876 if(layers_pointers.size() == 0) return nullptr;
2877
2878 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
2879
2880 const Index trainable_layers_number = get_trainable_layers_number();
2881
2882 return trainable_layers_pointers(trainable_layers_number-1);
2883}
2884
2885}
2886
2887// OpenNN: Open Neural Networks Library.
2888// Copyright(C) 2005-2021 Artificial Intelligence Techniques, SL.
2889//
2890// This library is free software; you can redistribute it and/or
2891// modify it under the terms of the GNU Lesser General Public
2892// License as published by the Free Software Foundation; either
2893// version 2.1 of the License, or any later version.
2894//
2895// This library is distributed in the hope that it will be useful,
2896// but WITHOUT ANY WARRANTY; without even the implied warranty of
2897// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2898// Lesser General Public License for more details.
2899
2900// You should have received a copy of the GNU Lesser General Public
2901// License along with this library; if not, write to the Free Software
2902// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
This class represents a layer of bounding neurons.
Tensor< Index, 1 > get_outputs_dimensions() const
Returns a vector containing the number of channels, rows and columns of the result of applying the la...
This abstract class represents the concept of layer of neurons in OpenNN.
Definition: layer.h:53
Type
This enumeration represents the possible types of layers.
Definition: layer.h:61
Type get_type() const
Definition: layer.cpp:25
string get_type_string() const
Takes the type of layer used by the model.
Definition: layer.cpp:33
Index get_neurons_number() const
Returns the size of the neurons vector.
Index get_timesteps() const
Returns the number of timesteps.
ScalingLayer * get_scaling_layer_pointer() const
Returns a pointer to the scaling layers object composing this neural network object.
string write_expression_c() const
Returns a string with the c function of the expression represented by the neural network.
Tensor< string, 1 > outputs_names
Names of ouputs.
Tensor< Layer *, 1 > get_trainable_layers_pointers() const
Returns a pointer to the trainable layers object composing this neural network object.
bool has_long_short_term_memory_layer() const
void load_parameters_binary(const string &)
bool has_scaling_layer() const
void set_parameters_constant(const type &)
Initializes all the neural and the independent parameters with a given value.
bool check_layer_type(const Layer::Type)
Tensor< Index, 1 > get_trainable_layers_indices() const
Returns a vector with the indices of the trainable layers.
const Tensor< string, 1 > & get_outputs_names() const
Returns a string vector with the names of the variables used as outputs.
type calculate_parameters_norm() const
Returns the norm of the vector of parameters.
const bool & get_display() const
Tensor< Layer *, 1 > layers_pointers
Layers.
Index get_inputs_number() const
Returns the number of inputs to the neural network.
LongShortTermMemoryLayer * get_long_short_term_memory_layer_pointer() const
Returns a pointer to the long short term memory layer of this neural network, if exits.
virtual void from_XML(const tinyxml2::XMLDocument &)
virtual void set_default()
Sets those members which are not pointer to their default values.
bool has_probabilistic_layer() const
virtual void load(const string &)
string write_expression_python() const
Returns a string with the python function of the expression represented by the neural network.
bool has_unscaling_layer() const
bool display
Display messages to screen.
Tensor< type, 2 > calculate_directional_inputs(const Index &, const Tensor< type, 1 > &, const type &, const type &, const Index &=101) const
bool has_recurrent_layer() const
bool has_convolutional_layer() const
bool has_bounding_layer() const
Tensor< Layer *, 1 > get_layers_pointers() const
Returns a pointer to the layers object composing this neural network object.
Index get_input_index(const string &) const
Tensor< string, 2 > get_information() const
const Tensor< string, 1 > & get_inputs_names() const
Returns a string vector with the names of the variables used as inputs.
void save_expression_python(const string &)
virtual ~NeuralNetwork()
Destructor.
void save_parameters(const string &) const
void forward_propagate(const DataSetBatch &, NeuralNetworkForwardPropagation &) const
Calculate forward propagation in neural network.
void save(const string &) const
Tensor< Index, 1 > get_architecture() const
void set_inputs_number(const Index &)
Index get_layers_number() const
string get_output_name(const Index &) const
Index get_output_index(const string &) const
Tensor< type, 2 > calculate_outputs(const Tensor< type, 2 > &)
void set_parameters(Tensor< type, 1 > &)
void save_expression_c(const string &)
Tensor< string, 2 > get_perceptron_layers_information() const
For each perceptron layer: inputs, neurons, activation function.
string get_input_name(const Index &) const
Tensor< string, 2 > get_probabilistic_layer_information() const
For each probabilistic layer: inputs, neurons, activation function.
BoundingLayer * get_bounding_layer_pointer() const
Returns a pointer to the bounding layers object composing this neural network object.
Tensor< string, 1 > inputs_names
Names of inputs.
void print() const
Prints to the screen the most important information about the neural network object.
UnscalingLayer * get_unscaling_layer_pointer() const
Returns a pointer to the unscaling layers object composing this neural network object.
void set_display(const bool &)
ProbabilisticLayer * get_probabilistic_layer_pointer() const
Returns a pointer to the first probabilistic layer composing this neural network.
void set_inputs_names(const Tensor< string, 1 > &)
virtual void write_XML(tinyxml2::XMLPrinter &) const
RecurrentLayer * get_recurrent_layer_pointer() const
Returns a pointer to the recurrent layer of this neural network, if exits.
Index get_parameters_number() const
void perturbate_parameters(const type &)
void save_outputs(const Tensor< type, 2 > &, const string &)
void set_outputs_names(const Tensor< string, 1 > &)
Tensor< type, 1 > get_parameters() const
This class represents a layer of perceptrons.
string write_activation_function() const
void set_activation_function(const ActivationFunction &)
Index get_neurons_number() const
Returns the number of neurons in the layer.
Tensor< Index, 1 > get_outputs_dimensions() const
Returns the layer's outputs dimensions.
This class represents a layer of probabilistic neurons.
This class represents a layer of scaling neurons.
Definition: scaling_layer.h:38
This class represents a layer of unscaling neurons.
const XMLElement * NextSiblingElement(const char *name=nullptr) const
Get the next(right) sibling element of this node, with an optionally supplied name.
Definition: tinyxml2.cpp:1059
void PushText(const char *text, bool cdata=false)
Add a text node.
Definition: tinyxml2.cpp:2878
void PushAttribute(const char *name, const char *value)
If streaming, add an attribute to an open element.
Definition: tinyxml2.cpp:2783
virtual void CloseElement(bool compactMode=false)
If streaming, close the Element.
Definition: tinyxml2.cpp:2834