From 569d5c902f3a9cc58a8e6271dbab403414d929f8 Mon Sep 17 00:00:00 2001
From: Martin Beseda <martin.beseda@vsb.cz>
Date: Tue, 27 Aug 2019 16:05:11 +0200
Subject: [PATCH] [WIP] Fixing ACSF NN constructor.

---
 src/LearningMethods/LevenbergMarquardt.cpp |   1 +
 src/Network/ACSFNeuralNetwork.cpp          |  80 ++++++++++++-
 src/Network/NeuralNetwork.cpp              | 125 +--------------------
 src/Network/NeuralNetwork.h                |   6 -
 src/examples/acsf2.cpp                     |  62 +++++++---
 5 files changed, 127 insertions(+), 147 deletions(-)

diff --git a/src/LearningMethods/LevenbergMarquardt.cpp b/src/LearningMethods/LevenbergMarquardt.cpp
index 273ccbcc..be12f7bf 100644
--- a/src/LearningMethods/LevenbergMarquardt.cpp
+++ b/src/LearningMethods/LevenbergMarquardt.cpp
@@ -170,6 +170,7 @@ namespace lib4neuro {
 
                 gradient_norm = 0;
 
+                // TODO parallelize with OpenMP?
                 for (size_t ci = 0; ci < n_parameters; ++ci) {
                     mem_double = rhs[ci];
                     mem_double *= mem_double;
diff --git a/src/Network/ACSFNeuralNetwork.cpp b/src/Network/ACSFNeuralNetwork.cpp
index 2236c356..2549aff9 100644
--- a/src/Network/ACSFNeuralNetwork.cpp
+++ b/src/Network/ACSFNeuralNetwork.cpp
@@ -14,6 +14,11 @@ lib4neuro::ACSFNeuralNetwork::ACSFNeuralNetwork(std::unordered_map<ELEMENT_SYMBO
     std::vector<size_t> inputs;
     std::vector<size_t> subnet_outputs;
     size_t              neuron_idx;
+
+    std::unordered_map<ELEMENT_SYMBOL, std::vector<size_t>> subnet_neuron_idxs;
+    std::unordered_map<ELEMENT_SYMBOL, std::vector<size_t>> subnet_connection_idxs;
+
+
     for(size_t i = 0; i < elements_list.size(); i++) {
         std::vector<size_t> previous_layer;
         std::vector<size_t> new_layer;
@@ -35,9 +40,20 @@ lib4neuro::ACSFNeuralNetwork::ACSFNeuralNetwork(std::unordered_map<ELEMENT_SYMBO
             inputs.emplace_back(neuron_idx);
         }
 
+        /* Create subnet for the current element */
+        bool new_subnet = false;
+        if(subnet_neuron_idxs.find(elements_list.at(i)) == subnet_neuron_idxs.end()) {
+            new_subnet = true;
+            subnet_neuron_idxs[elements_list.at(i)] = std::vector<size_t>();
+            subnet_connection_idxs[elements_list.at(i)] = std::vector<size_t>();
+        }
+
         /* Create hidden layers in sub-net */
         std::vector<unsigned int> n_neurons = n_hidden_neurons[elements_list.at(i)];
         std::vector<NEURON_TYPE> types = type_hidden_neurons[elements_list.at(i)];
+        size_t local_neuron_idx = 0;
+        size_t local_connection_idx = 0;
+
         for(size_t j = 0; j < n_neurons.size(); j++) { /* Iterate over hidden layers */
             /* Create hidden neurons */
             for(size_t k = 0; k < n_neurons.at(j); k++) {
@@ -61,18 +77,74 @@ lib4neuro::ACSFNeuralNetwork::ACSFNeuralNetwork(std::unordered_map<ELEMENT_SYMBO
                     }
                 }
 
-                neuron_idx = this->add_neuron(hid_n, BIAS_TYPE::NEXT_BIAS);
+                if(new_subnet) {
+                    neuron_idx = this->add_neuron(hid_n,
+                                                  BIAS_TYPE::NEXT_BIAS);
+                    subnet_neuron_idxs[elements_list.at(i)].emplace_back(neuron_idx);
+                } else {
+                    neuron_idx = this->add_neuron(hid_n,
+                                                  BIAS_TYPE::EXISTING_BIAS, subnet_neuron_idxs[elements_list.at(i)].at(0)+local_neuron_idx);
+                }
+                local_neuron_idx++;
                 new_layer.emplace_back(neuron_idx);
 
                 /* Connect hidden neuron to the previous layer */
                 for(auto prev_n : previous_layer) {
-                    this->add_connection_simple(prev_n, neuron_idx, SIMPLE_CONNECTION_TYPE::NEXT_WEIGHT);
+                    if(new_subnet) {
+                        subnet_connection_idxs[elements_list.at(i)].emplace_back(this->add_connection_simple(prev_n,
+                                                    neuron_idx,
+                                                    SIMPLE_CONNECTION_TYPE::NEXT_WEIGHT));
+
+                    } else {
+                        this->add_connection_simple(prev_n,
+                                                    neuron_idx,
+                                                    SIMPLE_CONNECTION_TYPE::EXISTING_WEIGHT, subnet_connection_idxs[elements_list.at(i)].at(0)+local_connection_idx);
+                    }
+                    local_connection_idx++;
                 }
-                previous_layer = new_layer;
-                new_layer.clear();
             }
+            previous_layer = new_layer;
+            new_layer.clear();
         }
 
+        /* Create hidden layers in sub-net */
+//        std::vector<unsigned int> n_neurons = n_hidden_neurons[elements_list.at(i)];
+//        std::vector<NEURON_TYPE> types = type_hidden_neurons[elements_list.at(i)];
+//        for(size_t j = 0; j < n_neurons.size(); j++) { /* Iterate over hidden layers */
+//            /* Create hidden neurons */
+//            for(size_t k = 0; k < n_neurons.at(j); k++) {
+//                std::shared_ptr<Neuron> hid_n;
+//                switch(types.at(j)) {
+//                    case NEURON_TYPE::LOGISTIC: {
+//                        hid_n = std::make_shared<NeuronLogistic>();
+//                        break;
+//                    }
+//                    case NEURON_TYPE::BINARY: {
+//                        hid_n = std::make_shared<NeuronBinary>();
+//                        break;
+//                    }
+//                    case NEURON_TYPE::CONSTANT: {
+//                        hid_n = std::make_shared<NeuronConstant>();
+//                        break;
+//                    }
+//                    case NEURON_TYPE::LINEAR: {
+//                        hid_n = std::make_shared<NeuronLinear>();
+//                        break;
+//                    }
+//                }
+//
+//                neuron_idx = this->add_neuron(hid_n, BIAS_TYPE::NEXT_BIAS);
+//                new_layer.emplace_back(neuron_idx);
+//
+//                /* Connect hidden neuron to the previous layer */
+//                for(auto prev_n : previous_layer) {
+//                    this->add_connection_simple(prev_n, neuron_idx, SIMPLE_CONNECTION_TYPE::NEXT_WEIGHT);
+//                }
+//                previous_layer = new_layer;
+//                new_layer.clear();
+//            }
+//        }
+
         /* Create output neurons for sub-net */
         std::shared_ptr<NeuronLinear> sub_out_n = std::make_shared<NeuronLinear>();
         neuron_idx = this->add_neuron(sub_out_n, BIAS_TYPE::NO_BIAS);
diff --git a/src/Network/NeuralNetwork.cpp b/src/Network/NeuralNetwork.cpp
index 0f5abd45..7a9ed274 100644
--- a/src/Network/NeuralNetwork.cpp
+++ b/src/Network/NeuralNetwork.cpp
@@ -260,7 +260,8 @@ namespace lib4neuro {
         }
 
         if (this->input_neuron_indices.size() != input.size()) {
-            THROW_INVALID_ARGUMENT_ERROR("Data input size != Network input size");
+            THROW_INVALID_ARGUMENT_ERROR("Network input size(" + std::to_string(this->input_neuron_indices.size())
+            + ") != Data input size(" + std::to_string(input.size()) + ")");
         }
 
         if (this->output_neuron_indices.size() != output.size()) {
@@ -1051,127 +1052,5 @@ namespace lib4neuro {
             error_partial[i] = 0;
         }
     }
-
-//    NeuralNetwork::NeuralNetwork(std::unordered_map<ELEMENT_SYMBOL, Element*, ELEMENT_SYMBOL_HASH>* elements,
-//                                 std::vector<std::pair<ELEMENT_SYMBOL, std::vector<double>>>* particles) {
-//
-//    }
-
-    NeuralNetwork::NeuralNetwork(std::unordered_map<ELEMENT_SYMBOL, Element*>& elements,
-                                 std::vector<std::pair<ELEMENT_SYMBOL,
-                                                             std::vector<double>>>& particles) {
-        /* Create a new set of Atomic-Centered Symmetry Functions serving as coordinates */
-//        std::vector<std::vector<double>> acsf_coords(particles.size());
-//        std::vector<double> acsf_coords_single;
-//        for(size_t i = 0; i < particles.size(); i++) { /* Iterate over all the particles */
-//            for (auto sym_func : elements[particles.at(i).first]->getSymmetryFunctions()) {
-//                acsf_coords_single.emplace_back(sym_func->eval(i, particles));
-//            }
-//
-//            acsf_coords.at(i) = acsf_coords_single;
-//            acsf_coords_single.clear();
-//        }
-//
-//        /* Check for duplicates in new coordinates */
-//        std::vector<std::vector<double>> unique_coords = acsf_coords;
-//        std::sort(unique_coords.begin(), unique_coords.end());
-//        unique_coords.erase(std::unique(unique_coords.begin(), unique_coords.end()), unique_coords.end());
-//
-//        if(unique_coords.size() != acsf_coords.size()) {
-//            THROW_RUNTIME_ERROR("Not all descriptors are unique with currently specified symmetry functions!");
-//        }
-//
-//        for(auto e : acsf_coords) {
-//            for(auto ee : e) {
-//                std::cout << ee << " ";
-//            }
-//            std::cout << std::endl;
-//        }
-
-        /* Construct the neural network */
-//        std::vector<size_t> inputs;
-//        std::vector<size_t> subnet_outputs;
-//        size_t              neuron_idx;
-//        for(size_t i = 0; i < particles.size(); i++) {
-//            std::vector<size_t> previous_layer;
-//            std::vector<size_t> new_layer;
-//
-//            /* Create input neurons for sub-net */
-//            std::shared_ptr<NeuronLinear> inp_n;
-//            for(size_t j = 0; j < acsf_coords.at(i).size(); j++) {
-//                inp_n = std::make_shared<NeuronLinear>();
-//                neuron_idx = this->add_neuron(inp_n, BIAS_TYPE::NO_BIAS);
-//                previous_layer.emplace_back(neuron_idx);
-//                inputs.emplace_back(neuron_idx);
-//            }
-//
-//            /* Add an additional input neuron for charge, if provided */
-//            if(elements[particles.at(i).first]->isCharge()) {
-//                inp_n = std::make_shared<NeuronLinear>();
-//                neuron_idx = this->add_neuron(inp_n, BIAS_TYPE::NO_BIAS);
-//                previous_layer.emplace_back(neuron_idx);
-//                inputs.emplace_back(neuron_idx);
-//            }
-//
-//            /* Create hidden layers in sub-net */
-//            std::vector<unsigned int> n_neurons = elements[particles.at(i).first]->getNHiddenNeurons();
-//            std::vector<NEURON_TYPE> types = elements[particles.at(i).first]->getHiddenNeuronTypes();
-//            for(size_t j = 0; j < n_neurons.size(); j++) { /* Iterate over hidden layers */
-//                /* Create hidden neurons */
-//                for(size_t k = 0; k < n_neurons.at(j); k++) {
-//                    std::shared_ptr<Neuron> hid_n;
-//                    switch(types.at(j)) {
-//                        case NEURON_TYPE::LOGISTIC: {
-//                            hid_n = std::make_shared<NeuronLogistic>();
-//                            break;
-//                        }
-//                        case NEURON_TYPE::BINARY: {
-//                            hid_n = std::make_shared<NeuronBinary>();
-//                            break;
-//                        }
-//                        case NEURON_TYPE::CONSTANT: {
-//                            hid_n = std::make_shared<NeuronConstant>();
-//                            break;
-//                        }
-//                        case NEURON_TYPE::LINEAR: {
-//                            hid_n = std::make_shared<NeuronLinear>();
-//                            break;
-//                        }
-//                    }
-//
-//                    neuron_idx = this->add_neuron(hid_n, BIAS_TYPE::NEXT_BIAS);
-//                    new_layer.emplace_back(neuron_idx);
-//
-//                    /* Connect hidden neuron to the previous layer */
-//                    for(auto prev_n : previous_layer) {
-//                        this->add_connection_simple(prev_n, neuron_idx, SIMPLE_CONNECTION_TYPE::NEXT_WEIGHT);
-//                    }
-//                    previous_layer = new_layer;
-//                    new_layer.clear();
-//                }
-//            }
-//
-//            /* Create output neurons for sub-net */
-//            std::shared_ptr<NeuronLinear> sub_out_n = std::make_shared<NeuronLinear>();
-//            neuron_idx = this->add_neuron(sub_out_n, BIAS_TYPE::NO_BIAS);
-//            subnet_outputs.emplace_back(neuron_idx);
-//            for(auto prev_n : previous_layer) {
-//                this->add_connection_simple(prev_n, neuron_idx);
-//            }
-//        }
-//
-//        /* Specify network inputs */
-//        this->specify_input_neurons(inputs);
-//
-//        /* Create final output layer */
-//        std::shared_ptr<NeuronLinear> final_out_n = std::make_shared<NeuronLinear>();
-//        neuron_idx = this->add_neuron(final_out_n, BIAS_TYPE::NO_BIAS);
-//        for(auto subnet_output : subnet_outputs) {
-//            this->add_connection_constant(subnet_output, neuron_idx, 1);
-//        }
-//        std::vector<size_t> outputs = {neuron_idx};
-//        this->specify_output_neurons(outputs);
-    }
-
 }
 
diff --git a/src/Network/NeuralNetwork.h b/src/Network/NeuralNetwork.h
index f9c2c600..499252ec 100644
--- a/src/Network/NeuralNetwork.h
+++ b/src/Network/NeuralNetwork.h
@@ -235,12 +235,6 @@ namespace lib4neuro {
          */
         LIB4NEURO_API explicit NeuralNetwork(std::string filepath);
 
-        // TODO remove method
-        LIB4NEURO_API explicit NeuralNetwork(std::unordered_map<ELEMENT_SYMBOL,
-                                                                      Element*>& elements,
-                                             std::vector<std::pair<ELEMENT_SYMBOL,
-                                                                         std::vector<double>>>& particles);
-
         /**
          *
          */
diff --git a/src/examples/acsf2.cpp b/src/examples/acsf2.cpp
index a9be9165..f896a108 100644
--- a/src/examples/acsf2.cpp
+++ b/src/examples/acsf2.cpp
@@ -133,7 +133,7 @@ int main() {
         elements[l4n::ELEMENT_SYMBOL::He] = &helium;
 
         /* Read data */
-        l4n::XYZReader reader("../../data/HE21+T4.xyz");
+        l4n::XYZReader reader("/home/martin/lib4neuro/data/HE21+T1.xyz");
         reader.read();
 
         std::cout << "Finished reading data" << std::endl;
@@ -142,18 +142,52 @@ int main() {
 
         /* Create a neural network */
         std::unordered_map<l4n::ELEMENT_SYMBOL, std::vector<unsigned int>> n_hidden_neurons;
-        n_hidden_neurons[l4n::ELEMENT_SYMBOL::He] = {10};
+        n_hidden_neurons[l4n::ELEMENT_SYMBOL::He] = {2};
 
         std::unordered_map<l4n::ELEMENT_SYMBOL, std::vector<l4n::NEURON_TYPE>> type_hidden_neurons;
         type_hidden_neurons[l4n::ELEMENT_SYMBOL::He] = {l4n::NEURON_TYPE::LOGISTIC};
 
         l4n::ACSFNeuralNetwork net(elements, *reader.get_element_list(), reader.contains_charge(), n_hidden_neurons, type_hidden_neurons);
+//        l4n::NeuralNetwork net;
+//        std::vector<std::shared_ptr<l4n::NeuronLinear>> inps;
+//        std::vector<size_t> inps_inds;
+//        for(unsigned int i = 0; i < 126; i++) {
+//            std::shared_ptr<l4n::NeuronLinear> inp = std::make_shared<l4n::NeuronLinear>();
+//            inps.emplace_back(inp);
+//            inps_inds.emplace_back(net.add_neuron(inp, l4n::BIAS_TYPE::NO_BIAS));
+//        }
+//
+//        net.specify_input_neurons(inps_inds);
+//
+//        std::vector<std::shared_ptr<l4n::NeuronLogistic>> hids;
+//
+//        std::vector<unsigned int> hids_idxs;
+//        size_t idx;
+//        unsigned int n_hidden = 5;
+//        for(unsigned int i = 0; i < n_hidden; i++) {
+//            std::shared_ptr<l4n::NeuronLogistic> hid = std::make_shared<l4n::NeuronLogistic>();
+//            hids.emplace_back(hid);
+//            idx = net.add_neuron(hid, l4n::BIAS_TYPE::NEXT_BIAS);
+//            hids_idxs.emplace_back(idx);
+//
+//            for(unsigned int j = 0; j < 126; j++) {
+//                net.add_connection_simple(j, idx);
+//            }
+//        }
+//
+//        std::shared_ptr<l4n::NeuronLinear> out = std::make_shared<l4n::NeuronLinear>();
+//        idx = net.add_neuron(out, l4n::BIAS_TYPE::NO_BIAS);
+//        std::vector<size_t> out_inds = {idx};
+//        for(unsigned int i = 0; i < n_hidden; i++) {
+//            net.add_connection_simple(hids_idxs.at(i), idx);
+//        }
+//        net.specify_output_neurons(out_inds);
 
         l4n::MSE mse(&net, ds.get());
 
         net.randomize_parameters();
         // optimize_via_particle_swarm(net, mse);
-		// double err1 = optimize_via_LBMQ(net, mse);
+        double err1 = optimize_via_LBMQ(net, mse);
         double err2 = optimize_via_gradient_descent(net, mse);
 		
 		if(err2 > 0.00001) {
@@ -161,17 +195,17 @@ int main() {
 		}
 
         /* Print fit comparison with real data */
-//        std::vector<double> output;
-//        output.resize(1);
-//
-//        for(auto e : *ds->get_data()) {
-//            for(auto inp_e : e.first) {
-//                std::cout << inp_e << " ";
-//            }
-//            std::cout << e.second.at(0) << " ";
-//            net.eval_single(e.first, output);
-//            std::cout << output.at(0) << std::endl;
-//        }
+        std::vector<double> output;
+        output.resize(1);
+
+        for(auto e : *ds->get_data()) {
+            for(auto inp_e : e.first) {
+                std::cout << inp_e << " ";
+            }
+            std::cout << e.second.at(0) << " ";
+            net.eval_single(e.first, output);
+            std::cout << output.at(0) << std::endl;
+        }
 
     } catch (const std::exception& e) {
         std::cerr << e.what() << std::endl;
-- 
GitLab