90% accuracy

This commit is contained in:
Gustav Louw 2018-03-27 00:16:37 -07:00
parent 39352c3809
commit ab10629287
3 changed files with 54 additions and 84 deletions

128
Genann.h
View File

@ -30,7 +30,6 @@
#pragma once #pragma once
#include <stdio.h>
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
@ -76,7 +75,7 @@ static inline double genann_act_sigmoid_cached(double a)
// delete this entire function and replace references // delete this entire function and replace references
// of genann_act_sigmoid_cached to genann_act_sigmoid. // of genann_act_sigmoid_cached to genann_act_sigmoid.
const double min = -15.0; const double min = -15.0;
const double max = 15.0; const double max = +15.0;
static double interval; static double interval;
static int initialized = 0; static int initialized = 0;
static double lookup[4096]; static double lookup[4096];
@ -137,7 +136,7 @@ static inline Genann *genann_init(int inputs, int hidden_layers, int hidden, int
const int total_neurons = inputs + hidden * hidden_layers + outputs; const int total_neurons = inputs + hidden * hidden_layers + outputs;
// Allocate extra size for weights, outputs, and deltas. // Allocate extra size for weights, outputs, and deltas.
const int size = sizeof(Genann) + sizeof(double) * (total_weights + total_neurons + (total_neurons - inputs)); const int size = sizeof(Genann) + sizeof(double) * (total_weights + total_neurons + (total_neurons - inputs));
Genann *ret = malloc(size); Genann* ret = (Genann*) malloc(size);
if(!ret) if(!ret)
return 0; return 0;
ret->inputs = inputs; ret->inputs = inputs;
@ -147,7 +146,7 @@ static inline Genann *genann_init(int inputs, int hidden_layers, int hidden, int
ret->total_weights = total_weights; ret->total_weights = total_weights;
ret->total_neurons = total_neurons; ret->total_neurons = total_neurons;
// Set pointers. // Set pointers.
ret->weight = (double*)((char*)ret + sizeof(Genann)); ret->weight = (double*) ((char*) ret + sizeof(Genann));
ret->output = ret->weight + ret->total_weights; ret->output = ret->weight + ret->total_weights;
ret->delta = ret->output + ret->total_neurons; ret->delta = ret->output + ret->total_neurons;
genann_randomize(ret); genann_randomize(ret);
@ -162,35 +161,10 @@ static inline void genann_free(Genann *ann)
free(ann); free(ann);
} }
static inline Genann *genann_read(FILE *in)
{
int inputs, hidden_layers, hidden, outputs;
errno = 0;
int rc = fscanf(in, "%d %d %d %d", &inputs, &hidden_layers, &hidden, &outputs);
if(rc < 4 || errno != 0)
{
perror("fscanf");
return NULL;
}
Genann *ann = genann_init(inputs, hidden_layers, hidden, outputs);
for(int i = 0; i < ann->total_weights; ++i)
{
errno = 0;
rc = fscanf(in, " %le", ann->weight + i);
if(rc < 1 || errno != 0)
{
perror("fscanf");
genann_free(ann);
return NULL;
}
}
return ann;
}
static inline Genann *genann_copy(Genann const *ann) static inline Genann *genann_copy(Genann const *ann)
{ {
const int size = sizeof(Genann) + sizeof(double) * (ann->total_weights + ann->total_neurons + (ann->total_neurons - ann->inputs)); const int size = sizeof(Genann) + sizeof(double) * (ann->total_weights + ann->total_neurons + (ann->total_neurons - ann->inputs));
Genann *ret = malloc(size); Genann* ret = (Genann*) malloc(size);
if(!ret) if(!ret)
return 0; return 0;
memcpy(ret, ann, size); memcpy(ret, ann, size);
@ -218,9 +192,7 @@ static inline double const *genann_run(Genann const *ann, double const *inputs)
{ {
double sum = *w++ * -1.0; double sum = *w++ * -1.0;
for(int k = 0; k < (h == 0 ? ann->inputs : ann->hidden); ++k) for(int k = 0; k < (h == 0 ? ann->inputs : ann->hidden); ++k)
{
sum += *w++ * i[k]; sum += *w++ * i[k];
}
*o++ = act(sum); *o++ = act(sum);
} }
i += (h == 0 ? ann->inputs : ann->hidden); i += (h == 0 ? ann->inputs : ann->hidden);
@ -253,20 +225,14 @@ static inline void genann_train(Genann const *ann, double const *inputs, double
double const *t = desired_outputs; double const *t = desired_outputs;
// Set output layer deltas. // Set output layer deltas.
if(ann->activation_output == genann_act_linear) if(ann->activation_output == genann_act_linear)
{
for(int j = 0; j < ann->outputs; ++j) for(int j = 0; j < ann->outputs; ++j)
{
*d++ = *t++ - *o++; *d++ = *t++ - *o++;
}
}
else else
{
for(int j = 0; j < ann->outputs; ++j) for(int j = 0; j < ann->outputs; ++j)
{ {
*d++ = (*t - *o) * *o * (1.0 - *o); *d++ = (*t - *o) * *o * (1.0 - *o);
++o; ++t; ++o; ++t;
} }
}
} }
// Set hidden layer deltas, start on last layer and work backwards. // Set hidden layer deltas, start on last layer and work backwards.
// Note that loop is skipped in the case of hidden_layers == 0. // Note that loop is skipped in the case of hidden_layers == 0.
@ -276,13 +242,13 @@ static inline void genann_train(Genann const *ann, double const *inputs, double
double const *o = ann->output + ann->inputs + (h * ann->hidden); double const *o = ann->output + ann->inputs + (h * ann->hidden);
double *d = ann->delta + (h * ann->hidden); double *d = ann->delta + (h * ann->hidden);
// Find first delta in following layer (which may be hidden or output). // Find first delta in following layer (which may be hidden or output).
double const * const dd = ann->delta + ((h+1) * ann->hidden); double const * const dd = ann->delta + ((h + 1) * ann->hidden);
// Find first weight in following layer (which may be hidden or output). // Find first weight in following layer (which may be hidden or output).
double const * const ww = ann->weight + ((ann->inputs+1) * ann->hidden) + ((ann->hidden+1) * ann->hidden * (h)); double const * const ww = ann->weight + ((ann->inputs + 1) * ann->hidden) + ((ann->hidden+1) * ann->hidden * (h));
for(int j = 0; j < ann->hidden; ++j) for(int j = 0; j < ann->hidden; ++j)
{ {
double delta = 0; double delta = 0;
for(int k = 0; k < (h == ann->hidden_layers-1 ? ann->outputs : ann->hidden); ++k) for(int k = 0; k < (h == ann->hidden_layers - 1 ? ann->outputs : ann->hidden); ++k)
{ {
const double forward_delta = dd[k]; const double forward_delta = dd[k];
const int windex = k * (ann->hidden + 1) + (j + 1); const int windex = k * (ann->hidden + 1) + (j + 1);
@ -290,34 +256,23 @@ static inline void genann_train(Genann const *ann, double const *inputs, double
delta += forward_delta * forward_weight; delta += forward_delta * forward_weight;
} }
*d = *o * (1.0-*o) * delta; *d = *o * (1.0-*o) * delta;
++d; ++o; ++d;
++o;
} }
} }
// Train the outputs. // Train the outputs.
{ {
// Find first output delta. // Find first output delta. First output delta.
// First output delta. const double * d = ann->delta + ann->hidden * ann->hidden_layers;
double const *d = ann->delta + ann->hidden * ann->hidden_layers;
// Find first weight to first output delta. // Find first weight to first output delta.
double *w = ann->weight + (ann->hidden_layers double* w = ann->weight + (ann->hidden_layers ? ((ann->inputs + 1) * ann->hidden + (ann->hidden + 1) * ann->hidden * (ann->hidden_layers - 1)) : 0);
? ((ann->inputs+1) * ann->hidden + (ann->hidden+1) * ann->hidden * (ann->hidden_layers-1))
: (0));
// Find first output in previous layer. // Find first output in previous layer.
double const * const i = ann->output + (ann->hidden_layers const double* const i = ann->output + (ann->hidden_layers ? (ann->inputs + ann->hidden * (ann->hidden_layers - 1)) : 0);
? (ann->inputs + (ann->hidden) * (ann->hidden_layers-1))
: 0);
// Set output layer weights. // Set output layer weights.
for(int j = 0; j < ann->outputs; ++j) { for(int j = 0; j < ann->outputs; ++j)
for(int k = 0; k < (ann->hidden_layers ? ann->hidden : ann->inputs) + 1; ++k) { {
if(k == 0) for(int k = 0; k < (ann->hidden_layers ? ann->hidden : ann->inputs) + 1; ++k)
{ *w++ += (k == 0) ? (*d * learning_rate * -1.0) : (*d * learning_rate * i[k-1]);
*w++ += *d * learning_rate * -1.0;
}
else
{
*w++ += *d * learning_rate * i[k-1];
}
}
++d; ++d;
} }
assert(w - ann->weight == ann->total_weights); assert(w - ann->weight == ann->total_weights);
@ -326,28 +281,15 @@ static inline void genann_train(Genann const *ann, double const *inputs, double
for(int h = ann->hidden_layers - 1; h >= 0; --h) for(int h = ann->hidden_layers - 1; h >= 0; --h)
{ {
// Find first delta in this layer. // Find first delta in this layer.
double const *d = ann->delta + (h * ann->hidden); const double* d = ann->delta + (h * ann->hidden);
// Find first input to this layer. // Find first input to this layer.
double const *i = ann->output + (h const double* i = ann->output + (h ? (ann->inputs + ann->hidden * (h - 1)) : 0);
? (ann->inputs + ann->hidden * (h-1))
: 0);
// Find first weight to this layer. // Find first weight to this layer.
double *w = ann->weight + (h double* w = ann->weight + (h ? ((ann->inputs + 1) * ann->hidden + (ann->hidden + 1) * (ann->hidden) * (h - 1)) : 0);
? ((ann->inputs+1) * ann->hidden + (ann->hidden+1) * (ann->hidden) * (h-1))
: 0);
for(int j = 0; j < ann->hidden; ++j) for(int j = 0; j < ann->hidden; ++j)
{ {
for(int k = 0; k < (h == 0 ? ann->inputs : ann->hidden) + 1; ++k) for(int k = 0; k < (h == 0 ? ann->inputs : ann->hidden) + 1; ++k)
{ *w++ += (k == 0) ? (*d * learning_rate * -1.0) : (*d * learning_rate * i[k - 1]);
if (k == 0)
{
*w++ += *d * learning_rate * -1.0;
}
else
{
*w++ += *d * learning_rate * i[k-1];
}
}
++d; ++d;
} }
} }
@ -359,3 +301,31 @@ static inline void genann_write(Genann const *ann, FILE *out)
for(int i = 0; i < ann->total_weights; ++i) for(int i = 0; i < ann->total_weights; ++i)
fprintf(out, " %.20e", ann->weight[i]); fprintf(out, " %.20e", ann->weight[i]);
} }
static inline Genann *genann_read(FILE *in)
{
int inputs;
int hidden_layers;
int hidden;
int outputs;
errno = 0;
int rc = fscanf(in, "%d %d %d %d", &inputs, &hidden_layers, &hidden, &outputs);
if(rc < 4 || errno != 0)
{
perror("fscanf");
return NULL;
}
Genann *ann = genann_init(inputs, hidden_layers, hidden, outputs);
for(int i = 0; i < ann->total_weights; ++i)
{
errno = 0;
rc = fscanf(in, " %le", ann->weight + i);
if(rc < 1 || errno != 0)
{
perror("fscanf");
genann_free(ann);
return NULL;
}
}
return ann;
}

View File

@ -1,4 +1,4 @@
CC = gcc CC = g++
NAME = shaper NAME = shaper

8
main.c
View File

@ -3,13 +3,13 @@
// Get it from the machine learning database: // Get it from the machine learning database:
// wget http://archive.ics.uci.edu/ml/machine-learning-databases/semeion/semeion.data // wget http://archive.ics.uci.edu/ml/machine-learning-databases/semeion/semeion.data
#include "Genann.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#include "Genann.h"
#define toss(t, n) ((t*) malloc((n) * sizeof(t))) #define toss(t, n) ((t*) malloc((n) * sizeof(t)))
#define retoss(ptr, t, n) (ptr = (t*) realloc((ptr), (n) * sizeof(t))) #define retoss(ptr, t, n) (ptr = (t*) realloc((ptr), (n) * sizeof(t)))
@ -69,7 +69,7 @@ static double** new2d(const int rows, const int cols)
static Data ndata(const int icols, const int ocols, const int rows, const double percentage) static Data ndata(const int icols, const int ocols, const int rows, const double percentage)
{ {
const Data data = { const Data data = {
new2d(rows, icols), new2d(rows, ocols), icols, ocols, rows, rows * percentage new2d(rows, icols), new2d(rows, ocols), icols, ocols, rows, (int) (rows * percentage)
}; };
return data; return data;
} }
@ -150,7 +150,7 @@ static void predict(Genann* ann, const Data d)
printf("%f\n", (double) matches / (d.rows - d.split)); printf("%f\n", (double) matches / (d.rows - d.split));
} }
static Data build(char* path, const int icols, const int ocols, const double percentage) static Data build(const char* path, const int icols, const int ocols, const double percentage)
{ {
FILE* file = fopen(path, "r"); FILE* file = fopen(path, "r");
const int rows = lns(file); const int rows = lns(file);