Blame simple/neural/nnlayer3.inc.cpp

53488e
#ifndef NNLAYER3_INC_CPP
53488e
#define NNLAYER3_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(T), 1, f); }
53488e
template<typename t=""></typename>
53488e
bool tread(T &x, FILE *f)
53488e
  { return fread(&x, sizeof(T), 1, f); }
53488e
53488e
53488e
struct Neuron {
53488e
  Real v, d;
53488e
};
53488e
53488e
53488e
class Layer {
53488e
public:
53488e
  Layer *prev, *next;
53488e
53488e
  int sx, sy, sz, sl;
53488e
  Neuron *neurons;
53488e
  Real *weights;
53488e
  int *invWeights;
53488e
  int *invNeurons;
53488e
53488e
53488e
  explicit Layer(Layer *prev = nullptr, int sx = 0, int sy = 0, int sz = 0, int sl = 0):
53488e
    prev(), next(), sx(), sy(), sz(), sl(), neurons(), weights(), invWeights(), invNeurons()
53488e
  {
53488e
    while(prev && prev->next) prev = prev->next;
53488e
    if (prev) prev->next = this;
53488e
    this->prev = prev;
53488e
    init(sx, sy, sz, sl);
53488e
  }
53488e
53488e
53488e
  virtual ~Layer() {
53488e
    clear();
53488e
    if (next) delete next;
53488e
    if (prev) prev->next = nullptr;
53488e
  }
53488e
53488e
53488e
  void clear() {
53488e
    if (next) next->clear();
53488e
    if (neurons) delete[] neurons;
53488e
    if (weights) delete[] weights;
53488e
    if (invWeights) delete[] invWeights;
53488e
    sx = sy = sz = sl = 0;
53488e
    neurons = nullptr;
53488e
    weights = nullptr;
53488e
    invWeights = nullptr;
53488e
    invNeurons = nullptr;
53488e
  }
53488e
53488e
53488e
  bool init(int sx, int sy, int sz, int sl = 0) {
53488e
    clear();
53488e
    if (prev && !prev->countNeurons()) return false;
53488e
    if (sx <= 0 || sy <= 0 || sz <= 0) return false;
53488e
    if (prev ? (sl <= 0 || sl > prev->sx || sl > prev->sy) : sl != 0) return false;
53488e
    printf("init %d %d %d %d\n", sx, sy, sz, sl);
53488e
53488e
    this->sx = sx;
53488e
    this->sy = sy;
53488e
    this->sz = sz;
53488e
53488e
    int size = sx*sy*sz;
53488e
    neurons = new Neuron[size];
53488e
    memset(neurons, 0, sizeof(*neurons)*size);
53488e
53488e
    if (prev) {
53488e
      int psx = prev->sx;
53488e
      int psy = prev->sy;
53488e
      int psz = prev->sz;
53488e
      int psize = psx*psy*psz;
53488e
53488e
      this->sl = sl;
53488e
      int wsize = size*sl*sl*psz;
53488e
      weights = new Real[wsize];
53488e
      double k = 1.0/(sl*sl*psz);
53488e
      for(int i = 0; i < wsize; ++i)
53488e
        weights[i] = Real( (rand()/(double)RAND_MAX*2 - 1)*k );
53488e
53488e
      struct Link {
53488e
        int n, w;
53488e
        inline bool operator< (const Link &b) const
53488e
          { return n < b.n ? true : (b.n < n ? false : w < b.w); }
53488e
      } *links = new Link[wsize], *il = links;
53488e
53488e
      int dx = sx > 1 ? sx - 1 : 1;
53488e
      int dy = sy > 1 ? sy - 1 : 1;
53488e
53488e
      for(int y = 0; y < sy; ++y)
53488e
      for(int x = 0; x < sx; ++x) {
53488e
        int py = y*(psy-sl)/dy;
53488e
        int px = x*(psx-sl)/dx;
53488e
        assert(py >= 0 && py <= psy-sl);
53488e
        assert(px >= 0 && px <= psx-sl);
53488e
53488e
        for(int z = 0; z < sz; ++z)
53488e
        for(int ly = 0; ly < sl; ++ly)
53488e
        for(int lx = 0; lx < sl; ++lx)
53488e
        for(int pz = 0; pz < psz; ++pz, ++il) {
53488e
          assert(il < links + wsize);
53488e
          il->n = ((py+ly)*psx + px+lx)*psz + pz;
53488e
          il->w = il - links;
53488e
          assert(il->n >= 0 && il->n < psize);
53488e
        }
53488e
      }
53488e
      assert(il == links + wsize);
53488e
      std::sort(links, il);
53488e
53488e
      invWeights = new int[wsize + psize + 1];
53488e
      invNeurons = invWeights + wsize;
53488e
      invNeurons[0] = 0;
53488e
      int pni = 0;
53488e
      for(int i = 0; i < wsize; ++i) {
53488e
        assert(pni == links[i].n || pni == links[i].n + 1);
53488e
        invWeights[i] = links[i].w;
53488e
        if (pni == links[i].n)
53488e
          invNeurons[pni++] = i;
53488e
      }
53488e
      assert(pni == psize);
53488e
      invNeurons[psize] = wsize;
53488e
53488e
      delete[] links;
53488e
    }
53488e
    return true;
53488e
  }
53488e
53488e
  bool save(FILE *f) const {
53488e
    return twrite(sx, f) && twrite(sy, f) && twrite(sz, f) && twrite(sl, f)
53488e
        && (!weights || fwrite(weights, sizeof(*weights)*sx*sy*sz*sl*sl*prev->sz, 1, f));
53488e
  }
53488e
53488e
  bool load(FILE *f) {
53488e
    clear();
53488e
    int sx = 0, sy = 0, sz = 0, sl = 0;
53488e
    return tread(sx, f) && tread(sy, f) && tread(sz, f) && tread(sl, f) && init(sx, sy, sz, sl)
53488e
        && (!weights || fread(weights, sizeof(*weights)*sx*sy*sz*sl*sl*prev->sz, 1, f));
53488e
  }
53488e
53488e
  bool saveAll(FILE *f) const
53488e
    { return save(f) && (!next || next->saveAll(f)); }
53488e
  bool loadAll(FILE *f)
53488e
    { return load(f) && (!next || next->loadAll(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
  inline int countNeurons() const
53488e
    { return sx*sy*sz; }
53488e
  inline int linksPerNeuron() const
53488e
    { return prev ? sl*sl*prev->sz : 0; }
53488e
  inline int countLinks() const
53488e
    { return countNeurons() * linksPerNeuron(); }
53488e
  inline size_t memSize() const {
53488e
    return sizeof(*neurons)*countNeurons()
53488e
         + (sizeof(*weights) + sizeof(*invWeights))*countLinks()
53488e
         + (prev ? sizeof(*invNeurons)*(prev->countNeurons() + 1) : 0);
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->countNeurons(); return t; }
53488e
  int totalLinks() const
53488e
    { int t = 0; for(const Layer *l = this; l; l = l->next) t += l->countLinks(); return t; }
53488e
  size_t totalMemSize() const
53488e
    { size_t t = 0; for(const Layer *l = this; l; l = l->next) t += l->memSize(); return t; }
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
53488e
  void pass(int y0, int y1) {
53488e
    if (!prev) return;
53488e
53488e
    int sx = this->sx;
53488e
    int sy = this->sy;
53488e
    int sz = this->sz;
53488e
    int sxz = sx*sz;
53488e
53488e
    int psx = prev->sx;
53488e
    int psy = prev->sy;
53488e
    int psz = prev->sz;
53488e
    int psxz = psx*psz;
53488e
    Neuron *pneurons = prev->neurons;
53488e
53488e
    int sl = this->sl;
53488e
    int slpz = sl*psz;
53488e
    int sllpz = sl*slpz;
53488e
53488e
    int ldy = psxz - slpz;
53488e
53488e
    int kpx = psx-sl, dpx = sx>1 ? sx-1 : 1;
53488e
    int kpy = psy-sl, dpy = sy>1 ? sy-1 : 1;
53488e
53488e
    Real *iw = weights + y0*sxz*sllpz;
53488e
    Neuron *in = neurons + y0*sxz;
53488e
    int fpy = y0*kpy;
53488e
    for(Neuron *e = in + (y1-y0)*sxz; in < e; fpy += kpy) {
53488e
      Neuron *pnrow = pneurons + fpy/dpy*psxz;
53488e
53488e
      int fpx = 0;
53488e
      for(Neuron *e = in + sxz; in < e; fpx += kpx) {
53488e
        Neuron *pn = pnrow + fpx/dpx*psz;
53488e
53488e
        for(Neuron *e = in + sz; in < e; ++in) {
53488e
          double s = 0;
53488e
53488e
          Neuron *ipn = pn;
53488e
          for(Real *e = iw + sllpz; iw < e; ipn += ldy)
53488e
          for(Real *e = iw + slpz; iw < e; ++iw, ++ipn)
53488e
            s += *iw * ipn->v;
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
  }
53488e
53488e
53488e
  void backpassWeights(int y0, int y1) {
53488e
    assert(prev);
53488e
53488e
    int sx = this->sx;
53488e
    int sy = this->sy;
53488e
    int sz = this->sz;
53488e
    int sxz = sx*sz;
53488e
53488e
    int psx = prev->sx;
53488e
    int psy = prev->sy;
53488e
    int psz = prev->sz;
53488e
    int psxz = psx*psz;
53488e
    Neuron *pneurons = prev->neurons;
53488e
53488e
    int sl = this->sl;
53488e
    int slpz = sl*psz;
53488e
    int sllpz = sl*slpz;
53488e
53488e
    int ldy = psxz - slpz;
53488e
53488e
    int kpx = psx-sl, dpx = sx>1 ? sx-1 : 1;
53488e
    int kpy = psy-sl, dpy = sy>1 ? sy-1 : 1;
53488e
53488e
    Real *iw = weights + y0*sxz*sllpz;
53488e
    Neuron *in = neurons + y0*sxz;
53488e
    int fpy = y0*kpy;
53488e
    for(Neuron *e = in + (y1-y0)*sxz; in < e; fpy += kpy) {
53488e
      Neuron *pnrow = pneurons + fpy/dpy*psxz;
53488e
53488e
      int fpx = 0;
53488e
      for(Neuron *e = in + sxz; in < e; fpx += kpx) {
53488e
        Neuron *pn = pnrow + fpx/dpx*psz;
53488e
53488e
        for(Neuron *e = in + sz; in < e; ++in) {
53488e
          Real d = in->d;
53488e
53488e
          Neuron *ipn = pn;
53488e
          for(Real *e = iw + sllpz; iw < e; ipn += ldy)
53488e
          for(Real *e = iw + slpz; iw < e; ++iw, ++ipn)
53488e
            *iw += ipn->v * d;
53488e
        }
53488e
      }
53488e
    }
53488e
  }
53488e
53488e
  template<bool withweights=""></bool>
53488e
  void backpassTpl(int y0, int y1) {
53488e
    assert(next);
53488e
53488e
    Neuron *nneurons = next->neurons;
53488e
    Real *nweights = next->weights;
53488e
    int *nInvWeights = next->invWeights;
53488e
    int lpn = next->linksPerNeuron();
53488e
53488e
    int sxz = sx*sz;
53488e
53488e
    Neuron *in = neurons + y0*sxz;
53488e
    int *inni = next->invNeurons + y0*sxz;
53488e
    for(Neuron *e = in + (y1-y0)*sxz; in < e; ++in) {
53488e
      Real v = in->v;
53488e
      double s = 0;
53488e
53488e
      int *iw = nInvWeights + *inni++;
53488e
      for(int *e = nInvWeights + *inni; iw < e; ++iw) {
53488e
        int wi = *iw;
53488e
        Real d = nneurons[wi/lpn].d;
53488e
        Real &nw = nweights[wi];
53488e
        s += nw * d;
53488e
        if (WithWeights) nw += d * v;
53488e
      }
53488e
53488e
      in->d *= s;
53488e
    }
53488e
  }
53488e
53488e
  void passAll() {
53488e
    if (prev) pass(0, sy);
53488e
    if (next) next->passAll();
53488e
  }
53488e
53488e
  void backpassAll() {
53488e
    if (!prev)
53488e
      return;
53488e
    if (!prev->prev)
53488e
      { backpassWeights(0, sy); return; }
53488e
    if (next)
53488e
      backpassTpl<true>(0, sy);</true>
53488e
    return prev->backpassAll();
53488e
  }
53488e
};
53488e
53488e
53488e
#endif