2016-02-10 02:53:54 +03:00
|
|
|
/*
|
|
|
|
* GENANN - Minimal C Artificial Neural Network
|
|
|
|
*
|
2018-07-06 18:50:44 +03:00
|
|
|
* Copyright (c) 2015-2018 Lewis Van Winkle
|
2016-02-10 02:53:54 +03:00
|
|
|
*
|
|
|
|
* http://CodePlea.com
|
|
|
|
*
|
|
|
|
* This software is provided 'as-is', without any express or implied
|
|
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
|
|
* arising from the use of this software.
|
|
|
|
*
|
|
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
|
|
* including commercial applications, and to alter it and redistribute it
|
|
|
|
* freely, subject to the following restrictions:
|
|
|
|
*
|
|
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
|
|
* claim that you wrote the original software. If you use this software
|
|
|
|
* in a product, an acknowledgement in the product documentation would be
|
|
|
|
* appreciated but is not required.
|
|
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
* misrepresented as being the original software.
|
|
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2018-07-08 19:59:37 +03:00
|
|
|
#ifndef GENANN_H
|
|
|
|
#define GENANN_H
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
2016-02-10 04:13:37 +03:00
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
#ifndef GENANN_RANDOM
|
|
|
|
/* We use the following for uniform random numbers between 0 and 1.
|
|
|
|
* If you have a better function, redefine this macro. */
|
|
|
|
#define GENANN_RANDOM() (((double)rand())/RAND_MAX)
|
|
|
|
#endif
|
|
|
|
|
genann: Optionally resolve activation functions at link time
Shave around 94 million instructions and 10 million branches off of execution
trace of example4 if the sigmoid activation function is resolved at link-time.
Before (`make`):
```
Performance counter stats for './example4':
98.988806 task-clock (msec) # 0.998 CPUs utilized
1 context-switches # 0.010 K/sec
0 cpu-migrations # 0.000 K/sec
79 page-faults # 0.798 K/sec
312,298,260 cycles # 3.155 GHz
1,094,183,752 instructions # 3.50 insn per cycle
212,007,732 branches # 2141.734 M/sec
62,774 branch-misses # 0.03% of all branches
0.099228100 seconds time elapsed
```
After:
`make`:
```
Performance counter stats for './example4':
97.335180 task-clock (msec) # 0.998 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
82 page-faults # 0.842 K/sec
306,722,357 cycles # 3.151 GHz
1,065,669,644 instructions # 3.47 insn per cycle
214,256,601 branches # 2201.225 M/sec
60,154 branch-misses # 0.03% of all branches
0.097577079 seconds time elapsed
```
`make sigmoid`:
```
Performance counter stats for './example4':
92.629610 task-clock (msec) # 0.997 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
78 page-faults # 0.842 K/sec
291,863,801 cycles # 3.151 GHz
1,000,931,204 instructions # 3.43 insn per cycle
202,465,800 branches # 2185.757 M/sec
50,949 branch-misses # 0.03% of all branches
0.092889789 seconds time elapsed
```
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
2017-12-18 05:38:30 +03:00
|
|
|
struct genann;
|
2016-02-10 02:53:54 +03:00
|
|
|
|
genann: Optionally resolve activation functions at link time
Shave around 94 million instructions and 10 million branches off of execution
trace of example4 if the sigmoid activation function is resolved at link-time.
Before (`make`):
```
Performance counter stats for './example4':
98.988806 task-clock (msec) # 0.998 CPUs utilized
1 context-switches # 0.010 K/sec
0 cpu-migrations # 0.000 K/sec
79 page-faults # 0.798 K/sec
312,298,260 cycles # 3.155 GHz
1,094,183,752 instructions # 3.50 insn per cycle
212,007,732 branches # 2141.734 M/sec
62,774 branch-misses # 0.03% of all branches
0.099228100 seconds time elapsed
```
After:
`make`:
```
Performance counter stats for './example4':
97.335180 task-clock (msec) # 0.998 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
82 page-faults # 0.842 K/sec
306,722,357 cycles # 3.151 GHz
1,065,669,644 instructions # 3.47 insn per cycle
214,256,601 branches # 2201.225 M/sec
60,154 branch-misses # 0.03% of all branches
0.097577079 seconds time elapsed
```
`make sigmoid`:
```
Performance counter stats for './example4':
92.629610 task-clock (msec) # 0.997 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
78 page-faults # 0.842 K/sec
291,863,801 cycles # 3.151 GHz
1,000,931,204 instructions # 3.43 insn per cycle
202,465,800 branches # 2185.757 M/sec
50,949 branch-misses # 0.03% of all branches
0.092889789 seconds time elapsed
```
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
2017-12-18 05:38:30 +03:00
|
|
|
typedef double (*genann_actfun)(const struct genann *ann, double a);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
2016-02-11 23:38:42 +03:00
|
|
|
typedef struct genann {
|
2016-02-10 02:53:54 +03:00
|
|
|
/* How many inputs, outputs, and hidden neurons. */
|
|
|
|
int inputs, hidden_layers, hidden, outputs;
|
|
|
|
|
|
|
|
/* Which activation function to use for hidden neurons. Default: gennann_act_sigmoid_cached*/
|
2016-02-11 23:38:42 +03:00
|
|
|
genann_actfun activation_hidden;
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Which activation function to use for output. Default: gennann_act_sigmoid_cached*/
|
2016-02-11 23:38:42 +03:00
|
|
|
genann_actfun activation_output;
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Total number of weights, and size of weights buffer. */
|
|
|
|
int total_weights;
|
|
|
|
|
|
|
|
/* Total number of neurons + inputs and size of output buffer. */
|
|
|
|
int total_neurons;
|
|
|
|
|
|
|
|
/* All weights (total_weights long). */
|
|
|
|
double *weight;
|
|
|
|
|
|
|
|
/* Stores input array and output of each neuron (total_neurons long). */
|
|
|
|
double *output;
|
|
|
|
|
|
|
|
/* Stores delta of each hidden and output neuron (total_neurons - inputs long). */
|
|
|
|
double *delta;
|
|
|
|
|
2016-02-11 23:38:42 +03:00
|
|
|
} genann;
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Creates and returns a new ann. */
|
2016-02-11 23:38:42 +03:00
|
|
|
genann *genann_init(int inputs, int hidden_layers, int hidden, int outputs);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Creates ANN from file saved with genann_write. */
|
2016-02-11 23:38:42 +03:00
|
|
|
genann *genann_read(FILE *in);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Sets weights randomly. Called by init. */
|
2016-02-11 23:38:42 +03:00
|
|
|
void genann_randomize(genann *ann);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Returns a new copy of ann. */
|
2016-02-11 23:38:42 +03:00
|
|
|
genann *genann_copy(genann const *ann);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Frees the memory used by an ann. */
|
2016-02-11 23:38:42 +03:00
|
|
|
void genann_free(genann *ann);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Runs the feedforward algorithm to calculate the ann's output. */
|
2016-02-11 23:38:42 +03:00
|
|
|
double const *genann_run(genann const *ann, double const *inputs);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Does a single backprop update. */
|
2016-02-11 23:38:42 +03:00
|
|
|
void genann_train(genann const *ann, double const *inputs, double const *desired_outputs, double learning_rate);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
/* Saves the ann. */
|
2016-02-11 23:38:42 +03:00
|
|
|
void genann_write(genann const *ann, FILE *out);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
genann: Optionally resolve activation functions at link time
Shave around 94 million instructions and 10 million branches off of execution
trace of example4 if the sigmoid activation function is resolved at link-time.
Before (`make`):
```
Performance counter stats for './example4':
98.988806 task-clock (msec) # 0.998 CPUs utilized
1 context-switches # 0.010 K/sec
0 cpu-migrations # 0.000 K/sec
79 page-faults # 0.798 K/sec
312,298,260 cycles # 3.155 GHz
1,094,183,752 instructions # 3.50 insn per cycle
212,007,732 branches # 2141.734 M/sec
62,774 branch-misses # 0.03% of all branches
0.099228100 seconds time elapsed
```
After:
`make`:
```
Performance counter stats for './example4':
97.335180 task-clock (msec) # 0.998 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
82 page-faults # 0.842 K/sec
306,722,357 cycles # 3.151 GHz
1,065,669,644 instructions # 3.47 insn per cycle
214,256,601 branches # 2201.225 M/sec
60,154 branch-misses # 0.03% of all branches
0.097577079 seconds time elapsed
```
`make sigmoid`:
```
Performance counter stats for './example4':
92.629610 task-clock (msec) # 0.997 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
78 page-faults # 0.842 K/sec
291,863,801 cycles # 3.151 GHz
1,000,931,204 instructions # 3.43 insn per cycle
202,465,800 branches # 2185.757 M/sec
50,949 branch-misses # 0.03% of all branches
0.092889789 seconds time elapsed
```
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
2017-12-18 05:38:30 +03:00
|
|
|
void genann_init_sigmoid_lookup(const genann *ann);
|
|
|
|
double genann_act_sigmoid(const genann *ann, double a);
|
|
|
|
double genann_act_sigmoid_cached(const genann *ann, double a);
|
|
|
|
double genann_act_threshold(const genann *ann, double a);
|
|
|
|
double genann_act_linear(const genann *ann, double a);
|
2016-02-10 02:53:54 +03:00
|
|
|
|
|
|
|
|
2016-02-10 04:13:37 +03:00
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
2016-02-10 02:53:54 +03:00
|
|
|
|
2018-07-08 19:59:37 +03:00
|
|
|
#endif /*GENANN_H*/
|