# Algorithms_in_C++: machine_learning Namespace Reference

machine_learning Namespace Reference
Machine Learning Algorithms

Machine learning algorithms. More...

## Classes

class | adaline

## Functions

int | save_u_matrix (const char *fname, const std::vector< std::vector< std::valarray< double >>> &W)
double | update_weights (const std::valarray< double > &X, std::vector< std::vector< std::valarray< double >>> *W, std::vector< std::valarray< double >> *D, double alpha, int R)
void | kohonen_som (const std::vector< std::valarray< double >> &X, std::vector< std::vector< std::valarray< double >>> *W, double alpha_min)
void | update_weights (const std::valarray< double > &x, std::vector< std::valarray< double >> *W, std::valarray< double > *D, double alpha, int R)
void | kohonen_som_tracer (const std::vector< std::valarray< double >> &X, std::vector< std::valarray< double >> *W, double alpha_min)

## Variables

constexpr double | MIN_DISTANCE = 1e-4

## Detailed Description

Machine learning algorithms.

## Function Documentation

## kohonen_som()

void machine_learning::kohonen_som | ( | const std::vector< std::valarray< double >> & | X,
|  | std::vector< std::vector< std::valarray< double >>> * | W,
|  | double | alpha_min
| ) |  |

Apply incremental algorithm with updating neighborhood and learning rates on all samples in the given datset.

Parameters

  [in] | X | data set
  [in,out] | W | weights matrix
  [in] | alpha_min | terminal value of alpha

{
size_t num_samples = X.size(); // number of rows
// size_t num_features = X[0].size(); // number of columns
size_t num_out = W->size(); // output matrix size
size_t R = num_out >> 2, iter = 0;
double alpha = 1.f;
std::vector<std::valarray<double>> D(num_out);
for (int i = 0; i < num_out; i++) D[i] = std::valarray<double>(num_out);
double dmin = 1.f; // average minimum distance of all samples
double past_dmin = 1.f; // average minimum distance of all samples
double dmin_ratio = 1.f; // change per step
// Loop alpha from 1 to slpha_min
for (; alpha > 0 && dmin_ratio > 1e-5; alpha -= 1e-4, iter++) {
// Loop for each sample pattern in the data set
for (int sample = 0; sample < num_samples; sample++) {
// update weights for the current input pattern sample
dmin += update_weights(X[sample], W, &D, alpha, R);
}
// every 100th iteration, reduce the neighborhood range
if (iter % 300 == 0 && R > 1) {
R--;
}
dmin /= num_samples;
// termination condition variable -> % change in minimum distance
dmin_ratio = (past_dmin - dmin) / past_dmin;
if (dmin_ratio < 0) {
dmin_ratio = 1.f;
}
past_dmin = dmin;
std::cout << "iter: " << iter << "\t alpha: " << alpha << "\t R: " << R
<< "\t d_min: " << dmin_ratio << "\r";
}
std::cout << "\n";
}
Here is the call graph for this function:

## kohonen_som_tracer()

void machine_learning::kohonen_som_tracer | ( | const std::vector< std::valarray< double >> & | X,
|  | std::vector< std::valarray< double >> * | W,
|  | double | alpha_min
| ) |  |

Apply incremental algorithm with updating neighborhood and learning rates on all samples in the given datset.

Parameters

  [in] | X | data set
  [in,out] | W | weights matrix
  [in] | alpha_min | terminal value of alpha

{
int num_samples = X.size(); // number of rows
// int num_features = X[0].size(); // number of columns
int num_out = W->size(); // number of rows
int R = num_out >> 2, iter = 0;
double alpha = 1.f;
std::valarray<double> D(num_out);
// Loop alpha from 1 to slpha_min
do {
// Loop for each sample pattern in the data set
for (int sample = 0; sample < num_samples; sample++) {
// update weights for the current input pattern sample
update_weights(X[sample], W, &D, alpha, R);
}
// every 10th iteration, reduce the neighborhood range
if (iter % 10 == 0 && R > 1) {
R--;
}
alpha -= 0.01;
iter++;
} while (alpha > alpha_min);
}
Here is the call graph for this function:

