making some good progress

This commit is contained in:
Gustav Louw 2018-03-28 16:59:15 -07:00
parent 758a0bcbbd
commit 756e383bb5
2 changed files with 188 additions and 55 deletions

131
test.c
View File

@ -2,72 +2,93 @@
#include <stdlib.h>
#include <math.h>
// [i1] [h1] [o1]
//
// [i2] [h2] [o2]
//
// [b1] [b2]
static double act(const double in)
{
return 1.0 / (1.0 + exp(-in));
}
static double shid(const double W[], const double I[], const int neuron, const int inputs)
{
double sum = 0.0;
int i;
for(i = 0; i < inputs; i++)
sum += I[i] * W[i + neuron * inputs];
return sum;
}
static double sout(const double W[], const double I[], const int neuron, const int inputs, const int hidden)
{
double sum = 0.0;
int i;
for(i = 0; i < inputs; i++)
sum += I[i] * W[i + hidden * (neuron + inputs)];
return sum;
}
static double cerr(const double T[], const double O[], const int count)
{
double ssqr = 0.0;
int i;
for(i = 0; i < count; i++)
{
const double sub = T[i] - O[i];
ssqr += sub * sub;
}
return 0.5 * ssqr;
}
static void bprop(double W[], const double I[], const double H[], const double O[], const double T[], const double rate)
{
const double a = -(T[0] - O[0]) * O[0] * (1.0 - O[0]);
const double b = -(T[1] - O[1]) * O[1] * (1.0 - O[1]);
const double c = (W[4] * a + W[6] * b) * (1.0 - H[0]);
const double d = (W[5] * a + W[7] * b) * (1.0 - H[1]);
/* Hidden layer */
W[0] -= rate * H[0] * c * I[0];
W[1] -= rate * H[0] * c * I[1];
W[2] -= rate * H[1] * d * I[0];
W[3] -= rate * H[1] * d * I[1];
/* Output layer */
W[4] -= rate * H[0] * a;
W[5] -= rate * H[1] * a;
W[6] -= rate * H[0] * b;
W[7] -= rate * H[1] * b;
}
/* Single layer feed forward neural network with back propogation error correction */
static double train(const double I[], const double T[], const int nips, const int nops, const double rate, const int iters)
{
const double B[] = { 0.35, 0.60 };
const int nhid = sizeof(B) / sizeof(*B);
double W[] = { 0.15, 0.20, 0.25, 0.30, 0.40, 0.45, 0.50, 0.55 };
double* H = (double*) malloc(sizeof(*H) * nhid);
double* O = (double*) malloc(sizeof(*O) * nops);
double error;
int iter;
for(iter = 0; iter < iters; iter++)
{
int i;
for(i = 0; i < nhid; i++) H[i] = act(B[0] + shid(W, I, i, nips));
for(i = 0; i < nops; i++) O[i] = act(B[1] + sout(W, H, i, nips, nhid));
bprop(W, I, H, O, T, rate);
}
error = cerr(T, O, nops);
free(H);
free(O);
return error;
}
int main()
{
const double rate = 0.5;
// Input.
const double i1 = 0.05;
const double i2 = 0.10;
// Output.
const double t1 = 0.01;
const double t2 = 0.99;
// Weights and biases.
double w[] = { 0.15, 0.20, 0.25, 0.30, 0.40, 0.45, 0.50, 0.55 };
double b[] = { 0.35, 0.60 };
double et = 0;
const double I[] = { 0.05, 0.10 };
for(int i = 0; i < 10000; i++)
{
// Compute.
const double h1 = act(w[0] * i1 + w[1] * i2 + b[0]);
const double h2 = act(w[2] * i1 + w[3] * i2 + b[0]);
const double o1 = act(w[4] * h1 + w[5] * h2 + b[1]);
const double o2 = act(w[6] * h1 + w[7] * h2 + b[1]);
const double T[] = { 0.01, 0.99 };
// Error calculation.
const double to1 = t1 - o1;
const double to2 = t2 - o2;
const double e1 = 0.5 * to1 * to1;
const double e2 = 0.5 * to2 * to2;
et = e1 + e2;
const double error = train(I, T, sizeof(I) / sizeof(*I), sizeof(T) / sizeof(*T), rate, 10000);
const double a = -to1 * o1 * (1.0 - o1);
const double b = -to2 * o2 * (1.0 - o2);
const double c = (w[4] * a + w[6] * b) * (1.0 - h1);
const double d = (w[5] * a + w[7] * b) * (1.0 - h2);
printf("%f\n", error);
// Back Propogation.
w[0] -= rate * h1 * c * i1;
w[1] -= rate * h1 * c * i2;
w[2] -= rate * h2 * d * i1;
w[3] -= rate * h2 * d * i2;
w[4] -= rate * h1 * a;
w[5] -= rate * h2 * a;
w[6] -= rate * h1 * b;
w[7] -= rate * h2 * b;
#if 0
printf("w1 %.9f\n", w[0]);
printf("w2 %.9f\n", w[1]);
printf("w3 %.9f\n", w[2]);
printf("w4 %.9f\n", w[3]);
printf("w5 %.9f\n", w[4]);
printf("w6 %.9f\n", w[5]);
printf("w7 %.9f\n", w[6]);
printf("w8 %.9f\n", w[7]);
#endif
}
printf("%0.12f\n", et);
return 0;
}

