Skip to content
Snippets Groups Projects
net_test_3.cpp 4.81 KiB
Newer Older
  • Learn to ignore specific revisions
  • Michal Kravcenko's avatar
    Michal Kravcenko committed
    /**
    
     * Example testing the correctness of back-propagation implementation
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
    #include <iostream>
    #include <cstdio>
    #include <fstream>
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    #include <vector>
    
    #include <utility>
    #include <algorithm>
    #include <assert.h>
    
    #include <ctime>
    
    David Vojtek's avatar
    David Vojtek committed
    
    
    #include <4neuro.h>
    
    David Vojtek's avatar
    David Vojtek committed
    
    
    #include <boost/random/mersenne_twister.hpp>
    #include <boost/random/uniform_int_distribution.hpp>
    #include <boost/random/uniform_real_distribution.hpp>
    
    Martin Beseda's avatar
    Martin Beseda committed
    double get_difference(std::vector<double>& a,
                          std::vector<double>& b) {
    
    David Vojtek's avatar
    David Vojtek committed
    
    
        double out = 0.0, m;
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
    Martin Beseda's avatar
    Martin Beseda committed
        for (size_t i = 0; i < a.size(); ++i) {
    
    Martin Beseda's avatar
    Martin Beseda committed
            m = a[i] - b[i];
    
            out += m * m;
        }
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
        return std::sqrt(out);
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
    Martin Beseda's avatar
    Martin Beseda committed
    void calculate_gradient_analytical(std::vector<double>& input,
                                       std::vector<double>& parameter_biases,
                                       std::vector<double>& parameter_weights,
                                       size_t n_hidden_neurons,
                                       std::vector<double>& gradient_analytical) {
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
        double      a, b, y, x = input[0];
        for (size_t i          = 0; i < n_hidden_neurons; ++i) {
    
            a = parameter_weights[i];
            b = parameter_biases[i];
            y = parameter_weights[n_hidden_neurons + i];
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
    Martin Beseda's avatar
    Martin Beseda committed
            gradient_analytical[i] += y * x * std::exp(b - a * x) / ((1 + std::exp(b - a * x)) * (1 + std::exp(b - a * x)));
            gradient_analytical[n_hidden_neurons + i] += 1.0 / ((1 + std::exp(b - a * x)));
            gradient_analytical[2 * n_hidden_neurons + i] -=
    
                y * std::exp(b - a * x) / ((1 + std::exp(b - a * x)) * (1 + std::exp(b - a * x)));
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
    Martin Beseda's avatar
    Martin Beseda committed
    int main(int argc,
             char** argv) {
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
        int n_tests          = 2;
    
        try {
            /* Numbers of neurons in layers (including input and output layers) */
            std::vector<unsigned int> neuron_numbers_in_layers(3);
            neuron_numbers_in_layers[0] = neuron_numbers_in_layers[2] = 1;
            neuron_numbers_in_layers[1] = n_hidden_neurons;
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
            /* Fully connected feed-forward network with linear activation functions for input and output */
            /* layers and the specified activation fns for the hidden ones (each entry = layer)*/
    
    Martin Beseda's avatar
    Martin Beseda committed
            std::vector<l4n::NEURON_TYPE> hidden_type_v = {l4n::NEURON_TYPE::LOGISTIC, l4n::NEURON_TYPE::LOGISTIC,
                                                           l4n::NEURON_TYPE::LOGISTIC, l4n::NEURON_TYPE::LOGISTIC,
                                                           l4n::NEURON_TYPE::LOGISTIC}; // hidden_type_v = {l4n::NEURON_TYPE::LOGISTIC, l4n::NEURON_TYPE::LINEAR}
    
            l4n::FullyConnectedFFN        nn1(&neuron_numbers_in_layers,
                                              &hidden_type_v);
    
            nn1.randomize_parameters();
    
            boost::random::mt19937                     gen(std::time(0));
    
    Martin Beseda's avatar
    Martin Beseda committed
            boost::random::uniform_real_distribution<> dist(-1,
                                                            1);
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
            size_t              n_parameters = nn1.get_n_weights() + nn1.get_n_biases();
    
            std::vector<double> gradient_backprogation(n_parameters);
            std::vector<double> gradient_analytical(n_parameters);
    
            std::vector<double>* parameter_biases  = nn1.get_parameter_ptr_biases();
    
    Martin Beseda's avatar
    Martin Beseda committed
            std::vector<double>* parameter_weights = nn1.get_parameter_ptr_weights();
    
            std::vector<double> error_derivative = {1};
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
            size_t n_good = 0, n_bad = 0;
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
    Martin Beseda's avatar
    Martin Beseda committed
            for (int i = 0; i < n_tests; ++i) {
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
                std::vector<double> input(1);
                std::vector<double> output(1);
    
    Michal Kravcenko's avatar
    Michal Kravcenko committed
    
    
                input[0]  = dist(gen);
    
                output[0] = 0;
    
    Martin Beseda's avatar
    Martin Beseda committed
                std::fill(gradient_backprogation.begin(),
                          gradient_backprogation.end(),
                          0);
                std::fill(gradient_analytical.begin(),
                          gradient_analytical.end(),
                          0);
    
    Martin Beseda's avatar
    Martin Beseda committed
                nn1.eval_single(input,
                                output);
    
    Martin Beseda's avatar
    Martin Beseda committed
                calculate_gradient_analytical(input,
                                              *parameter_biases,
                                              *parameter_weights,
                                              n_hidden_neurons,
                                              gradient_analytical);
                nn1.add_to_gradient_single(input,
                                           error_derivative,
                                           1,
                                           gradient_backprogation);
    
    Martin Beseda's avatar
    Martin Beseda committed
                double diff = get_difference(gradient_backprogation,
                                             gradient_analytical);
    
    Martin Beseda's avatar
    Martin Beseda committed
                if (diff < 1e-6) {
    
                    n_good++;
    
    Martin Beseda's avatar
    Martin Beseda committed
                } else {
    
            std::cout << "Good gradients: " << n_good << ", Bad gradients: " << n_bad << std::endl;
    
            return 0;
    
        catch (const std::exception& e) {
            std::cerr << e.what() << std::endl;
            exit(EXIT_FAILURE);