mirror of
https://github.com/codeplea/genann.git
synced 2025-10-03 08:42:44 +00:00
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>
277 lines
6.4 KiB
C
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;
|
|
}
|