Blame simple/neural/nnlayer2.inc.cpp

53488e
#ifndef NNLAYER2_INC_CPP
53488e
#define NNLAYER2_INC_CPP
53488e
53488e
53488e
#include <cmath></cmath>
53488e
#include <cstdio></cstdio>
53488e
#include <cstdlib></cstdlib>
53488e
#include <cstring></cstring>
53488e
#include <cassert></cassert>
53488e
53488e
#include <vector></vector>
53488e
#include <algorithm></algorithm>
53488e
53488e
53488e
typedef float Real;
53488e
53488e
53488e
template<typename t=""></typename>
53488e
bool twrite(const T &x, FILE *f)
53488e
  { return fwrite(&x, sizeof(x), 1, f); }
53488e
template<typename t=""></typename>
53488e
bool tread(const T &x, FILE *f)
53488e
  { return fwrite(&x, sizeof(x), 1, f); }
53488e
53488e
53488e
struct Link;
53488e
struct Neuron {
53488e
  Real v, d;
53488e
  inline Neuron(): v(), d() { }
53488e
};
53488e
53488e
struct Link {
53488e
  int nprev, lnext;
53488e
  Real w;
53488e
  inline Link(): nprev(), lnext(), w((Real)rand()/(Real)RAND_MAX*2 - 1) { }
53488e
};
53488e
53488e
53488e
class Layer {
53488e
public:
53488e
  Layer *prev, *next;
53488e
53488e
  int size, lsize;
53488e
  Neuron *neurons;
53488e
  Link *links;
53488e
  int lfirst;
53488e
53488e
  explicit Layer(Layer *prev = nullptr, int size = 0, int lsize = 0):
53488e
    prev(), next(), size(), lsize(), neurons(), links(), lfirst()
53488e
  {
53488e
    while(prev && prev->next) prev = prev->next;
53488e
    if (prev) prev->next = this;
53488e
    this->prev = prev;
53488e
    init(size, lsize);
53488e
  }
53488e
53488e
  virtual ~Layer() {
53488e
    if (next) delete next;
53488e
    if (prev) prev->next = nullptr;
53488e
    delete[] neurons;
53488e
    if (links) delete[] links;
53488e
  }
53488e
53488e
  bool init(int size, int lsize = 0) {
53488e
    clear();
53488e
    if (size <= 0) return false;
53488e
    if (lsize < 0) lsize = 0;
53488e
53488e
    if (prev ? lsize <= 0 : lsize) return false;
53488e
    if (size) neurons = new Neuron[size];
53488e
    if (lsize) links = new Link[lsize*size];
53488e
    this->size = size;
53488e
    this->lsize = lsize;
53488e
    return true;
53488e
  }
53488e
53488e
  void clear() {
53488e
    if (neurons) delete[] neurons;
53488e
    if (links) delete[] links;
53488e
    this->size = lsize = 0;
53488e
    neurons = nullptr;
53488e
    links = nullptr;
53488e
    lfirst = 0;
53488e
  }
53488e
53488e
  void prepareBackLinks() {
53488e
    if (!links || lsize <= 0) return;
53488e
53488e
    lfirst = 0;
53488e
    int lend = size*lsize;
53488e
    for(Link *il = links, *e = il + lend; il < e; ++il) {
53488e
      assert(prev && prev->neurons && il->nprev >= 0 && il->nprev < prev->size);
53488e
      il->lnext = il - links + 1;
53488e
    }
53488e
53488e
    while(true) {
53488e
      bool done = true;
53488e
      for(int *il = &lfirst; links[*il].lnext != lend; il = &links[*il].lnext) {
53488e
        int a = *il, b = links[a].lnext;
53488e
        if (links[a].nprev > links[b].nprev) {
53488e
          links[a].lnext = links[b].lnext;
53488e
          links[b].lnext = a;
53488e
          *il = b;
53488e
          done = false;
53488e
        }
53488e
      }
53488e
      if (done) break;
53488e
    }
53488e
53488e
    #ifndef NDEBUG
53488e
    if (lsize) {
53488e
      int next = 0;
53488e
      for(int il = lfirst; il != lend; il = links[il].lnext) {
53488e
        assert(links[il].nprev == next || links[il].nprev == next-1);
53488e
        if (links[il].nprev == next) ++next;
53488e
      }
53488e
      assert(next = prev->size);
53488e
    }
53488e
    #endif
53488e
  }
53488e
53488e
  bool save(FILE *f) const {
53488e
    if (!twrite(size, f) || !twrite(lsize, f))
53488e
      return false;
53488e
    for(Link *il = links, *e = il + lsize*size; il < e; ++il)
53488e
      if (!twrite(il->nprev, f) || !twrite(il->w, f))
53488e
          return false;
53488e
    return true;
53488e
  }
53488e
53488e
  bool load(FILE *f) {
53488e
    clear();
53488e
    int size = 0, lsize = 0;
53488e
    if (!tread(size, f) || !tread(lsize, f) || !init(size, lsize))
53488e
      return false;
53488e
    for(Link *il = links, *e = il + lsize*size; il < e; ++il)
53488e
      if (!tread(il->nprev, f) || !tread(il->w, f) || !prev || !prev->neurons || il->nprev < 0 || il->nprev >= prev->size)
53488e
          return false;
53488e
    prepareBackLinks();
53488e
    return true;
53488e
  }
53488e
53488e
  bool saveAll(FILE *f) const
53488e
    { return save(f) && (!next || next->save(f)); }
53488e
  bool loadAll(FILE *f)
53488e
    { return load(f) && (!next || next->load(f)); }
53488e
53488e
  bool saveAll(const char *filename) const {
53488e
    assert(!prev);
53488e
    FILE *f = fopen(filename, "wb");
53488e
    if (!f)
53488e
      { printf("cannot open file for write: %s\n", filename); return false; }
53488e
    int count = totalLayers();
53488e
    if (!twrite(count, f) || !saveAll(f))
53488e
      { printf("cannot save to file: %s\n", filename); fclose(f); return false; }
53488e
    fclose(f);
53488e
    return true;
53488e
  }
53488e
53488e
  bool loadAll(const char *filename) {
53488e
    assert(!prev);
53488e
    FILE *f = fopen(filename, "rb");
53488e
    if (!f)
53488e
      { printf("cannot open file for read: %s\n", filename); return false; }
53488e
    int count = 0;
53488e
    if (!tread(count, f) || count <= 0)
53488e
      { printf("cannot load from file: %s\n", filename); fclose(f); return false; }
53488e
    if (next)
53488e
      delete next;
53488e
    while(--count)
53488e
      new Layer(this);
53488e
    if (!loadAll(f))
53488e
      { printf("cannot load from file: %s\n", filename); fclose(f); return false; }
53488e
    fclose(f);
53488e
    return true;
53488e
  }
53488e
53488e
  int totalLayers() const
53488e
    { int t = 0; for(const Layer *l = this; l; l = l->next) ++t; return t; }
53488e
  int totalNeurons() const
53488e
    { int t = 0; for(const Layer *l = this; l; l = l->next) t += l->size; return t; }
53488e
  int totalLinks() const
53488e
    { int t = 0; for(const Layer *l = this; l; l = l->next) t += l->size*l->lsize; return t; }
53488e
  inline size_t totalMemSize() const
53488e
    { return totalNeurons()*sizeof(Neuron) + totalLinks()*sizeof(Link); }
53488e
53488e
  inline Layer& front()
53488e
    { Layer *l = this; while(l->prev) l = l->prev; return *l; }
53488e
  inline Layer& back()
53488e
    { Layer *l = this; while(l->next) l = l->next; return *l; }
53488e
53488e
  void pass(int nb, int ne) {
53488e
    assert(prev);
53488e
    int lsize = this->lsize;
53488e
    Neuron *pn = prev->neurons;
53488e
    Link *il = links + nb*lsize;
53488e
    for(Neuron *in = neurons + nb, *e = neurons + ne; in < e; ++in) {
53488e
      double s = 0;
53488e
      for(Link *e = il + lsize; il < e; ++il)
53488e
        s += pn[il->nprev].v * il->w;
53488e
53488e
      // exp sigmoid
53488e
      double ss = 1/(1 + exp(-s));
53488e
      in->v = ss;
53488e
      in->d = ss * (1-ss);
53488e
53488e
      // 1/(x+1) sigmoid
53488e
      //double ss = 1/(1+fabs(s));
53488e
      //double ss2 = ss*0.5;
53488e
      //in->v = s > 0 ? 1 - ss2 : ss2;
53488e
      //in->d = ss2 * ss;
53488e
    }
53488e
  }
53488e
53488e
  template<bool hasprev=""></bool>
53488e
  void backpassTpl(int lb, int le) {
53488e
    assert(hasPrev == (bool)prev);
53488e
    if (lb == le) return;
53488e
    Link *links = this->links;
53488e
    Neuron *neurons = this->neurons;
53488e
    Neuron *pneurons = prev->neurons;
53488e
53488e
    double s = 0;
53488e
    int ipn = links[lb].nprev;
53488e
    for(int il = lb; il != le; ) {
53488e
      Link &l = links[il];
53488e
      if (hasPrev)
53488e
        if (ipn != l.nprev)
53488e
          { pneurons[ipn].d *= s; ipn = l.nprev; }
53488e
      Neuron &n = neurons[ il/lsize ];
53488e
      Real d = n.d;
53488e
      if (hasPrev) s += d * l.w;
53488e
      l.w += d * n.v;
53488e
      il = l.lnext;
53488e
    }
53488e
    if (hasPrev)
53488e
        pneurons[ipn].d *= s;
53488e
53488e
    assert(le == size*lsize || ipn < links[le].nprev);
53488e
  }
53488e
53488e
  void backpass(int lb, int le) {
53488e
    if (prev) backpassTpl<true>(lb, le); else backpassTpl<false>(lb, le);</false></true>
53488e
  }
53488e
53488e
  void passAll() {
53488e
    if (prev) pass(0, size);
53488e
    if (next) next->passAll();
53488e
  }
53488e
53488e
  void backpassAll(Real k) {
53488e
    if (next) backpass(lfirst, size*lsize);
53488e
    if (prev) prev->passAll();
53488e
  }
53488e
};
53488e
53488e
53488e
#endif