Blob Blame Raw
#ifndef NNLAYER_INC_CPP
#define NNLAYER_INC_CPP


#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cassert>



class Layer {
public:
  Layer *prev, *next;
  size_t memsize;
  int size, wsize, links;
  double *a, *da, *w;

  Layer(Layer *prev, int size):
    prev(), next(), memsize(), size(size), wsize(), links(), w()
  {
    assert(size > 0);
    a = new double[size*2];
    da = a + size;
    memset(a, 0, sizeof(*a)*size*2);
    if (prev) (this->prev = &prev->back())->next = this;
    memsize += size*2*sizeof(double);
  }

  virtual ~Layer() {
    if (next) delete next;
    if (prev) prev->next = nullptr;
    delete[] a;
    if (w) delete[] w;
  }

  virtual Layer& pass()
    { return next ? next->pass() : *this; }
  virtual Layer& backpass(double trainRatio)
    { return prev ? prev->backpass(trainRatio) : *this; }

  inline Layer& front()
    { Layer *l = this; while(l->prev) l = l->prev; return *l; }
  inline Layer& back()
    { Layer *l = this; while(l->next) l = l->next; return *l; }

  inline size_t totalMemSize() const
    { size_t s = 0; for(const Layer *l = this; l; l = l->next) s += l->memsize; return s; }
  inline int totalSize() const
    { int c = 0; for(const Layer *l = this; l; l = l->next) c += l->size; return c; }
  inline int totalLinks() const
    { int c = 0; for(const Layer *l = this; l; l = l->next) c += l->links; return c; }

  bool toStream(FILE *f)
    { return (!w || fwrite(w, sizeof(double)*wsize, 1, f)) && (!next || next->toStream(f)); }
  bool fromStream(FILE *f)
    { return (!w || fread (w, sizeof(double)*wsize, 1, f)) && (!next || next->fromStream(f)); }

  bool save(const char *filename) {
    assert(!prev);
    FILE *f = fopen(filename, "wb");
    if (!f) return printf("cannot open file '%s' for write\n", filename), false;
    if (!toStream(f)) return printf("cannot write to file '%s'\n", filename), fclose(f), false;
    fclose(f);
    return 1;
  }

  bool load(const char *filename) {
    assert(!prev);
    FILE *f = fopen(filename, "rb");
    if (!f) return printf("cannot open file '%s' for read\n", filename), false;
    if (!fromStream(f)) return printf("cannot read from file '%s'\n", filename), fclose(f), false;
    fclose(f);
    return 1;
  }

  double trainPass(double ratio, double *x, double *y, double qmin) {
    assert(!prev);
    memcpy(a, x, sizeof(*a)*size);
    Layer &b = pass();

    double qmax = 0;
    for(double *pa = b.a, *pda = b.da, *e = pa + b.size; pa < e; ++pa, ++pda, ++y) {
      assert(*pa == *pa);
      double d = *y - *pa;
      *pda = d;
      //qmax += d*d;
      double q = fabs(d);
      if (qmax < q) qmax = q;
    }
    //qmax = sqrt(qmax/b.size);
    if (qmax > qmin)
      b.backpass(ratio);

    //if (qmax < 1e-6) {
    //  printf("strange:\n");
    //  y -= b.size;
    //  for(double *pa = b.a, *e = pa + b.size; pa < e; ++pa, ++y)
    //    printf("%f - %f = %f\n", *y, *pa, *y - *pa);
    //}

    return qmax;
  }
};


class LayerSimple: public Layer {
public:
  LayerSimple(Layer &prev, int size):
    Layer(&prev, size)
  {
    links = wsize = size * this->prev->size;
    w = new double[wsize];
    double k = 1.0/this->prev->size;
    for(double *iw = w, *e = iw + wsize; iw < e; ++iw)
      *iw = (rand()/(double)RAND_MAX*2 - 1)*k;
    memsize += wsize*sizeof(double);
  }

  Layer& pass() override {
    double *pa = prev->a, *ee = pa + prev->size;
    double *iw = w;
    for(double *ia = a, *e = ia + size; ia < e; ++ia) {
      double s = 0;
      for(double *ipa = pa; ipa < ee; ++ipa, ++iw)
        s += *ipa * *iw;
      *ia = 1/(1 + exp(-s)); // sigmoid
      //*ia = s > 0 ? s : 0; // RaLU
    }
    return next ? next->pass() : *this;
  }

  Layer& backpass(double trainRatio) override {
    double *pa = prev->a, *pda = prev->da, *ee = pa + prev->size;
    double *iw = w;
    if (prev->prev) {
      memset(pda, 0, sizeof(*prev->da) * prev->size);
      for(double *ia = a, *ida = da, *e = ia + size; ia < e; ++ia, ++ida) {
        double a = *ia;
        double ds = a * (1-a) * *ida; // sigmoid derivation * ida
        //if (!*ia) continue; // RaLU derivation is zero
        //double ds = *ida;
        double dst = ds*trainRatio;
        for(double *ipa = pa, *ipda = pda; ipa < ee; ++ipa, ++ipda, ++iw) {
          *ipda += ds * *iw;
          *iw += dst * *ipa;
        }
      }
    } else {
      for(double *ia = a, *ida = da, *e = ia + size; ia < e; ++ia, ++ida) {
        double a = *ia;
        double dst = a * (1-a) * *ida * trainRatio; // sigmoid derivation * ida * trainRatio
        //if (!*ia) continue; // RaLU derivation is zero
        //double dst = *ida * trainRatio;
        for(double *ipa = pa; ipa < ee; ++ipa, ++iw)
          *iw += dst * *ipa;
      }
    }
    return prev->backpass(trainRatio);
  }
};


#endif