2010-10-30 17:23:51 +02:00
/*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*
* Filename : fsom . c
*
* Description : Manage a self - organizing map ( SOM ) as a neural network
*
* Version : 0.1
* Created : 15 / 10 / 2010 13 : 53 : 31
* Revision : none
* Compiler : gcc
*
* Author : BlackLight ( http : //0x00.ath.cx), <blacklight@autistici.org>
2010-10-31 18:06:29 +01:00
* Contributor : evilsocket ( http : //www.evilsocket.net), <evilsocket@gmail.com>
2010-10-30 17:23:51 +02:00
* Licence : GNU GPL v .3
* Company : DO WHAT YOU WANT CAUSE A PIRATE IS FREE , YOU ARE A PIRATE !
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "fsom.h"
# include <alloca.h>
# include <float.h>
# include <limits.h>
# include <math.h>
# include <memory.h>
# include <stdio.h>
# include <stdlib.h>
# ifndef M_E
# define M_E 2.7182818284590452354
# endif
/**
* \ brief Create a new synapsis between two neurons
* \ param input_neuron Input neuron for the synapsis
* \ param output_neuron Output neuron for the synapsis
* \ param weight Weight of the synapsis ( set it to 0 for a random value between 0 and 1 )
* \ return A pointer representing the new synapsis
*/
static som_synapsis_t *
som_synapsis_new ( som_neuron_t * input_neuron , som_neuron_t * output_neuron , double weight )
{
som_synapsis_t * synapsis = NULL ;
if ( ! ( synapsis = ( som_synapsis_t * ) malloc ( sizeof ( som_synapsis_t ) ) ) )
{
return NULL ;
}
synapsis - > neuron_in = input_neuron ;
synapsis - > neuron_out = output_neuron ;
if ( weight = = 0.0 )
{
synapsis - > weight = ( double ) rand ( ) / ( double ) UINT_MAX ;
} else {
synapsis - > weight = weight ;
}
if ( ! ( input_neuron - > synapses = ( som_synapsis_t * * ) realloc ( input_neuron - > synapses , ( + + ( input_neuron - > synapses_count ) ) * sizeof ( som_synapsis_t ) ) ) )
{
free ( synapsis ) ;
return NULL ;
}
if ( ! ( output_neuron - > synapses = ( som_synapsis_t * * ) realloc ( output_neuron - > synapses , ( + + ( output_neuron - > synapses_count ) ) * sizeof ( som_synapsis_t ) ) ) )
{
free ( synapsis ) ;
return NULL ;
}
input_neuron - > synapses [ input_neuron - > synapses_count - 1 ] = synapsis ;
output_neuron - > synapses [ output_neuron - > synapses_count - 1 ] = synapsis ;
return synapsis ;
} /* ----- end of function som_synapsis_new ----- */
/**
* \ brief Create a new neuron
* \ return The new neuron
*/
2010-10-31 18:06:29 +01:00
# define som_neuron_new() ( som_neuron_t *)calloc( 1, sizeof ( som_neuron_t ) )
/* ----- end of macro som_neuron_new ----- */
2010-10-30 17:23:51 +02:00
/**
* \ brief Deallocate a neuron
* \ param neuron Neuron to be deallocated
*/
2010-10-31 18:06:29 +01:00
# define som_neuron_destroy( neuron ) if( neuron ){ free(neuron); neuron = NULL; }
/* ----- end of macro som_neuron_destroy ----- */
2010-10-30 17:23:51 +02:00
/**
* \ brief Create a new input layer
* \ param neurons_count Number of neurons in the new input layer
* \ return The new layer
*/
static som_input_layer_t *
som_input_layer_new ( size_t neurons_count )
{
size_t i = 0 ,
j = 0 ;
som_input_layer_t * layer = NULL ;
if ( ! ( layer = ( som_input_layer_t * ) malloc ( sizeof ( som_input_layer_t ) ) ) )
{
return NULL ;
}
layer - > neurons_count = neurons_count ;
if ( ! ( layer - > neurons = ( som_neuron_t * * ) malloc ( neurons_count * sizeof ( som_neuron_t * ) ) ) )
{
free ( layer ) ;
return NULL ;
}
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
if ( ! ( layer - > neurons [ i ] = som_neuron_new ( ) ) )
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < i ; + + j )
2010-10-30 17:23:51 +02:00
{
som_neuron_destroy ( layer - > neurons [ j ] ) ;
}
free ( layer - > neurons ) ;
free ( layer ) ;
return NULL ;
}
}
return layer ;
} /* ----- end of function som_input_layer_new ----- */
/**
* \ brief Create a new output layer
* \ param neurons_rows Number of rows in the matrix of output neurons
* \ param neurons_cols Number of cols in the matrix of output neurons
* \ return The new layer
*/
static som_output_layer_t *
som_output_layer_new ( size_t neurons_rows , size_t neurons_cols )
{
size_t i = 0 ,
j = 0 ,
k = 0 ,
l = 0 ;
som_output_layer_t * layer = NULL ;
if ( ! ( layer = ( som_output_layer_t * ) malloc ( sizeof ( som_output_layer_t ) ) ) )
{
return NULL ;
}
layer - > neurons_rows = neurons_rows ;
layer - > neurons_cols = neurons_cols ;
if ( ! ( layer - > neurons = ( som_neuron_t * * * ) malloc ( neurons_rows * neurons_cols * sizeof ( som_neuron_t * * ) ) ) )
{
free ( layer ) ;
return NULL ;
}
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
if ( ! ( layer - > neurons [ i ] = ( som_neuron_t * * ) malloc ( neurons_cols * sizeof ( som_neuron_t * ) ) ) )
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < i ; + + j )
2010-10-30 17:23:51 +02:00
{
free ( layer - > neurons [ j ] ) ;
layer - > neurons [ j ] = NULL ;
}
free ( layer - > neurons ) ;
free ( layer ) ;
return NULL ;
}
}
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < neurons_cols ; + + j )
2010-10-30 17:23:51 +02:00
{
if ( ! ( layer - > neurons [ i ] [ j ] = som_neuron_new ( ) ) )
{
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < i ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( l = 0 ; l < j ; + + l )
2010-10-30 17:23:51 +02:00
{
som_neuron_destroy ( layer - > neurons [ k ] [ l ] ) ;
}
free ( layer - > neurons [ k ] ) ;
layer - > neurons [ k ] = NULL ;
}
free ( layer - > neurons ) ;
return NULL ;
}
}
}
return layer ;
} /* ----- end of function som_output_layer_new ----- */
/**
* \ brief Connect two layers of a neural SOM
* \ param input_layer Reference to the input layer
* \ param output_layer Reference to the output layer
*/
static void
som_connect_layers ( som_input_layer_t * * input_layer , som_output_layer_t * * output_layer )
{
size_t i = 0 ,
j = 0 ,
k = 0 ;
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < ( * output_layer ) - > neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < ( * output_layer ) - > neurons_cols ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < ( * input_layer ) - > neurons_count ; + + k )
2010-10-30 17:23:51 +02:00
{
if ( ! ( som_synapsis_new ( ( * input_layer ) - > neurons [ k ] , ( * output_layer ) - > neurons [ i ] [ j ] , 0.0 ) ) )
{
return ;
}
}
}
}
} /* ----- end of function som_connect_layers ----- */
/**
* \ brief Initialize a new SOM neural network
* \ param input_neurons Number of neurons in the input layer
* \ param output_neurons_rows Number of rows of neurons in the output layer
* \ param output_neurons_cols Number of cols of neurons in the output layer
* \ return The new SOM neural network
*/
som_network_t *
som_network_new ( size_t input_neurons , size_t output_neurons_rows , size_t output_neurons_cols )
{
som_network_t * net = NULL ;
srand ( time ( NULL ) ) ;
2010-10-31 18:06:29 +01:00
if ( ! ( net = ( som_network_t * ) calloc ( 1 , sizeof ( som_network_t ) ) ) )
2010-10-30 17:23:51 +02:00
{
return NULL ;
}
if ( ! ( net - > input_layer = som_input_layer_new ( input_neurons ) ) )
{
free ( net ) ;
return NULL ;
}
if ( ! ( net - > output_layer = som_output_layer_new ( output_neurons_rows , output_neurons_cols ) ) )
{
free ( net - > input_layer ) ;
free ( net ) ;
return NULL ;
}
net - > T_learning_param = 0.0 ;
net - > serialization_time = ( time_t ) 0 ;
som_connect_layers ( & ( net - > input_layer ) , & ( net - > output_layer ) ) ;
return net ;
} /* ----- end of function som_network_new ----- */
/**
* \ brief Deallocate an input layer
* \ param net Network whose input layer should be deallocated
*/
static void
som_input_layer_destroy ( som_network_t * net )
{
size_t i = 0 ,
j = 0 ,
k = 0 ;
if ( ! ( net - > input_layer ) )
{
return ;
}
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < net - > input_layer - > neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < net - > input_layer - > neurons [ i ] - > synapses_count ; + + j )
2010-10-30 17:23:51 +02:00
{
if ( ( int ) j < 0 )
{
break ;
}
if ( net - > input_layer - > neurons [ i ] - > synapses )
{
if ( net - > input_layer - > neurons [ i ] - > synapses [ j ] )
{
if ( net - > input_layer - > neurons [ i ] - > synapses [ j ] - > neuron_out )
{
/* net->input_layer->neurons[i]->synapses[j]->neuron_out->synapses[k]->neuron_in = NULL; */
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < net - > input_layer - > neurons [ i ] - > synapses [ j ] - > neuron_out - > synapses_count ; + + k )
2010-10-30 17:23:51 +02:00
{
if ( net - > input_layer - > neurons [ i ] - > synapses [ j ] - > neuron_out - > synapses [ k ] )
{
net - > input_layer - > neurons [ i ] - > synapses [ j ] - > neuron_out - > synapses [ k ] - > neuron_in = NULL ;
net - > input_layer - > neurons [ i ] - > synapses [ j ] - > neuron_out - > synapses [ k ] = NULL ;
}
}
}
free ( net - > input_layer - > neurons [ i ] - > synapses [ j ] ) ;
net - > input_layer - > neurons [ i ] - > synapses [ j ] = NULL ;
}
free ( net - > input_layer - > neurons [ i ] - > synapses ) ;
net - > input_layer - > neurons [ i ] - > synapses = NULL ;
}
}
som_neuron_destroy ( net - > input_layer - > neurons [ i ] ) ;
}
free ( net - > input_layer - > neurons ) ;
net - > input_layer - > neurons = NULL ;
free ( net - > input_layer ) ;
net - > input_layer = NULL ;
} /* ----- end of function som_input_layer_destroy ----- */
/**
* \ brief Deallocate an output layer
* \ param net Network whose output layer should be deallocated
*/
static void
som_output_layer_destroy ( som_network_t * net )
{
size_t i = 0 ,
j = 0 ,
k = 0 ;
if ( ! ( net - > output_layer ) )
{
return ;
}
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < net - > output_layer - > neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < net - > output_layer - > neurons_cols ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < net - > output_layer - > neurons [ i ] [ j ] - > synapses_count ; + + k )
2010-10-30 17:23:51 +02:00
{
if ( net - > output_layer - > neurons [ i ] [ j ] - > synapses )
{
if ( net - > output_layer - > neurons [ i ] [ j ] - > synapses [ k ] )
{
free ( net - > output_layer - > neurons [ i ] [ j ] - > synapses [ k ] ) ;
net - > output_layer - > neurons [ i ] [ j ] - > synapses [ k ] = NULL ;
}
free ( net - > output_layer - > neurons [ i ] [ j ] - > synapses ) ;
net - > output_layer - > neurons [ i ] [ j ] - > synapses = NULL ;
}
}
som_neuron_destroy ( net - > output_layer - > neurons [ i ] [ j ] ) ;
}
free ( net - > output_layer - > neurons [ i ] ) ;
net - > output_layer - > neurons [ i ] = NULL ;
}
free ( net - > output_layer - > neurons ) ;
net - > output_layer - > neurons = NULL ;
free ( net - > output_layer ) ;
net - > output_layer = NULL ;
} /* ----- end of function som_output_layer_destroy ----- */
/**
* \ brief Deallocate a SOM neural network
* \ param net Network to be deallocated
*/
void
som_network_destroy ( som_network_t * net )
{
if ( ! net )
{
return ;
}
som_input_layer_destroy ( net ) ;
som_output_layer_destroy ( net ) ;
free ( net ) ;
net = NULL ;
} /* ----- end of function som_network_destroy ----- */
/**
* \ brief Set a vector as input for the network
* \ param net SOM neural network
* \ param data Vector to be passed as input for the network
*/
void
som_set_inputs ( som_network_t * net , double * data )
{
size_t i = 0 ;
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < net - > input_layer - > neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
net - > input_layer - > neurons [ i ] - > input = data [ i ] ;
}
} /* ----- end of function som_set_inputs ----- */
/**
* \ brief Get the coordinates of the output neuron closest to the current input data
* \ param net SOM neural network
* \ param x Reference to the X coordinate of the best output neuron
* \ param y Reference to the Y coordinate of the best output neuron
* \ return The value of the module | | X - W | | ( squared euclidean distance ) for the best neuron
*/
double
som_get_best_neuron_coordinates ( som_network_t * net , size_t * x , size_t * y )
{
size_t i = 0 ,
2010-10-31 18:06:29 +01:00
j = 0 ,
k = 0 ;
double mod = 0.0 ,
best_dist = DBL_MAX ;
2010-10-30 17:23:51 +02:00
2010-10-31 18:06:29 +01:00
som_neuron_t * neuron ;
2010-10-30 17:23:51 +02:00
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < net - > output_layer - > neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < net - > output_layer - > neurons_cols ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
mod = 0.0 ;
neuron = net - > output_layer - > neurons [ i ] [ j ] ;
2010-10-30 17:23:51 +02:00
2010-10-31 18:06:29 +01:00
for ( k = 0 ; k < neuron - > synapses_count ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
mod + = pow ( net - > input_layer - > neurons [ k ] - > input - neuron - > synapses [ k ] - > weight , 2 ) ;
2010-10-30 17:23:51 +02:00
}
2010-10-31 18:06:29 +01:00
if ( mod < best_dist )
2010-10-30 17:23:51 +02:00
{
best_dist = mod ;
* x = i ;
* y = j ;
}
}
}
return mod ;
} /* ----- end of function som_get_best_neuron_coordinates ----- */
/**
* \ brief Get the n - th approximated step of the analytic continuation of the Lambert W - function of a real number x ( see " Numerical Evaluation of the Lambert W Function and Application to Generation of Generalized Gaussian Noise With Exponent 1/2 " from Chapeau - Blondeau and Monir , IEEE Transactions on Signal Processing , vol .50 , no .9 , Sep .2002 )
* \ param x Input variable of which we ' re going to compute W [ - 1 ] ( x )
* \ return W [ - 1 ] ( x )
*/
static double
2010-10-31 18:06:29 +01:00
lambert_W1_function ( som_network_t * net , double x )
2010-10-30 17:23:51 +02:00
{
int j = 0 ,
2010-10-30 20:09:03 +02:00
k = 0 ;
2010-10-30 17:23:51 +02:00
2010-10-31 18:06:29 +01:00
double p = 0.0 ,
res = 0.0 ,
k_plus = 0 ,
k_less = 0 ;
2010-10-30 17:23:51 +02:00
p = - sqrt ( 2 * ( M_E * x + 1 ) ) ;
2010-10-31 18:06:29 +01:00
net - > mus [ 0 ] = - 1 ;
net - > mus [ 1 ] = 1 ;
net - > alphas [ 0 ] = 2 ;
net - > alphas [ 1 ] = - 1 ;
for ( k = 2 ; k < TAYLOR_LAMBERT_LAST_ELEMENT ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
net - > alphas [ k ] = 0.0 ;
2010-10-30 17:23:51 +02:00
2010-10-30 20:09:03 +02:00
for ( j = 2 ; j < k ; + + j )
{
2010-10-31 18:06:29 +01:00
net - > alphas [ k ] + = net - > mus [ j ] * net - > mus [ k - j + 1 ] ;
2010-10-30 17:23:51 +02:00
}
2010-10-30 20:09:03 +02:00
k_plus = k + 1 ;
k_less = k - 1 ;
2010-10-31 18:06:29 +01:00
net - > mus [ k ] = ( k_less / k_plus ) *
( ( net - > mus [ k - 2 ] / 2.0 ) + ( net - > alphas [ k - 2 ] / 4.0 ) ) -
( net - > alphas [ k ] / 2.0 ) -
( net - > mus [ ( int ) k_less ] / k_plus ) ;
2010-10-30 17:23:51 +02:00
2010-10-31 18:06:29 +01:00
res + = ( net - > mus [ k ] * pow ( p , k ) ) ;
2010-10-30 17:23:51 +02:00
}
return res ;
} /* ----- end of function lambert_W1_function ----- */
/**
* \ brief Get the learning rate of a step of the learning process in function of the current iteration number
* \ param net SOM neural network
* \ param t Iteration number
* \ param M Maximum value for the learning rate ( in [ 0 : 1 ] )
* \ param N Iteration number after which the function equals the " cutoff " value ( 0.01 ) , i . e . the learning rate becomes almost meaningless
* \ return Learning rate
*/
static double
som_learning_rate ( som_network_t * net , size_t t , double M , size_t N )
{
double value = 0.0 ,
T = 0.0 ,
K = 0.0 ,
W = 0.0 ,
W_arg = 0.0 ;
if ( net - > T_learning_param = = 0.0 )
{
K = ( M * ( double ) N * M_E ) / 0.01 ;
W_arg = - ( ( double ) N ) / K ;
2010-10-31 18:06:29 +01:00
W = lambert_W1_function ( net , W_arg ) ;
2010-10-30 17:23:51 +02:00
T = K * exp ( W ) ;
net - > T_learning_param = T ;
} else {
T = net - > T_learning_param ;
}
value = M * ( ( double ) t / T ) * exp ( 1 - ( ( double ) t / T ) ) ;
return value ;
} /* ----- end of function som_learning_rate ----- */
2010-10-30 20:09:03 +02:00
/**
* \ brief Get the learning rate of a step of the learning process in function of the current iteration number once T_learning_param is set
* \ param net SOM neural network
* \ param t Iteration number
* \ param M Maximum value for the learning rate ( in [ 0 : 1 ] )
* \ param N Iteration number after which the function equals the " cutoff " value ( 0.01 ) , i . e . the learning rate becomes almost meaningless
* \ return Learning rate
*/
2010-10-31 18:06:29 +01:00
INLINE double
2010-10-30 20:09:03 +02:00
som_learning_rate_fast ( som_network_t * net , size_t t , double M , size_t N )
{
2010-10-31 18:06:29 +01:00
double inv_lrate = ( double ) t / net - > T_learning_param ;
return M * inv_lrate * exp ( 1 - inv_lrate ) ;
2010-10-30 20:09:03 +02:00
} /* ----- end of function som_learning_rate ----- */
2010-10-30 17:23:51 +02:00
/**
* \ brief Training iteration for the network given a single input data set
* \ param net SOM neural network
* \ param data Input data
* \ param iter Iteration number
*/
static void
som_train_iteration ( som_network_t * net , double * data , size_t iter )
{
size_t x = 0 ,
y = 0 ,
i = 0 ,
j = 0 ,
k = 0 ,
2010-10-30 20:09:03 +02:00
dist = 0 ,
dist_i ;
2010-10-30 17:23:51 +02:00
2010-10-30 20:09:03 +02:00
double l_rate = 0.0 ,
inv_dist ;
2010-10-30 17:23:51 +02:00
2010-10-30 20:09:03 +02:00
l_rate = som_learning_rate_fast ( net , iter , 0.8 , 200 ) ;
2010-10-30 17:23:51 +02:00
som_set_inputs ( net , data ) ;
som_get_best_neuron_coordinates ( net , & x , & y ) ;
2010-10-30 20:09:03 +02:00
som_neuron_t * neuron ;
for ( i = 0 ; i < net - > output_layer - > neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
dist_i = abs ( x - i ) ;
for ( j = 0 ; j < net - > output_layer - > neurons_cols ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
dist = pow ( dist_i + abs ( y - j ) , 4 ) ;
inv_dist = ( 1.0 / ( ( double ) dist + 1 ) ) * l_rate ;
neuron = net - > output_layer - > neurons [ i ] [ j ] ;
for ( k = 0 ; k < net - > input_layer - > neurons_count ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
neuron - > synapses [ k ] - > weight + = inv_dist * ( net - > input_layer - > neurons [ k ] - > input - neuron - > synapses [ k ] - > weight ) ;
2010-10-30 17:23:51 +02:00
}
}
}
} /* ----- end of function som_train_loop ----- */
/**
* \ brief Initialize the synaptical weights of the network using the algorithm proposed in " Improving the Self-Organization Feature Map Algorithm Using an Efficient Initialization Scheme " , by Su , Liu and Chang , on " Tamkang Journal of Science and Engineering " , vol .5 , no .1 , pp .35 - 48 , 2002
* \ param net SOM neural network
* \ param data Input data set
* \ param n_data Number of vectors in the input set
*/
void
som_init_weights ( som_network_t * net , double * * data , size_t n_data )
{
size_t i = 0 ,
j = 0 ,
k = 0 ,
out_rows = 0 ,
out_cols = 0 ,
in_size = 0 ,
max_i = 0 ,
max_j = 0 ,
medium_i = 0 ,
medium_j = 0 ;
double dist = 0.0 ,
max_dist = 0.0 ;
double * avg_data = NULL ;
if ( ! ( avg_data = ( double * ) alloca ( net - > input_layer - > neurons_count * sizeof ( double ) ) ) )
{
return ;
}
/* Find the couple of data sets with the maximum distance */
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < n_data ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < n_data ; + + j )
2010-10-30 17:23:51 +02:00
{
if ( i ! = j )
{
dist = 0.0 ;
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < net - > input_layer - > neurons_count ; + + k )
2010-10-30 17:23:51 +02:00
{
dist + = fabs ( data [ i ] [ k ] - data [ j ] [ k ] ) ;
}
if ( dist > max_dist )
{
max_dist = dist ;
max_i = i ;
max_j = j ;
}
}
}
}
/* Compute the avg_data vector as the vector containing the average values of (data[max_i], data[max_j]) */
2010-10-30 20:09:03 +02:00
double * max_i_row = data [ max_i ] ,
* max_j_row = data [ max_j ] ;
for ( i = 0 ; i < net - > input_layer - > neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
avg_data [ i ] = fabs ( max_i_row [ i ] + max_j_row [ i ] ) / 2.0 ;
2010-10-30 17:23:51 +02:00
}
/* Initialize the upper-right and bottom-left vertex of the output matrix with these values */
2010-10-30 20:09:03 +02:00
som_neuron_t * ur_neuron = net - > output_layer - > neurons [ 0 ] [ net - > output_layer - > neurons_cols - 1 ] ,
* bl_neuron = net - > output_layer - > neurons [ net - > output_layer - > neurons_rows - 1 ] [ 0 ] ;
for ( i = 0 ; i < net - > input_layer - > neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
ur_neuron - > synapses [ i ] - > weight = max_i_row [ i ] ;
bl_neuron - > synapses [ i ] - > weight = max_j_row [ i ] ;
2010-10-30 17:23:51 +02:00
}
/* Find the vector having the maximum distance from the maximum distance vectors */
max_dist = DBL_MAX ;
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < n_data ; + + i )
2010-10-30 17:23:51 +02:00
{
if ( i ! = max_i & & i ! = max_j )
{
dist = 0.0 ;
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < net - > input_layer - > neurons_count ; + + k )
2010-10-30 17:23:51 +02:00
{
dist + = fabs ( data [ i ] [ k ] - avg_data [ i ] ) ;
if ( dist < max_dist )
{
max_dist = dist ;
medium_i = i ;
}
}
}
}
2010-10-30 20:09:03 +02:00
double * med_i_row = data [ medium_i ] ;
2010-10-30 17:23:51 +02:00
/* Initialize the upper-left corner with the values of this vector */
2010-10-30 20:09:03 +02:00
som_neuron_t * ul_neuron = net - > output_layer - > neurons [ 0 ] [ 0 ] ;
for ( i = 0 ; i < net - > input_layer - > neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
ul_neuron - > synapses [ i ] - > weight = med_i_row [ i ] ;
2010-10-30 17:23:51 +02:00
}
/* avg_data contains the average values of the 3 vectors computed above */
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < net - > input_layer - > neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
avg_data [ i ] = fabs ( max_i_row [ i ] + max_j_row [ i ] + med_i_row [ i ] ) / 3.0 ;
2010-10-30 17:23:51 +02:00
}
/* Find the vector having the maximum distance from the 3 vectors above */
max_dist = DBL_MAX ;
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < n_data ; + + i )
2010-10-30 17:23:51 +02:00
{
if ( i ! = max_i & & i ! = max_j & & i ! = medium_i )
{
dist = 0.0 ;
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < net - > input_layer - > neurons_count ; + + k )
2010-10-30 17:23:51 +02:00
{
dist + = fabs ( data [ i ] [ k ] - avg_data [ i ] ) ;
if ( dist < max_dist )
{
max_dist = dist ;
medium_j = i ;
}
}
}
}
2010-10-30 20:09:03 +02:00
double * med_j_row = data [ medium_j ] ;
2010-10-30 17:23:51 +02:00
/* Initialize the bottom-right corner with the values of this vector */
2010-10-30 20:09:03 +02:00
som_neuron_t * br_neuron = net - > output_layer - > neurons [ net - > output_layer - > neurons_rows - 1 ] [ net - > output_layer - > neurons_cols - 1 ] ;
for ( i = 0 ; i < net - > input_layer - > neurons_count ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
br_neuron - > synapses [ i ] - > weight = med_j_row [ i ] ;
2010-10-30 17:23:51 +02:00
}
/* Initialize the weights on the 4 edges */
out_rows = net - > output_layer - > neurons_rows ;
out_cols = net - > output_layer - > neurons_cols ;
in_size = net - > input_layer - > neurons_count ;
2010-10-30 20:09:03 +02:00
som_neuron_t * * edges = net - > output_layer - > neurons [ 0 ] ;
size_t last_out_col = out_cols - 1 ,
span_cols ;
double a , b ;
for ( j = 1 ; j < out_cols - 1 ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
span_cols = out_cols - j ;
a = ( ( double ) ( j - 1 ) / last_out_col ) ;
b = ( ( double ) span_cols / ( double ) last_out_col ) ;
for ( k = 0 ; k < in_size ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
edges [ j ] - > synapses [ k ] - > weight =
a * edges [ last_out_col ] - > synapses [ k ] - > weight +
b * ul_neuron - > synapses [ k ] - > weight ;
2010-10-30 17:23:51 +02:00
}
}
2010-10-31 18:06:29 +01:00
size_t last_out_row = out_rows - 1 ;
som_neuron_t * j_neuron ,
* br_edge = net - > output_layer - > neurons [ last_out_row ] [ last_out_col ] ,
* bl_edge = net - > output_layer - > neurons [ last_out_row ] [ 0 ] ;
2010-10-30 20:09:03 +02:00
for ( j = 1 ; j < out_cols - 1 ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
j_neuron = net - > output_layer - > neurons [ last_out_row ] [ j ] ;
a = ( double ) ( j - 1 ) / ( double ) last_out_col ;
b = ( double ) ( out_cols - j ) / ( double ) last_out_col ;
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < in_size ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
j_neuron - > synapses [ k ] - > weight = a * br_edge - > synapses [ k ] - > weight + b * bl_edge - > synapses [ k ] - > weight ;
2010-10-30 17:23:51 +02:00
}
}
2010-10-31 18:06:29 +01:00
som_neuron_t * i_neuron ,
* tl_edge = net - > output_layer - > neurons [ 0 ] [ 0 ] ;
2010-10-30 20:09:03 +02:00
for ( i = 1 ; i < out_rows - 1 ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
i_neuron = net - > output_layer - > neurons [ i ] [ 0 ] ;
a = ( ( ( double ) i - 1 ) / ( double ) last_out_row ) ;
b = ( ( double ) ( out_rows - i ) / ( double ) last_out_row ) ;
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < in_size ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
i_neuron - > synapses [ k ] - > weight = a * bl_edge - > synapses [ k ] - > weight + b * tl_edge - > synapses [ k ] - > weight ;
2010-10-30 17:23:51 +02:00
}
}
2010-10-31 18:06:29 +01:00
som_neuron_t * tr_edge = net - > output_layer - > neurons [ 0 ] [ last_out_col ] ;
2010-10-30 20:09:03 +02:00
for ( i = 1 ; i < out_rows - 1 ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
i_neuron = net - > output_layer - > neurons [ i ] [ last_out_col ] ;
a = ( ( ( double ) i - 1 ) / ( ( double ) last_out_row ) ) ;
b = ( ( double ) ( out_rows - i ) / ( ( double ) last_out_row ) ) ;
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < in_size ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
i_neuron - > synapses [ k ] - > weight = a * br_edge - > synapses [ k ] - > weight + b * tr_edge - > synapses [ k ] - > weight ;
2010-10-30 17:23:51 +02:00
}
}
/* Initialize the weights in the middle of the matrix */
2010-10-31 18:06:29 +01:00
som_neuron_t * ij_neuron ;
double sqr_index = ( double ) last_out_row * ( double ) last_out_col ,
prev_i ,
prev_j ,
prev_out_rows ,
prev_out_cols ,
c ,
d ;
2010-10-30 20:09:03 +02:00
for ( i = 1 ; i < out_rows - 1 ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
prev_i = i - 1 ;
prev_out_rows = out_rows - i ;
2010-10-30 20:09:03 +02:00
for ( j = 1 ; j < out_cols - 1 ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
prev_j = j - 1 ;
ij_neuron = net - > output_layer - > neurons [ i ] [ j ] ;
prev_out_cols = out_cols - j ;
a = ( prev_j * prev_i ) / sqr_index ;
b = ( prev_j * prev_out_rows ) / sqr_index ;
c = ( prev_out_cols * prev_i ) / sqr_index ;
d = ( prev_out_cols * prev_out_rows ) / sqr_index ;
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < in_size ; + + k )
2010-10-30 17:23:51 +02:00
{
2010-10-31 18:06:29 +01:00
ij_neuron - > synapses [ k ] - > weight =
a *
br_edge - > synapses [ k ] - > weight +
b *
tr_edge - > synapses [ k ] - > weight +
c *
bl_edge - > synapses [ k ] - > weight +
d *
tl_edge - > synapses [ k ] - > weight ;
2010-10-30 17:23:51 +02:00
}
}
}
} /* ----- end of function som_init_weights ----- */
/**
* \ brief Train the self - organizing map through a data set
* \ param net SOM neural network
* \ param data Data set ( set of input vectors )
* \ param n_data Number of input vectors in data
* \ param iter Number of iterations
*/
void
som_train ( som_network_t * net , double * * data , size_t n_data , size_t iter )
{
size_t n = 0 ,
k = 0 ,
x = 0 ,
y = 0 ;
2010-10-30 20:09:03 +02:00
som_learning_rate ( net , iter , 0.8 , 200 ) ;
2010-10-30 17:23:51 +02:00
2010-10-30 20:09:03 +02:00
for ( n = 0 ; n < n_data ; + + n )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( k = 1 ; k < = iter ; + + k )
2010-10-30 17:23:51 +02:00
{
som_train_iteration ( net , data [ n ] , k ) ;
if ( som_get_best_neuron_coordinates ( net , & x , & y ) = = 0.0 )
break ;
}
}
} /* ----- end of function som_train ----- */
/**
* \ brief Serialize a neural network on a binary file
* \ param net SOM network to be serialized
* \ param fname Output file name
*/
void
som_serialize ( som_network_t * net , const char * fname )
{
FILE * fp = NULL ;
size_t i = 0 ,
j = 0 ,
k = 0 ;
if ( ! ( fp = fopen ( fname , " w " ) ) )
{
return ;
}
net - > serialization_time = time ( NULL ) ;
fwrite ( & ( net - > serialization_time ) , sizeof ( time_t ) , 1 , fp ) ;
fwrite ( & ( net - > T_learning_param ) , sizeof ( double ) , 1 , fp ) ;
fwrite ( & ( net - > input_layer - > neurons_count ) , sizeof ( size_t ) , 1 , fp ) ;
fwrite ( & ( net - > output_layer - > neurons_rows ) , sizeof ( size_t ) , 1 , fp ) ;
fwrite ( & ( net - > output_layer - > neurons_cols ) , sizeof ( size_t ) , 1 , fp ) ;
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < net - > output_layer - > neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < net - > output_layer - > neurons_cols ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < net - > output_layer - > neurons [ i ] [ j ] - > synapses_count ; + + k )
2010-10-30 17:23:51 +02:00
{
fwrite ( & ( net - > output_layer - > neurons [ i ] [ j ] - > synapses [ k ] - > weight ) , sizeof ( double ) , 1 , fp ) ;
}
}
}
fclose ( fp ) ;
} /* ----- end of function som_serialize ----- */
/**
* \ brief Initialize a SOM neural network from a serialized one on a file
* \ param fname Binary file containing the network
* \ return The initialized network in case of success , NULL otherwise
*/
som_network_t *
som_deserialize ( const char * fname )
{
som_network_t * net = NULL ;
FILE * fp = NULL ;
double weight = 0.0 ;
size_t i = 0 ,
j = 0 ,
k = 0 ,
input_neurons = 0 ,
output_neurons_rows = 0 ,
output_neurons_cols = 0 ;
if ( ! ( fp = fopen ( fname , " r " ) ) )
{
return NULL ;
}
2010-10-31 18:06:29 +01:00
if ( ! ( net = ( som_network_t * ) calloc ( 1 , sizeof ( som_network_t ) ) ) )
2010-10-30 17:23:51 +02:00
{
return NULL ;
}
fread ( & ( net - > serialization_time ) , sizeof ( time_t ) , 1 , fp ) ;
fread ( & ( net - > T_learning_param ) , sizeof ( double ) , 1 , fp ) ;
fread ( & input_neurons , sizeof ( size_t ) , 1 , fp ) ;
fread ( & output_neurons_rows , sizeof ( size_t ) , 1 , fp ) ;
fread ( & output_neurons_cols , sizeof ( size_t ) , 1 , fp ) ;
if ( ! ( net - > input_layer = som_input_layer_new ( input_neurons ) ) )
{
free ( net ) ;
return NULL ;
}
if ( ! ( net - > output_layer = som_output_layer_new ( output_neurons_rows , output_neurons_cols ) ) )
{
free ( net - > input_layer ) ;
free ( net ) ;
return NULL ;
}
2010-10-30 20:09:03 +02:00
for ( i = 0 ; i < output_neurons_rows ; + + i )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( j = 0 ; j < output_neurons_cols ; + + j )
2010-10-30 17:23:51 +02:00
{
2010-10-30 20:09:03 +02:00
for ( k = 0 ; k < input_neurons ; + + k )
2010-10-30 17:23:51 +02:00
{
fread ( & weight , sizeof ( double ) , 1 , fp ) ;
if ( ! ( som_synapsis_new ( net - > input_layer - > neurons [ k ] , net - > output_layer - > neurons [ i ] [ j ] , weight ) ) )
{
som_input_layer_destroy ( net ) ;
som_output_layer_destroy ( net ) ;
return NULL ;
}
}
}
}
return net ;
} /* ----- end of function som_deserialize ----- */