112
test2.c Normal file
View File

@ -0,0 +1,112 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
static double act(double net)
{
return 1.0 / (1.0 + exp(-net));
}
static void forepass(double* I, double* O, double* H, double* W, double* B, const int inputs, const int output, const int hidden)
{
double* X = W + hidden * inputs;
for(int i = 0; i < hidden; i++) { for(int j = 0; j < inputs; j++) H[i] += I[j] * W[i * inputs + j]; H[i] = act(H[i] + B[0]); }
for(int i = 0; i < output; i++) { for(int j = 0; j < hidden; j++) O[i] += H[j] * X[i * hidden + j]; O[i] = act(O[i] + B[1]); }
}
static void backpass(double* I, double* O, double* H, double* W, double* T, const int inputs, const int output, const int hidden, const double rate)
{
double* X = W + hidden * inputs;
for(int i = 0; i < output; i++)
for(int j = 0; j < hidden; j++)
X[2 * i + j] -= rate * ((O[i] - T[i]) * (O[i] * (1 - O[i])) * H[j]);
//W[4] -= rate * ((T[0] - O[0]) * (T[0] * (1 - T[0])) * H[0]);
//W[5] -= rate * ((T[0] - O[0]) * (T[0] * (1 - T[0])) * H[1]);
//W[6] -= rate * ((T[1] - O[1]) * (T[1] * (1 - T[1])) * H[0]);
//W[7] -= rate * ((T[1] - O[1]) * (T[1] * (1 - T[1])) * H[1]);
}
static double cerror(double *O, double* T, const int output)
{
double error = 0.0;
for(int i = 0; i < output; i++)
error += 0.5 * pow(T[i] - O[i], 2.0);
return error;
}
static double* train(double* I, double* T, const int inputs, const int output, const int hidden)
{
// Weights.
double* W = (double*) calloc(hidden * (inputs + output), sizeof(*W));
W[0] = 0.15;
W[1] = 0.20;
W[2] = 0.25;
W[3] = 0.30;
W[4] = 0.40;
W[5] = 0.45;
W[6] = 0.50;
W[7] = 0.55;
// Fixed at single hidden layer - only two biases are needed.
double B[] = { 0.35, 0.60 };
// Hidden layer.
double* H = (double*) calloc(hidden, sizeof(*H));
// Output layer. Will eventually converge to output with enough iterations.
double* O = (double*) calloc(output, sizeof(*O));
// Computes hidden and target nodes.
forepass(I, O, H, W, B, inputs, output, hidden);
// Computes output to target error.
double err = cerror(O, O, output);
printf("error: %f\n", err);
// Updates weights based on target error.
backpass(I, O, H, W, T, inputs, output, hidden, 0.5);
printf("W5: %f\n", W[4]);
printf("W6: %f\n", W[5]);
printf("W7: %f\n", W[6]);
printf("W8: %f\n", W[7]);
printf("%f\n", H[0]);
printf("%f\n", H[1]);
printf("%f\n", O[0]);
printf("%f\n", O[1]);
free(H);
return W;
}
double* predict(double* I, double* W, const int inputs, const int output)
{
double* O = NULL;
// ...
return O;
}
int main()
{
const int inputs = 2, output = 2, hidden = 2;
// Input.
double* I = (double*) calloc(inputs, sizeof(*I));
I[0] = 0.05;
I[1] = 0.10;
// Target.
double* T = (double*) calloc(output, sizeof(*I));
T[0] = 0.01;
T[1] = 0.99;
train(I, T, inputs, output, hidden);
return 0;
}