Blob Blame Raw
#ifndef LAYER_INC_CPP
#define LAYER_INC_CPP


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

#include <atomic>
#include <vector>
#include <algorithm>


#include "layout.inc.cpp"



typedef double WeightReal;
typedef double NeuronReal;
typedef double AccumReal;

typedef int WeightInt;
typedef int AccumInt;


#define RANDOM_MAX 0x7fffffff
inline unsigned int randomNext(unsigned int prev)
  { return (1103515245*prev + 12345) & RANDOM_MAX; }


struct Accum {
  union { AccumReal v; AccumInt i; };
};


struct Neuron {
  NeuronReal v, d;
  Accum a;
};


struct Weight {
  union { WeightReal w; WeightInt i; };
};


struct Iter {
  typedef Accum AccumType;
  typedef NeuronReal* DataType;
  typedef AccumType DataAccumType;
  static inline void init(Neuron&, AccumType&) { }
  static inline void iter(Neuron&, Weight&, AccumType&) { }
  static inline void done(Neuron&, AccumType&) { }
  static inline void iter2(Neuron&, Neuron&, Weight&) { }
  static inline void iter3(Neuron&) { }
  static inline void iter4(Neuron&, DataType, DataAccumType&) { }
};


class Barrier {
private:
  std::atomic<unsigned int> &counter;
  unsigned int next;
public:
  const unsigned int tid;
  const unsigned int threads;

  Barrier(const Barrier&) = delete;
  inline Barrier(std::atomic<unsigned int> &counter, unsigned int tid, unsigned int threads):
    counter(counter), next(), tid(tid), threads(threads) { assert(tid < threads); }
  inline void wait() { next += threads; ++counter; while(counter < next); }
  inline void subwait() { while(counter < next + tid); }
};


struct Stat {
  int neurons;
  int activeNeurons;
  int weights;
  int links;
  size_t memsize;

  Stat(): neurons(), activeNeurons(), weights(), links(), memsize() { }

  Stat& operator+= (const Stat &b) {
    neurons += b.neurons;
    activeNeurons += b.activeNeurons;
    weights += b.weights;
    links   += b.links;
    memsize += b.memsize;
    return *this;
  }

  void print(const char *prefix = nullptr) const {
    if (prefix && *prefix) printf("%s: ", prefix);
    printf("neurons: %d / %d, links %d / %d, memSize: %llu\n", activeNeurons, neurons, weights, links, (unsigned long long)memsize);
  }
};


class Layer {
public:
  Layer *prev, *next;

  Layout layout;

  Neuron *neurons;
  int neuronsCount;

  Weight *weights;
  int weightsCount;
  bool ownWeights;

  const char *filename;

  Stat stat;

  Layout::List mtLayouts;


  Layer(Layer *prev, const Layout &layout, int weightsCount = 0, Weight *weights = nullptr):
    prev(prev ? &prev->back() : nullptr),
    next(),
    layout(layout),
    neurons(),
    neuronsCount(layout.getCount()),
    weights(weights),
    weightsCount(weightsCount),
    ownWeights(!weights && weightsCount),
    filename()
  {
    assert(layout);
    assert(neuronsCount > 0);
    assert(weightsCount >= 0);
    assert(!prev == !weightsCount);

    if (this->prev) this->prev->next = this;
    if (neuronsCount) {
      neurons = new Neuron[neuronsCount];
      memset(neurons, 0, sizeof(*neurons)*neuronsCount);
    }
    if (ownWeights) {
      this->weights = new Weight[weightsCount];
      memset(this->weights, 0, sizeof(*this->weights)*weightsCount);
    }

    stat.neurons = neuronsCount;
    stat.activeNeurons = layout.getActiveCount();
    stat.weights = weightsCount;
    stat.links = weightsCount;
    stat.memsize = neuronsCount*sizeof(*neurons);
    if (ownWeights) stat.memsize += weightsCount*sizeof(*weights);
  }


  virtual ~Layer() {
    if (next) delete next;
    if (neurons) delete[] neurons;
    if (ownWeights) delete[] weights;
  }


  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 Stat sumStat() const
    { Stat s; for(const Layer *l = this; l; l = l->next) s += l->stat; return s; }

  bool save() const {
    if (filename && weightsCount) {
      FILE *f = fopen(filename, "wb");
      if (!f)
        return printf("cannot open file for write: %s\n", filename), false;
      if (!fwrite(weights, sizeof(*weights)*weightsCount, 1, f))
        return fclose(f), printf("cannot write to file: %s\n", filename), false;
      fclose(f);
    }
    return !next || next->save();
  }


  bool load() {
    if (filename && weightsCount) {
      FILE *f = fopen(filename, "rb");
      if (!f)
        return printf("cannot open file for read: %s\n", filename), false;
      if (!fread(weights, sizeof(*weights)*weightsCount, 1, f))
        return fclose(f), printf("cannot read from file: %s\n", filename), false;
      fclose(f);
    }
    return !next || next->load();
  }

  
  void clearAccum() {
    Accum a = {};
    for(Neuron *in = neurons, *e = in + neuronsCount; in < e; ++in)
      in->a = a;
  }

  
  void fillWeights(WeightReal wmin, WeightReal wmax) {
    WeightReal k = (wmax - wmin)/RAND_MAX;
    for(Weight *iw = weights, *e = iw + weightsCount; iw < e; ++iw)
      iw->w = rand()*k + wmin;
  }

 
  virtual void split(int threadsCount)
    { layout.split(mtLayouts, threadsCount); }
  virtual void pass(Barrier &barrier) { }
  virtual void backpassWeights(Barrier &barrier) { }
  virtual void backpassDeltas(Barrier &barrier) { }
  
  virtual void testPass() { }
  virtual void testBackpass() { }
};


#endif