Files
genann/test.c
Andrew Jeffery db51375bb7 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 22:36:44 +10:30

277 lines
6.4 KiB
C

/*
* GENANN - Minimal C Artificial Neural Network
*
* Copyright (c) 2015, 2016 Lewis Van Winkle
*
* 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.
*
*/
#include "genann.h"
#include "minctest.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
void basic() {
genann *ann = genann_init(1, 0, 0, 1);
lequal(ann->total_weights, 2);
double a;
a = 0;
ann->weight[0] = 0;
ann->weight[1] = 0;
lfequal(0.5, *genann_run(ann, &a));
a = 1;
lfequal(0.5, *genann_run(ann, &a));
a = 11;
lfequal(0.5, *genann_run(ann, &a));
a = 1;
ann->weight[0] = 1;
ann->weight[1] = 1;
lfequal(0.5, *genann_run(ann, &a));
a = 10;
ann->weight[0] = 1;
ann->weight[1] = 1;
lfequal(1.0, *genann_run(ann, &a));
a = -10;
lfequal(0.0, *genann_run(ann, &a));
genann_free(ann);
}
void xor() {
genann *ann = genann_init(2, 1, 2, 1);
ann->activation_hidden = genann_act_threshold;
ann->activation_output = genann_act_threshold;
lequal(ann->total_weights, 9);
/* First hidden. */
ann->weight[0] = .5;
ann->weight[1] = 1;
ann->weight[2] = 1;
/* Second hidden. */
ann->weight[3] = 1;
ann->weight[4] = 1;
ann->weight[5] = 1;
/* Output. */
ann->weight[6] = .5;
ann->weight[7] = 1;
ann->weight[8] = -1;
double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
double output[4] = {0, 1, 1, 0};
lfequal(output[0], *genann_run(ann, input[0]));
lfequal(output[1], *genann_run(ann, input[1]));
lfequal(output[2], *genann_run(ann, input[2]));
lfequal(output[3], *genann_run(ann, input[3]));
genann_free(ann);
}
void backprop() {
genann *ann = genann_init(1, 0, 0, 1);
double input, output;
input = .5;
output = 1;
double first_try = *genann_run(ann, &input);
genann_train(ann, &input, &output, .5);
double second_try = *genann_run(ann, &input);
lok(fabs(first_try - output) > fabs(second_try - output));
genann_free(ann);
}
void train_and() {
double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
double output[4] = {0, 0, 0, 1};
genann *ann = genann_init(2, 0, 0, 1);
int i, j;
for (i = 0; i < 50; ++i) {
for (j = 0; j < 4; ++j) {
genann_train(ann, input[j], output + j, .8);
}
}
ann->activation_output = genann_act_threshold;
lfequal(output[0], *genann_run(ann, input[0]));
lfequal(output[1], *genann_run(ann, input[1]));
lfequal(output[2], *genann_run(ann, input[2]));
lfequal(output[3], *genann_run(ann, input[3]));
genann_free(ann);
}
void train_or() {
double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
double output[4] = {0, 1, 1, 1};
genann *ann = genann_init(2, 0, 0, 1);
genann_randomize(ann);
int i, j;
for (i = 0; i < 50; ++i) {
for (j = 0; j < 4; ++j) {
genann_train(ann, input[j], output + j, .8);
}
}
ann->activation_output = genann_act_threshold;
lfequal(output[0], *genann_run(ann, input[0]));
lfequal(output[1], *genann_run(ann, input[1]));
lfequal(output[2], *genann_run(ann, input[2]));
lfequal(output[3], *genann_run(ann, input[3]));
genann_free(ann);
}
void train_xor() {
double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
double output[4] = {0, 1, 1, 0};
genann *ann = genann_init(2, 1, 2, 1);
int i, j;
for (i = 0; i < 500; ++i) {
for (j = 0; j < 4; ++j) {
genann_train(ann, input[j], output + j, 3);
}
/* printf("%1.2f ", xor_score(ann)); */
}
ann->activation_output = genann_act_threshold;
lfequal(output[0], *genann_run(ann, input[0]));
lfequal(output[1], *genann_run(ann, input[1]));
lfequal(output[2], *genann_run(ann, input[2]));
lfequal(output[3], *genann_run(ann, input[3]));
genann_free(ann);
}
void persist() {
genann *first = genann_init(1000, 5, 50, 10);
FILE *out = fopen("persist.txt", "w");
genann_write(first, out);
fclose(out);
FILE *in = fopen("persist.txt", "r");
genann *second = genann_read(in);
fclose(out);
lequal(first->inputs, second->inputs);
lequal(first->hidden_layers, second->hidden_layers);
lequal(first->hidden, second->hidden);
lequal(first->outputs, second->outputs);
lequal(first->total_weights, second->total_weights);
int i;
for (i = 0; i < first->total_weights; ++i) {
lok(first->weight[i] == second->weight[i]);
}
genann_free(first);
genann_free(second);
}
void copy() {
genann *first = genann_init(1000, 5, 50, 10);
genann *second = genann_copy(first);
lequal(first->inputs, second->inputs);
lequal(first->hidden_layers, second->hidden_layers);
lequal(first->hidden, second->hidden);
lequal(first->outputs, second->outputs);
lequal(first->total_weights, second->total_weights);
int i;
for (i = 0; i < first->total_weights; ++i) {
lfequal(first->weight[i], second->weight[i]);
}
genann_free(first);
genann_free(second);
}
void sigmoid() {
double i = -20;
const double max = 20;
const double d = .0001;
while (i < max) {
lfequal(genann_act_sigmoid(NULL, i), genann_act_sigmoid_cached(NULL, i));
i += d;
}
}
int main(int argc, char *argv[])
{
printf("GENANN TEST SUITE\n");
srand(100);
lrun("basic", basic);
lrun("xor", xor);
lrun("backprop", backprop);
lrun("train and", train_and);
lrun("train or", train_or);
lrun("train xor", train_xor);
lrun("persist", persist);
lrun("copy", copy);
lrun("sigmoid", sigmoid);
lresults();
return lfails != 0;
}