Skip to content
Snippets Groups Projects
ErrorFunctions.cpp 9.26 KiB
Newer Older
  • Learn to ignore specific revisions
  • //
    // Created by martin on 7/15/18.
    //
    
    
    #include <vector>
    
    #include <cmath>
    #include <boost/random/mersenne_twister.hpp>
    #include <boost/random/uniform_int_distribution.hpp>
    
    #include "ErrorFunctions.h"
    
        size_t ErrorFunction::get_dimension() {
            return this->dimension;
        }
    
        NeuralNetwork* ErrorFunction::get_network_instance() {
            return this->net;
        }
    
        void ErrorFunction::divide_data_train_test(double percent_test) {
            size_t ds_size = this->ds->get_n_elements();
    
            /* Store the full data set */
            this->ds_full = this->ds;
    
            /* Choose random subset of the DataSet for training and the remaining part for validation */
            boost::random::mt19937 gen;
            boost::random::uniform_int_distribution<> dist(0, ds_size - 1);
    
            size_t test_set_size = ceil(ds_size * percent_test);
    
            std::vector<unsigned int> test_indices;
            test_indices.reserve(test_set_size);
            for (unsigned int i = 0; i < test_set_size; i++) {
                test_indices.emplace_back(dist(gen));
            }
            std::sort(test_indices.begin(), test_indices.end(), std::greater<unsigned int>());
    
            std::vector<std::pair<std::vector<double>, std::vector<double>>> test_data, train_data;
    
            /* Copy all the data to train_data */
            for(auto e : *this->ds_full->get_data()) {
                train_data.emplace_back(e);
            }
    
            /* Move the testing data from train_data to test_data */
            for(auto ind : test_indices) {
                test_data.emplace_back(train_data.at(ind));
                train_data.erase(train_data.begin() + ind);
            }
    
            /* Re-initialize data set for training */
    
            this->ds = new DataSet(&train_data, this->ds_full->get_normalization_strategy());
    
            /* Initialize test data */
    
            this->ds_test = new DataSet(&test_data, this->ds_full->get_normalization_strategy());
    
        }
    
        void ErrorFunction::return_full_data_set_for_training() {
            if(this->ds_test) {
                this->ds = this->ds_full;
    
        MSE::MSE(NeuralNetwork *net, DataSet *ds) {
            this->net = net;
            this->ds = ds;
            this->dimension = net->get_n_weights() + net->get_n_biases();
    
        double MSE::eval_general(DataSet* data_set, std::vector<double> *weights) {
            size_t dim_out = data_set->get_output_dim();
            size_t n_elements = data_set->get_n_elements();
    
            std::vector<std::pair<std::vector<double>, std::vector<double>>>* data = data_set->get_data();
    
            //TODO instead use something smarter
    
            for (auto el: *data) {  // Iterate through every element in the test set
    
                this->net->eval_single(el.first,
                                       output,
    
                                       weights);  // Compute the net output and store it into 'output' variable
    
                for (size_t j = 0; j < dim_out; ++j) {  // Compute difference for every element of the output vector
                    val = output[j] - el.second[j];
    
                    error += val * val;
                }
            }
            return error / n_elements;
    
        double MSE::eval(std::vector<double> *weights) {
    
            size_t dim_out = this->ds->get_output_dim();
    
            size_t n_elements = this->ds->get_n_elements();
            double error = 0.0, val;
    
            std::vector<std::pair<std::vector<double>, std::vector<double>>> *data = this->ds->get_data();
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    //    //TODO instead use something smarter
    //    this->net->copy_weights(weights);
    
            std::vector<double> output(dim_out);
    
            for (auto el: *data) {  // Iterate through every element in the test set
    
                this->net->eval_single(el.first, output,
                                       weights);  // Compute the net output and store it into 'output' variable
    
                for (size_t j = 0; j < dim_out; ++j) {  // Compute difference for every element of the output vector
    
                    val = output[j] - el.second[j];
                    error += val * val;
                }
            }
            return error / n_elements;
    
        double MSE::eval_on_test_data(std::vector<double> *weights) {
            return this->eval_general(this->ds_test, weights);
        }
    
    //    void MSE::calculate_error_gradient(std::vector<double> &params, std::vector<double> &grad, double alpha) {
    //
    //        size_t dim_out = this->ds->get_output_dim();
    //        size_t n_elements = this->ds->get_n_elements();
    //
    //        std::vector<std::pair<std::vector<double>, std::vector<double>>> *data = this->ds->get_data();
    //
    //        std::vector<double> error_derivative(dim_out);
    //
    //
    //        for (auto el: *data) {  // Iterate through every element in the test set
    //
    //            this->net->eval_single(el.first, error_derivative,
    //                                   &params);  // Compute the net output and store it into 'output' variable
    //
    //            for (size_t j = 0; j < dim_out; ++j) {
    //                error_derivative[j] = 2.0 * (error_derivative[j] - el.second[j]); //real - expected result
    //            }
    //
    //            this->net->add_to_gradient_single(el.first, error_derivative, alpha / n_elements, grad);
    //        }
    //    }
    
    
        void MSE::calculate_error_gradient(std::vector<double> &params, std::vector<double> &grad, double alpha, size_t batch) {
    
            size_t dim_out = this->ds->get_output_dim();
            size_t n_elements = this->ds->get_n_elements();
            std::vector<std::pair<std::vector<double>, std::vector<double>>> *data = this->ds->get_data();
    
            if(batch) {
                *data = this->ds->get_random_data_batch(batch);
                n_elements = data->size();
            }
    
            std::vector<double> error_derivative(dim_out);
    
            for (auto el: *data) {  // Iterate through every element in the test set
    
                this->net->eval_single(el.first, error_derivative,
                                       &params);  // Compute the net output and store it into 'output' variable
    
                for (size_t j = 0; j < dim_out; ++j) {
                    error_derivative[j] = 2.0 * (error_derivative[j] - el.second[j]); //real - expected result
                }
    
                this->net->add_to_gradient_single(el.first, error_derivative, alpha / n_elements, grad);
            }
    
        std::vector<double> *MSE::get_parameters() {
            std::vector<double> *output = new std::vector<double>(this->net->get_n_weights() + this->net->get_n_biases());
    
            size_t i = 0;
    
            for (auto el: *this->net->get_parameter_ptr_weights()) {
                output->at(i) = el;
                ++i;
            }
    
            for (auto el: *this->net->get_parameter_ptr_biases()) {
                output->at(i) = el;
                ++i;
            }
    
            return output;
        }
    
        ErrorSum::ErrorSum() {
            this->summand = nullptr;
            this->summand_coefficient = nullptr;
            this->dimension = 0;
        }
    
        ErrorSum::~ErrorSum() {
            if (this->summand) {
                delete this->summand;
            }
            if (this->summand_coefficient) {
                delete this->summand_coefficient;
    
        double ErrorSum::eval_on_test_data(std::vector<double>* weights) {
            //TODO take care of the case, when there are no test data
    
            double output = 0.0;
            ErrorFunction *ef = nullptr;
    
            for(unsigned int i = 0; i < this->summand->size(); ++i) {
                ef = this->summand->at(i);
    
                if (ef) {
                    output += ef->eval_on_test_data(weights) * this->summand_coefficient->at(i);
                }
    
        double ErrorSum::eval(std::vector<double>* weights) {
    
            ErrorFunction *ef = nullptr;
    
            for (unsigned int i = 0; i < this->summand->size(); ++i) {
    
                ef = this->summand->at(i);
    
                if (ef) {
                    output += ef->eval(weights) * this->summand_coefficient->at(i);
                }
    
        void ErrorSum::calculate_error_gradient(std::vector<double> &params, std::vector<double> &grad, double alpha, size_t batch) {
    
            ErrorFunction *ef = nullptr;
            for (size_t i = 0; i < this->summand->size(); ++i) {
                ef = this->summand->at(i);
    
                if (ef) {
    
                    ef->calculate_error_gradient(params, grad, this->summand_coefficient->at(i) * alpha, batch);
    
        void ErrorSum::add_error_function(ErrorFunction *F, double alpha) {
            if (!this->summand) {
                this->summand = new std::vector<ErrorFunction *>(0);
            }
            this->summand->push_back(F);
    
            if (!this->summand_coefficient) {
                this->summand_coefficient = new std::vector<double>(0);
            }
            this->summand_coefficient->push_back(alpha);
    
    
            if (F) {
                if (F->get_dimension() > this->dimension) {
                    this->dimension = F->get_dimension();
                }
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
        }
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    //    if(!this->dimension) {
    //        size_t max = 0;
    //        for(auto e : *this->summand) {
    //            if(e->get_dimension() > max) {
    //                max = e->get_dimension();
    //            }
    //        };
    //
    //        this->dimension = max;
    //    }
    
        std::vector<double> *ErrorSum::get_parameters() {
            return this->summand->at(0)->get_parameters();
        }