Newer
Older
/**
* DESCRIPTION OF THE FILE
*
* @author Michal Kravčenko

Michal Kravcenko
committed
#include <random.hpp>
#include "message.h"

Michal Kravcenko
committed
GradientDescent::GradientDescent(double epsilon,
size_t n_to_restart,
int max_iters,
size_t batch) {
this->maximum_niters = max_iters;
this->batch = batch;

Michal Kravcenko
committed
}

Michal Kravcenko
committed
}
void GradientDescent::eval_step_size_mk(double& gamma,
Martin Beseda
committed
double beta,
Martin Beseda
committed
double grad_norm_prev,
double grad_norm,
double fi,
double fim) {

Michal Kravcenko
committed
if (fi > fim) {
c /= 1.0000005;
} else if (fi < fim) {
c *= 1.0000005;
}
gamma *= std::pow(c,
1.0 - 2.0 * beta) * std::pow(grad_norm_prev / grad_norm,
1.0 / c);

Michal Kravcenko
committed

Michal Kravcenko
committed

Michal Kravcenko
committed
bool GradientDescent::perform_feasible_1D_step(
lib4neuro::ErrorFunction& ef,
double error_previous,
double step_coefficient,
std::shared_ptr<std::vector<double>> direction,
std::shared_ptr<std::vector<double>> parameters_before,
std::shared_ptr<std::vector<double>> parameters_after

Michal Kravcenko
committed
size_t i;
boost::random::mt19937 gen(std::time(0));
boost::random::uniform_int_distribution<> dis(0,
direction->size());

Michal Kravcenko
committed
double error_current = error_previous + 1.0;
while (error_current >= error_previous) {
(*parameters_after)[max_dir_idx] =
(*parameters_before)[max_dir_idx] - step_coefficient * (*direction)[max_dir_idx];

Michal Kravcenko
committed
error_current = ef.eval(parameters_after.get());
if (step_coefficient < 1e-32) {

Michal Kravcenko
committed
for (i = 0; i < direction->size(); ++i) {
(*parameters_after)[i] = (*parameters_before)[i] - step_coefficient * (*direction)[i];
}
return false;
} else {
if (error_current >= error_previous) {

Michal Kravcenko
committed
step_coefficient *= 0.5;

Michal Kravcenko
committed
}
}
}
return true;
}
void GradientDescent::optimize(lib4neuro::ErrorFunction& ef,
std::ofstream* ofs) {

Michal Kravcenko
committed
COUT_INFO("Finding a solution via a Gradient Descent method with adaptive step-length..." << std::endl);
COUT_INFO("Initial error: " << err_ << std::endl);
if (ofs && ofs->is_open() && lib4neuro::mpi_rank == 0) {
Martin Beseda
committed
*ofs << "Finding a solution via a Gradient Descent method with adaptive step-length..." << std::endl;
*ofs << "Initial error: " << err_ << std::endl;
Martin Beseda
committed
}
double grad_norm = this->tolerance * 10.0, gamma, sx, beta;
double grad_norm_prev;
size_t i;
long long int iter_idx = this->maximum_niters;
size_t iter_counter = 0;

Michal Kravcenko
committed

Michal Kravcenko
committed
size_t n_parameters = ef.get_dimension();

Michal Kravcenko
committed
std::vector<double>* gradient_current(new std::vector<double>(n_parameters));
std::vector<double>* gradient_prev(new std::vector<double>(n_parameters));
std::vector<double>* params_current = new std::vector<double>(ef.get_parameters());
std::vector<double>* params_prev(new std::vector<double>(n_parameters));
std::vector<double>* ptr_mem;

Michal Kravcenko
committed
std::fill(gradient_current->begin(),
gradient_current->end(),
0.0);
std::fill(gradient_prev->begin(),
gradient_prev->end(),
0.0);

Michal Kravcenko
committed
val = ef.eval(params_current);

Michal Kravcenko
committed
size_t counter_good_guesses = 0, counter_bad_guesses = 0, counter_simplified_direction_good = 0, counter_simplified_direction_bad = 0;
while (grad_norm > this->tolerance && (iter_idx != 0)) {
iter_idx--;
iter_counter++;

Michal Kravcenko
committed
std::fill(gradient_current->begin(),
gradient_current->end(),
0.0);
ef.calculate_error_gradient(*params_current,
*gradient_current,
1.0,
this->batch);

Michal Kravcenko
committed
grad_norm = 0.0;
for (auto v: *gradient_current) {
grad_norm += v * v;
}
grad_norm = std::sqrt(grad_norm);
/* Update of the parameters */
/* step length calculation */
if (iter_counter < 10 || iter_counter % this->restart_frequency == 0) {

Michal Kravcenko
committed
cooling = 1.0;
} else {
/* angle between two consecutive gradients */
for (i = 0; i < gradient_current->size(); ++i) {
sx += (gradient_current->at(i) * gradient_prev->at(i));
}
sx /= grad_norm * grad_norm_prev;

Michal Kravcenko
committed
sx = -1 + 5e-12;

Michal Kravcenko
committed
sx = 1 - 5e-12;
}
beta = std::sqrt(std::acos(sx) / lib4neuro::PI);
eval_step_size_mk(gamma,
beta,
c,
grad_norm_prev,
grad_norm,
val,
prev_val);

