Skip to content
Snippets Groups Projects
NeuralNetwork.h 12.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • Michal Kravcenko's avatar
    Michal Kravcenko committed
     * This file contains the header for the NeuralNetwork class representing a function in the form of a directed graph,
     * in which the vertices are called Neurons (with activation functions) and the edges Connections (with transfer functions)
    
     *
     * @author Michal Kravčenko
     * @date 13.6.18 -
     */
    
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    //TODO preprocess the feed-forward and backward passes for more efficient parallelism
    
    #ifndef INC_4NEURO_NEURALNETWORK_H
    #define INC_4NEURO_NEURALNETWORK_H
    
    
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <vector>
    #include <utility>
    #include <algorithm>
    #include <assert.h>
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    #include <algorithm>
    #include <utility>
    
    #include "../Neuron/Neuron.h"
    #include "../Neuron/NeuronConstant.h"
    #include "../Neuron/NeuronBinary.h"
    #include "../Neuron/NeuronLinear.h"
    #include "../Neuron/NeuronLogistic.h"
    #include "../NetConnection/ConnectionFunctionGeneral.h"
    #include "../NetConnection/ConnectionFunctionIdentity.h"
    
    #include "../NormalizationStrategy/NormalizationStrategy.h"
    
    #include <boost/random/mersenne_twister.hpp>
    #include <boost/random/uniform_int_distribution.hpp>
    #include <boost/random/uniform_real_distribution.hpp>
    
    
        enum class BIAS_TYPE {
            NEXT_BIAS, NO_BIAS, EXISTING_BIAS
        };
    
    
        enum class SIMPLE_CONNECTION_TYPE {
            NEXT_WEIGHT, UNITARY_WEIGHT, EXISTING_WEIGHT
        };
    
    
    
        protected:
    
    
            /**
             *
             */
            std::vector<Neuron *> *neurons = nullptr;
    
            /**
             *
             */
            std::vector<size_t> *input_neuron_indices = nullptr;
    
            /**
             *
             */
            std::vector<size_t> *output_neuron_indices = nullptr;
    
            /**
             *
             */
            std::vector<double> *connection_weights = nullptr;
    
            /**
             *
             */
            std::vector<double> *neuron_biases = nullptr;
    
            /**
             *
             */
            std::vector<int> *neuron_bias_indices = nullptr;
    
            /**
             *
             */
            std::vector<double> *neuron_potentials = nullptr;
    
            /**
             *
             */
            std::vector<ConnectionFunctionGeneral *> *connection_list = nullptr;
    
            /**
             *
             */
            std::vector<std::vector<std::pair<size_t, size_t>> *> *inward_adjacency = nullptr;
    
            /**
             *
             */
            std::vector<std::vector<std::pair<size_t, size_t>> *> *outward_adjacency = nullptr;
    
            /**
             *
             */
            std::vector<std::vector<size_t> *> *neuron_layers_feedforward = nullptr;
    
            /**
             *
             */
            std::vector<std::vector<size_t> *> *neuron_layers_feedbackward = nullptr;
    
            /**
            *
            */
            bool layers_analyzed = false;
    
            /**
             *
             */
            bool delete_weights = true;
    
            /**
             *
             */
            bool delete_biases = true;
    
    
            /**
             *
             */
            NormalizationStrategy* normalization_strategy = nullptr;
    
    
            /**
             * Adds a new connection to the local list of connections
             * @param con Connection object to be added
             * @return Returns the index of the added connection among all the connections
             */
            size_t add_new_connection_to_list(ConnectionFunctionGeneral *con);
    
            /**
             * Adds a new entry (oriented edge s -> t) to the adjacency list of this network
             * @param s Index of the source neuron
             * @param t Index of the target neuron
             * @param con_idx Index of the connection representing the edge
             */
            void add_outward_connection(size_t s, size_t t, size_t con_idx);
    
            /**
             * Adds a new entry (oriented edge s <- t) to the adjacency list of this network
             * @param s Index of the source neuron
             * @param t Index of the target neuron
             * @param con_idx Index of the connection representing the edge
             */
            void add_inward_connection(size_t s, size_t t, size_t con_idx);
    
            /**
             * Performs one feedforward pass and feedbackward pass during which determines the layers of this neural network
             * for simpler use during evaluation and learning
             */
            void analyze_layer_structure();
    
        public:
    
            /**
             * Struct used to access private properties from
             * the serialization function
             */
            struct access;
    
            /**
             *
             */
            LIB4NEURO_API explicit NeuralNetwork();
    
            /**
             *
             */
            LIB4NEURO_API explicit NeuralNetwork(std::string filepath);
    
            /**
             *
             */
            LIB4NEURO_API virtual ~NeuralNetwork();
    
            /**
             * If possible, returns a neural net with 'input_neuron_indices' neurons as inputs and 'output_neuron_indices' as
             * outputs, otherwise returns nullptr. The returned object shares adjustable weights with this network. All
             * neurons are coppied (new instances), edges also. Uses a breadth-first search as the underlying algorithm.
             * @param input_neuron_indices
             * @param output_neuron_indices
             * @return
             */
            LIB4NEURO_API NeuralNetwork *
            get_subnet(std::vector<size_t> &input_neuron_indices, std::vector<size_t> &output_neuron_indices);
    
            /**
             * Replaces the values in @{this->connection_weights} and @{this->neuron_biases} by the provided values
             * @param parameters
             */
            LIB4NEURO_API virtual void copy_parameter_space(std::vector<double> *parameters);
    
            /**
             * Copies the pointers @{this->connection_weights} and @{this->neuron_biases} from the parental network, sets
             * flags to not delete the vectors in this object
             * @param parent_network
             */
            LIB4NEURO_API virtual void set_parameter_space_pointers(NeuralNetwork &parent_network);
    
            /**
             *
             * @param input
             * @param output
             * @param custom_weights_and_biases
             */
            LIB4NEURO_API virtual void eval_single(std::vector<double> &input, std::vector<double> &output,
                                                   std::vector<double> *custom_weights_and_biases = nullptr);
    
    
            /**
             *
             * @param input
             * @param output
             * @param custom_weights_and_biases
             */
            LIB4NEURO_API virtual void eval_single_debug(std::vector<double> &input, std::vector<double> &output,
                                                   std::vector<double> *custom_weights_and_biases = nullptr);
    
    
            /**
             *
             * @param error_derivative
             * @param gradient
             */
            LIB4NEURO_API virtual void
            add_to_gradient_single(std::vector<double> &input, std::vector<double> &error_derivative, double error_scaling,
                                   std::vector<double> &gradient);
    
    
            /**
              *
              * @param error_derivative
              * @param gradient
              */
            LIB4NEURO_API virtual void
            add_to_gradient_single_debug(std::vector<double> &input, std::vector<double> &error_derivative, double error_scaling,
                                   std::vector<double> &gradient);
    
    
            /**
             * Adds a new neuron to the list of neurons. Also assigns a valid bias value to its activation function
             * @param[in] n
             * @return
             */
            LIB4NEURO_API size_t add_neuron(Neuron *n, BIAS_TYPE bt = BIAS_TYPE::NEXT_BIAS, size_t bias_idx = 0);
    
            /**
             *
             * @param n1_idx
             * @param n2_idx
             * @return
             */
            LIB4NEURO_API size_t add_connection_simple(size_t n1_idx, size_t n2_idx,
                                                       SIMPLE_CONNECTION_TYPE sct = SIMPLE_CONNECTION_TYPE::NEXT_WEIGHT,
                                                       size_t weight_idx = 0);
    
            /**
             * Take the existing connection with index 'connection_idx' in 'parent_network' and adds it to the structure of this
             * object
             * @param n1_idx
             * @param n2_idx
             * @param connection_idx
             * @param parent_network
             */
            LIB4NEURO_API void
            add_existing_connection(size_t n1_idx, size_t n2_idx, size_t connection_idx, NeuralNetwork &parent_network);
    
    
            /**
             *
             */
            LIB4NEURO_API virtual void randomize_weights();
    
            LIB4NEURO_API virtual void randomize_biases();
    
            LIB4NEURO_API virtual void randomize_parameters();
    
            /**
             *
             */
            LIB4NEURO_API virtual void scale_biases(double alpha);
            /**
             *
             */
            LIB4NEURO_API virtual void scale_weights(double alpha);
            /**
             *
             */
            LIB4NEURO_API virtual void scale_parameters(double alpha);
    
    
            /**
             *
             * @return
             */
            LIB4NEURO_API virtual size_t get_n_inputs();
    
            /**
             *
             * @return
             */
            LIB4NEURO_API virtual size_t get_n_outputs();
    
            /**
             *
             * @return
             */
            LIB4NEURO_API virtual size_t get_n_weights();
    
            /**
             *
             * @return
             */
            LIB4NEURO_API virtual size_t get_n_biases();
    
            /**
             *
             * @return
             */
            LIB4NEURO_API virtual int get_neuron_bias_index(size_t neuron_idx);
    
            /**
             *
             * @return
             */
            LIB4NEURO_API virtual size_t get_n_neurons();
    
            /**
             *
             * @param input_neurons_indices
             */
            LIB4NEURO_API void specify_input_neurons(std::vector<size_t> &input_neurons_indices);
    
            /**
             *
             * @param output_neurons_indices
             */
            LIB4NEURO_API void specify_output_neurons(std::vector<size_t> &output_neurons_indices);
    
            /**
             *
             */
    
            LIB4NEURO_API void write_weights(std::string file_path);
    
            /**
             *
             * @param file_path
             */
            LIB4NEURO_API void write_weights(std::ofstream* file_path);
    
            /**
             *
             */
            LIB4NEURO_API void write_biases();
    
            /**
             *
             * @param file_name
             */
            LIB4NEURO_API void write_biases(std::string file_path);
    
            /**
             *
             * @param file_path
             */
            LIB4NEURO_API void write_biases(std::ofstream* file_path);
    
            /**
             *
             */
            LIB4NEURO_API void write_stats();
    
            /**
             *
             * @param file_path
             */
            LIB4NEURO_API void write_stats(std::string file_path);
    
            /**
             *
             * @param file_path
             */
            LIB4NEURO_API void write_stats(std::ofstream* file_path);
    
            LIB4NEURO_API virtual std::vector<double> *get_parameter_ptr_weights();
    
            LIB4NEURO_API virtual std::vector<double> *get_parameter_ptr_biases();
    
    
            /**
             *
             * @param filepath
             */
            LIB4NEURO_API void save_text(std::string filepath);
    
    
            /**
             *
             * @return
             */
            LIB4NEURO_API NormalizationStrategy* get_normalization_strategy_instance();
    
            /**
             *
             * @param ns
             */
            LIB4NEURO_API void set_normalization_strategy_instance(NormalizationStrategy* ns);
    
    
        }; // class NeuralNetwork
    
        class FullyConnectedFFN: public NeuralNetwork {
        public:
    
            /**
    
             * Constructs a fully connected feed-forward neural network
    
             * @param neuron_numbers Pointer to vector containing number of vectors in every layer (from input to output)
             * @param hidden_layer_neuron_type
             */
    
            LIB4NEURO_API explicit FullyConnectedFFN(std::vector<unsigned int>* neuron_numbers,
                                                     NEURON_TYPE hidden_layer_neuron_type,
                                                     std::ofstream* ofs = nullptr);
    
    
            /**
             *
             * @param neuron_numbers
             * @param hidden_layer_neuron_types
             */
    
            LIB4NEURO_API explicit FullyConnectedFFN(std::vector<unsigned int>* neuron_numbers,
                                                     std::vector<NEURON_TYPE>* hidden_layer_neuron_types,
                                                     std::ofstream* ofs = nullptr);
    
            void init(std::vector<unsigned int>* neuron_numbers,
                      std::vector<NEURON_TYPE>* hidden_layer_neuron_types,
                      std::ofstream* ofs = nullptr);