XCSF  1.4.7
XCSF learning classifier system
neural_layer_connected.c
Go to the documentation of this file.
1 /*
2  * This program is free software: you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation, either version 3 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program. If not, see <http://www.gnu.org/licenses/>.
14  */
15 
24 #include "neural_layer_connected.h"
25 #include "blas.h"
26 #include "neural_activations.h"
27 #include "sam.h"
28 #include "utils.h"
29 
30 #define N_MU (6)
31 
35 static const int MU_TYPE[N_MU] = {
42 };
43 
48 static void
50 {
53  l->state = calloc(l->n_outputs, sizeof(double));
54  l->output = calloc(l->n_outputs, sizeof(double));
55  l->biases = malloc(sizeof(double) * l->n_outputs);
56  l->bias_updates = calloc(l->n_outputs, sizeof(double));
57  l->delta = calloc(l->n_outputs, sizeof(double));
58  l->weight_updates = calloc(l->n_weights, sizeof(double));
59  l->weight_active = malloc(sizeof(bool) * l->n_weights);
60  l->weights = malloc(sizeof(double) * l->n_weights);
61  l->mu = malloc(sizeof(double) * N_MU);
62 }
63 
69 void
70 neural_layer_connected_init(struct Layer *l, const struct ArgsLayer *args)
71 {
72  l->options = layer_args_opt(args);
73  l->function = args->function;
74  l->n_inputs = args->n_inputs;
75  l->n_outputs = args->n_init;
76  l->max_outputs = args->n_max;
77  l->out_w = l->n_outputs;
78  l->out_h = 1;
79  l->out_c = 1;
80  l->n_weights = l->n_inputs * l->n_outputs;
81  l->n_biases = l->n_outputs;
82  l->n_active = l->n_weights;
83  l->eta_max = args->eta;
84  l->eta_min = args->eta_min;
85  l->momentum = args->momentum;
87  l->decay = args->decay;
88  layer_init_eta(l);
90  for (int i = 0; i < l->n_weights; ++i) {
92  l->weight_active[i] = true;
93  }
94  memset(l->biases, 0, sizeof(double) * l->n_biases);
95  sam_init(l->mu, N_MU, MU_TYPE);
96 }
97 
102 void
104 {
105  free(l->state);
106  free(l->output);
107  free(l->biases);
108  free(l->bias_updates);
109  free(l->delta);
110  free(l->weight_updates);
111  free(l->weight_active);
112  free(l->weights);
113  free(l->mu);
114 }
115 
121 struct Layer *
123 {
124  if (src->type != CONNECTED) {
125  printf("neural_layer_connected_copy(): incorrect source layer type\n");
126  exit(EXIT_FAILURE);
127  }
128  struct Layer *l = malloc(sizeof(struct Layer));
129  layer_defaults(l);
130  l->type = src->type;
131  l->layer_vptr = src->layer_vptr;
132  l->function = src->function;
133  l->n_inputs = src->n_inputs;
134  l->n_outputs = src->n_outputs;
135  l->max_outputs = src->max_outputs;
136  l->out_c = src->out_c;
137  l->out_h = src->out_h;
138  l->out_w = src->out_w;
139  l->n_weights = src->n_weights;
140  l->n_biases = src->n_biases;
141  l->options = src->options;
142  l->eta = src->eta;
143  l->eta_max = src->eta_max;
144  l->eta_min = src->eta_min;
145  l->momentum = src->momentum;
146  l->decay = src->decay;
148  l->n_active = src->n_active;
150  memcpy(l->biases, src->biases, sizeof(double) * src->n_biases);
151  memcpy(l->weights, src->weights, sizeof(double) * src->n_weights);
152  memcpy(l->weight_active, src->weight_active, sizeof(bool) * src->n_weights);
153  memcpy(l->mu, src->mu, sizeof(double) * N_MU);
154  return l;
155 }
156 
161 void
163 {
165 }
166 
173 void
174 neural_layer_connected_forward(const struct Layer *l, const struct Net *net,
175  const double *input)
176 {
177  (void) net;
178  const int k = l->n_inputs;
179  const int n = l->n_outputs;
180  const double *a = input;
181  const double *b = l->weights;
182  double *c = l->state;
183  memcpy(l->state, l->biases, sizeof(double) * l->n_outputs);
184  blas_gemm(0, 1, 1, n, k, 1, a, k, b, k, 1, c, n);
186 }
187 
195 void
196 neural_layer_connected_backward(const struct Layer *l, const struct Net *net,
197  const double *input, double *delta)
198 {
199  (void) net;
201  if (l->options & LAYER_SGD_WEIGHTS) {
202  const int m = l->n_outputs;
203  const int n = l->n_inputs;
204  const double *a = l->delta;
205  const double *b = input;
206  double *c = l->weight_updates;
207  blas_axpy(l->n_outputs, 1, l->delta, 1, l->bias_updates, 1);
208  blas_gemm(1, 0, m, n, 1, 1, a, m, b, n, 1, c, n);
209  }
210  if (delta) {
211  const int k = l->n_outputs;
212  const int n = l->n_inputs;
213  const double *a = l->delta;
214  const double *b = l->weights;
215  double *c = delta;
216  blas_gemm(0, 0, 1, n, k, 1, a, k, b, n, 1, c, n);
217  }
218 }
219 
224 void
226 {
227  if (l->options & LAYER_SGD_WEIGHTS && l->eta > 0) {
228  blas_axpy(l->n_biases, l->eta, l->bias_updates, 1, l->biases, 1);
229  blas_scal(l->n_biases, l->momentum, l->bias_updates, 1);
230  if (l->decay > 0) {
231  blas_axpy(l->n_weights, -(l->decay), l->weights, 1,
232  l->weight_updates, 1);
233  }
234  blas_axpy(l->n_weights, l->eta, l->weight_updates, 1, l->weights, 1);
237  }
238 }
239 
245 void
246 neural_layer_connected_resize(struct Layer *l, const struct Layer *prev)
247 {
248  const int n_weights = prev->n_outputs * l->n_outputs;
249  if (n_weights < 1 || n_weights > N_WEIGHTS_MAX) {
250  printf("neural_layer_connected: malloc() invalid resize\n");
251  layer_print(l, false);
252  exit(EXIT_FAILURE);
253  }
254  double *weights = malloc(sizeof(double) * n_weights);
255  double *weight_updates = malloc(sizeof(double) * n_weights);
256  bool *weight_active = malloc(sizeof(bool) * n_weights);
257  for (int i = 0; i < l->n_outputs; ++i) {
258  const int orig_offset = i * l->n_inputs;
259  const int offset = i * prev->n_outputs;
260  for (int j = 0; j < prev->n_outputs; ++j) {
261  if (j < l->n_inputs) {
262  weights[offset + j] = l->weights[orig_offset + j];
263  weight_updates[offset + j] = l->weight_updates[orig_offset + j];
264  weight_active[offset + j] = l->weight_active[orig_offset + j];
265  } else {
266  weights[offset + j] = rand_normal(0, WEIGHT_SD);
267  weight_updates[offset + j] = 0;
268  weight_active[offset + j] = true;
269  }
270  }
271  }
272  free(l->weights);
273  free(l->weight_updates);
274  free(l->weight_active);
275  l->weights = weights;
278  l->n_weights = n_weights;
279  l->n_inputs = prev->n_outputs;
281  if (l->options & LAYER_EVOLVE_CONNECT) {
283  }
284 }
285 
291 bool
293 {
294  sam_adapt(l->mu, N_MU, MU_TYPE);
295  bool mod = false;
296  if ((l->options & LAYER_EVOLVE_ETA) && layer_mutate_eta(l, l->mu[0])) {
297  mod = true;
298  }
299  if (l->options & LAYER_EVOLVE_NEURONS) {
300  const int n = layer_mutate_neurons(l, l->mu[1]);
301  if (n != 0) {
302  layer_add_neurons(l, n);
303  mod = true;
304  }
305  }
306  if ((l->options & LAYER_EVOLVE_CONNECT) &&
307  layer_mutate_connectivity(l, l->mu[2], l->mu[3])) {
309  mod = true;
310  }
311  if ((l->options & LAYER_EVOLVE_WEIGHTS) &&
312  layer_mutate_weights(l, l->mu[4])) {
313  mod = true;
314  }
315  if ((l->options & LAYER_EVOLVE_FUNCTIONS) &&
316  layer_mutate_functions(l, l->mu[5])) {
317  mod = true;
318  }
319  return mod;
320 }
321 
327 double *
329 {
330  return l->output;
331 }
332 
338 void
339 neural_layer_connected_print(const struct Layer *l, const bool print_weights)
340 {
341  char *json_str = neural_layer_connected_json_export(l, print_weights);
342  printf("%s\n", json_str);
343  free(json_str);
344 }
345 
353 char *
355  const bool return_weights)
356 {
357  cJSON *json = cJSON_CreateObject();
358  cJSON_AddStringToObject(json, "type", "connected");
359  cJSON_AddStringToObject(json, "activation",
361  cJSON_AddNumberToObject(json, "n_inputs", l->n_inputs);
362  cJSON_AddNumberToObject(json, "n_outputs", l->n_outputs);
363  cJSON_AddNumberToObject(json, "eta", l->eta);
364  cJSON *mutation = cJSON_CreateDoubleArray(l->mu, N_MU);
365  cJSON_AddItemToObject(json, "mutation", mutation);
366  char *weights_str = layer_weight_json(l, return_weights);
367  cJSON *weights = cJSON_Parse(weights_str);
368  free(weights_str);
369  cJSON_AddItemToObject(json, "weights", weights);
370  char *string = cJSON_Print(json);
371  cJSON_Delete(json);
372  return string;
373 }
374 
381 size_t
382 neural_layer_connected_save(const struct Layer *l, FILE *fp)
383 {
384  size_t s = 0;
385  s += fwrite(&l->n_inputs, sizeof(int), 1, fp);
386  s += fwrite(&l->n_outputs, sizeof(int), 1, fp);
387  s += fwrite(&l->n_biases, sizeof(int), 1, fp);
388  s += fwrite(&l->max_outputs, sizeof(int), 1, fp);
389  s += fwrite(&l->n_weights, sizeof(int), 1, fp);
390  s += fwrite(&l->options, sizeof(uint32_t), 1, fp);
391  s += fwrite(&l->function, sizeof(int), 1, fp);
392  s += fwrite(&l->max_neuron_grow, sizeof(int), 1, fp);
393  s += fwrite(&l->eta, sizeof(double), 1, fp);
394  s += fwrite(&l->eta_max, sizeof(double), 1, fp);
395  s += fwrite(&l->eta_min, sizeof(double), 1, fp);
396  s += fwrite(&l->momentum, sizeof(double), 1, fp);
397  s += fwrite(&l->decay, sizeof(double), 1, fp);
398  s += fwrite(&l->n_active, sizeof(int), 1, fp);
399  s += fwrite(l->weights, sizeof(double), l->n_weights, fp);
400  s += fwrite(l->weight_active, sizeof(bool), l->n_weights, fp);
401  s += fwrite(l->biases, sizeof(double), l->n_biases, fp);
402  s += fwrite(l->bias_updates, sizeof(double), l->n_biases, fp);
403  s += fwrite(l->weight_updates, sizeof(double), l->n_weights, fp);
404  s += fwrite(l->mu, sizeof(double), N_MU, fp);
405  return s;
406 }
407 
414 size_t
415 neural_layer_connected_load(struct Layer *l, FILE *fp)
416 {
417  size_t s = 0;
418  s += fread(&l->n_inputs, sizeof(int), 1, fp);
419  s += fread(&l->n_outputs, sizeof(int), 1, fp);
420  s += fread(&l->n_biases, sizeof(int), 1, fp);
421  s += fread(&l->max_outputs, sizeof(int), 1, fp);
422  s += fread(&l->n_weights, sizeof(int), 1, fp);
423  s += fread(&l->options, sizeof(uint32_t), 1, fp);
424  s += fread(&l->function, sizeof(int), 1, fp);
425  s += fread(&l->max_neuron_grow, sizeof(int), 1, fp);
426  s += fread(&l->eta, sizeof(double), 1, fp);
427  s += fread(&l->eta_max, sizeof(double), 1, fp);
428  s += fread(&l->eta_min, sizeof(double), 1, fp);
429  s += fread(&l->momentum, sizeof(double), 1, fp);
430  s += fread(&l->decay, sizeof(double), 1, fp);
431  s += fread(&l->n_active, sizeof(int), 1, fp);
432  l->out_w = l->n_outputs;
433  l->out_c = 1;
434  l->out_h = 1;
436  s += fread(l->weights, sizeof(double), l->n_weights, fp);
437  s += fread(l->weight_active, sizeof(bool), l->n_weights, fp);
438  s += fread(l->biases, sizeof(double), l->n_biases, fp);
439  s += fread(l->bias_updates, sizeof(double), l->n_biases, fp);
440  s += fread(l->weight_updates, sizeof(double), l->n_weights, fp);
441  s += fread(l->mu, sizeof(double), N_MU, fp);
442  return s;
443 }
void blas_scal(const int N, const double ALPHA, double *X, const int INCX)
Scales vector X by the scalar ALPHA and overwrites it with the result.
Definition: blas.c:160
void blas_axpy(const int N, const double ALPHA, const double *X, const int INCX, double *Y, const int INCY)
Multiplies vector X by the scalar ALPHA and adds it to the vector Y.
Definition: blas.c:138
void blas_gemm(const int TA, const int TB, const int M, const int N, const int K, const double ALPHA, const double *A, const int lda, const double *B, const int ldb, const double BETA, double *C, const int ldc)
Performs the matrix-matrix multiplication: .
Definition: blas.c:108
Basic linear algebra functions.
const char * neural_activation_string(const int a)
Returns the name of a specified activation function.
void neural_gradient_array(const double *state, double *delta, const int n, const int a)
Applies a gradient function to a vector of neuron states.
void neural_activate_array(double *state, double *output, const int n, const int a)
Applies an activation function to a vector of neuron states.
Neural network activation functions.
bool layer_mutate_connectivity(struct Layer *l, const double mu_enable, const double mu_disable)
Mutates a layer's connectivity by zeroing weights.
Definition: neural_layer.c:176
void layer_defaults(struct Layer *l)
Initialises a layer to default values.
Definition: neural_layer.c:413
int layer_mutate_neurons(const struct Layer *l, const double mu)
Returns the number of neurons to add or remove from a layer.
Definition: neural_layer.c:106
bool layer_mutate_functions(struct Layer *l, const double mu)
Mutates a layer's activation function by random selection.
Definition: neural_layer.c:283
char * layer_weight_json(const struct Layer *l, const bool return_weights)
Returns a json formatted string representation of a layer's weights.
Definition: neural_layer.c:324
void layer_weight_clamp(const struct Layer *l)
Clamps a layer's weights and biases in range [WEIGHT_MIN, WEIGHT_MAX].
Definition: neural_layer.c:365
void layer_guard_outputs(const struct Layer *l)
Check number of outputs is within bounds.
Definition: neural_layer.c:595
void layer_weight_rand(struct Layer *l)
Randomises a layer's weights and biases.
Definition: neural_layer.c:348
void layer_add_neurons(struct Layer *l, const int N)
Adds N neurons to a layer. Negative N removes neurons.
Definition: neural_layer.c:130
void layer_ensure_input_represention(struct Layer *l)
Ensures that each neuron is connected to at least one input and each input is connected to at least o...
Definition: neural_layer.c:204
void layer_calc_n_active(struct Layer *l)
Recalculates the number of active connections within a layer.
Definition: neural_layer.c:384
void layer_init_eta(struct Layer *l)
Initialises a layer's gradient descent rate.
Definition: neural_layer.c:399
bool layer_mutate_eta(struct Layer *l, const double mu)
Mutates the gradient descent rate of a neural layer.
Definition: neural_layer.c:88
bool layer_mutate_weights(struct Layer *l, const double mu)
Mutates a layer's weights and biases by adding random numbers from a Gaussian normal distribution wit...
Definition: neural_layer.c:252
void layer_guard_weights(const struct Layer *l)
Check number of weights is within bounds.
Definition: neural_layer.c:609
#define LAYER_EVOLVE_ETA
Layer may evolve rate of gradient descent.
Definition: neural_layer.h:55
#define LAYER_EVOLVE_FUNCTIONS
Layer may evolve functions.
Definition: neural_layer.h:53
#define WEIGHT_SD_INIT
Std dev of Gaussian for weight initialisation.
Definition: neural_layer.h:66
#define LAYER_EVOLVE_WEIGHTS
Layer may evolve weights.
Definition: neural_layer.h:51
#define LAYER_EVOLVE_NEURONS
Layer may evolve neurons.
Definition: neural_layer.h:52
#define LAYER_EVOLVE_CONNECT
Layer may evolve connectivity.
Definition: neural_layer.h:56
#define WEIGHT_SD
Std dev of Gaussian for weight resizing.
Definition: neural_layer.h:67
#define LAYER_SGD_WEIGHTS
Layer may perform gradient descent.
Definition: neural_layer.h:54
static void layer_print(const struct Layer *l, const bool print_weights)
Prints the layer.
Definition: neural_layer.h:270
#define CONNECTED
Layer type connected.
Definition: neural_layer.h:29
#define N_WEIGHTS_MAX
Maximum number of weights per layer.
Definition: neural_layer.h:62
uint32_t layer_args_opt(const struct ArgsLayer *args)
Returns a bitstring representing the permissions granted by a layer.
size_t neural_layer_connected_save(const struct Layer *l, FILE *fp)
Writes a connected layer to a file.
struct Layer * neural_layer_connected_copy(const struct Layer *src)
Initialises and creates a copy of one connected layer from another.
void neural_layer_connected_print(const struct Layer *l, const bool print_weights)
Prints a connected layer.
char * neural_layer_connected_json_export(const struct Layer *l, const bool return_weights)
Returns a json formatted string representation of a connected layer.
void neural_layer_connected_rand(struct Layer *l)
Randomises a connected layer weights.
void neural_layer_connected_resize(struct Layer *l, const struct Layer *prev)
Resizes a connected layer if the previous layer has changed size.
double * neural_layer_connected_output(const struct Layer *l)
Returns the output from a connected layer.
static void malloc_layer_arrays(struct Layer *l)
Allocate memory used by a connected layer.
#define N_MU
Number of mutation rates applied to a connected layer.
static const int MU_TYPE[(6)]
Self-adaptation method for mutating a connected layer.
size_t neural_layer_connected_load(struct Layer *l, FILE *fp)
Reads a connected layer from a file.
void neural_layer_connected_backward(const struct Layer *l, const struct Net *net, const double *input, double *delta)
Backward propagates a connected layer.
bool neural_layer_connected_mutate(struct Layer *l)
Mutates a connected layer.
void neural_layer_connected_forward(const struct Layer *l, const struct Net *net, const double *input)
Forward propagates a connected layer.
void neural_layer_connected_init(struct Layer *l, const struct ArgsLayer *args)
Initialises a fully-connected layer.
void neural_layer_connected_update(const struct Layer *l)
Updates the weights and biases of a connected layer.
void neural_layer_connected_free(const struct Layer *l)
Free memory used by a connected layer.
An implementation of a fully-connected layer of perceptrons.
void sam_init(double *mu, const int N, const int *type)
Initialises self-adaptive mutation rates.
Definition: sam.c:43
void sam_adapt(double *mu, const int N, const int *type)
Self-adapts mutation rates.
Definition: sam.c:68
Self-adaptive mutation functions.
#define SAM_RATE_SELECT
Ten normally distributed rates.
Definition: sam.h:29
Parameters for initialising a neural network layer.
int n_init
Initial number of units / neurons / filters.
double decay
Weight decay for gradient descent.
double momentum
Momentum for gradient descent.
int function
Activation function.
int max_neuron_grow
Maximum number neurons to add per mutation event.
double eta
Gradient descent rate.
double eta_min
Current gradient descent rate.
int n_max
Maximum number of units / neurons.
int n_inputs
Number of inputs.
Neural network layer data structure.
Definition: neural_layer.h:73
double * output
Current neuron outputs (after activation function)
Definition: neural_layer.h:76
double decay
Weight decay for gradient descent.
Definition: neural_layer.h:89
double * state
Current neuron states (before activation function)
Definition: neural_layer.h:75
int max_neuron_grow
Maximum number neurons to add per mutation event.
Definition: neural_layer.h:93
int n_inputs
Number of layer inputs.
Definition: neural_layer.h:90
int n_biases
Number of layer biases.
Definition: neural_layer.h:95
bool * weight_active
Whether each connection is present in the layer.
Definition: neural_layer.h:79
double * weights
Weights for calculating neuron states.
Definition: neural_layer.h:78
double * weight_updates
Updates to weights.
Definition: neural_layer.h:82
double * mu
Mutation rates.
Definition: neural_layer.h:84
int function
Layer activation function.
Definition: neural_layer.h:97
double * c
LSTM.
Definition: neural_layer.h:120
struct LayerVtbl const * layer_vptr
Functions acting on layers.
Definition: neural_layer.h:100
int max_outputs
Maximum number of neurons in the layer.
Definition: neural_layer.h:92
int n_weights
Number of layer weights.
Definition: neural_layer.h:94
double * bias_updates
Updates to biases.
Definition: neural_layer.h:81
double eta_max
Maximum gradient descent rate.
Definition: neural_layer.h:86
double * i
LSTM.
Definition: neural_layer.h:117
int n_outputs
Number of layer outputs.
Definition: neural_layer.h:91
double * biases
Biases for calculating neuron states.
Definition: neural_layer.h:80
int n_active
Number of active weights / connections.
Definition: neural_layer.h:96
int out_w
Pool, Conv, and Upsample.
Definition: neural_layer.h:130
int type
Layer type: CONNECTED, DROPOUT, etc.
Definition: neural_layer.h:74
int out_c
Pool, Conv, and Upsample.
Definition: neural_layer.h:132
double * delta
Delta for updating weights.
Definition: neural_layer.h:83
uint32_t options
Bitwise layer options permitting evolution, SGD, etc.
Definition: neural_layer.h:77
int out_h
Pool, Conv, and Upsample.
Definition: neural_layer.h:131
double eta_min
Minimum gradient descent rate.
Definition: neural_layer.h:87
double eta
Gradient descent rate.
Definition: neural_layer.h:85
double momentum
Momentum for gradient descent.
Definition: neural_layer.h:88
Neural network data structure.
Definition: neural.h:48
double rand_normal(const double mu, const double sigma)
Returns a random Gaussian with specified mean and standard deviation.
Definition: utils.c:87
Utility functions for random number handling, etc.