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

e865c9
#ifndef LAYER_CONV_TEST_INC_CPP
e865c9
#define LAYER_CONV_TEST_INC_CPP
e865c9
e865c9
e865c9
e865c9
#include "layer.test.inc.cpp"
e865c9
#include "layer.conv.inc.cpp"
e865c9
e865c9
e865c9
class ConvTest: public Test {
e865c9
public:
e865c9
  static void init(const Layout &cl, const Layout &pl, const Kernel &k, bool shared = false)
e865c9
    { Test::init(cl.getCount(), pl.getCount(), (shared ? 1 : cl.getActiveCount())*k.sx*k.sy*pl.getD()); }
e865c9
e865c9
e865c9
  static bool verifyWeights(const char *name, const Layout &cl, const Layout &pl, const Kernel &k) {
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
      for(int ky = 0; ky < k.sy; ++ky)
e865c9
      for(int kx = 0; kx < k.sx; ++kx)
e865c9
      for(int pz = pl.z0; pz < pl.z1; ++pz) {
e865c9
        int wi = ((cy - cl.y0)*cl.getW() + cx - cl.x0)*cl.getD() + cz - cl.z0;
e865c9
        wi = ((wi*k.sy + ky)*k.sx + kx)*pl.getD() + pz - pl.z0;
e865c9
e865c9
        int px = pl.x0 + (cx - cl.x0)*k.dx + k.ox + kx;
e865c9
        int py = pl.y0 + (cy - cl.y0)*k.dy + k.oy + ky;
e865c9
        if ( px < pl.x0 || px >= pl.x1
e865c9
          || py < pl.y0 || py >= pl.y1 ) continue;
e865c9
e865c9
        int pi = (py*pl.sx + px)*pl.sz + pz;
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, ky %d, kx %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, ky, kx );
e865c9
          pl.printYXZ("prev layout");
e865c9
          cl.printYXZ("curr layout");
e865c9
          k.printYX("kernel");
e865c9
          ++errors;
e865c9
          return st;
e865c9
        }
e865c9
      }
e865c9
    }
e865c9
    return st;
e865c9
  }
e865c9
e865c9
  static bool testIterators(const char *name, const Layout &cl, const Layout &pl, const Kernel &k, int threads) {
e865c9
    Stage st(name);
e865c9
e865c9
    assert(cl && pl && k && threads > 0);
e865c9
    Layout::List clist, plist;
e865c9
    cl.split(clist, threads);
e865c9
    pl.split(plist, threads);
e865c9
    
e865c9
    struct I: public Iter {
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 iter2(Neuron &cn, Neuron &pn, Weight &w) {
e865c9
        if (w.i)
e865c9
          ++errors;
e865c9
        w.i = (WeightInt)((&cn - c_neurons.data())*p_neurons.size() + &pn - p_neurons.data() + 1);
e865c9
        pn.v = pn.v + 1;
e865c9
      }
e865c9
    };
e865c9
e865c9
    if (threads == 1) {
e865c9
      Stage st("iterateTestConvolution");
e865c9
      init(cl, pl, k);
e865c9
      iterateTestConvolution(cl, pl, k, c_neurons.data(), p_neurons.data(), weights.data());
e865c9
      verifyNeurons("conv-neurons", cl, c_neurons.data());
e865c9
      verifyWeights("conv-weights", cl, pl, k);
e865c9
    }
e865c9
e865c9
    {
e865c9
      Stage st("iterateConvolution");
e865c9
      init(cl, pl, k);
e865c9
      for(int i = 0; i < threads; ++i)
e865c9
        iterateConvolution(clist[i], pl, cl, k, c_neurons.data(), p_neurons.data(), weights.data());
e865c9
      verifyNeurons("conv-neurons", cl, c_neurons.data());
e865c9
      verifyWeights("conv-weights", cl, pl, k);
e865c9
    }
e865c9
e865c9
    {
e865c9
      Stage st("iterateConvolutionPoint");
e865c9
      init(cl, pl, k);
e865c9
      int e = errors;
e865c9
      for(int ky = 0; ky < k.sy && errors == e; ++ky)
e865c9
      for(int kx = 0; kx < k.sx && errors == e; ++kx) {
e865c9
        for(int i = 0; i < threads; ++i)
e865c9
          iterateConvolutionPoint(clist[i], pl, cl, k, kx, ky, c_neurons.data(), p_neurons.data(), weights.data());
e865c9
        if (!verifyNeuronsAccum(pl, p_neurons.data(), cl.getD(), true))
e865c9
          printf("kx: %d, ky: %d\n", kx, ky), k.printYX("kernel");
e865c9
      }
e865c9
      verifyNeurons("conv-neurons", pl, p_neurons.data(), true);
e865c9
      verifyWeights("conv-weights", cl, pl, k);
e865c9
    }
e865c9
e865c9
    return st;
e865c9
  }
e865c9
e865c9
  static bool testIterators(const char *name, const Layout &cl, const Layout &pl, const Kernel &k) {
e865c9
    Stage st(name);
e865c9
    testIterators( "single-thread", cl, pl, k,   1 );
e865c9
    testIterators( "2-threads",     cl, pl, k,   2 );
e865c9
    testIterators( "7-threads",     cl, pl, k,   7 );
e865c9
    testIterators( "8-threads",     cl, pl, k,   8 );
e865c9
    testIterators( "512-threads",   cl, pl, k, 512 );
e865c9
    return st;
e865c9
  }
e865c9
  
e865c9
  static bool test(const char *name, const Layout &cl, const Layout &pl, const Kernel &k) {
e865c9
    Stage st(name);
e865c9
    
e865c9
    testIterators("iterators", cl, pl, k);
e865c9
e865c9
    {
e865c9
      Layer l(nullptr, pl);
e865c9
      new LayerConv<funcsigmoidexp>(l, cl, k);</funcsigmoidexp>
e865c9
      Test::testLayer("LayerConv", l);
e865c9
    }
e865c9
e865c9
    {
e865c9
      Layer l(nullptr, pl);
e865c9
      new LayerConv<funcsigmoidexp>(l, cl, k);</funcsigmoidexp>
e865c9
      Test::testLayer("LayerDeconv", l);
e865c9
    }
e865c9
e865c9
    return st;
e865c9
  }
e865c9
e865c9
  static bool test(const char *name = "convolution") {
e865c9
    Stage st(name);
e865c9
    test( "square", Layout(64, 64, 4), Layout(128, 128, 4).expandXY(2),                 Kernel(5, 2, -2)           );
e865c9
    test( "rect1",  Layout(63, 43, 5), Layout( 63,  85, 3).expandX(2).   expandY(3),    Kernel(5, 7, 1, 2, -2, -3) );
e865c9
    test( "rect2",  Layout(43, 63, 3), Layout( 85,  63, 5).expandX(3).   expandY(3, 2), Kernel(7, 5, 2, 1, -3, -2) );
e865c9
    test( "rect3",  Layout(64, 48, 5), Layout( 64,  96, 3).expandX(1, 2).expandY(3, 1), Kernel(4, 6, 1, 2, -1, -3) );
e865c9
    test( "pad",    Layout(64, 48, 5).expandX(3, 4).expandY(4, 3).expandZ(5, 4),
e865c9
                    Layout(64, 96, 3).expandX(6, 5).expandY(7, 6).expandZ(0, 1),        Kernel(4, 6, 1, 2, -1, -3) );
e865c9
    return st;
e865c9
  }
e865c9
};
e865c9
e865c9
e865c9
#endif