Skip to content
Snippets Groups Projects
NeuralNetwork.h 13.2 KiB
Newer Older
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

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"
    enum class BIAS_TYPE {
        NEXT_BIAS, NO_BIAS, EXISTING_BIAS
    };

    enum class SIMPLE_CONNECTION_TYPE {
        NEXT_WEIGHT, UNITARY_WEIGHT, EXISTING_WEIGHT
    };


Martin Beseda's avatar
Martin Beseda committed

        /**
         *
         */
        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:

Martin Beseda's avatar
Martin Beseda committed
        /**
         * Runs @data through the network and then computes partial derivatives with respect to each output function and adds them
         * to seperate vectors in @jacobian. Also computes the out error and stores in the vector @error
         * @param[out] jacobian
         * @param[in] data
         * @param[out] error
         */
        LIB4NEURO_API virtual void
        get_jacobian(std::vector<std::vector<double>> &jacobian, std::pair<std::vector<double>, std::vector<double>> &data, std::vector<double> &error);



        /**
        *
        * @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_debug(std::vector<double> &input, std::vector<double> &error_derivative, double error_scaling,
                                     std::vector<double> &gradient);

        /**
         * 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 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);

        /**
         * 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);

        /**
         * Adds a connection with constant weight value, will not be altered during any learning process
         * @param n1_idx
         * @param n2_idx
         * @param weight
         */
        LIB4NEURO_API size_t add_connection_constant(size_t n1_idx, size_t n2_idx, double weight);
        /**
         * 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);