#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