Michal Kravcenko
committed
for (i = 0; i < gradient_current->size(); ++i) {

Michal Kravcenko
committed
(*params_prev)[i] = (*params_current)[i] - cooling * gamma * (*gradient_current)[i];

Michal Kravcenko
committed
}

Michal Kravcenko
committed

Michal Kravcenko
committed
ptr_mem = gradient_prev;
gradient_prev = gradient_current;
ptr_mem = params_prev;
params_prev = params_current;

Michal Kravcenko
committed
COUT_DEBUG(std::string("Iteration: ") << (unsigned int) (iter_counter)

Michal Kravcenko
committed
<< ". Step size: " << gamma * cooling
<< ". C: " << c
<< ". Gradient norm: " << grad_norm
<< ". Total error: " << val
Martin Beseda
committed
WRITE_TO_OFS_DEBUG(ofs,
"Iteration: " << (unsigned int) (iter_counter)
<< ". Step size: " << gamma * cooling
<< ". C: " << c
<< ". Gradient norm: " << grad_norm
<< ". Total error: " << val
<< "." << std::endl);
Martin Beseda
committed

Michal Kravcenko
committed
cooling *= 0.9999;
Martin Beseda
committed

Michal Kravcenko
committed
}
COUT_DEBUG(std::string("Iteration: ") << (unsigned int) (iter_counter)

Michal Kravcenko
committed
<< ". Step size: " << gamma
<< ". C: " << c
<< ". Gradient norm: " << grad_norm
<< ". Total error: " << val
<< "." << std::endl);
COUT_DEBUG("Number of total steps: " << counter_bad_guesses + counter_good_guesses << ", good: "
<< counter_good_guesses << ", bad: " << counter_bad_guesses
<< ", from which "
<< counter_simplified_direction_good + counter_simplified_direction_bad
<< " were attempted by simplified direction, success: "
<< counter_simplified_direction_good << ", fail: "
<< counter_simplified_direction_bad << std::endl << std::endl);
if (iter_idx == 0) {
COUT_INFO(std::endl << "Maximum number of iterations (" << this->maximum_niters
<< ") was reached! Final error: " << val << std::endl);
if (ofs && ofs->is_open() && lib4neuro::mpi_rank == 0) {
*ofs << "Maximum number of iterations (" << this->maximum_niters << ") was reached! Final error: "
<< val << std::endl;
Martin Beseda
committed
}
} else {

Michal Kravcenko
committed
COUT_INFO(std::endl << "Gradient Descent method converged after "
<< this->maximum_niters - iter_idx
<< " iterations. Final error:" << val
<< std::endl);
Martin Beseda
committed
#ifdef L4N_DEBUG
if (ofs && ofs->is_open() && lib4neuro::mpi_rank == 0) {
Martin Beseda
committed
*ofs << "Gradient Descent method converged after "
<< std::endl;
Martin Beseda
committed
}
#endif

Michal Kravcenko
committed
Martin Beseda
committed
this->optimal_parameters = *params_current;
ef.set_parameters(this->optimal_parameters);
delete gradient_current;
delete gradient_prev;
delete params_current;
delete params_prev;

Michal Kravcenko
committed
}