Blame projects/neural/layer.simple.test.inc.cpp

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