Blame simple/neural/nnlayer.inc.c

Ivan Mahonin ec0d7e
#ifndef NNLAYER_INC_C
Ivan Mahonin ec0d7e
#define NNLAYER_INC_C
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
#include <math.h>
Ivan Mahonin ec0d7e
#include <stdio.h>
Ivan Mahonin ec0d7e
#include <stdlib.h>
Ivan Mahonin ec0d7e
#include <string.h>
Ivan Mahonin ec0d7e
#include <assert.h>
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
typedef struct NeuralLayer {
Ivan Mahonin ec0d7e
  struct NeuralLayer *prev, *next;
Ivan Mahonin ec0d7e
  int size;
Ivan Mahonin ec0d7e
  double trainRatio;
Ivan Mahonin 56d550
  double *a, *b, *d, *da, *w;
Ivan Mahonin ec0d7e
} NeuralLayer;
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
NeuralLayer* nlNew(NeuralLayer *prev, int size, double trainRatio) {
Ivan Mahonin ec0d7e
  assert(size > 0);
Ivan Mahonin ec0d7e
  while(prev && prev->next) prev = prev->next;
Ivan Mahonin ec0d7e
  NeuralLayer *nl = calloc(sizeof(NeuralLayer), 1);
Ivan Mahonin ec0d7e
  nl->size = size;
Ivan Mahonin ec0d7e
  nl->prev = prev;
Ivan Mahonin ec0d7e
  nl->trainRatio = trainRatio;
Ivan Mahonin 56d550
  nl->a = calloc(sizeof(*nl->a), size*4);
Ivan Mahonin ec0d7e
  nl->d = nl->a + size;
Ivan Mahonin ec0d7e
  nl->da = nl->d + size;
Ivan Mahonin ec0d7e
  if (prev) {
Ivan Mahonin ec0d7e
    assert(prev->size > 0);
Ivan Mahonin 56d550
    nl->b = calloc(sizeof(*nl->b), size*(1 + prev->size));
Ivan Mahonin 56d550
    nl->w = nl->b + size;
Ivan Mahonin 56d550
    for(double *p = nl->b, *e = p + size*(1 + prev->size); p < e; ++p)
Ivan Mahonin ec0d7e
      *p = rand()/(double)RAND_MAX*2 - 1;
Ivan Mahonin ec0d7e
    prev->next = nl;
Ivan Mahonin ec0d7e
  }
Ivan Mahonin ec0d7e
  return nl;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
void nlFree(NeuralLayer *nl) {
Ivan Mahonin ec0d7e
  if (nl->next) nlFree(nl->next);
Ivan Mahonin ec0d7e
  if (nl->prev) nl->prev->next = NULL;
Ivan Mahonin ec0d7e
  free(nl->a);
Ivan Mahonin 56d550
  if (nl->prev) free(nl->b);
Ivan Mahonin ec0d7e
  free(nl);
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
NeuralLayer* nlFront(NeuralLayer *nl)
Ivan Mahonin ec0d7e
  { while(nl->prev) nl = nl->prev; return nl; }
Ivan Mahonin ec0d7e
NeuralLayer* nlBack(NeuralLayer *nl)
Ivan Mahonin ec0d7e
  { while(nl->next) nl = nl->next; return nl; }
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
int nlToStream(NeuralLayer *nl, FILE *f) {
Ivan Mahonin ec0d7e
  if (nl->prev)
Ivan Mahonin 56d550
    if (!fwrite(nl->b, sizeof(double) * nl->size * (1 + nl->prev->size), 1, f))
Ivan Mahonin ec0d7e
      return 0;
Ivan Mahonin ec0d7e
  return nl->next ? nlToStream(nl->next, f) : 1;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
int nlFromStream(NeuralLayer *nl, FILE *f) {
Ivan Mahonin ec0d7e
  if (nl->prev)
Ivan Mahonin 56d550
    if (!fread(nl->b, sizeof(double) * nl->size * (1 + nl->prev->size), 1, f))
Ivan Mahonin ec0d7e
      return 0;
Ivan Mahonin ec0d7e
  return nl->next ? nlFromStream(nl->next, f) : 1;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
int nlSave(NeuralLayer *nl, const char *filename) {
Ivan Mahonin ec0d7e
  FILE *f = fopen(filename, "wb");
Ivan Mahonin ec0d7e
  if (!f)
Ivan Mahonin ec0d7e
    return printf("cannot open file '%s' for write\n", filename), 0;
Ivan Mahonin ec0d7e
  if (!nlToStream(nl, f))
Ivan Mahonin ec0d7e
    return printf("cannot write to file '%s'\n", filename), fclose(f), 0;
Ivan Mahonin ec0d7e
  fclose(f);
Ivan Mahonin ec0d7e
  return 1;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
int nlLoad(NeuralLayer *nl, const char *filename) {
Ivan Mahonin ec0d7e
  FILE *f = fopen(filename, "rb");
Ivan Mahonin ec0d7e
  if (!f)
Ivan Mahonin ec0d7e
    return printf("cannot open file '%s' for read\n", filename), 0;
Ivan Mahonin ec0d7e
  if (!nlFromStream(nl, f))
Ivan Mahonin ec0d7e
    return printf("cannot read from file '%s'\n", filename), fclose(f), 0;
Ivan Mahonin ec0d7e
  fclose(f);
Ivan Mahonin ec0d7e
  return 1;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
NeuralLayer* nlPass(NeuralLayer *nl) {
Ivan Mahonin ec0d7e
  NeuralLayer *nlp = nl->prev;
Ivan Mahonin ec0d7e
  if (nlp) {
Ivan Mahonin ec0d7e
    double *nlpa = nlp->a, *ee = nlpa + nlp->size;
Ivan Mahonin ec0d7e
    double *w = nl->w;
Ivan Mahonin 56d550
    for(double *a = nl->a, *b = nl->b, *d = nl->d, *e = a + nl->size; a < e; ++a, ++b, ++d) {
Ivan Mahonin 56d550
      double s = *b;
Ivan Mahonin ec0d7e
      for(double *pa = nlpa; pa < ee; ++pa, ++w)
Ivan Mahonin ec0d7e
        s += *w * *pa;
Ivan Mahonin ec0d7e
      double ex = exp(-s);
Ivan Mahonin ec0d7e
      double ex1 = ex + 1;
Ivan Mahonin ec0d7e
      double ex2 = 1/ex1;
Ivan Mahonin ec0d7e
      *a = ex2;        // sigmoid
Ivan Mahonin ec0d7e
      *d = ex*ex2*ex2; // sigmoid derivation
Ivan Mahonin ec0d7e
    }
Ivan Mahonin ec0d7e
  }
Ivan Mahonin ec0d7e
  return nl->next ? nlPass(nl->next) : nl;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
NeuralLayer* nlBackpass(NeuralLayer *nl) {
Ivan Mahonin ec0d7e
  NeuralLayer *nlp = nl->prev;
Ivan Mahonin ec0d7e
  if (nlp) {
Ivan Mahonin ec0d7e
    double tr = nl->trainRatio;
Ivan Mahonin ec0d7e
    double *nlpa = nlp->a, *nlpda = nlp->da, *ee = nlpa + nlp->size;
Ivan Mahonin ec0d7e
    double *w = nl->w;
Ivan Mahonin ec0d7e
    if (nlp->prev) {
Ivan Mahonin ec0d7e
      memset(nlp->da, 0, sizeof(*nlp->da) * nlp->size);
Ivan Mahonin 56d550
      for(double *b = nl->b, *d = nl->d, *da = nl->da, *e = b + nl->size; b < e; ++b, ++d, ++da) {
Ivan Mahonin ec0d7e
        double ds = *d * *da;
Ivan Mahonin ec0d7e
        double dst = ds*tr;
Ivan Mahonin 56d550
        *b -= dst;
Ivan Mahonin ec0d7e
        for(double *pa = nlpa, *pda = nlpda; pa < ee; ++pa, ++pda, ++w) {
Ivan Mahonin ec0d7e
          *pda += ds * *w;
Ivan Mahonin ec0d7e
          *w += dst * *pa;
Ivan Mahonin ec0d7e
        }
Ivan Mahonin ec0d7e
      }
Ivan Mahonin ec0d7e
    } else {
Ivan Mahonin 56d550
      for(double *b = nl->b, *d = nl->d, *da = nl->da, *e = b + nl->size; b < e; ++b, ++d, ++da) {
Ivan Mahonin ec0d7e
        double dst = *d * *da * tr;
Ivan Mahonin 56d550
        *b -= dst;
Ivan Mahonin ec0d7e
        for(double *pa = nlpa; pa < ee; ++pa, ++w)
Ivan Mahonin ec0d7e
          *w += dst * *pa;
Ivan Mahonin ec0d7e
      }
Ivan Mahonin ec0d7e
    }
Ivan Mahonin ec0d7e
    return nlBackpass(nlp);
Ivan Mahonin ec0d7e
  }
Ivan Mahonin ec0d7e
  return nl;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
double nlTrainPass(NeuralLayer *nl, double *x, double *y, double qmin) {
Ivan Mahonin ec0d7e
  assert(!nl->prev);
Ivan Mahonin ec0d7e
  double *fa = nl->a;
Ivan Mahonin ec0d7e
  nl->a = x;
Ivan Mahonin ec0d7e
  NeuralLayer *nlb = nlPass(nl);
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
  double qmax = 0;
Ivan Mahonin ec0d7e
  for(double *a = nlb->a, *da = nlb->da, *e = a + nlb->size; a < e; ++a, ++da, ++y) {
Ivan Mahonin ec0d7e
    double d = *y - *a;
Ivan Mahonin ec0d7e
    *da = d;
Ivan Mahonin ec0d7e
    double q = fabs(d);
Ivan Mahonin ec0d7e
    if (qmax < q) qmax = q;
Ivan Mahonin ec0d7e
  }
Ivan Mahonin ec0d7e
  if (qmax > qmin) nlBackpass(nlb);
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
  nl->a = fa;
Ivan Mahonin ec0d7e
  return qmax;
Ivan Mahonin ec0d7e
}
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
Ivan Mahonin ec0d7e
#endif