#ifndef LAYER_SIMPLE_TEST_INC_CPP
#define LAYER_SIMPLE_TEST_INC_CPP
#include "layer.test.inc.cpp"
#include "layer.simple.inc.cpp"
class SimpleTest: public Test {
public:
static void init(const Layout &cl, const Layout &pl = Layout())
{ Test::init(cl.getCount(), pl.getCount(), cl.getActiveCount()*pl.getActiveCount()); }
static bool verifyWeights(const char *name, const Layout &cl, const Layout &pl) {
Stage st(name);
for(int cy = cl.y0; cy < cl.y1; ++cy)
for(int cx = cl.x0; cx < cl.x1; ++cx)
for(int cz = cl.z0; cz < cl.z1; ++cz) {
int ci = (cy*cl.sx + cx)*cl.sz + cz;
for(int py = pl.y0; py < pl.y1; ++py)
for(int px = pl.x0; px < pl.x1; ++px)
for(int pz = pl.z0; pz < pl.z1; ++pz) {
int pi = (py*pl.sx + px)*pl.sz + pz;
int wi = ((cy - cl.y0)*cl.getW() + cx - cl.x0)*cl.getD() + cz - cl.z0;
wi = ((wi*pl.getH() + py - pl.y0)*pl.getW() + px - pl.x0)*pl.getD() + pz - pl.z0;
int s = (int)p_neurons.size();
int w = weights[wi].i;
int i = ci*s + pi + 1;
if (w != i) {
int ww = w;
int wpz = ww%pl.sz; ww /= pl.sz;
int wpx = ww%pl.sx; ww /= pl.sx;
int wpy = ww%pl.sy; ww /= pl.sy;
int wcz = ww%cl.sz; ww /= cl.sz;
int wcx = ww%cl.sx; ww /= cl.sx;
int wcy = ww;
printf(
"wrong index: %d = ((%d*%d + %d)*%d + %d)*%d + (%d*%d + %d)*%d + %d + 1,\n"
"expected: %d = ((%d*%d + %d)*%d + %d)*%d + (%d*%d + %d)*%d + %d + 1\n"
"wi = %d\n",
w,
wcy, cl.sx, wcx, cl.sz, wcz, s,
wpy, pl.sx, wpx, pl.sz, wpz,
i,
cy, cl.sx, cx, cl.sz, cz, s,
py, pl.sx, px, pl.sz, pz,
wi );
pl.printYXZ("prev layout");
cl.printYXZ("curr layout");
++errors;
return st;
}
}
}
return st;
}
static bool testIterators(const char *name, const Layout &cl, const Layout &pl, const Layout &ocl, const Layout &opl, int threads) {
Stage st(name);
assert(cl && pl && ocl && opl && threads > 0);
Layout::List oclist, oplist;
ocl.split(oclist, threads);
opl.split(oplist, threads);
struct I: public Iter {
typedef int DataType;
typedef int DataAccumType;
static inline void init(Neuron &n, Iter::AccumType &a) { ++n.a.i; a.i = (AccumInt)(&n - c_neurons.data()); }
static inline void iter(Neuron &n, Weight &w, Iter::AccumType &a) {
if (w.i)
++errors;
w.i = (WeightInt)(&n - p_neurons.data() + a.i*p_neurons.size() + 1);
}
static inline void iter3(Neuron &n) { ++n.a.i; }
static inline void iter4(Neuron &n, DataType d, DataAccumType &a) { n.a.i = d; ++a; }
};
struct IB: public Iter {
static inline void init(Neuron &n, Iter::AccumType &a) { ++n.a.i; a.i = (AccumInt)(&n - p_neurons.data()); }
static inline void iter(Neuron &n, Weight &w, Iter::AccumType &a) {
if (w.i)
++errors;
w.i = (WeightInt)((&n - c_neurons.data())*p_neurons.size() + a.i + 1);
}
};
{
Stage st("iterateNeurons");
init(cl);
for(int i = 0; i < threads; ++i)
iterateNeurons<I>(oclist[i], c_neurons.data());
verifyNeurons("check-neurons", cl, c_neurons.data());
}
{
Stage st("iterateNeurons2");
init(cl);
for(int i = 0; i < threads; ++i) {
int a = 5, aa = a + oclist[i].getActiveCount();
iterateNeurons2<I>(oclist[i], ocl, c_neurons.data(), 5, 3, &a);
if (a != aa) {
printf("wrong accum value %d, expected %d, tid: %d/%d\n", a, aa, i, threads);
oclist[i].printYXZ("sub layout");
oclist[i].printYXZ("orig layout");
}
}
verifyNeuronIndices("check-neuron-indices", cl, c_neurons.data(), 5, 3);
}
{
Stage st("iterateSimple");
init(cl, pl);
for(int i = 0; i < threads; ++i)
iterateSimple<I>(oclist[i], opl, ocl, c_neurons.data(), p_neurons.data(), weights.data());
verifyNeurons("check-neurons", cl, c_neurons.data());
verifyWeights("check-weights", cl, pl);
}
{
Stage st("iterateSimpleInv");
init(cl, pl);
for(int i = 0; i < threads; ++i)
iterateSimpleInv<IB>(oplist[i], ocl, opl, p_neurons.data(), c_neurons.data(), weights.data());
verifyNeurons("check-neurons", pl, p_neurons.data());
verifyWeights("check-weights", cl, pl);
}
return st;
}
static bool testIterators(const char *name, const Layout &cl, const Layout &pl) {
Stage st(name);
{
Stage st("plain");
testIterators( "single-thread", cl, pl, cl, pl, 1 );
testIterators( "2-threads", cl, pl, cl, pl, 2 );
testIterators( "7-threads", cl, pl, cl, pl, 7 );
testIterators( "8-threads", cl, pl, cl, pl, 8 );
testIterators( "512-threads", cl, pl, cl, pl, 512 );
}
{
Stage st("optimized");
Layout ocl = optimizeLayoutSimple(cl);
Layout opl = optimizeLayoutSimple(pl);
testIterators( "single-thread", cl, pl, ocl, opl, 1 );
testIterators( "2-threads", cl, pl, ocl, opl, 2 );
testIterators( "7-threads", cl, pl, ocl, opl, 7 );
testIterators( "8-threads", cl, pl, ocl, opl, 8 );
testIterators( "512-threads", cl, pl, ocl, opl, 512 );
}
return st;
}
static bool test(const char *name, const Layout &cl, const Layout &pl) {
Stage st(name);
testIterators(name, cl, pl);
{
Layer l(nullptr, pl);
new LayerSimple<funcSigmoidExp>(l, cl);
Test::testLayer("LayerSimple", l);
}
return st;
}
static bool test(const char *name = "simple") {
Stage st(name);
test("square-16x8", Layout(8, 8, 4), Layout(16, 16, 3));
test("random-rect", Layout( 7, 4, 3).expandX(1, 2).expandY(3, 1).expandZ(5, 8),
Layout(13, 9, 4).expandX(2, 0).expandY(5, 3).expandZ(3, 1) );
return st;
}
};
#endif