#ifndef LAYER_TEST_INC_CPP
#define LAYER_TEST_INC_CPP
#include "test.inc.cpp"
#include "layer.inc.cpp"
class LayerTest: public Test {
public:
static bool testLayer(const char *name, Layer &l) {
Stage st(name);
assert(l.next);
Layer &p = l;
Layer &c = *l.next;
class H: public ThreadControl {
public:
Layer &p;
Layer &c;
H(Layer &p, Layer &c): p(p), c(c) { }
void fillLayout(Layout l, Neuron *neurons) {
for(int y = 0; y < l.sy; ++y)
for(int x = 0; x < l.sx; ++x)
for(int z = 0; z < l.sz; ++z) {
Neuron &n = neurons[ (y*l.sx + x)*l.sz + z ];
n = Neuron{};
if ( x >= l.x0 && x < l.x1
&& y >= l.y0 && y < l.y1
&& z >= l.z0 && z < l.z1 )
{
n.v = rand()/(NeuronReal)RAND_MAX;
n.d = rand()/(NeuronReal)RAND_MAX;
}
}
}
void prepareData() {
memcpy(c.neurons, c_neurons.data(), c.neuronsCount*sizeof(Neuron));
memcpy(p.neurons, p_neurons.data(), p.neuronsCount*sizeof(Neuron));
if (c.weightsCount)
memcpy(c.weights, weights.data(), c.weightsCount*sizeof(Weight));
}
void applyDelta() {
for(int i = 0; i < c.neuronsCount; ++i)
c.neurons[i].d *= c_neurons[i].v - c.neurons[i].v;
}
void threadFunc(Barrier &barrier) override {
c.pass(barrier);
barrier.wait();
if (!barrier.tid) applyDelta();
barrier.wait();
c.backpassDeltas(barrier);
barrier.wait();
c.backpassWeights(barrier);
}
bool test(const char *name, int threadsCount) {
Stage st(name);
assert(threadsCount > 0);
prepareData();
p.split(threadsCount);
c.split(threadsCount);
runThreads(threadsCount);
for(int i = 0; i < c.neuronsCount; ++i) {
NeuronReal a = c.neurons[i].v;
NeuronReal b = c_neurons[i + c.neuronsCount].v;
if (fabs(a - b) > 1e-6)
{ printf("results differs at neuron %d, was %g, expected %g\n", i, a, b); ++errors; break; }
}
for(int i = 0; i < p.neuronsCount; ++i) {
NeuronReal a = p.neurons[i].d;
NeuronReal b = p_neurons[i + p.neuronsCount].d;
if (fabs(a - b) > 1e-6)
{ printf("deltas differs at neuron %d, was %g, expected %g\n", i, a, b); ++errors; break; }
}
for(int i = 0; i < c.weightsCount; ++i) {
WeightReal a = c.weights[i].w;
WeightReal b = weights[i + c.weightsCount].w;
if (fabs(a - b) > 1e-6)
{ printf("weights differs at %d, was %g, expected %g\n", i, a, b); ++errors; break; }
}
if (!st) {
p.layout.printYXZ("prev layout");
c.layout.printYXZ("curr layout");
}
return st;
}
} h(p, c);
// make base data
init(c.neuronsCount*2, p.neuronsCount*2, c.weightsCount*2);
h.fillLayout(c.layout, c_neurons.data());
h.fillLayout(p.layout, p_neurons.data());
if (c.weightsCount)
memcpy(weights.data(), c.weights, c.weightsCount*sizeof(Weight));
h.prepareData();
c.testPass();
h.applyDelta();
c.testBackpass();
memcpy(&c_neurons[c.neuronsCount], c.neurons, c.neuronsCount*sizeof(Neuron));
memcpy(&p_neurons[p.neuronsCount], p.neurons, p.neuronsCount*sizeof(Neuron));
if (c.weightsCount)
memcpy(&weights[c.weightsCount], c.weights, c.weightsCount*sizeof(Weight));
h.test("single-thread", 1);
h.test("2-threads", 2);
h.test("7-threads", 7);
h.test("8-threads", 8);
//h.test("512-threads", 512);
return st;
}
};
#endif