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
642
643void NeuralNetwork::set(const NeuralNetwork::ProjectType& model_type, const Tensor<Index, 1>& architecture)
644{
645 delete_layers();
646
647 if(architecture.size() <= 1) return;
648
649 const Index size = architecture.size();
650
651 const Index inputs_number = architecture[0];
652 const Index outputs_number = architecture[size-1];
653
654 inputs_names.resize(inputs_number);
655
656 ScalingLayer* scaling_layer_pointer = new ScalingLayer(inputs_number);
657
658 this->add_layer(scaling_layer_pointer);
659
660 if(model_type == ProjectType::Approximation)
661 {
662 for(Index i = 0; i < size-1; i++)
663 {
664 PerceptronLayer* perceptron_layer_pointer = new PerceptronLayer(architecture[i], architecture[i+1]);
665 perceptron_layer_pointer->set_name("perceptron_layer_" + to_string(i+1));
666
667 this->add_layer(perceptron_layer_pointer);
668
669 if(i == size-2) perceptron_layer_pointer->set_activation_function(PerceptronLayer::ActivationFunction::Linear);
670 }
671
672 UnscalingLayer* unscaling_layer_pointer = new UnscalingLayer(outputs_number);
673
674 this->add_layer(unscaling_layer_pointer);
675
676 BoundingLayer* bounding_layer_pointer = new BoundingLayer(outputs_number);
677
678 this->add_layer(bounding_layer_pointer);
679 }
680 else if(model_type == ProjectType::Classification)
681 {
682 for(Index i = 0; i < size-2; i++)
683 {
684 PerceptronLayer* perceptron_layer_pointer = new PerceptronLayer(architecture[i], architecture[i+1]);
685
686 perceptron_layer_pointer->set_name("perceptron_layer_" + to_string(i+1));
687
688 this->add_layer(perceptron_layer_pointer);
689 }
690
691 ProbabilisticLayer* probabilistic_layer_pointer = new ProbabilisticLayer(architecture[size-2], architecture[size-1]);
692
693 this->add_layer(probabilistic_layer_pointer);
694 }
695 else if(model_type == ProjectType::Forecasting)
696 {
697 LongShortTermMemoryLayer* long_short_term_memory_layer_pointer = new LongShortTermMemoryLayer(architecture[0], architecture[1]);
698// RecurrentLayer* long_short_term_memory_layer_pointer = new RecurrentLayer(architecture[0], architecture[1]);
699
700 this->add_layer(long_short_term_memory_layer_pointer);
701
702 for(Index i = 1; i < size-1; i++)
703 {
704 PerceptronLayer* perceptron_layer_pointer = new PerceptronLayer(architecture[i], architecture[i+1]);
705
706 perceptron_layer_pointer->set_name("perceptron_layer_" + to_string(i));
707
708 this->add_layer(perceptron_layer_pointer);
709
710 if(i == size-2) perceptron_layer_pointer->set_activation_function(PerceptronLayer::ActivationFunction::Linear);
711 }
712
713 UnscalingLayer* unscaling_layer_pointer = new UnscalingLayer(architecture[size-1]);
714
715 this->add_layer(unscaling_layer_pointer);
716
717 BoundingLayer* bounding_layer_pointer = new BoundingLayer(outputs_number);
718
719 this->add_layer(bounding_layer_pointer);
720 }
721
722 outputs_names.resize(outputs_number);
723
724 set_default();
725}
726
727
728void NeuralNetwork::set(const NeuralNetwork::ProjectType& model_type, const initializer_list<Index>& architecture_list)
729{
730 Tensor<Index, 1> architecture(architecture_list.size());
731 architecture.setValues(architecture_list);
732
733 set(model_type, architecture);
734}
735
736
743
744void NeuralNetwork::set(const Tensor<Index, 1>& input_variables_dimensions,
745 const Index& blocks_number,
746 const Tensor<Index, 1>& filters_dimensions,
747 const Index& outputs_number)
748{
749 delete_layers();
750
751 ScalingLayer* scaling_layer = new ScalingLayer(input_variables_dimensions);
752 this->add_layer(scaling_layer);
753
754 Tensor<Index, 1> outputs_dimensions = scaling_layer->get_outputs_dimensions();
755
756 for(Index i = 0; i < blocks_number; i++)
757 {
758 //ConvolutionalLayer* convolutional_layer = new ConvolutionalLayer(outputs_dimensions, filters_dimensions);
759 //add_layer(convolutional_layer);
760
761 //outputs_dimensions = convolutional_layer->get_outputs_dimensions();
762
763 // Pooling layer 1
764
765 //PoolingLayer* pooling_layer_1 = new PoolingLayer(outputs_dimensions);
766 //add_layer(pooling_layer_1);
767
768 //outputs_dimensions = pooling_layer_1->get_outputs_dimensions();
769 }
770
771 const Tensor<Index, 0> outputs_dimensions_sum = outputs_dimensions.sum();
772
773 PerceptronLayer* perceptron_layer = new PerceptronLayer(outputs_dimensions_sum(0), 18);
774 add_layer(perceptron_layer);
775
776 const Index perceptron_layer_outputs = perceptron_layer->get_neurons_number();
777
778 ProbabilisticLayer* probabilistic_layer = new ProbabilisticLayer(perceptron_layer_outputs, outputs_number);
779 add_layer(probabilistic_layer);
780}
781
782
785
786void NeuralNetwork::set(const string& file_name)
787{
788 delete_layers();
789
790 load(file_name);
791}
792
793
796
797void NeuralNetwork::set_inputs_names(const Tensor<string, 1>& new_inputs_names)
798{
799 inputs_names = new_inputs_names;
800}
801
802
805
806void NeuralNetwork::set_outputs_names(const Tensor<string, 1>& new_outputs_names)
807{
808 outputs_names = new_outputs_names;
809}
810
811
814
815void NeuralNetwork::set_inputs_number(const Index& new_inputs_number)
816{
817#ifdef OPENNN_DEBUG
818
819 if(new_inputs_number == 0)
820 {
821 ostringstream buffer;
822
823 buffer << "OpenNN Exception: NeuralNetwork class.\n"
824 << "void set_inputs_number(const Index&) method.\n"
825 << "The number of inputs (" << new_inputs_number << ") must be greater than 0.\n";
826
827 throw logic_error(buffer.str());
828 }
829
830#endif
831
832 inputs_names.resize(new_inputs_number);
833
835 {
836 ScalingLayer* scaling_layer_pointer = get_scaling_layer_pointer();
837
838 scaling_layer_pointer->set_inputs_number(new_inputs_number);
839 }
840
841 const Index trainable_layers_number = get_trainable_layers_number();
842 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
843
844 if(trainable_layers_number > 0)
845 {
846 trainable_layers_pointers[0]->set_inputs_number(new_inputs_number);
847 }
848}
849
850
853
854void NeuralNetwork::set_inputs_number(const Tensor<bool, 1>& inputs)
855{
856 if(layers_pointers.dimension(0) == 0) return;
857
858 Index new_inputs_number = 0;
859
860 for(Index i = 0; i < inputs.dimension(0); i++)
861 {
862 if(inputs(i)) new_inputs_number++;
863 }
864
865 set_inputs_number(new_inputs_number);
866}
867
868
870
872{
873 display = true;
874}
875
876
877void NeuralNetwork::set_threads_number(const int& new_threads_number)
878{
879 const Index layers_number = get_layers_number();
880
881 for(Index i = 0; i < layers_number; i++)
882 {
883 layers_pointers(i)->set_threads_number(new_threads_number);
884 }
885}
886
887
888void NeuralNetwork::set_layers_pointers(Tensor<Layer*, 1>& new_layers_pointers)
889{
890 layers_pointers = new_layers_pointers;
891}
892
893
894PerceptronLayer* NeuralNetwork::get_first_perceptron_layer_pointer() const
895{
896 const Index layers_number = get_layers_number();
897
898 for(Index i = 0; i < layers_number; i++)
899 {
900 if(layers_pointers(i)->get_type() == Layer::Type::Perceptron)
901 {
902 return static_cast<PerceptronLayer*>(layers_pointers[i]);
903 }
904 }
905
906 return nullptr;
907}
908
909
911
913{
914 if(layers_pointers.dimension(0) != 0)
915 {
916 return layers_pointers(0)->get_inputs_number();
917 }
918
919 return 0;
920}
921
922
923Index NeuralNetwork::get_outputs_number() const
924{
925 if(layers_pointers.size() > 0)
926 {
927 Layer* last_layer = layers_pointers[layers_pointers.size()-1];
928
929 return last_layer->get_neurons_number();
930 }
931
932 return 0;
933}
934
935
936Tensor<Index, 1> NeuralNetwork::get_trainable_layers_neurons_numbers() const
937{
938 const Index trainable_layers_number = get_trainable_layers_number();
939
940 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
941
942 Index count = 0;
943
944 for(Index i = 0; i < layers_pointers.size(); i++)
945 {
946 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
947 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
948 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
949 {
950 layers_neurons_number(count) = layers_pointers[i]->get_neurons_number();
951
952 count++;
953 }
954
955 }
956
957 return layers_neurons_number;
958}
959
960
961Tensor<Index, 1> NeuralNetwork::get_trainable_layers_inputs_numbers() const
962{
963 const Index trainable_layers_number = get_trainable_layers_number();
964
965 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
966
967 Index count = 0;
968
969 for(Index i = 0; i < layers_pointers.size(); i++)
970 {
971 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
972 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
973 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
974 {
975 layers_neurons_number(count) = layers_pointers[i]->get_inputs_number();
976
977 count++;
978 }
979 }
980
981 return layers_neurons_number;
982}
983
984
985Tensor<Index, 1> NeuralNetwork::get_trainable_layers_synaptic_weight_numbers() const
986{
987 const Index trainable_layers_number = get_trainable_layers_number();
988
989 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
990
991 Index count = 0;
992
993 for(Index i = 0; i < layers_pointers.size(); i++)
994 {
995 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
996 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
997 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
998 {
999 layers_neurons_number(count) = layers_pointers[i]->get_synaptic_weights_number();
1000
1001 count++;
1002 }
1003 }
1004
1005 return layers_neurons_number;
1006}
1007
1008
1019
1020Tensor<Index, 1> NeuralNetwork::get_architecture() const
1021{
1022 const Index layers_number = get_layers_number();
1023
1024 Tensor<Index, 1> architecture(layers_number);
1025
1026 const Index inputs_number = get_inputs_number();
1027
1028 if(inputs_number == 0) return architecture;
1029
1030 if(layers_number > 0)
1031 {
1032 for(Index i = 0; i < layers_number; i++)
1033 {
1034 architecture(i) = layers_pointers(i)->get_neurons_number();
1035 }
1036 }
1037
1038 return architecture;
1039}
1040
1041
1044
1046{
1047 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1048
1049 Index parameters_number = 0;
1050
1051 for(Index i = 0; i < trainable_layers_pointers.size(); i++)
1052 {
1053 parameters_number += trainable_layers_pointers[i]->get_parameters_number();
1054 }
1055
1056 return parameters_number;
1057}
1058
1059
1062
1063Tensor<type, 1> NeuralNetwork::get_parameters() const
1064{
1065 const Index parameters_number = get_parameters_number();
1066
1067 Tensor<type, 1> parameters(parameters_number);
1068
1069 const Index trainable_layers_number = get_trainable_layers_number();
1070
1071 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1072
1073 Index position = 0;
1074
1075 for(Index i = 0; i < trainable_layers_number; i++)
1076 {
1077 const Tensor<type, 1> layer_parameters = trainable_layers_pointers(i)->get_parameters();
1078
1079 for(Index j = 0; j < layer_parameters.size(); j++)
1080 {
1081 parameters(j + position) = layer_parameters(j);
1082 }
1083
1084 position += layer_parameters.size();
1085 }
1086
1087 return parameters;
1088}
1089
1090
1091Tensor<Index, 1> NeuralNetwork::get_trainable_layers_parameters_numbers() const
1092{
1093 const Index trainable_layers_number = get_trainable_layers_number();
1094
1095 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1096
1097 Tensor<Index, 1> trainable_layers_parameters_number(trainable_layers_number);
1098
1099 for(Index i = 0; i < trainable_layers_number; i++)
1100 {
1101 trainable_layers_parameters_number[i] = trainable_layers_pointers[i]->get_parameters_number();
1102 }
1103
1104 return trainable_layers_parameters_number;
1105}
1106
1107
1108Tensor<Tensor<type, 1>, 1> NeuralNetwork::get_trainable_layers_parameters(const Tensor<type, 1>& parameters) const
1109{
1110 const Index trainable_layers_number = get_trainable_layers_number();
1111
1112 const Tensor<Index, 1> trainable_layers_parameters_number = get_trainable_layers_parameters_numbers();
1113
1114 Tensor<Tensor<type, 1>, 1> trainable_layers_parameters(trainable_layers_number);
1115
1116 Index index = 0;
1117
1118 for(Index i = 0; i < trainable_layers_number; i++)
1119 {
1120
1121 trainable_layers_parameters(i).resize(trainable_layers_parameters_number(i));
1122
1123 trainable_layers_parameters(i) = parameters.slice(Eigen::array<Eigen::Index, 1>({index}), Eigen::array<Eigen::Index, 1>({trainable_layers_parameters_number(i)}));
1124
1125 index += trainable_layers_parameters_number(i);
1126
1127 }
1128
1129 return trainable_layers_parameters;
1130}
1131
1132
1135
1136void NeuralNetwork::set_parameters(Tensor<type, 1>& new_parameters)
1137{
1138#ifdef OPENNN_DEBUG
1139
1140 const Index size = new_parameters.size();
1141
1142 const Index parameters_number = get_parameters_number();
1143
1144 if(size < parameters_number)
1145 {
1146 ostringstream buffer;
1147
1148 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1149 << "void set_parameters(const Tensor<type, 1>&) method.\n"
1150 << "Size (" << size << ") must be grater or equal to number of parameters (" << parameters_number << ").\n";
1151
1152 throw logic_error(buffer.str());
1153 }
1154
1155#endif
1156
1157 const Index trainable_layers_number = get_trainable_layers_number();
1158
1159 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1160
1161 const Tensor<Index, 1> trainable_layers_parameters_numbers = get_trainable_layers_parameters_numbers();
1162
1163 Index index = 0;
1164
1165 for(Index i = 0; i < trainable_layers_number; i++)
1166 {
1167 trainable_layers_pointers(i)->set_parameters(new_parameters, index);
1168
1169 index += trainable_layers_parameters_numbers(i);
1170 }
1171}
1172
1173
1178
1179void NeuralNetwork::set_display(const bool& new_display)
1180{
1181 display = new_display;
1182}
1183
1184
1187
1189{
1190 return layers_pointers.size();
1191}
1192
1193
1194Tensor<Index, 1> NeuralNetwork::get_layers_neurons_numbers() const
1195{
1196 Tensor<Index, 1> layers_neurons_number(layers_pointers.size());
1197
1198 for(Index i = 0; i < layers_pointers.size(); i++)
1199 {
1200 layers_neurons_number(i) = layers_pointers[i]->get_neurons_number();
1201 }
1202
1203 return layers_neurons_number;
1204}
1205
1206
1207Index NeuralNetwork::get_trainable_layers_number() const
1208{
1209 const Index layers_number = get_layers_number();
1210
1211 Index count = 0;
1212
1213 for(Index i = 0; i < layers_number; i++)
1214 {
1215 if(layers_pointers(i)->get_type() != Layer::Type::Scaling
1216 && layers_pointers(i)->get_type() != Layer::Type::Unscaling
1217 && layers_pointers(i)->get_type() != Layer::Type::Bounding)
1218 {
1219 count++;
1220 }
1221 }
1222
1223 return count;
1224}
1225
1226
1227Index NeuralNetwork::get_perceptron_layers_number() const
1228{
1229 const Index layers_number = get_layers_number();
1230
1231 Index count = 0;
1232
1233 for(Index i = 0; i < layers_number; i++)
1234 {
1235 if(layers_pointers(i)->get_type() == Layer::Type::Perceptron)
1236 {
1237 count++;
1238 }
1239 }
1240
1241 return count;
1242}
1243
1244
1245Index NeuralNetwork::get_probabilistic_layers_number() const
1246{
1247 const Index layers_number = get_layers_number();
1248
1249 Index count = 0;
1250
1251 for(Index i = 0; i < layers_number; i++)
1252 {
1253 if(layers_pointers(i)->get_type() == Layer::Type::Probabilistic)
1254 {
1255 count++;
1256 }
1257 }
1258
1259 return count;
1260}
1261
1262
1263Index NeuralNetwork::get_long_short_term_memory_layers_number() const
1264{
1265 const Index layers_number = get_layers_number();
1266
1267 Index count = 0;
1268
1269 for(Index i = 0; i < layers_number; i++)
1270 {
1271 if(layers_pointers(i)->get_type() == Layer::Type::LongShortTermMemory)
1272 {
1273 count++;
1274 }
1275 }
1276
1277 return count;
1278}
1279
1280Index NeuralNetwork::get_recurrent_layers_number() const
1281{
1282 const Index layers_number = get_layers_number();
1283
1284 Index count = 0;
1285
1286 for(Index i = 0; i < layers_number; i++)
1287 {
1288 if(layers_pointers(i)->get_type() == Layer::Type::Recurrent)
1289 {
1290 count++;
1291 }
1292 }
1293
1294 return count;
1295}
1296
1298
1300{
1301 const Index trainable_layers_number = get_trainable_layers_number();
1302
1303 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1304
1305 for(Index i = 0; i < trainable_layers_number; i++)
1306 {
1307 trainable_layers_pointers[i]->set_parameters_constant(value);
1308 }
1309}
1310
1311
1316
1318{
1319 const Index trainable_layers_number = get_trainable_layers_number();
1320
1321 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1322
1323 for(Index i = 0; i < trainable_layers_number; i++)
1324 {
1325 trainable_layers_pointers[i]->set_parameters_random();
1326 }
1327}
1328
1329
1331
1333{
1334 const Tensor<type, 1> parameters = get_parameters();
1335
1336 const Tensor<type, 0> parameters_norm = parameters.square().sum().sqrt();
1337
1338 return parameters_norm(0);
1339}
1340
1341
1344
1345void NeuralNetwork::perturbate_parameters(const type& perturbation)
1346{
1347#ifdef OPENNN_DEBUG
1348
1349 if(perturbation < 0)
1350 {
1351 ostringstream buffer;
1352
1353 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1354 << "void perturbate_parameters(const type&) method.\n"
1355 << "Perturbation must be equal or greater than 0.\n";
1356
1357 throw logic_error(buffer.str());
1358 }
1359
1360#endif
1361
1362 Tensor<type, 1> parameters = get_parameters();
1363
1364 for (Index i = 0; i < parameters.size(); i++) parameters(i) += perturbation;
1365
1366 set_parameters(parameters);
1367}
1368
1369
1373
1375 NeuralNetworkForwardPropagation& forward_propagation) const
1376{
1377 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1378
1379 const Index trainable_layers_number = trainable_layers_pointers.size();
1380
1381 if(trainable_layers_pointers(0)->get_type() == Layer::Type::Convolutional)
1382 {
1383 trainable_layers_pointers(0)->forward_propagate(batch.inputs_4d, forward_propagation.layers(0));
1384 }
1385 else
1386 {
1387 trainable_layers_pointers(0)->forward_propagate(batch.inputs_2d, forward_propagation.layers(0));
1388 }
1389
1390 for(Index i = 1; i < trainable_layers_number; i++)
1391 {
1392 switch(trainable_layers_pointers(i-1)->get_type())
1393 {
1394 case Layer::Type::Perceptron:
1395
1396 trainable_layers_pointers(i)
1397 ->forward_propagate(static_cast<PerceptronLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1398 forward_propagation.layers(i));
1399 break;
1400
1401 case Layer::Type::Probabilistic:
1402
1403 trainable_layers_pointers(i)
1404 ->forward_propagate(static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1405 forward_propagation.layers(i));
1406 break;
1407
1408 case Layer::Type::Recurrent:
1409
1410 trainable_layers_pointers(i)
1411 ->forward_propagate(static_cast<RecurrentLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1412 forward_propagation.layers(i));
1413
1414 break;
1415
1416 case Layer::Type::LongShortTermMemory:
1417
1418 trainable_layers_pointers(i)
1419 ->forward_propagate(static_cast<LongShortTermMemoryLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1420 forward_propagation.layers(i));
1421 break;
1422
1423 case Layer::Type::Pooling:
1424
1425 break;
1426
1427 case Layer::Type::Convolutional:
1428
1429 break;
1430
1431 default: break;
1432 }
1433 }
1434}
1435
1436
1441
1443 Tensor<type, 1>& parameters,
1444 NeuralNetworkForwardPropagation& forward_propagation) const
1445{
1446 const Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1447
1448 const Index trainable_layers_number = trainable_layers_pointers.size();
1449
1450 const Index parameters_number = trainable_layers_pointers(0)->get_parameters_number();
1451
1452 const TensorMap<Tensor<type, 1>> potential_parameters(parameters.data(), parameters_number);
1453
1454 if(trainable_layers_pointers(0)->get_type() == Layer::Type::Convolutional)
1455 {
1456 trainable_layers_pointers(0)->forward_propagate(batch.inputs_4d, potential_parameters, forward_propagation.layers(0));
1457 }
1458 else
1459 {
1460 trainable_layers_pointers(0)->forward_propagate(batch.inputs_2d, potential_parameters, forward_propagation.layers(0));
1461 }
1462
1463 Index index = parameters_number;
1464
1465 for(Index i = 1; i < trainable_layers_number; i++)
1466 {
1467 const Index parameters_number = trainable_layers_pointers(i)->get_parameters_number();
1468
1469 const TensorMap<Tensor<type, 1>> potential_parameters(parameters.data() + index, parameters_number);
1470
1471 switch(trainable_layers_pointers(i-1)->get_type())
1472 {
1473 case Layer::Type::Perceptron:
1474 {
1475 trainable_layers_pointers(i)
1476 ->forward_propagate(static_cast<PerceptronLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1477 potential_parameters,
1478 forward_propagation.layers(i));
1479 }
1480 break;
1481
1482 case Layer::Type::Probabilistic:
1483 {
1484 trainable_layers_pointers(i)
1485 ->forward_propagate(static_cast<ProbabilisticLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1486 potential_parameters,
1487 forward_propagation.layers(i));
1488 }
1489 break;
1490
1491 case Layer::Type::Recurrent:
1492 {
1493 trainable_layers_pointers(i)
1494 ->forward_propagate(static_cast<RecurrentLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1495 potential_parameters,
1496 forward_propagation.layers(i));
1497 }
1498 break;
1499
1500 case Layer::Type::LongShortTermMemory:
1501 {
1502 trainable_layers_pointers(i)
1503 ->forward_propagate(static_cast<LongShortTermMemoryLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1504 potential_parameters,
1505 forward_propagation.layers(i));
1506 }
1507 break;
1508
1509 case Layer::Type::Convolutional:
1510 {
1511 //trainable_layers_pointers(i)->forward_propagate(static_cast<ConvolutionalLayer::ConvolutionalLayerForwardPropagation*>(forward_propagation.layers(i-1))->activations,
1512 // potential_parameters,
1513 // forward_propagation.layers(i));
1514 }
1515 break;
1516
1517 default: break;
1518
1519 }
1520
1521 index += parameters_number;
1522 }
1523}
1524
1525
1537
1538Tensor<type, 2> NeuralNetwork::calculate_outputs(const Tensor<type, 2>& inputs)
1539{
1540#ifdef OPENNN_DEBUG
1541
1542 const Index inputs_dimensions_number = inputs.rank();
1543
1544 if(inputs_dimensions_number != 2 && inputs_dimensions_number != 4)
1545 {
1546 ostringstream buffer;
1547
1548 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1549 << "Tensor<type, 2> calculate_outputs(const Tensor<type, 2>&) const method.\n"
1550 << "Inputs dimensions number (" << inputs_dimensions_number << ") must be 2 or 4.\n";
1551
1552 throw logic_error(buffer.str());
1553 }
1554
1555#endif
1556
1557 Tensor<type, 2> outputs;
1558
1559 const Index layers_number = get_layers_number();
1560
1561 if(layers_number == 0) return inputs;
1562
1563 outputs = layers_pointers(0)->calculate_outputs(inputs);
1564
1565 for(Index i = 1; i < layers_number; i++)
1566 {
1567 outputs = layers_pointers(i)->calculate_outputs(outputs);
1568 }
1569
1570 return outputs;
1571}
1572
1573
1574Tensor<type, 2> NeuralNetwork::calculate_outputs(const Tensor<type, 4>& inputs)
1575{
1576#ifdef OPENNN_DEBUG
1577
1578 const Index inputs_dimensions_number = inputs.rank();
1579
1580 if(inputs_dimensions_number != 2 && inputs_dimensions_number != 4)
1581 {
1582 ostringstream buffer;
1583
1584 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1585 << "Tensor<type, 2> calculate_outputs(const Tensor<type, 2>&) const method.\n"
1586 << "Inputs dimensions number (" << inputs_dimensions_number << ") must be 2 or 4.\n";
1587
1588 throw logic_error(buffer.str());
1589 }
1590
1591#endif
1592
1593 Tensor<type, 4> outputs_4d;
1594 Tensor<type, 2> outputs, inputs_2d;
1595
1596 const Index layers_number = get_layers_number();
1597
1598 if(layers_number == 0) return inputs_2d;
1599
1600 // First layer output
1601
1602 if(layers_pointers(1)->get_type() == Layer::Type::Convolutional)
1603 {
1604 outputs_4d = layers_pointers(0)->calculate_outputs_4d(inputs);
1605 }
1606 else
1607 {
1608 outputs = layers_pointers(0)->calculate_outputs_from4D(inputs);
1609 }
1610
1611 for(Index i = 1; i < layers_number; i++)
1612 {
1613 if(layers_pointers(i + 1)->get_type() == Layer::Type::Convolutional)
1614 {
1615 outputs_4d = layers_pointers(i)->calculate_outputs_4d(outputs_4d);
1616 }
1617 else
1618 {
1619/*
1620 if(layers_pointers(i)->get_type() != Layer::Type::Convolutional && layers_pointers(i)->get_type() != Layer::Type::Pooling)
1621 {
1622 outputs = layers_pointers(i)->calculate_outputs(outputs);
1623 }
1624 else
1625 {
1626 outputs = layers_pointers(i)->calculate_outputs_from4D(outputs_4d);
1627 }
1628*/
1629 }
1630 }
1631
1632 return outputs;
1633}
1634
1635
1642
1643Tensor<type, 2> NeuralNetwork::calculate_directional_inputs(const Index& direction,
1644 const Tensor<type, 1>& point,
1645 const type& minimum,
1646 const type& maximum,
1647 const Index& points_number) const
1648{
1649 const Index inputs_number = get_inputs_number();
1650
1651 Tensor<type, 2> directional_inputs(points_number, inputs_number);
1652
1653 Tensor<type, 1> inputs(inputs_number);
1654
1655 inputs = point;
1656
1657 for(Index i = 0; i < points_number; i++)
1658 {
1659 inputs(direction) = minimum + (maximum - minimum)*static_cast<type>(i)/static_cast<type>(points_number-1);
1660
1661 for(Index j = 0; j < inputs_number; j++)
1662 {
1663 directional_inputs(i,j) = inputs(j);
1664 }
1665 }
1666
1667 return directional_inputs;
1668}
1669
1670
1673
1674Tensor<string, 2> NeuralNetwork::get_information() const
1675{
1676 const Index trainable_layers_number = get_trainable_layers_number();
1677
1678 Tensor<string, 2> information(trainable_layers_number, 3);
1679
1680 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1681
1682 for(Index i = 0; i < trainable_layers_number; i++)
1683 {
1684 information(i,0) = to_string(trainable_layers_pointers(i)->get_inputs_number());
1685 information(i,1) = to_string(trainable_layers_pointers(i)->get_neurons_number());
1686
1687 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1688
1689 if(layer_type == "Perceptron")
1690 {
1691 PerceptronLayer* perceptron_layer = static_cast<PerceptronLayer*>(trainable_layers_pointers(i));
1692
1693 information(i,2) = perceptron_layer->write_activation_function();
1694 }
1695 else
1696 {
1697
1698 }
1699 }
1700
1701 return information;
1702}
1703
1704
1706
1708{
1709 const Index trainable_layers_number = get_trainable_layers_number();
1710
1711 const Index perceptron_layers_number = get_perceptron_layers_number();
1712
1713 Tensor<string, 2> information(perceptron_layers_number, 3);
1714
1715 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1716
1717 Index perceptron_layer_index = 0;
1718
1719 for(Index i = 0; i < trainable_layers_number; i++)
1720 {
1721 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1722
1723 if(layer_type == "Perceptron")
1724 {
1725 information(perceptron_layer_index,0) = to_string(trainable_layers_pointers(i)->get_inputs_number());
1726 information(perceptron_layer_index,1) = to_string(trainable_layers_pointers(i)->get_neurons_number());
1727
1728 const PerceptronLayer* perceptron_layer = static_cast<PerceptronLayer*>(trainable_layers_pointers(i));
1729
1730 information(perceptron_layer_index, 2) = perceptron_layer->write_activation_function();
1731
1732 perceptron_layer_index++;
1733 }
1734 }
1735
1736 return information;
1737}
1738
1739
1741
1743{
1744 const Index trainable_layers_number = get_trainable_layers_number();
1745
1746 const Index probabilistic_layers_number = get_probabilistic_layers_number();
1747
1748 Tensor<string, 2> information(probabilistic_layers_number, 3);
1749
1750 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
1751
1752 Index probabilistic_layer_index = 0;
1753
1754 for(Index i = 0; i < trainable_layers_number; i++)
1755 {
1756 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1757
1758 if(layer_type == "Probabilistic")
1759 {
1760 information(probabilistic_layer_index,0) = to_string(trainable_layers_pointers(i)->get_inputs_number());
1761 information(probabilistic_layer_index,1) = to_string(trainable_layers_pointers(i)->get_neurons_number());
1762
1763 ProbabilisticLayer* probabilistic_layer = static_cast<ProbabilisticLayer*>(trainable_layers_pointers(i));
1764
1765 information(probabilistic_layer_index,2) = probabilistic_layer->write_activation_function();
1766
1767 probabilistic_layer_index++;
1768 }
1769 }
1770
1771 return information;
1772}
1773
1774
1777
1779{
1780 ostringstream buffer;
1781
1782 file_stream.OpenElement("NeuralNetwork");
1783
1784 // Inputs
1785
1786 file_stream.OpenElement("Inputs");
1787
1788 // Inputs number
1789
1790 file_stream.OpenElement("InputsNumber");
1791
1792 buffer.str("");
1793 buffer << get_inputs_number();
1794
1795 file_stream.PushText(buffer.str().c_str());
1796
1797 file_stream.CloseElement();
1798
1799 // Inputs names
1800
1801 for(Index i = 0; i < inputs_names.size(); i++)
1802 {
1803 file_stream.OpenElement("Input");
1804
1805 file_stream.PushAttribute("Index", to_string(i+1).c_str());
1806
1807 file_stream.PushText(inputs_names[i].c_str());
1808
1809 file_stream.CloseElement();
1810 }
1811
1812 // Inputs (end tag)
1813
1814 file_stream.CloseElement();
1815
1816 // Layers
1817
1818 file_stream.OpenElement("Layers");
1819
1820 // Layers number
1821
1822 file_stream.OpenElement("LayersTypes");
1823
1824 buffer.str("");
1825
1826 for(Index i = 0; i < layers_pointers.size(); i++)
1827 {
1828 buffer << layers_pointers[i]->get_type_string();
1829 if(i != (layers_pointers.size()-1)) buffer << " ";
1830 }
1831
1832 file_stream.PushText(buffer.str().c_str());
1833
1834 file_stream.CloseElement();
1835
1836 // Layers information
1837
1838 for(Index i = 0; i < layers_pointers.size(); i++)
1839 {
1840 layers_pointers[i]->write_XML(file_stream);
1841 }
1842
1843 // Layers (end tag)
1844
1845 file_stream.CloseElement();
1846
1847 // Ouputs
1848
1849 file_stream.OpenElement("Outputs");
1850
1851 // Outputs number
1852
1853 const Index outputs_number = outputs_names.size();
1854
1855 file_stream.OpenElement("OutputsNumber");
1856
1857 buffer.str("");
1858 buffer << outputs_number;
1859
1860 file_stream.PushText(buffer.str().c_str());
1861
1862 file_stream.CloseElement();
1863
1864 // Outputs names
1865
1866 for(Index i = 0; i < outputs_number; i++)
1867 {
1868 file_stream.OpenElement("Output");
1869
1870 file_stream.PushAttribute("Index", to_string(i+1).c_str());
1871
1872 file_stream.PushText(outputs_names[i].c_str());
1873
1874 file_stream.CloseElement();
1875 }
1876
1877 //Outputs (end tag)
1878
1879 file_stream.CloseElement();
1880
1881 // Neural network (end tag)
1882
1883 file_stream.CloseElement();
1884}
1885
1886
1889
1891{
1892 ostringstream buffer;
1893
1894 const tinyxml2::XMLElement* root_element = document.FirstChildElement("NeuralNetwork");
1895
1896 if(!root_element)
1897 {
1898 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1899 << "void from_XML(const tinyxml2::XMLDocument&) method.\n"
1900 << "Neural network element is nullptr.\n";
1901
1902 throw logic_error(buffer.str());
1903 }
1904
1905 // Inputs
1906 {
1907 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Inputs");
1908
1909 if(element)
1910 {
1911 tinyxml2::XMLDocument inputs_document;
1912 tinyxml2::XMLNode* element_clone;
1913
1914 element_clone = element->DeepClone(&inputs_document);
1915
1916 inputs_document.InsertFirstChild(element_clone);
1917
1918 inputs_from_XML(inputs_document);
1919 }
1920 }
1921
1922 // Layers
1923 {
1924 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Layers");
1925
1926 if(element)
1927 {
1928 tinyxml2::XMLDocument layers_document;
1929 tinyxml2::XMLNode* element_clone;
1930
1931 element_clone = element->DeepClone(&layers_document);
1932
1933 layers_document.InsertFirstChild(element_clone);
1934
1935 layers_from_XML(layers_document);
1936 }
1937 }
1938
1939 // Outputs
1940 {
1941 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Outputs");
1942
1943 if(element)
1944 {
1945
1946 tinyxml2::XMLDocument outputs_document;
1947 tinyxml2::XMLNode* element_clone;
1948
1949 element_clone = element->DeepClone(&outputs_document);
1950
1951 outputs_document.InsertFirstChild(element_clone);
1952
1953 outputs_from_XML(outputs_document);
1954
1955 }
1956 }
1957
1958 // Display
1959 {
1960 const tinyxml2::XMLElement* element = root_element->FirstChildElement("Display");
1961
1962 if(element)
1963 {
1964 const string new_display_string = element->GetText();
1965
1966 try
1967 {
1968 set_display(new_display_string != "0");
1969 }
1970 catch(const logic_error& e)
1971 {
1972 cerr << e.what() << endl;
1973 }
1974 }
1975 }
1976}
1977
1978
1979void NeuralNetwork::inputs_from_XML(const tinyxml2::XMLDocument& document)
1980{
1981 ostringstream buffer;
1982
1983 const tinyxml2::XMLElement* root_element = document.FirstChildElement("Inputs");
1984
1985 if(!root_element)
1986 {
1987 buffer << "OpenNN Exception: NeuralNetwork class.\n"
1988 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
1989 << "Inputs element is nullptr.\n";
1990
1991 throw logic_error(buffer.str());
1992 }
1993
1994 // Inputs number
1995
1996 const tinyxml2::XMLElement* inputs_number_element = root_element->FirstChildElement("InputsNumber");
1997
1998 if(!inputs_number_element)
1999 {
2000 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2001 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2002 << "Inputs number element is nullptr.\n";
2003
2004 throw logic_error(buffer.str());
2005 }
2006
2007 Index new_inputs_number = 0;
2008
2009 if(inputs_number_element->GetText())
2010 {
2011 new_inputs_number = static_cast<Index>(atoi(inputs_number_element->GetText()));
2012
2013 set_inputs_number(new_inputs_number);
2014 }
2015
2016 // Inputs names
2017
2018 const tinyxml2::XMLElement* start_element = inputs_number_element;
2019
2020 if(new_inputs_number > 0)
2021 {
2022 for(Index i = 0; i < new_inputs_number; i++)
2023 {
2024 const tinyxml2::XMLElement* input_element = start_element->NextSiblingElement("Input");
2025 start_element = input_element;
2026
2027 if(input_element->Attribute("Index") != to_string(i+1))
2028 {
2029 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2030 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2031 << "Input index number (" << i+1 << ") does not match (" << input_element->Attribute("Item") << ").\n";
2032
2033 throw logic_error(buffer.str());
2034 }
2035
2036 if(!input_element->GetText())
2037 {
2038 inputs_names(i) = "";
2039 }
2040 else
2041 {
2042 inputs_names(i) = input_element->GetText();
2043 }
2044 }
2045 }
2046}
2047
2048
2049void NeuralNetwork::layers_from_XML(const tinyxml2::XMLDocument& document)
2050{
2051 ostringstream buffer;
2052
2053 const tinyxml2::XMLElement* root_element = document.FirstChildElement("Layers");
2054
2055 if(!root_element)
2056 {
2057 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2058 << "void layers_from_XML(const tinyxml2::XMLDocument&) method.\n"
2059 << "Layers element is nullptr.\n";
2060
2061 throw logic_error(buffer.str());
2062 }
2063
2064 // Layers types
2065
2066 const tinyxml2::XMLElement* layers_types_element = root_element->FirstChildElement("LayersTypes");
2067
2068 if(!layers_types_element)
2069 {
2070 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2071 << "void layers_from_XML(const tinyxml2::XMLDocument&) method.\n"
2072 << "Layers types element is nullptr.\n";
2073
2074 throw logic_error(buffer.str());
2075 }
2076
2077 Tensor<string, 1> layers_types;
2078
2079 if(layers_types_element->GetText())
2080 {
2081 layers_types = get_tokens(layers_types_element->GetText(), ' ');
2082 }
2083
2084 // Add layers
2085
2086 const tinyxml2::XMLElement* start_element = layers_types_element;
2087
2088 for(Index i = 0; i < layers_types.size(); i++)
2089 {
2090 if(layers_types(i) == "Scaling")
2091 {
2092 ScalingLayer* scaling_layer = new ScalingLayer();
2093
2094 const tinyxml2::XMLElement* scaling_element = start_element->NextSiblingElement("ScalingLayer");
2095 start_element = scaling_element;
2096
2097 if(scaling_element)
2098 {
2099 tinyxml2::XMLDocument scaling_document;
2100 tinyxml2::XMLNode* element_clone;
2101
2102 element_clone = scaling_element->DeepClone(&scaling_document);
2103
2104 scaling_document.InsertFirstChild(element_clone);
2105
2106 scaling_layer->from_XML(scaling_document);
2107 }
2108
2109 add_layer(scaling_layer);
2110 }
2111 else if(layers_types(i) == "Convolutional")
2112 {
2113/*
2114 ConvolutionalLayer* convolutional_layer = new ConvolutionalLayer();
2115
2116 const tinyxml2::XMLElement* convolutional_element = start_element->NextSiblingElement("ConvolutionalLayer");
2117 start_element = convolutional_element;
2118
2119 if(convolutional_element)
2120 {
2121 tinyxml2::XMLDocument convolutional_document;
2122 tinyxml2::XMLNode* element_clone;
2123
2124 element_clone = convolutional_element->DeepClone(&convolutional_document);
2125
2126 convolutional_document.InsertFirstChild(element_clone);
2127
2128 convolutional_layer->from_XML(convolutional_document);
2129 }
2130
2131 add_layer(convolutional_layer);
2132*/
2133 }
2134 else if(layers_types(i) == "Perceptron")
2135 {
2136 PerceptronLayer* perceptron_layer = new PerceptronLayer();
2137
2138 const tinyxml2::XMLElement* perceptron_element = start_element->NextSiblingElement("PerceptronLayer");
2139 start_element = perceptron_element;
2140
2141 if(perceptron_element)
2142 {
2143 tinyxml2::XMLDocument perceptron_document;
2144 tinyxml2::XMLNode* element_clone;
2145
2146 element_clone = perceptron_element->DeepClone(&perceptron_document);
2147
2148 perceptron_document.InsertFirstChild(element_clone);
2149
2150 perceptron_layer->from_XML(perceptron_document);
2151 }
2152
2153 add_layer(perceptron_layer);
2154 }
2155 else if(layers_types(i) == "Pooling")
2156 {
2157/*
2158 PoolingLayer* pooling_layer = new PoolingLayer();
2159
2160 const tinyxml2::XMLElement* pooling_element = start_element->NextSiblingElement("PoolingLayer");
2161 start_element = pooling_element;
2162
2163 if(pooling_element)
2164 {
2165 tinyxml2::XMLDocument pooling_document;
2166 tinyxml2::XMLNode* element_clone;
2167
2168 element_clone = pooling_element->DeepClone(&pooling_document);
2169
2170 pooling_document.InsertFirstChild(element_clone);
2171
2172 pooling_layer->from_XML(pooling_document);
2173 }
2174
2175 add_layer(pooling_layer);
2176*/
2177 }
2178 else if(layers_types(i) == "Probabilistic")
2179 {
2180 ProbabilisticLayer* probabilistic_layer = new ProbabilisticLayer();
2181
2182 const tinyxml2::XMLElement* probabilistic_element = start_element->NextSiblingElement("ProbabilisticLayer");
2183 start_element = probabilistic_element;
2184
2185 if(probabilistic_element)
2186 {
2187 tinyxml2::XMLDocument probabilistic_document;
2188 tinyxml2::XMLNode* element_clone;
2189
2190 element_clone = probabilistic_element->DeepClone(&probabilistic_document);
2191
2192 probabilistic_document.InsertFirstChild(element_clone);
2193 probabilistic_layer->from_XML(probabilistic_document);
2194 }
2195
2196 add_layer(probabilistic_layer);
2197 }
2198 else if(layers_types(i) == "LongShortTermMemory")
2199 {
2200 LongShortTermMemoryLayer* long_short_term_memory_layer = new LongShortTermMemoryLayer();
2201
2202 const tinyxml2::XMLElement* long_short_term_memory_element = start_element->NextSiblingElement("LongShortTermMemoryLayer");
2203 start_element = long_short_term_memory_element;
2204
2205 if(long_short_term_memory_element)
2206 {
2207 tinyxml2::XMLDocument long_short_term_memory_document;
2208 tinyxml2::XMLNode* element_clone;
2209
2210 element_clone = long_short_term_memory_element->DeepClone(&long_short_term_memory_document);
2211
2212 long_short_term_memory_document.InsertFirstChild(element_clone);
2213
2214 long_short_term_memory_layer->from_XML(long_short_term_memory_document);
2215 }
2216
2217 add_layer(long_short_term_memory_layer);
2218 }
2219 else if(layers_types(i) == "Recurrent")
2220 {
2221 RecurrentLayer* recurrent_layer = new RecurrentLayer();
2222
2223 const tinyxml2::XMLElement* recurrent_element = start_element->NextSiblingElement("RecurrentLayer");
2224 start_element = recurrent_element;
2225
2226 if(recurrent_element)
2227 {
2228 tinyxml2::XMLDocument recurrent_document;
2229 tinyxml2::XMLNode* element_clone;
2230
2231 element_clone = recurrent_element->DeepClone(&recurrent_document);
2232
2233 recurrent_document.InsertFirstChild(element_clone);
2234
2235 recurrent_layer->from_XML(recurrent_document);
2236 }
2237
2238 add_layer(recurrent_layer);
2239 }
2240 else if(layers_types(i) == "Unscaling")
2241 {
2242 UnscalingLayer* unscaling_layer = new UnscalingLayer();
2243
2244 const tinyxml2::XMLElement* unscaling_element = start_element->NextSiblingElement("UnscalingLayer");
2245 start_element = unscaling_element;
2246
2247 if(unscaling_element)
2248 {
2249 tinyxml2::XMLDocument unscaling_document;
2250 tinyxml2::XMLNode* element_clone;
2251
2252 element_clone = unscaling_element->DeepClone(&unscaling_document);
2253
2254 unscaling_document.InsertFirstChild(element_clone);
2255
2256 unscaling_layer->from_XML(unscaling_document);
2257 }
2258
2259 add_layer(unscaling_layer);
2260 }
2261 else if(layers_types(i) == "Bounding")
2262 {
2263 BoundingLayer* bounding_layer = new BoundingLayer();
2264
2265 const tinyxml2::XMLElement* bounding_element = start_element->NextSiblingElement("BoundingLayer");
2266
2267 start_element = bounding_element;
2268
2269 if(bounding_element)
2270 {
2271 tinyxml2::XMLDocument bounding_document;
2272 tinyxml2::XMLNode* element_clone;
2273
2274 element_clone = bounding_element->DeepClone(&bounding_document);
2275
2276 bounding_document.InsertFirstChild(element_clone);
2277
2278 bounding_layer->from_XML(bounding_document);
2279 }
2280
2281 add_layer(bounding_layer);
2282 }
2283 }
2284}
2285
2286
2287void NeuralNetwork::outputs_from_XML(const tinyxml2::XMLDocument& document)
2288{
2289 ostringstream buffer;
2290
2291 const tinyxml2::XMLElement* root_element = document.FirstChildElement("Outputs");
2292
2293 if(!root_element)
2294 {
2295 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2296 << "void outputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2297 << "Outputs element is nullptr.\n";
2298
2299 throw logic_error(buffer.str());
2300 }
2301
2302 // Outputs number
2303
2304 const tinyxml2::XMLElement* outputs_number_element = root_element->FirstChildElement("OutputsNumber");
2305
2306 if(!outputs_number_element)
2307 {
2308 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2309 << "void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2310 << "Outputs number element is nullptr.\n";
2311
2312 throw logic_error(buffer.str());
2313 }
2314
2315 Index new_outputs_number = 0;
2316
2317 if(outputs_number_element->GetText())
2318 {
2319 new_outputs_number = static_cast<Index>(atoi(outputs_number_element->GetText()));
2320 }
2321
2322 // Outputs names
2323
2324 const tinyxml2::XMLElement* start_element = outputs_number_element;
2325
2326 if(new_outputs_number > 0)
2327 {
2328 outputs_names.resize(new_outputs_number);
2329
2330 for(Index i = 0; i < new_outputs_number; i++)
2331 {
2332 const tinyxml2::XMLElement* output_element = start_element->NextSiblingElement("Output");
2333 start_element = output_element;
2334
2335 if(output_element->Attribute("Index") != to_string(i+1))
2336 {
2337 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2338 << "void outputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2339 << "Output index number (" << i+1 << ") does not match (" << output_element->Attribute("Item") << ").\n";
2340
2341 throw logic_error(buffer.str());
2342 }
2343
2344 if(!output_element->GetText())
2345 {
2346 outputs_names(i) = "";
2347 }
2348 else
2349 {
2350 outputs_names(i) = output_element->GetText();
2351 }
2352 }
2353 }
2354}
2355
2356
2358
2360{
2361 cout << "Neural network" << endl;
2362
2363 const Index layers_number = get_layers_number();
2364
2365 cout << "Layers number: " << layers_number << endl;
2366
2367 for(Index i = 0; i < layers_number; i++)
2368 {
2369 cout << "Layer " << i+1 << ": " << layers_pointers[i]->get_neurons_number()
2370 << " " << layers_pointers[i]->get_type_string() << " neurons" << endl;
2371 }
2372}
2373
2374
2377
2378void NeuralNetwork::save(const string& file_name) const
2379{
2380 FILE * file = fopen(file_name.c_str(), "w");
2381
2382 tinyxml2::XMLPrinter printer(file);
2383
2384 write_XML(printer);
2385
2386 fclose(file);
2387}
2388
2389
2392
2393void NeuralNetwork::save_parameters(const string& file_name) const
2394{
2395 ofstream file(file_name.c_str());
2396
2397 if(!file.is_open())
2398 {
2399 ostringstream buffer;
2400
2401 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2402 << "void save_parameters(const string&) const method.\n"
2403 << "Cannot open parameters data file.\n";
2404
2405 throw logic_error(buffer.str());
2406 }
2407
2408 const Tensor<type, 1> parameters = get_parameters();
2409
2410 file << parameters << endl;
2411
2412 // Close file
2413
2414 file.close();
2415}
2416
2417
2421
2422void NeuralNetwork::load(const string& file_name)
2423{
2424 set_default();
2425
2426 tinyxml2::XMLDocument document;
2427
2428 if(document.LoadFile(file_name.c_str()))
2429 {
2430 ostringstream buffer;
2431
2432 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2433 << "void load(const string&) method.\n"
2434 << "Cannot load XML file " << file_name << ".\n";
2435
2436 throw logic_error(buffer.str());
2437
2438 }
2439
2440 from_XML(document);
2441}
2442
2443
2447
2448void NeuralNetwork::load_parameters_binary(const string& file_name)
2449{
2450 ifstream file;
2451
2452 file.open(file_name.c_str(), ios::binary);
2453
2454 if(!file.is_open())
2455 {
2456 ostringstream buffer;
2457
2458 buffer << "OpenNN Exception: NeuralNetwork template.\n"
2459 << "void load_parameters_binary(const string&) method.\n"
2460 << "Cannot open binary file: " << file_name << "\n";
2461
2462 throw logic_error(buffer.str());
2463 }
2464
2465 streamsize size = sizeof(double);
2466
2467 const Index parameters_number = get_parameters_number();
2468
2469 Tensor<type, 1> new_parameters(parameters_number);
2470
2471 type value;
2472
2473 for(Index i = 0; i < parameters_number; i++)
2474 {
2475 file.read(reinterpret_cast<char*>(&value), size);
2476
2477 new_parameters(i) = value;
2478 }
2479
2480 set_parameters(new_parameters);
2481}
2482
2483
2485
2487{
2488 const Index layers_number = get_layers_number();
2489
2490 const Tensor<Layer*, 1> layers_pointers = get_layers_pointers();
2491 const Tensor<string, 1> layers_names = get_layers_names();
2492
2493 ostringstream buffer;
2494
2495 buffer <<"// Artificial Intelligence Techniques SL\t"<<endl;
2496 buffer <<"// artelnics@artelnics.com\t"<<endl;
2497 buffer <<"// "<<endl;
2498 buffer <<"// Your model has been exported to this file." <<endl;
2499 buffer <<"// You can manage it with the 'neural network' method.\t"<<endl;
2500 buffer <<"// Example:"<<endl;
2501 buffer <<"// "<<endl;
2502 buffer <<"// \tvector<float> sample(n);\t"<<endl;
2503 buffer <<"// \tsample[0] = 1;\t"<<endl;
2504 buffer <<"// \tsample[1] = 2;\t"<<endl;
2505 buffer <<"// \tsample[n] = 10;\t"<<endl;
2506 buffer <<"// \tvector<float> outputs = neural_network(sample);"<<endl;
2507 buffer <<"// "<<endl;
2508 buffer <<"// Notice that only one sample is allowed as input. DataSetBatch of inputs are not yet implement,\t"<<endl;
2509 buffer <<"// however you can loop through neural network function in order to get multiple outputs.\t"<<endl;
2510 buffer <<""<<endl;
2511
2512 buffer << "#include <vector>\n" << endl;
2513
2514 buffer << "using namespace std;\n" << endl;
2515
2517 {
2518 LongShortTermMemoryLayer* long_short_term_memory_pointer = get_long_short_term_memory_layer_pointer();
2519 Index timestep = long_short_term_memory_pointer->get_timesteps();
2520 Index neurons_number = long_short_term_memory_pointer->get_neurons_number();
2521
2522 buffer << "class LSTMNetwork\n";
2523 buffer << "{\n" << endl;
2524 buffer << "public:\n" << endl;
2525 buffer << " LSTMNetwork()\n";
2526 buffer << " {\n";
2527 buffer << " hidden_states.resize(" << neurons_number << ");\n";
2528 buffer << " cell_states.resize(" << neurons_number << ");\n";
2529 buffer << " }\n" << endl;
2530 buffer << " vector<vector<float>> neural_network_batch(const vector<vector<float>>& inputs)\n";
2531 buffer << " {\n";
2532 buffer << " vector<vector<float>> outputs(inputs.size());\n" << endl;
2533 buffer << " for(size_t i = 0; i < inputs.size(); i++)\n";
2534 buffer << " {\n";
2535 buffer << " if(i % " << timestep << " == 0)\n";
2536 buffer << " {\n";
2537 buffer << " fill(hidden_states.begin(), hidden_states.end(), 0.0);\n";
2538 buffer << " fill(cell_states.begin(), cell_states.end(), 0.0);\n";
2539 buffer << " }\n" << endl;
2540 buffer << " outputs[i] = neural_network(inputs[i]);\n";
2541 buffer << " }\n" << endl;
2542 buffer << " return outputs;\n";
2543 buffer << " }\n" << endl << endl;
2544 buffer << "private:\n" << endl;
2545 buffer << " vector<float> hidden_states;\n";
2546 buffer << " vector<float> cell_states;\n" << endl << endl;
2547 }
2548
2549 for(Index i = 0; i < layers_number; i++)
2550 {
2551 buffer << layers_pointers[i]->write_expression_c() << endl;
2552 }
2553
2554 buffer << "vector<float> neural_network(const vector<float>& inputs)\n{" << endl;
2555
2556 buffer << "\tvector<float> outputs;\n" << endl;
2557
2558 if(layers_number > 0)
2559 {
2560 buffer << "\toutputs = " << layers_names[0] << "(inputs);\n";
2561 }
2562
2563 for(Index i = 1; i < layers_number; i++)
2564 {
2565 buffer << "\toutputs = " << layers_names[i] << "(outputs);\n";
2566 }
2567
2568 buffer << "\n\treturn outputs;\n}" << endl;
2569
2570 if(has_long_short_term_memory_layer()) buffer << "\n};\n" << endl;
2571
2572 buffer << "int main(){return 0;}" << endl;
2573
2574 string expression = buffer.str();
2575
2576 replace(expression, "+-", "-");
2577 replace(expression, "-+", "-");
2578 replace(expression, "--", "+");
2579
2580 return expression;
2581}
2582
2583
2584string NeuralNetwork::write_expression() const
2585{
2586 const Index layers_number = get_layers_number();
2587
2588 const Tensor<Layer*, 1> layers_pointers = get_layers_pointers();
2589 const Tensor<string, 1> layers_names = get_layers_names();
2590
2591 Tensor<string, 1> outputs_names_vector;
2592 Tensor<string, 1> inputs_names_vector;
2593 inputs_names_vector = inputs_names;
2594
2595 Index layer_neurons_number;
2596
2597 ostringstream buffer;
2598
2599 for(Index i = 0; i < layers_number; i++)
2600 {
2601 if(i == layers_number-1)
2602 {
2603 outputs_names_vector = outputs_names;
2604 buffer << layers_pointers[i]->write_expression(inputs_names_vector, outputs_names_vector) << endl;
2605 }
2606 else
2607 {
2608 layer_neurons_number = layers_pointers[i]->get_neurons_number();
2609 outputs_names_vector.resize(layer_neurons_number);
2610
2611 for(Index j = 0; j < layer_neurons_number; j++)
2612 {
2613 if(layers_names(i) == "scaling_layer")
2614 {
2615 outputs_names_vector(j) = "scaled_" + inputs_names(j);
2616 }
2617 else
2618 {
2619 outputs_names_vector(j) = layers_names(i) + "_output_" + to_string(j);
2620 }
2621 }
2622 buffer << layers_pointers[i]->write_expression(inputs_names_vector, outputs_names_vector) << endl;
2623
2624 inputs_names_vector = outputs_names_vector;
2625 }
2626 }
2627
2628 string expression = buffer.str();
2629
2630 replace(expression, "+-", "-");
2631
2632 return expression;
2633}
2634
2635
2638{
2639 const Index layers_number = get_layers_number();
2640
2641 const Tensor<Layer*, 1> layers_pointers = get_layers_pointers();
2642 const Tensor<string, 1> layers_names = get_layers_names();
2643
2644 ostringstream buffer;
2645
2646 buffer <<"'''"<<endl;
2647 buffer <<"Artificial Intelligence Techniques SL\t"<<endl;
2648 buffer <<"artelnics@artelnics.com\t"<<endl;
2649 buffer <<""<<endl;
2650 buffer <<"Your model has been exported to this python file." <<endl;
2651 buffer <<"You can manage it with the 'NeuralNetwork' class.\t"<<endl;
2652 buffer <<"Example:"<<endl;
2653 buffer <<""<<endl;
2654 buffer <<"\tmodel = NeuralNetwork()\t"<<endl;
2655 buffer <<"\tsample = [input_1, input_2, input_3, input_4, ...] \t"<<endl;
2656 buffer <<"\toutputs = model.calculate_output(sample)"<<endl;
2657 buffer <<""<<endl;
2658 buffer <<"\tInputs Names: \t"<<endl;
2659
2660 const Tensor<string, 1> inputs = get_inputs_names();
2661
2662 for(int i = 0; i < inputs.dimension(0); i++)
2663 {
2664 if(inputs[i] == "")
2665 {
2666 buffer <<"\t" << to_string(1+i) + " )" << "input_"+ to_string(1+i) << endl;
2667 }
2668 else
2669 {
2670 buffer <<"\t" << to_string(1+i) + " )" << inputs[i] << endl;
2671 }
2672 }
2673
2674 buffer <<""<<endl;
2675 buffer <<"You can predict with a batch of samples using calculate_batch_output method\t" <<endl;
2676 buffer <<"IMPORTANT: input batch must be <class 'numpy.ndarray'> type\t" <<endl;
2677 buffer <<"Example_1:\t" <<endl;
2678 buffer <<"\tmodel = NeuralNetwork()\t"<<endl;
2679 buffer <<"\tinput_batch = np.array([[1, 2], [4, 5]], np.int32)\t" <<endl;
2680 buffer <<"\toutputs = model.calculate_batch_output(input_batch)"<<endl;
2681 buffer <<"Example_2:\t" <<endl;
2682 buffer <<"\tinput_batch = pd.DataFrame( {'col1': [1, 2], 'col2': [3, 4]})\t" <<endl;
2683 buffer <<"\toutputs = model.calculate_batch_output(input_batch.values)"<<endl;
2684 buffer <<"'''"<<endl;
2685 buffer <<""<<endl;
2686 buffer << "import numpy as np\n" << endl;
2687 buffer << "class NeuralNetwork:\n " << endl;
2688 buffer << "\tdef __init__(self):\n " << endl;
2689
2691 {
2692 buffer << "\t\tself.timestep = "+to_string(get_recurrent_layer_pointer()->get_timesteps())+"\n " << endl;
2693 buffer << "\t\tself.hidden_states = " + to_string(get_recurrent_layer_pointer()->get_neurons_number()) + "*[0]\n " << endl;
2694 }
2695
2697 {
2698 buffer << "\t\tself.timestep = "+to_string(get_long_short_term_memory_layer_pointer()->get_timesteps())+"\n " << endl;
2699 buffer << "\t\tself.hidden_states = " + to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number()) + "*[0]\n " << endl;
2700 buffer << "\t\tself.cell_states = " + to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number()) + "*[0]\n " << endl;
2701 }
2702
2703 buffer << "\t\tself.parameters_number = " + to_string(get_parameters_number()) + "\n " << endl;
2704
2705 for(Index i = 0; i < layers_number; i++)
2706 {
2707 buffer << layers_pointers[i]->write_expression_python() << endl;
2708 }
2709
2710 buffer << "\tdef calculate_output(self, inputs):\n" << endl;
2711
2712 buffer << "\t\toutput_" + layers_pointers[0]->get_name() + " = self." +layers_pointers[0]->get_name() + "(inputs)\n" << endl;
2713
2714 for(Index i = 1; i < layers_number; i++)
2715 {
2716 buffer << "\t\toutput_" + layers_pointers[i]->get_name() + " = self." +layers_pointers[i]->get_name() + "(output_"+layers_pointers[i-1]->get_name() + ")\n" << endl;
2717 }
2718
2719 buffer << "\t\treturn output_" + layers_pointers[layers_number-1]->get_name()<<endl;
2720
2721 buffer << "\n\n\tdef calculate_batch_output(self, input_batch):\n" << endl;
2722
2723 buffer << "\t\toutput = []\n" << endl;
2724
2725 buffer << "\t\tfor i in range(input_batch.shape[0]):\n" << endl;
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_recurrent_layer_pointer()->get_neurons_number())+"*[0]\n" << endl;
2732 }
2733
2735 {
2736 buffer << "\t\t\tif(i%self.timestep==0):\n" << endl;
2737
2738 buffer << "\t\t\t\tself.hidden_states = "+to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number())+"*[0]\n" << endl;
2739
2740 buffer << "\t\t\t\tself.cell_states = "+to_string(get_long_short_term_memory_layer_pointer()->get_neurons_number())+"*[0]\n" << endl;
2741 }
2742
2743
2744 buffer << "\t\t\tinputs = list(input_batch[i])\n" << endl;
2745
2746 buffer << "\t\t\toutput_" + layers_pointers[0]->get_name() + " = self." +layers_pointers[0]->get_name() + "(inputs)\n" << endl;
2747
2748 for(Index i = 1; i < layers_number; i++)
2749 {
2750 buffer << "\t\t\toutput_" + layers_pointers[i]->get_name() + " = self." +layers_pointers[i]->get_name() + "(output_"+layers_pointers[i-1]->get_name() + ")\n" << endl;
2751 }
2752
2753 buffer << "\t\t\toutput = np.append(output,output_" + layers_pointers[layers_number-1]->get_name()+ ", axis=0)\n"<< endl;
2754
2755 buffer << "\t\treturn output"<<endl;
2756
2757 string expression = buffer.str();
2758
2759 replace(expression, "+-", "-");
2760 replace(expression, "-+", "-");
2761 replace(expression, "--", "+");
2762
2763 return expression;
2764}
2765
2766
2769
2770void NeuralNetwork::save_expression_c(const string& file_name)
2771{
2772 ofstream file(file_name.c_str());
2773
2774 if(!file.is_open())
2775 {
2776 ostringstream buffer;
2777
2778 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2779 << "void save_expression(const string&) method.\n"
2780 << "Cannot open expression text file.\n";
2781
2782 throw logic_error(buffer.str());
2783 }
2784
2785 file << write_expression_c();
2786
2787 file.close();
2788}
2789
2790
2793
2794void NeuralNetwork::save_expression_python(const string& file_name)
2795{
2796 ofstream file(file_name.c_str());
2797
2798 if(!file.is_open())
2799 {
2800 ostringstream buffer;
2801
2802 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2803 << "void save_expression_python(const string&) method.\n"
2804 << "Cannot open expression text file.\n";
2805
2806 throw logic_error(buffer.str());
2807 }
2808
2809 file << write_expression_python();
2810
2811 file.close();
2812}
2813
2814
2818
2819void NeuralNetwork::save_outputs(const Tensor<type, 2>& inputs, const string & file_name)
2820{
2821 const Tensor<type, 2> outputs = calculate_outputs(inputs);
2822
2823 ofstream file(file_name.c_str());
2824
2825 if(!file.is_open())
2826 {
2827 ostringstream buffer;
2828
2829 buffer << "OpenNN Exception: NeuralNetwork class.\n"
2830 << "void save_expression_python(const string&) method.\n"
2831 << "Cannot open expression text file.\n";
2832
2833 throw logic_error(buffer.str());
2834 }
2835
2836 const Tensor<string, 1> outputs_names = get_outputs_names();
2837
2838 const Index outputs_number = get_outputs_number();
2839 const Index samples_number = inputs.dimension(0);
2840
2841 for(Index i = 0; i < outputs_number; i++)
2842 {
2843 file << outputs_names[i];
2844
2845 if(i != outputs_names.size()-1) file << ";";
2846 }
2847
2848 file << "\n";
2849
2850 for(Index i = 0; i < samples_number; i++)
2851 {
2852 for(Index j = 0; j < outputs_number; j++)
2853 {
2854 file << outputs(i,j);
2855
2856 if(j != outputs_number-1) file << ";";
2857 }
2858
2859 file << "\n";
2860 }
2861
2862 file.close();
2863}
2864
2865
2866Tensor<string, 1> NeuralNetwork::get_layers_names() const
2867{
2868 const Index layers_number = get_layers_number();
2869
2870 Tensor<string, 1> layers_names(layers_number);
2871
2872 for(Index i = 0; i < layers_number; i++)
2873 {
2874 layers_names[i] = layers_pointers[i]->get_name();
2875 }
2876
2877 return layers_names;
2878}
2879
2880
2881Layer* NeuralNetwork::get_last_trainable_layer_pointer() const
2882{
2883 if(layers_pointers.size() == 0) return nullptr;
2884
2885 Tensor<Layer*, 1> trainable_layers_pointers = get_trainable_layers_pointers();
2886
2887 const Index trainable_layers_number = get_trainable_layers_number();
2888
2889 return trainable_layers_pointers(trainable_layers_number-1);
2890}
2891
2892}
2893
2894// OpenNN: Open Neural Networks Library.
2895// Copyright(C) 2005-2021 Artificial Intelligence Techniques, SL.
2896//
2897// This library is free software; you can redistribute it and/or
2898// modify it under the terms of the GNU Lesser General Public
2899// License as published by the Free Software Foundation; either
2900// version 2.1 of the License, or any later version.
2901//
2902// This library is distributed in the hope that it will be useful,
2903// but WITHOUT ANY WARRANTY; without even the implied warranty of
2904// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2905// Lesser General Public License for more details.
2906
2907// You should have received a copy of the GNU Lesser General Public
2908// License along with this library; if not, write to the Free Software
2909// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
This class represents a layer of bounding neurons.
This abstract class represents the concept of a 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
This class represents a layer of LSTM neurons.
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.
This class represents a layer of probabilistic neurons.
This class represents a recurrent layer of 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
This structure contains the batches of the data set.
Definition: data_set.h:886
This structure contains information for the forward propagation of the LSTM layer.
This structure contains information for the forward propagation of the neural network.
This structure contains information for the forward propagation of the perceptron layer.
This structure contains information for the forward propagation of the probabilistic layer.
This structure contains information for the forward propagation of the recurrent layer.