## save_u_matrix()

int machine_learning::save_u_matrix | ( | const char * | fname,
|  | const std::vector< std::vector< std::valarray< double >>> & | W
| ) |  |

Create the distance matrix or U-matrix from the trained 3D weiths matrix and save to disk.

Parameters

  [in] | fname | filename to save in (gets overwriten without confirmation)
  [in] | W | model matrix to save

Returns
  0 if all ok
  -1 if file creation failed

{
std::ofstream fp(fname);
if (!fp) { // error with fopen
std::cerr << "File error (" << fname << "): " << std::strerror(errno)
<< std::endl;
return -1;
}
// neighborhood range
unsigned int R = 1;
for (int i = 0; i < W.size(); i++) { // for each x
for (int j = 0; j < W[0].size(); j++) { // for each y
double distance = 0.f;
int from_x = std::max<int>(0, i - R);
int to_x = std::min<int>(W.size(), i + R + 1);
int from_y = std::max<int>(0, j - R);
int to_y = std::min<int>(W[0].size(), j + R + 1);
int l = 0, m = 0;
#ifdef _OPENMP
#pragma omp parallel for reduction(+ : distance)
#endif
for (l = from_x; l < to_x; l++) { // scan neighborhoor in x
for (m = from_y; m < to_y; m++) { // scan neighborhood in y
auto d = W[i][j] - W[l][m];
double d2 = std::pow(d, 2).sum();
distance += std::sqrt(d2);
// distance += d2;
}
}
distance /= R * R; // mean distance from neighbors
fp << distance; // print the mean separation
if (j < W[0].size() - 1) { // if not the last column
fp << ','; // suffix comma
}
}
if (i < W.size() - 1) { // if not the last row
fp << '\n'; // start a new line
}
}
fp.close();
return 0;
}
Here is the call graph for this function:

## update_weights() [1/2]

void machine_learning::update_weights | ( | const std::valarray< double > & | x,
|  | std::vector< std::valarray< double >> * | W,
|  | std::valarray< double > * | D,
|  | double | alpha,
|  | int | R
| ) |  |

Update weights of the SOM using Kohonen algorithm

Parameters

  [in] | X | data point
  [in,out] | W | weights matrix
  [in,out] | D | temporary vector to store distances
  [in] | alpha | learning rate \(0<\alpha\le1\)
  [in] | R | neighborhood range

{
int j = 0, k = 0;
int num_out = W->size(); // number of SOM output nodes
// int num_features = x.size(); // number of data features
#ifdef _OPENMP
#pragma omp for
#endif
// step 1: for each output point
for (j = 0; j < num_out; j++) {
// compute Euclidian distance of each output
// point from the current sample
(*D)[j] = (((*W)[j] - x) * ((*W)[j] - x)).sum();
}
// step 2: get closest node i.e., node with snallest Euclidian distance to
// the current pattern
auto result = std::min_element(std::begin(*D), std::end(*D));
// double d_min = *result;
int d_min_idx = std::distance(std::begin(*D), result);
// step 3a: get the neighborhood range
int from_node = std::max(0, d_min_idx - R);
int to_node = std::min(num_out, d_min_idx + R + 1);
// step 3b: update the weights of nodes in the
// neighborhood
#ifdef _OPENMP
#pragma omp for
#endif
for (j = from_node; j < to_node; j++) {
// update weights of nodes in the neighborhood
(*W)[j] += alpha * (x - (*W)[j]);
}
}
Here is the call graph for this function:

## update_weights() [2/2]

double machine_learning::update_weights | ( | const std::valarray< double > & | X,
|  | std::vector< std::vector< std::valarray< double >>> * | W,
|  | std::vector< std::valarray< double >> * | D,
|  | double | alpha,
|  | int | R
| ) |  |

