Blob Blame Raw
#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