9#include "neural_network.h"
34 set(model_type, architecture);
40 Tensor<Index, 1> architecture(architecture_list.size());
41 architecture.setValues(architecture_list);
43 set(model_type, architecture);
52 const Index& new_blocks_number,
53 const Tensor<Index, 1>& new_filters_dimensions,
54 const Index& new_outputs_number)
56 set(new_inputs_dimensions, new_blocks_number, new_filters_dimensions, new_outputs_number);
101void NeuralNetwork::delete_layers()
105 for(Index i = 0; i < layers_number; i++)
123 ostringstream buffer;
125 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
126 <<
"NeuralNetwork::add_layer() method.\n"
127 <<
"No layers can be added after a bounding layer.\n";
131 throw logic_error(buffer.str());
136 ostringstream buffer;
138 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
139 <<
"NeuralNetwork::add_layer() method.\n"
140 <<
"No layers can be added after a probabilistic layer.\n";
142 throw logic_error(buffer.str());
147 ostringstream buffer;
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";
153 throw logic_error(buffer.str());
158 ostringstream buffer;
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";
164 throw logic_error(buffer.str());
177 for(Index i = 0; i < old_layers_number; i++)
layers_pointers(i) = old_layers_pointers(i);
183 ostringstream buffer;
185 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
186 <<
"void add_layer(const Layer*) method.\n"
188 <<
" in the neural network architecture.\n";
190 throw logic_error(buffer.str());
203 if(layers_number > 1 && (layer_type == Layer::Type::Recurrent || layer_type == Layer::Type::LongShortTermMemory))
207 else if(layers_number == 1 && (layer_type == Layer::Type::Recurrent || layer_type == Layer::Type::LongShortTermMemory))
211 if(first_layer_type != Layer::Type::Scaling)
return false;
225 for(Index i = 0; i < layers_number; i++)
227 if(
layers_pointers[i]->get_type() == Layer::Type::Scaling)
return true;
241 for(Index i = 0; i < layers_number; i++)
243 if(
layers_pointers[i]->get_type() == Layer::Type::LongShortTermMemory)
return true;
257 for(Index i = 0; i < layers_number; i++)
259 if(
layers_pointers[i]->get_type() == Layer::Type::Convolutional)
return true;
273 for(Index i = 0; i < layers_number; i++)
275 if(
layers_pointers[i]->get_type() == Layer::Type::Recurrent)
return true;
289 for(Index i = 0; i < layers_number; i++)
291 if(
layers_pointers[i]->get_type() == Layer::Type::Unscaling)
return true;
305 for(Index i = 0; i < layers_number; i++)
307 if(
layers_pointers[i]->get_type() == Layer::Type::Bounding)
return true;
321 for(Index i = 0; i < layers_number; i++)
323 if(
layers_pointers[i]->get_type() == Layer::Type::Probabilistic)
return true;
411Layer* NeuralNetwork::get_layer_pointer(
const Index& layer_index)
const
423 const Index trainable_layers_number = get_trainable_layers_number();
425 Tensor<Layer*, 1> trainable_layers_pointers(trainable_layers_number);
429 for(Index i = 0; i < layers_number; i++)
440 return trainable_layers_pointers;
450 const Index trainable_layers_number = get_trainable_layers_number();
452 Tensor<Index, 1> trainable_layers_indices(trainable_layers_number);
454 Index trainable_layer_index = 0;
456 for(Index i = 0; i < layers_number; i++)
462 trainable_layers_indices[trainable_layer_index] = i;
463 trainable_layer_index++;
467 return trainable_layers_indices;
477 for(Index i = 0; i < layers_number; i++)
485 ostringstream buffer;
487 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
488 <<
"ScalingLayer* get_scaling_layer_pointer() const method.\n"
489 <<
"No scaling layer in neural network.\n";
491 throw logic_error(buffer.str());
501 for(Index i = 0; i < layers_number; i++)
509 ostringstream buffer;
511 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
512 <<
"UnscalingLayer* get_unscaling_layer_pointer() const method.\n"
513 <<
"No unscaling layer in neural network.\n";
515 throw logic_error(buffer.str());
525 for(Index i = 0; i < layers_number; i++)
533 ostringstream buffer;
535 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
536 <<
"BoundingLayer* get_bounding_layer_pointer() const method.\n"
537 <<
"No bounding layer in neural network.\n";
539 throw logic_error(buffer.str());
549 for(Index i = 0; i < layers_number; i++)
557 ostringstream buffer;
559 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
560 <<
"ProbabilisticLayer* get_probabilistic_layer_pointer() const method.\n"
561 <<
"No probabilistic layer in neural network.\n";
563 throw logic_error(buffer.str());
572 for(Index i = 0; i < layers_number; i++)
580 ostringstream buffer;
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";
586 throw logic_error(buffer.str());
596 for(Index i = 0; i < layers_number; i++)
604 ostringstream buffer;
606 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
607 <<
"RecurrentLayer* get_recurrent_layer_pointer() const method.\n"
608 <<
"No recurrent layer in neural network.\n";
610 throw logic_error(buffer.str());
642void NeuralNetwork::set(
const NeuralNetwork::ProjectType& model_type,
const Tensor<Index, 1>& architecture)
646 if(architecture.size() <= 1)
return;
648 const Index size = architecture.size();
650 const Index inputs_number = architecture[0];
651 const Index outputs_number = architecture[size-1];
659 if(model_type == ProjectType::Approximation)
661 for(Index i = 0; i < size-1; i++)
664 perceptron_layer_pointer->set_name(
"perceptron_layer_" + to_string(i+1));
666 this->
add_layer(perceptron_layer_pointer);
668 if(i == size-2) perceptron_layer_pointer->
set_activation_function(PerceptronLayer::ActivationFunction::Linear);
673 this->
add_layer(unscaling_layer_pointer);
679 else if(model_type == ProjectType::Classification)
681 for(Index i = 0; i < size-2; i++)
685 perceptron_layer_pointer->set_name(
"perceptron_layer_" + to_string(i+1));
687 this->
add_layer(perceptron_layer_pointer);
692 this->
add_layer(probabilistic_layer_pointer);
694 else if(model_type == ProjectType::Forecasting)
699 this->
add_layer(long_short_term_memory_layer_pointer);
701 for(Index i = 1; i < size-1; i++)
705 perceptron_layer_pointer->set_name(
"perceptron_layer_" + to_string(i));
707 this->
add_layer(perceptron_layer_pointer);
709 if(i == size-2) perceptron_layer_pointer->
set_activation_function(PerceptronLayer::ActivationFunction::Linear);
714 this->
add_layer(unscaling_layer_pointer);
727void NeuralNetwork::set(
const NeuralNetwork::ProjectType& model_type,
const initializer_list<Index>& architecture_list)
729 Tensor<Index, 1> architecture(architecture_list.size());
730 architecture.setValues(architecture_list);
732 set(model_type, architecture);
744 const Index& blocks_number,
745 const Tensor<Index, 1>& filters_dimensions,
746 const Index& outputs_number)
753 Tensor<Index, 1> outputs_dimensions = scaling_layer->get_outputs_dimensions();
755 for(Index i = 0; i < blocks_number; i++)
770 const Tensor<Index, 0> outputs_dimensions_sum = outputs_dimensions.sum();
818 if(new_inputs_number == 0)
820 ostringstream buffer;
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";
826 throw logic_error(buffer.str());
837 scaling_layer_pointer->set_inputs_number(new_inputs_number);
840 const Index trainable_layers_number = get_trainable_layers_number();
843 if(trainable_layers_number > 0)
845 trainable_layers_pointers[0]->set_inputs_number(new_inputs_number);
857 Index new_inputs_number = 0;
859 for(Index i = 0; i < inputs.dimension(0); i++)
861 if(inputs(i)) new_inputs_number++;
876void NeuralNetwork::set_threads_number(
const int& new_threads_number)
880 for(Index i = 0; i < layers_number; i++)
887void NeuralNetwork::set_layers_pointers(Tensor<Layer*, 1>& new_layers_pointers)
893PerceptronLayer* NeuralNetwork::get_first_perceptron_layer_pointer()
const
897 for(Index i = 0; i < layers_number; i++)
922Index NeuralNetwork::get_outputs_number()
const
928 return last_layer->get_neurons_number();
935Tensor<Index, 1> NeuralNetwork::get_trainable_layers_neurons_numbers()
const
937 const Index trainable_layers_number = get_trainable_layers_number();
939 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
949 layers_neurons_number(count) =
layers_pointers[i]->get_neurons_number();
956 return layers_neurons_number;
960Tensor<Index, 1> NeuralNetwork::get_trainable_layers_inputs_numbers()
const
962 const Index trainable_layers_number = get_trainable_layers_number();
964 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
974 layers_neurons_number(count) =
layers_pointers[i]->get_inputs_number();
980 return layers_neurons_number;
984Tensor<Index, 1> NeuralNetwork::get_trainable_layers_synaptic_weight_numbers()
const
986 const Index trainable_layers_number = get_trainable_layers_number();
988 Tensor<Index, 1> layers_neurons_number(trainable_layers_number);
998 layers_neurons_number(count) =
layers_pointers[i]->get_synaptic_weights_number();
1004 return layers_neurons_number;
1023 Tensor<Index, 1> architecture(layers_number);
1027 if(inputs_number == 0)
return architecture;
1029 if(layers_number > 0)
1031 for(Index i = 0; i < layers_number; i++)
1037 return architecture;
1048 Index parameters_number = 0;
1050 for(Index i = 0; i < trainable_layers_pointers.size(); i++)
1052 parameters_number += trainable_layers_pointers[i]->get_parameters_number();
1055 return parameters_number;
1066 Tensor<type, 1> parameters(parameters_number);
1068 const Index trainable_layers_number = get_trainable_layers_number();
1074 for(Index i = 0; i < trainable_layers_number; i++)
1076 const Tensor<type, 1> layer_parameters = trainable_layers_pointers(i)->get_parameters();
1078 for(Index j = 0; j < layer_parameters.size(); j++)
1080 parameters(j + position) = layer_parameters(j);
1083 position += layer_parameters.size();
1090Tensor<Index, 1> NeuralNetwork::get_trainable_layers_parameters_numbers()
const
1092 const Index trainable_layers_number = get_trainable_layers_number();
1096 Tensor<Index, 1> trainable_layers_parameters_number(trainable_layers_number);
1098 for(Index i = 0; i < trainable_layers_number; i++)
1100 trainable_layers_parameters_number[i] = trainable_layers_pointers[i]->get_parameters_number();
1103 return trainable_layers_parameters_number;
1107Tensor<Tensor<type, 1>, 1> NeuralNetwork::get_trainable_layers_parameters(
const Tensor<type, 1>& parameters)
const
1109 const Index trainable_layers_number = get_trainable_layers_number();
1111 const Tensor<Index, 1> trainable_layers_parameters_number = get_trainable_layers_parameters_numbers();
1113 Tensor<Tensor<type, 1>, 1> trainable_layers_parameters(trainable_layers_number);
1117 for(Index i = 0; i < trainable_layers_number; i++)
1120 trainable_layers_parameters(i).resize(trainable_layers_parameters_number(i));
1122 trainable_layers_parameters(i) = parameters.slice(Eigen::array<Eigen::Index, 1>({index}), Eigen::array<Eigen::Index, 1>({trainable_layers_parameters_number(i)}));
1124 index += trainable_layers_parameters_number(i);
1128 return trainable_layers_parameters;
1139 const Index size = new_parameters.size();
1143 if(size < parameters_number)
1145 ostringstream buffer;
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";
1151 throw logic_error(buffer.str());
1156 const Index trainable_layers_number = get_trainable_layers_number();
1160 const Tensor<Index, 1> trainable_layers_parameters_numbers = get_trainable_layers_parameters_numbers();
1164 for(Index i = 0; i < trainable_layers_number; i++)
1166 trainable_layers_pointers(i)->set_parameters(new_parameters, index);
1168 index += trainable_layers_parameters_numbers(i);
1193Tensor<Index, 1> NeuralNetwork::get_layers_neurons_numbers()
const
1202 return layers_neurons_number;
1206Index NeuralNetwork::get_trainable_layers_number()
const
1212 for(Index i = 0; i < layers_number; i++)
1226Index NeuralNetwork::get_perceptron_layers_number()
const
1232 for(Index i = 0; i < layers_number; i++)
1244Index NeuralNetwork::get_probabilistic_layers_number()
const
1250 for(Index i = 0; i < layers_number; i++)
1262Index NeuralNetwork::get_long_short_term_memory_layers_number()
const
1268 for(Index i = 0; i < layers_number; i++)
1270 if(
layers_pointers(i)->get_type() == Layer::Type::LongShortTermMemory)
1279Index NeuralNetwork::get_recurrent_layers_number()
const
1285 for(Index i = 0; i < layers_number; i++)
1300 const Index trainable_layers_number = get_trainable_layers_number();
1304 for(Index i = 0; i < trainable_layers_number; i++)
1306 trainable_layers_pointers[i]->set_parameters_constant(value);
1318 const Index trainable_layers_number = get_trainable_layers_number();
1322 for(Index i = 0; i < trainable_layers_number; i++)
1324 trainable_layers_pointers[i]->set_parameters_random();
1335 const Tensor<type, 0> parameters_norm = parameters.square().sum().sqrt();
1337 return parameters_norm(0);
1348 if(perturbation < 0)
1350 ostringstream buffer;
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";
1356 throw logic_error(buffer.str());
1363 parameters = parameters + perturbation;
1378 const Index trainable_layers_number = trainable_layers_pointers.size();
1380 if(trainable_layers_pointers(0)->get_type() == Layer::Type::Convolutional)
1382 trainable_layers_pointers(0)->forward_propagate(batch.inputs_4d, forward_propagation.layers(0));
1386 trainable_layers_pointers(0)->forward_propagate(batch.inputs_2d, forward_propagation.layers(0));
1389 for(Index i = 1; i < trainable_layers_number; i++)
1391 switch(trainable_layers_pointers(i-1)->get_type())
1393 case Layer::Type::Perceptron:
1395 trainable_layers_pointers(i)
1397 forward_propagation.layers(i));
1400 case Layer::Type::Probabilistic:
1402 trainable_layers_pointers(i)
1404 forward_propagation.layers(i));
1407 case Layer::Type::Recurrent:
1409 trainable_layers_pointers(i)
1411 forward_propagation.layers(i));
1415 case Layer::Type::LongShortTermMemory:
1417 trainable_layers_pointers(i)
1419 forward_propagation.layers(i));
1422 case Layer::Type::Pooling:
1426 case Layer::Type::Convolutional:
1442 Tensor<type, 1>& parameters,
1447 const Index trainable_layers_number = trainable_layers_pointers.size();
1449 const Index parameters_number = trainable_layers_pointers(0)->get_parameters_number();
1451 const TensorMap<Tensor<type, 1>> potential_parameters(parameters.data(), parameters_number);
1453 if(trainable_layers_pointers(0)->get_type() == Layer::Type::Convolutional)
1455 trainable_layers_pointers(0)->forward_propagate(batch.inputs_4d, potential_parameters, forward_propagation.layers(0));
1459 trainable_layers_pointers(0)->forward_propagate(batch.inputs_2d, potential_parameters, forward_propagation.layers(0));
1462 Index index = parameters_number;
1464 for(Index i = 1; i < trainable_layers_number; i++)
1466 const Index parameters_number = trainable_layers_pointers(i)->get_parameters_number();
1468 const TensorMap<Tensor<type, 1>> potential_parameters(parameters.data() + index, parameters_number);
1470 switch(trainable_layers_pointers(i-1)->get_type())
1472 case Layer::Type::Perceptron:
1474 trainable_layers_pointers(i)
1476 potential_parameters,
1477 forward_propagation.layers(i));
1481 case Layer::Type::Probabilistic:
1483 trainable_layers_pointers(i)
1485 potential_parameters,
1486 forward_propagation.layers(i));
1490 case Layer::Type::Recurrent:
1492 trainable_layers_pointers(i)
1494 potential_parameters,
1495 forward_propagation.layers(i));
1499 case Layer::Type::LongShortTermMemory:
1501 trainable_layers_pointers(i)
1503 potential_parameters,
1504 forward_propagation.layers(i));
1508 case Layer::Type::Convolutional:
1520 index += parameters_number;
1541 const Index inputs_dimensions_number = inputs.rank();
1543 if(inputs_dimensions_number != 2 && inputs_dimensions_number != 4)
1545 ostringstream buffer;
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";
1551 throw logic_error(buffer.str());
1556 Tensor<type, 2> outputs;
1560 if(layers_number == 0)
return inputs;
1564 for(Index i = 1; i < layers_number; i++)
1577 const Index inputs_dimensions_number = inputs.rank();
1579 if(inputs_dimensions_number != 2 && inputs_dimensions_number != 4)
1581 ostringstream buffer;
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";
1587 throw logic_error(buffer.str());
1592 Tensor<type, 4> outputs_4d;
1593 Tensor<type, 2> outputs, inputs_2d;
1597 if(layers_number == 0)
return inputs_2d;
1610 for(Index i = 1; i < layers_number; i++)
1641 const Tensor<type, 1>& point,
1642 const type& minimum,
1643 const type& maximum,
1644 const Index& points_number)
const
1648 Tensor<type, 2> directional_inputs(points_number, inputs_number);
1650 Tensor<type, 1> inputs(inputs_number);
1654 for(Index i = 0; i < points_number; i++)
1656 inputs(direction) = minimum + (maximum - minimum)*
static_cast<type
>(i)/
static_cast<type
>(points_number-1);
1658 for(Index j = 0; j < inputs_number; j++)
1660 directional_inputs(i,j) = inputs(j);
1664 return directional_inputs;
1673 const Index trainable_layers_number = get_trainable_layers_number();
1675 Tensor<string, 2> information(trainable_layers_number, 3);
1679 for(Index i = 0; i < trainable_layers_number; i++)
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());
1684 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1686 if(layer_type ==
"Perceptron")
1706 const Index trainable_layers_number = get_trainable_layers_number();
1708 const Index perceptron_layers_number = get_perceptron_layers_number();
1710 Tensor<string, 2> information(perceptron_layers_number, 3);
1714 Index perceptron_layer_index = 0;
1716 for(Index i = 0; i < trainable_layers_number; i++)
1718 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1720 if(layer_type ==
"Perceptron")
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());
1729 perceptron_layer_index++;
1741 const Index trainable_layers_number = get_trainable_layers_number();
1743 const Index probabilistic_layers_number = get_probabilistic_layers_number();
1745 Tensor<string, 2> information(probabilistic_layers_number, 3);
1749 Index probabilistic_layer_index = 0;
1751 for(Index i = 0; i < trainable_layers_number; i++)
1753 const string layer_type = trainable_layers_pointers(i)->get_type_string();
1755 if(layer_type ==
"Probabilistic")
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());
1764 probabilistic_layer_index++;
1777 ostringstream buffer;
1779 file_stream.OpenElement(
"NeuralNetwork");
1783 file_stream.OpenElement(
"Inputs");
1787 file_stream.OpenElement(
"InputsNumber");
1792 file_stream.
PushText(buffer.str().c_str());
1800 file_stream.OpenElement(
"Input");
1815 file_stream.OpenElement(
"Layers");
1819 file_stream.OpenElement(
"LayersTypes");
1829 file_stream.
PushText(buffer.str().c_str());
1846 file_stream.OpenElement(
"Outputs");
1852 file_stream.OpenElement(
"OutputsNumber");
1855 buffer << outputs_number;
1857 file_stream.
PushText(buffer.str().c_str());
1863 for(Index i = 0; i < outputs_number; i++)
1865 file_stream.OpenElement(
"Output");
1889 ostringstream buffer;
1895 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
1896 <<
"void from_XML(const tinyxml2::XMLDocument&) method.\n"
1897 <<
"Neural network element is nullptr.\n";
1899 throw logic_error(buffer.str());
1911 element_clone = element->DeepClone(&inputs_document);
1913 inputs_document.InsertFirstChild(element_clone);
1915 inputs_from_XML(inputs_document);
1928 element_clone = element->DeepClone(&layers_document);
1930 layers_document.InsertFirstChild(element_clone);
1932 layers_from_XML(layers_document);
1946 element_clone = element->DeepClone(&outputs_document);
1948 outputs_document.InsertFirstChild(element_clone);
1950 outputs_from_XML(outputs_document);
1961 const string new_display_string = element->GetText();
1967 catch(
const logic_error& e)
1969 cerr << e.what() << endl;
1978 ostringstream buffer;
1984 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
1985 <<
"void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
1986 <<
"Inputs element is nullptr.\n";
1988 throw logic_error(buffer.str());
1993 const tinyxml2::XMLElement* inputs_number_element = root_element->FirstChildElement(
"InputsNumber");
1995 if(!inputs_number_element)
1997 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
1998 <<
"void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
1999 <<
"Inputs number element is nullptr.\n";
2001 throw logic_error(buffer.str());
2004 Index new_inputs_number = 0;
2006 if(inputs_number_element->GetText())
2008 new_inputs_number =
static_cast<Index
>(atoi(inputs_number_element->GetText()));
2017 if(new_inputs_number > 0)
2019 for(Index i = 0; i < new_inputs_number; i++)
2022 start_element = input_element;
2024 if(input_element->Attribute(
"Index") != to_string(i+1))
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";
2030 throw logic_error(buffer.str());
2033 if(!input_element->GetText())
2048 ostringstream buffer;
2054 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2055 <<
"void layers_from_XML(const tinyxml2::XMLDocument&) method.\n"
2056 <<
"Layers element is nullptr.\n";
2058 throw logic_error(buffer.str());
2063 const tinyxml2::XMLElement* layers_types_element = root_element->FirstChildElement(
"LayersTypes");
2065 if(!layers_types_element)
2067 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2068 <<
"void layers_from_XML(const tinyxml2::XMLDocument&) method.\n"
2069 <<
"Layers types element is nullptr.\n";
2071 throw logic_error(buffer.str());
2074 Tensor<string, 1> layers_types;
2076 if(layers_types_element->GetText())
2078 layers_types = get_tokens(layers_types_element->GetText(),
' ');
2085 for(Index i = 0; i < layers_types.size(); i++)
2087 if(layers_types(i) ==
"Scaling")
2089 ScalingLayer* scaling_layer =
new ScalingLayer();
2092 start_element = scaling_element;
2099 element_clone = scaling_element->DeepClone(&scaling_document);
2101 scaling_document.InsertFirstChild(element_clone);
2103 scaling_layer->from_XML(scaling_document);
2108 else if(layers_types(i) ==
"Convolutional")
2110 ConvolutionalLayer* convolutional_layer =
new ConvolutionalLayer();
2113 start_element = convolutional_element;
2115 if(convolutional_element)
2120 element_clone = convolutional_element->DeepClone(&convolutional_document);
2122 convolutional_document.InsertFirstChild(element_clone);
2124 convolutional_layer->from_XML(convolutional_document);
2129 else if(layers_types(i) ==
"Perceptron")
2131 PerceptronLayer* perceptron_layer =
new PerceptronLayer();
2134 start_element = perceptron_element;
2136 if(perceptron_element)
2141 element_clone = perceptron_element->DeepClone(&perceptron_document);
2143 perceptron_document.InsertFirstChild(element_clone);
2145 perceptron_layer->from_XML(perceptron_document);
2150 else if(layers_types(i) ==
"Pooling")
2152 PoolingLayer* pooling_layer =
new PoolingLayer();
2155 start_element = pooling_element;
2162 element_clone = pooling_element->DeepClone(&pooling_document);
2164 pooling_document.InsertFirstChild(element_clone);
2166 pooling_layer->from_XML(pooling_document);
2171 else if(layers_types(i) ==
"Probabilistic")
2173 ProbabilisticLayer* probabilistic_layer =
new ProbabilisticLayer();
2176 start_element = probabilistic_element;
2178 if(probabilistic_element)
2183 element_clone = probabilistic_element->DeepClone(&probabilistic_document);
2185 probabilistic_document.InsertFirstChild(element_clone);
2186 probabilistic_layer->from_XML(probabilistic_document);
2191 else if(layers_types(i) ==
"LongShortTermMemory")
2193 LongShortTermMemoryLayer* long_short_term_memory_layer =
new LongShortTermMemoryLayer();
2196 start_element = long_short_term_memory_element;
2198 if(long_short_term_memory_element)
2203 element_clone = long_short_term_memory_element->DeepClone(&long_short_term_memory_document);
2205 long_short_term_memory_document.InsertFirstChild(element_clone);
2207 long_short_term_memory_layer->from_XML(long_short_term_memory_document);
2210 add_layer(long_short_term_memory_layer);
2212 else if(layers_types(i) ==
"Recurrent")
2214 RecurrentLayer* recurrent_layer =
new RecurrentLayer();
2217 start_element = recurrent_element;
2219 if(recurrent_element)
2224 element_clone = recurrent_element->DeepClone(&recurrent_document);
2226 recurrent_document.InsertFirstChild(element_clone);
2228 recurrent_layer->from_XML(recurrent_document);
2233 else if(layers_types(i) ==
"Unscaling")
2235 UnscalingLayer* unscaling_layer =
new UnscalingLayer();
2238 start_element = unscaling_element;
2240 if(unscaling_element)
2245 element_clone = unscaling_element->DeepClone(&unscaling_document);
2247 unscaling_document.InsertFirstChild(element_clone);
2249 unscaling_layer->from_XML(unscaling_document);
2254 else if(layers_types(i) ==
"Bounding")
2256 BoundingLayer* bounding_layer =
new BoundingLayer();
2260 start_element = bounding_element;
2262 if(bounding_element)
2267 element_clone = bounding_element->DeepClone(&bounding_document);
2269 bounding_document.InsertFirstChild(element_clone);
2271 bounding_layer->from_XML(bounding_document);
2282 ostringstream buffer;
2288 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2289 <<
"void outputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2290 <<
"Outputs element is nullptr.\n";
2292 throw logic_error(buffer.str());
2297 const tinyxml2::XMLElement* outputs_number_element = root_element->FirstChildElement(
"OutputsNumber");
2299 if(!outputs_number_element)
2301 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2302 <<
"void inputs_from_XML(const tinyxml2::XMLDocument&) method.\n"
2303 <<
"Outputs number element is nullptr.\n";
2305 throw logic_error(buffer.str());
2308 Index new_outputs_number = 0;
2310 if(outputs_number_element->GetText())
2312 new_outputs_number =
static_cast<Index
>(atoi(outputs_number_element->GetText()));
2319 if(new_outputs_number > 0)
2323 for(Index i = 0; i < new_outputs_number; i++)
2326 start_element = output_element;
2328 if(output_element->Attribute(
"Index") != to_string(i+1))
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";
2334 throw logic_error(buffer.str());
2337 if(!output_element->GetText())
2354 cout <<
"Neural network" << endl;
2358 cout <<
"Layers number: " << layers_number << endl;
2360 for(Index i = 0; i < layers_number; i++)
2362 cout <<
"Layer " << i+1 <<
": " <<
layers_pointers[i]->get_neurons_number()
2363 <<
" " <<
layers_pointers[i]->get_type_string() <<
" neurons" << endl;
2373 FILE * file = fopen(file_name.c_str(),
"w");
2388 ofstream file(file_name.c_str());
2392 ostringstream buffer;
2394 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2395 <<
"void save_parameters(const string&) const method.\n"
2396 <<
"Cannot open parameters data file.\n";
2398 throw logic_error(buffer.str());
2403 file << parameters << endl;
2421 if(document.LoadFile(file_name.c_str()))
2423 ostringstream buffer;
2425 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2426 <<
"void load(const string&) method.\n"
2427 <<
"Cannot load XML file " << file_name <<
".\n";
2429 throw logic_error(buffer.str());
2445 file.open(file_name.c_str(), ios::binary);
2449 ostringstream buffer;
2451 buffer <<
"OpenNN Exception: NeuralNetwork template.\n"
2452 <<
"void load_parameters_binary(const string&) method.\n"
2453 <<
"Cannot open binary file: " << file_name <<
"\n";
2455 throw logic_error(buffer.str());
2458 streamsize size =
sizeof(double);
2462 Tensor<type, 1> new_parameters(parameters_number);
2466 for(Index i = 0; i < parameters_number; i++)
2468 file.read(
reinterpret_cast<char*
>(&value), size);
2470 new_parameters(i) = value;
2484 const Tensor<string, 1> layers_names = get_layers_names();
2486 ostringstream buffer;
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;
2505 buffer <<
"#include <vector>\n" << endl;
2507 buffer <<
"using namespace std;\n" << endl;
2512 Index timestep = long_short_term_memory_pointer->
get_timesteps();
2515 buffer <<
"class LSTMNetwork\n";
2516 buffer <<
"{\n" << endl;
2517 buffer <<
"public:\n" << endl;
2518 buffer <<
" LSTMNetwork()\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";
2525 buffer <<
" vector<vector<float>> outputs(inputs.size());\n" << endl;
2526 buffer <<
" for(size_t i = 0; i < inputs.size(); i++)\n";
2528 buffer <<
" if(i % " << timestep <<
" == 0)\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;
2542 for(Index i = 0; i < layers_number; i++)
2547 buffer <<
"vector<float> neural_network(const vector<float>& inputs)\n{" << endl;
2549 buffer <<
"\tvector<float> outputs;\n" << endl;
2551 if(layers_number > 0)
2553 buffer <<
"\toutputs = " << layers_names[0] <<
"(inputs);\n";
2556 for(Index i = 1; i < layers_number; i++)
2558 buffer <<
"\toutputs = " << layers_names[i] <<
"(outputs);\n";
2561 buffer <<
"\n\treturn outputs;\n}" << endl;
2565 buffer <<
"int main(){return 0;}" << endl;
2567 string expression = buffer.str();
2569 replace(expression,
"+-",
"-");
2570 replace(expression,
"-+",
"-");
2571 replace(expression,
"--",
"+");
2577string NeuralNetwork::write_expression()
const
2582 const Tensor<string, 1> layers_names = get_layers_names();
2584 Tensor<string, 1> outputs_names_vector;
2585 Tensor<string, 1> inputs_names_vector;
2588 Index layer_neurons_number;
2590 ostringstream buffer;
2592 for(Index i = 0; i < layers_number; i++)
2594 if(i == layers_number-1)
2597 buffer <<
layers_pointers[i]->write_expression(inputs_names_vector, outputs_names_vector) << endl;
2602 outputs_names_vector.resize(layer_neurons_number);
2604 for(Index j = 0; j < layer_neurons_number; j++)
2606 if(layers_names(i) ==
"scaling_layer")
2612 outputs_names_vector(j) = layers_names(i) +
"_output_" + to_string(j);
2615 buffer <<
layers_pointers[i]->write_expression(inputs_names_vector, outputs_names_vector) << endl;
2617 inputs_names_vector = outputs_names_vector;
2621 string expression = buffer.str();
2623 replace(expression,
"+-",
"-");
2635 const Tensor<string, 1> layers_names = get_layers_names();
2637 ostringstream buffer;
2639 buffer <<
"'''"<<endl;
2640 buffer <<
"Artificial Intelligence Techniques SL\t"<<endl;
2641 buffer <<
"artelnics@artelnics.com\t"<<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;
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;
2651 buffer <<
"\tInputs Names: \t"<<endl;
2655 for(
int i = 0; i < inputs.dimension(0); i++)
2659 buffer <<
"\t" << to_string(1+i) +
" )" <<
"input_"+ to_string(1+i) << endl;
2663 buffer <<
"\t" << to_string(1+i) +
" )" << inputs[i] << 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;
2679 buffer <<
"import numpy as np\n" << endl;
2680 buffer <<
"class NeuralNetwork:\n " << endl;
2681 buffer <<
"\tdef __init__(self):\n " << endl;
2698 for(Index i = 0; i < layers_number; i++)
2703 buffer <<
"\tdef calculate_output(self, inputs):\n" << endl;
2707 for(Index i = 1; i < layers_number; i++)
2712 buffer <<
"\t\treturn output_" +
layers_pointers[layers_number-1]->get_name()<<endl;
2714 buffer <<
"\n\n\tdef calculate_batch_output(self, input_batch):\n" << endl;
2716 buffer <<
"\t\toutput = []\n" << endl;
2718 buffer <<
"\t\tfor i in range(input_batch.shape[0]):\n" << endl;
2722 buffer <<
"\t\t\tif(i%self.timestep==0):\n" << endl;
2729 buffer <<
"\t\t\tif(i%self.timestep==0):\n" << endl;
2737 buffer <<
"\t\t\tinputs = list(input_batch[i])\n" << endl;
2741 for(Index i = 1; i < layers_number; i++)
2746 buffer <<
"\t\t\toutput = np.append(output,output_" +
layers_pointers[layers_number-1]->get_name()+
", axis=0)\n"<< endl;
2748 buffer <<
"\t\treturn output"<<endl;
2750 string expression = buffer.str();
2752 replace(expression,
"+-",
"-");
2753 replace(expression,
"-+",
"-");
2754 replace(expression,
"--",
"+");
2765 ofstream file(file_name.c_str());
2769 ostringstream buffer;
2771 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2772 <<
"void save_expression(const string&) method.\n"
2773 <<
"Cannot open expression text file.\n";
2775 throw logic_error(buffer.str());
2789 ofstream file(file_name.c_str());
2793 ostringstream buffer;
2795 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2796 <<
"void save_expression_python(const string&) method.\n"
2797 <<
"Cannot open expression text file.\n";
2799 throw logic_error(buffer.str());
2816 ofstream file(file_name.c_str());
2820 ostringstream buffer;
2822 buffer <<
"OpenNN Exception: NeuralNetwork class.\n"
2823 <<
"void save_expression_python(const string&) method.\n"
2824 <<
"Cannot open expression text file.\n";
2826 throw logic_error(buffer.str());
2831 const Index outputs_number = get_outputs_number();
2832 const Index samples_number = inputs.dimension(0);
2834 for(Index i = 0; i < outputs_number; i++)
2843 for(Index i = 0; i < samples_number; i++)
2845 for(Index j = 0; j < outputs_number; j++)
2847 file << outputs(i,j);
2849 if(j != outputs_number-1) file <<
";";
2859Tensor<string, 1> NeuralNetwork::get_layers_names()
const
2863 Tensor<string, 1> layers_names(layers_number);
2865 for(Index i = 0; i < layers_number; i++)
2870 return layers_names;
2874Layer* NeuralNetwork::get_last_trainable_layer_pointer()
const
2880 const Index trainable_layers_number = get_trainable_layers_number();
2882 return trainable_layers_pointers(trainable_layers_number-1);
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.
Type
This enumeration represents the possible types of layers.
string get_type_string() const
Takes the type of layer used by the model.
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.
void set_parameters_random()
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.
string write_activation_function() const
This class represents a layer of scaling neurons.
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.
void PushText(const char *text, bool cdata=false)
Add a text node.
void PushAttribute(const char *name, const char *value)
If streaming, add an attribute to an open element.
virtual void CloseElement(bool compactMode=false)
If streaming, close the Element.