From a3c47005ae08fa8eda2523bb2f9fc47c250a13f9 Mon Sep 17 00:00:00 2001 From: Michal Kravcenko <michal.kravcenko@vsb.cz> Date: Fri, 15 Jun 2018 12:24:08 +0200 Subject: [PATCH] - cleaned up the way neural nets are initialized and added some docs --- .idea/usage.statistics.xml | 4 +- src/NetConnection/Connection.cpp | 9 ++-- src/NetConnection/Connection.h | 52 +++++++++--------- src/NetConnection/ConnectionWeight.cpp | 4 +- src/NetConnection/ConnectionWeight.h | 4 +- src/NetConnection/ConnectionWeightIdentity.h | 7 +++ src/Network/NeuralNetwork.cpp | 56 +++++++++++++++++++- src/Network/NeuralNetwork.h | 27 +++++++++- src/Neuron/Neuron.cpp | 3 ++ src/main.cpp | 52 +++++++++--------- 10 files changed, 152 insertions(+), 66 deletions(-) diff --git a/.idea/usage.statistics.xml b/.idea/usage.statistics.xml index 317c2d7f..f6e9b451 100644 --- a/.idea/usage.statistics.xml +++ b/.idea/usage.statistics.xml @@ -5,7 +5,7 @@ <usages-collector id="statistics.file.extensions.open"> <counts> <entry key="Makefile" value="1" /> - <entry key="cpp" value="58" /> + <entry key="cpp" value="59" /> <entry key="f90" value="4" /> <entry key="h" value="71" /> <entry key="txt" value="7" /> @@ -14,7 +14,7 @@ <usages-collector id="statistics.file.types.open"> <counts> <entry key="CMakeLists.txt" value="7" /> - <entry key="ObjectiveC" value="129" /> + <entry key="ObjectiveC" value="130" /> <entry key="PLAIN_TEXT" value="5" /> </counts> </usages-collector> diff --git a/src/NetConnection/Connection.cpp b/src/NetConnection/Connection.cpp index a11c1703..d36db016 100644 --- a/src/NetConnection/Connection.cpp +++ b/src/NetConnection/Connection.cpp @@ -14,9 +14,12 @@ Connection::Connection(Neuron *n_in, Neuron *n_out, ConnectionWeight* con) { this->con = con; } -//Connection::~Connection() { - // -//} +Connection::~Connection() { + if(this->con){ + delete this->con; + this->con = nullptr; + } +} void Connection::adjust_weights(double* values) { this->con->adjust_weights(values); diff --git a/src/NetConnection/Connection.h b/src/NetConnection/Connection.h index bdcbfb3c..f6c166c9 100644 --- a/src/NetConnection/Connection.h +++ b/src/NetConnection/Connection.h @@ -15,77 +15,73 @@ class Neuron; class ConnectionWeight; /** - * + * Class representing directed connection between two neurons */ class Connection { private: /** - * + * Pointer to an object evaluating the weight function */ ConnectionWeight *con = nullptr; /** - * + * Pointer to the Neuron on the receiving end of this connection */ Neuron *neuron_in = nullptr; /** - * + * Pointer to the Neuron on the signaling end of this connection */ Neuron *neuron_out = nullptr; - //TODO pridat gradient + //TODO pridat gradient pro ucely backpropagation public: - /** - * - * @param[in] n_in - * @param[in] n_out - */ + /** + * Constructor + * @param[in] n_in Pointer to the Neuron on the receiving end of this connection + * @param[in] n_out Pointer to the Neuron on the signaling end of this connection + * @param[in] con Pointer to an object evaluating the weight function + */ Connection(Neuron *n_in, Neuron *n_out, ConnectionWeight* con); -// Connection(Neuron *n_in, Neuron *n_out, Connection* ref_con); - /** - * + * Destructor, deletes the 'con' object */ - ~Connection()=default; + ~Connection(); /** - * - * @param[in] values + * Takes the array of double values and alters the corresponding weights associated + * with the 'con' object + * @param[in] values Values to be added to the associated weights */ void adjust_weights(double *values); /** - * - * @param[in] values + * Takes the array of double values and sets the corresponding weights associated + * with the 'con' object + * @param[in] values Values to be set to the associated weights */ void set_weights(double *values); -// /** -// * -// * @return -// */ -// double get_weight(); - - /** - * + * Takes the output signal of Neuron 'neuron_out', multiplies it by the result of the + * weight function associated with this connection and adds the result to the potential + * of the Neuron 'neuron_in' */ void pass_signal(); /** - * + * Returns the pointer to the Neuron on the receiving end of this connection * @return */ Neuron* get_neuron_in(); /** - * + * Returns the pointer to the Neuron on the signaling end of this connection * @return */ Neuron* get_neuron_out(); diff --git a/src/NetConnection/ConnectionWeight.cpp b/src/NetConnection/ConnectionWeight.cpp index b4fdf7e2..cc1efb34 100644 --- a/src/NetConnection/ConnectionWeight.cpp +++ b/src/NetConnection/ConnectionWeight.cpp @@ -12,7 +12,7 @@ ConnectionWeight::ConnectionWeight() { } -ConnectionWeight::ConnectionWeight(int param_count, std::function<double(double **, int)> f) { +ConnectionWeight::ConnectionWeight(int param_count, std::function<double(double **, int)> *f) { this->param_ptrs = new double*[param_count]; this->n_params = param_count; @@ -49,5 +49,5 @@ void ConnectionWeight::SetParamPointer(double *param_ptr, int idx) { } double ConnectionWeight::eval() { - return this->weight_function(this->param_ptrs, this->n_params); + return (*this->weight_function)(this->param_ptrs, this->n_params); } \ No newline at end of file diff --git a/src/NetConnection/ConnectionWeight.h b/src/NetConnection/ConnectionWeight.h index 295549ab..c961324a 100644 --- a/src/NetConnection/ConnectionWeight.h +++ b/src/NetConnection/ConnectionWeight.h @@ -25,7 +25,7 @@ protected: /** * */ - std::function<double(double **, int)> weight_function; + std::function<double(double **, int)> *weight_function = nullptr; public: @@ -39,7 +39,7 @@ public: * @param param_count * @param f */ - ConnectionWeight(int param_count, std::function<double(double **, int)> f); + ConnectionWeight(int param_count, std::function<double(double **, int)> *f); /** * diff --git a/src/NetConnection/ConnectionWeightIdentity.h b/src/NetConnection/ConnectionWeightIdentity.h index e121ddf7..f2e26f40 100644 --- a/src/NetConnection/ConnectionWeightIdentity.h +++ b/src/NetConnection/ConnectionWeightIdentity.h @@ -19,8 +19,15 @@ class ConnectionWeightIdentity:public ConnectionWeight { private: public: + /** + * + */ ConnectionWeightIdentity(); + /** + * + * @return + */ double eval() override; }; diff --git a/src/Network/NeuralNetwork.cpp b/src/Network/NeuralNetwork.cpp index a5090d0a..ffa3354d 100644 --- a/src/Network/NeuralNetwork.cpp +++ b/src/Network/NeuralNetwork.cpp @@ -6,9 +6,11 @@ */ #include "NeuralNetwork.h" +#include "../NetConnection/ConnectionWeightIdentity.h" NeuralNetwork::NeuralNetwork() { this->neurons = new std::vector<Neuron*>(0); + this->connection_weights = new std::vector<double>(0); } NeuralNetwork::~NeuralNetwork() { @@ -28,11 +30,63 @@ NeuralNetwork::~NeuralNetwork() { delete this->active_eval_set; this->active_eval_set = nullptr; } + if(this->connection_weights){ + delete this->connection_weights; + this->connection_weights = nullptr; + } } -void NeuralNetwork::add_neuron(Neuron *n) { +int NeuralNetwork::add_neuron(Neuron *n) { this->neurons->push_back(n); this->in_out_determined = false; + + return (int)this->neurons->size() - 1; +} + +void NeuralNetwork::add_connection_simple(int n1_idx, int n2_idx, int weight_idx, double weight_value) { + + if(weight_idx < 0 || weight_idx >= this->connection_weights->size()){ + //this weight is a new one, we add it to the system of weights + this->connection_weights->push_back(weight_value); + weight_idx = (int)this->connection_weights->size() - 1; + } + Neuron *neuron_out = this->neurons->at(n1_idx); + Neuron *neuron_in = this->neurons->at(n2_idx); + + ConnectionWeightIdentity *con_weight_u1u2 = new ConnectionWeightIdentity(); + con_weight_u1u2->SetParamPointer(&this->connection_weights->at(weight_idx), 0); + + Connection *u1u2 = new Connection(neuron_out, neuron_in, con_weight_u1u2); + + neuron_out->add_connection_out(u1u2); + neuron_in->add_connection_in(u1u2); +} + +void NeuralNetwork::add_connection_general(int n1_idx, int n2_idx, std::function<double(double **, int)> *f, int* weight_indices, double* weight_values, int n_weights) { + + ConnectionWeight *con_weight_u1u2 = new ConnectionWeight(n_weights, f); + //we analyze weights + int weight_idx = 0; + double weight_value = 0.0; + for(int wi = 0; wi < n_weights; ++wi){ + weight_idx = weight_indices[wi]; + weight_value = weight_values[wi]; + + if(weight_idx < 0 || weight_idx >= this->connection_weights->size()){ + //this weight is a new one, we add it to the system of weights + this->connection_weights->push_back(weight_value); + weight_indices[wi] = (int)this->connection_weights->size() - 1; + } + + con_weight_u1u2->SetParamPointer(&this->connection_weights->at(weight_indices[wi]), wi); + } + + Neuron *neuron_out = this->neurons->at(n1_idx); + Neuron *neuron_in = this->neurons->at(n2_idx); + Connection *u1u2 = new Connection(neuron_out, neuron_in, con_weight_u1u2); + + neuron_out->add_connection_out(u1u2); + neuron_in->add_connection_in(u1u2); } void NeuralNetwork::determine_inputs_outputs() { diff --git a/src/Network/NeuralNetwork.h b/src/Network/NeuralNetwork.h index d6acc945..cb77c595 100644 --- a/src/Network/NeuralNetwork.h +++ b/src/Network/NeuralNetwork.h @@ -42,6 +42,8 @@ private: */ std::vector<Neuron*>* output_neurons = nullptr; + std::vector<double>* connection_weights = nullptr; + /** * */ @@ -86,9 +88,30 @@ public: /** * - * @param n + * @param[in] n + * @return + */ + int add_neuron(Neuron* n); + + /** + * + * @param[in] n1_idx + * @param[in] n2_idx + * @param[in] weight_idx + * @param[in] weight_value + */ + void add_connection_simple(int n1_idx, int n2_idx, int weight_idx, double weight_value); + + /** + * + * @param n1_idx + * @param n2_idx + * @param f + * @param weight_indices + * @param weight_values + * @param n_weights */ - void add_neuron(Neuron* n); + void add_connection_general(int n1_idx, int n2_idx, std::function<double(double **, int)> *f, int* weight_indices, double* weight_values, int n_weights); diff --git a/src/Neuron/Neuron.cpp b/src/Neuron/Neuron.cpp index bb074f84..22afd530 100644 --- a/src/Neuron/Neuron.cpp +++ b/src/Neuron/Neuron.cpp @@ -8,6 +8,9 @@ Neuron::~Neuron() { } if(this->edges_out){ + for(auto *edge: *this->edges_out){ + delete edge; + } delete this->edges_out; this->edges_out = nullptr; } diff --git a/src/main.cpp b/src/main.cpp index 4e601007..483fdab0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include "NetConnection/ConnectionWeightIdentity.h" +//TODO prepsat tak, aby neuronova sit managovala destruktory vsech potrebnych objektu (kvuli serializaci) /** * Test of simple neural network * Network should evaluate the function f(x) = x + 1 @@ -22,28 +23,29 @@ void test1(){ std::vector<double> in(1); std::vector<double> out(1); - NeuralNetwork net; - - NeuronLinear u1(1.0, 1.0); //f(x) = x + 1.0 - NeuronLinear u2(0.0, 1.0); //f(x) = x - - auto * parameters = new double[1]; - parameters[0] = 1.0; - -// ConnectionWeight con_weight_u1u2(1, [](double ** params, int n_params){ return (*params[0]);}); - ConnectionWeightIdentity con_weight_u1u2; - -// con_weight_u1u2.SetParamPointer(¶meters[0], 0); - con_weight_u1u2.SetParamPointer(¶meters); - - - Connection u1u2(&u1, &u2, &con_weight_u1u2); - u1.add_connection_out(&u1u2); - u2.add_connection_in(&u1u2); - - net.add_neuron(&u1); - net.add_neuron(&u2); + NeuralNetwork net; + NeuronLinear* u1 = new NeuronLinear(1.0, 1.0); //f(x) = x + 1.0 + NeuronLinear* u2 = new NeuronLinear(0.0, 1.0); //f(x) = x + int idx1 = net.add_neuron(u1); + int idx2 = net.add_neuron(u2); +////////////////////// SIMPLE EDGE WEIGHT //////////////////////////////////////// +// net.add_connection_simple(idx1, idx2, -1, 1.0); +////////////////////// END SIMPLE EDGE WEIGHT //////////////////////////////////////// + +/////////////////////////BEGIN OF COMPLEX EDGE WEIGHT////////////////////////////// +//TODO vyresit memleak + std::function<double(double **, int)> weight_function = [](double ** params, int n_params){ + //w(x, y) = x + y + double a = (*(params[0])); + double b = (*(params[1])); + printf("eval: %f, %f\n", a, b); + return (a + 0.0 * b); + }; + int weight_indices [2]= {0, -1}; + double weight_values [2] = {1.0, 5.0}; + net.add_connection_general(idx1, idx2, &weight_function, weight_indices, weight_values, 2); +/////////////////////////END OF COMPLEX EDGE WEIGHT////////////////////////////// for(int i = 0; i < 20; ++i){ in[0] = 0.05 * i; net.eval_single(in, out); @@ -51,11 +53,9 @@ void test1(){ printf("x = %3.2f, f(x) = %3.2f, expected output = %3.2f\n", in[0], out[0], in[0] + 1.0); } - - - - - delete [] parameters; + //clean-up phase + delete u1; + delete u2; } int main(int argc, char** argv){ -- GitLab