Update weights of the SOM using Kohonen algorithm

Parameters

  [in] | X | data point - N features
  [in,out] | W | weights matrix - PxQxN
  [in,out] | D | temporary vector to store distances PxQ
  [in] | alpha | learning rate \(0<\alpha\le1\)
  [in] | R | neighborhood range

Returns
  minimum distance of sample and trained weights

{
int x = 0, y = 0;
int num_out_x = static_cast<int>(W->size()); // output nodes - in X
int num_out_y = static_cast<int>(W[0][0].size()); // output nodes - in Y
// int num_features = static_cast<int>(W[0][0][0].size()); // features =
// in Z
double d_min = 0.f;
#ifdef _OPENMP
#pragma omp for
#endif
// step 1: for each output point
for (x = 0; x < num_out_x; x++) {
for (y = 0; y < num_out_y; y++) {
(*D)[x][y] = 0.f;
// compute Euclidian distance of each output
// point from the current sample
auto d = ((*W)[x][y] - X);
(*D)[x][y] = (d * d).sum();
(*D)[x][y] = std::sqrt((*D)[x][y]);
}
}
// step 2: get closest node i.e., node with snallest Euclidian distance
// to the current pattern
int d_min_x = 0, d_min_y = 0;
get_min_2d(*D, &d_min, &d_min_x, &d_min_y);
// step 3a: get the neighborhood range
int from_x = std::max(0, d_min_x - R);
int to_x = std::min(num_out_x, d_min_x + R + 1);
int from_y = std::max(0, d_min_y - R);
int to_y = std::min(num_out_y, d_min_y + R + 1);
// step 3b: update the weights of nodes in the
// neighborhood
#ifdef _OPENMP
#pragma omp for
#endif
for (x = from_x; x < to_x; x++) {
for (y = from_y; y < to_y; y++) {
/* you can enable the following normalization if needed.
personally, I found it detrimental to convergence */
// const double s2pi = sqrt(2.f * M_PI);
// double normalize = 1.f / (alpha * s2pi);
/* apply scaling inversely proportional to distance from the
current node */
double d2 =
(d_min_x - x) * (d_min_x - x) + (d_min_y - y) * (d_min_y - y);
double scale_factor = std::exp(-d2 / (2.f * alpha * alpha));
(*W)[x][y] += (X - (*W)[x][y]) * alpha * scale_factor;
}
}
return d_min;
}
Here is the call graph for this function:

## Variable Documentation

## MIN_DISTANCE

constexpr double machine_learning::MIN_DISTANCE = 1e-4

constexpr

Minimum average distance of image nodes

machine_learning::update_weights
void update_weights(const std::valarray< double > &x, std::vector< std::valarray< double >> *W, std::valarray< double > *D, double alpha, int R)
Definition: kohonen_som_trace.cpp:103
std::vector
STL class.
std::vector::size
T size(T... args)
std::distance
T distance(T... args)
std::strerror
T strerror(T... args)
machine_learning::update_weights
double update_weights(const std::valarray< double > &X, std::vector< std::vector< std::valarray< double >>> *W, std::vector< std::valarray< double >> *D, double alpha, int R)
Definition: kohonen_som_topology.cpp:200
get_min_2d
void get_min_2d(const std::vector< std::valarray< double >> &X, double *val, int *x_idx, int *y_idx)
Definition: kohonen_som_topology.cpp:105
std::sqrt
T sqrt(T... args)
std::cout
std::ofstream
STL class.
std::min_element
T min_element(T... args)
std::valarray
STL class.
std::min
T min(T... args)
std::endl
T endl(T... args)
std::exp
T exp(T... args)
std::begin
T begin(T... args)
std::end
T end(T... args)
std::max
T max(T... args)
std::pow
T pow(T... args)