/******************************************************* * Copyright (c) 2014, ArrayFire * All rights reserved. * * This file is distributed under 3-clause BSD license. * The complete license agreement can be obtained at: * http://arrayfire.com/licenses/BSD-3-Clause ********************************************************/ #include #include #include #include #include #include #include using std::vector; using std::string; using af::cfloat; using af::cdouble; template class Convolve : public ::testing::Test { public: virtual void SetUp() {} }; // create a list of types to be tested typedef ::testing::Types TestTypes; // register the type list TYPED_TEST_CASE(Convolve, TestTypes); template void convolveTest(string pTestFile, int baseDim, bool expand) { if (noDoubleTests()) return; using af::dim4; vector numDims; vector > in; vector > tests; readTests(pTestFile, numDims, in, tests); dim4 sDims = numDims[0]; dim4 fDims = numDims[1]; af_array signal = 0; af_array filter = 0; af_array outArray = 0; ASSERT_EQ(AF_SUCCESS, af_create_array(&signal, &(in[0].front()), sDims.ndims(), sDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_SUCCESS, af_create_array(&filter, &(in[1].front()), fDims.ndims(), fDims.get(), (af_dtype)af::dtype_traits::af_type)); af_conv_mode mode = expand ? AF_CONV_EXPAND : AF_CONV_DEFAULT; switch(baseDim) { case 1: ASSERT_EQ(AF_SUCCESS, af_convolve1(&outArray, signal, filter, mode, AF_CONV_AUTO)); break; case 2: ASSERT_EQ(AF_SUCCESS, af_convolve2(&outArray, signal, filter, mode, AF_CONV_AUTO)); break; case 3: ASSERT_EQ(AF_SUCCESS, af_convolve3(&outArray, signal, filter, mode, AF_CONV_AUTO)); break; } vector currGoldBar = tests[0]; size_t nElems = currGoldBar.size(); T *outData = new T[nElems]; ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outData, outArray)); for (size_t elIter=0; elIter(string(TEST_DIR"/convolve/vector.test"), 1, true); } TYPED_TEST(Convolve, Rectangle) { convolveTest(string(TEST_DIR"/convolve/rectangle.test"), 2, true); } TYPED_TEST(Convolve, Cuboid) { convolveTest(string(TEST_DIR"/convolve/cuboid.test"), 3, true); } TYPED_TEST(Convolve, Vector_Many2One) { convolveTest(string(TEST_DIR"/convolve/vector_many2one.test"), 1, true); } TYPED_TEST(Convolve, Rectangle_Many2One) { convolveTest(string(TEST_DIR"/convolve/rectangle_many2one.test"), 2, true); } TYPED_TEST(Convolve, Cuboid_Many2One) { convolveTest(string(TEST_DIR"/convolve/cuboid_many2one.test"), 3, true); } TYPED_TEST(Convolve, Vector_Many2Many) { convolveTest(string(TEST_DIR"/convolve/vector_many2many.test"), 1, true); } TYPED_TEST(Convolve, Rectangle_Many2Many) { convolveTest(string(TEST_DIR"/convolve/rectangle_many2many.test"), 2, true); } TYPED_TEST(Convolve, Cuboid_Many2Many) { convolveTest(string(TEST_DIR"/convolve/cuboid_many2many.test"), 3, true); } TYPED_TEST(Convolve, Vector_One2Many) { convolveTest(string(TEST_DIR"/convolve/vector_one2many.test"), 1, true); } TYPED_TEST(Convolve, Rectangle_One2Many) { convolveTest(string(TEST_DIR"/convolve/rectangle_one2many.test"), 2, true); } TYPED_TEST(Convolve, Cuboid_One2Many) { convolveTest(string(TEST_DIR"/convolve/cuboid_one2many.test"), 3, true); } TYPED_TEST(Convolve, Same_Vector) { convolveTest(string(TEST_DIR"/convolve/vector_same.test"), 1, false); } TYPED_TEST(Convolve, Same_Rectangle) { convolveTest(string(TEST_DIR"/convolve/rectangle_same.test"), 2, false); } TYPED_TEST(Convolve, Same_Cuboid) { convolveTest(string(TEST_DIR"/convolve/cuboid_same.test"), 3, false); } TYPED_TEST(Convolve, Same_Vector_Many2One) { convolveTest(string(TEST_DIR"/convolve/vector_same_many2one.test"), 1, false); } TYPED_TEST(Convolve, Same_Rectangle_Many2One) { convolveTest(string(TEST_DIR"/convolve/rectangle_same_many2one.test"), 2, false); } TYPED_TEST(Convolve, Same_Cuboid_Many2One) { convolveTest(string(TEST_DIR"/convolve/cuboid_same_many2one.test"), 3, false); } TYPED_TEST(Convolve, Same_Vector_Many2Many) { convolveTest(string(TEST_DIR"/convolve/vector_same_many2many.test"), 1, false); } TYPED_TEST(Convolve, Same_Rectangle_Many2Many) { convolveTest(string(TEST_DIR"/convolve/rectangle_same_many2many.test"), 2, false); } TYPED_TEST(Convolve, Same_Cuboid_Many2Many) { convolveTest(string(TEST_DIR"/convolve/cuboid_same_many2many.test"), 3, false); } TYPED_TEST(Convolve, Same_Vector_One2Many) { convolveTest(string(TEST_DIR"/convolve/vector_same_one2many.test"), 1, false); } TYPED_TEST(Convolve, Same_Rectangle_One2Many) { convolveTest(string(TEST_DIR"/convolve/rectangle_same_one2many.test"), 2, false); } TYPED_TEST(Convolve, Same_Cuboid_One2Many) { convolveTest(string(TEST_DIR"/convolve/cuboid_same_one2many.test"), 3, false); } template void sepConvolveTest(string pTestFile, bool expand) { if (noDoubleTests()) return; using af::dim4; vector numDims; vector > in; vector > tests; readTests(pTestFile, numDims, in, tests); dim4 sDims = numDims[0]; dim4 cfDims = numDims[1]; dim4 rfDims = numDims[2]; af_array signal = 0; af_array c_filter = 0; af_array r_filter = 0; af_array outArray = 0; ASSERT_EQ(AF_SUCCESS, af_create_array(&signal, &(in[0].front()), sDims.ndims(), sDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_SUCCESS, af_create_array(&c_filter, &(in[1].front()), cfDims.ndims(), cfDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_SUCCESS, af_create_array(&r_filter, &(in[2].front()), rfDims.ndims(), rfDims.get(), (af_dtype)af::dtype_traits::af_type)); af_conv_mode mode = expand ? AF_CONV_EXPAND : AF_CONV_DEFAULT; ASSERT_EQ(AF_SUCCESS, af_convolve2_sep(&outArray, c_filter, r_filter, signal, mode)); vector currGoldBar = tests[0]; size_t nElems = currGoldBar.size(); T *outData = new T[nElems]; ASSERT_EQ(AF_SUCCESS, af_get_data_ptr((void*)outData, outArray)); for (size_t elIter=0; elIter(string(TEST_DIR"/convolve/separable_conv2d_full.test"), true); } TYPED_TEST(Convolve, Separable2D_Full_Batch) { sepConvolveTest(string(TEST_DIR"/convolve/separable_conv2d_full_batch.test"), true); } TYPED_TEST(Convolve, Separable2D_Full_Rectangle) { sepConvolveTest(string(TEST_DIR"/convolve/separable_conv2d_full_rectangle.test"), true); } TYPED_TEST(Convolve, Separable2D_Full_Rectangle_Batch) { sepConvolveTest(string(TEST_DIR"/convolve/separable_conv2d_full_rectangle_batch.test"), true); } TYPED_TEST(Convolve, Separable2D_Same) { sepConvolveTest(string(TEST_DIR"/convolve/separable_conv2d_same.test"), false); } TYPED_TEST(Convolve, Separable2D_Same_Batch) { sepConvolveTest(string(TEST_DIR"/convolve/separable_conv2d_same_batch.test"), false); } TYPED_TEST(Convolve, Separable2D_Same_Rectangle) { sepConvolveTest(string(TEST_DIR"/convolve/separable_conv2d_same_rectangle.test"), false); } TYPED_TEST(Convolve, Separable2D_Same_Rectangle_Batch) { sepConvolveTest(string(TEST_DIR"/convolve/separable_conv2d_same_rectangle_batch.test"), false); } TEST(Convolve, Separable_TypeCheck) { if (noDoubleTests()) return; if (noDoubleTests()) return; using af::dim4; dim4 sDims(10, 1, 1, 1); dim4 fDims(4, 1, 1, 1); vector in(10,1); vector filt(4,1); af_array signal = 0; af_array c_filter = 0; af_array r_filter = 0; af_array outArray = 0; ASSERT_EQ(AF_SUCCESS, af_create_array(&signal, &(in.front()), sDims.ndims(), sDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_SUCCESS, af_create_array(&c_filter, &(filt.front()), fDims.ndims(), fDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_SUCCESS, af_create_array(&r_filter, &(filt.front()), fDims.ndims(), fDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_ERR_ARG, af_convolve2_sep(&outArray, c_filter, r_filter, signal, AF_CONV_EXPAND)); ASSERT_EQ(AF_SUCCESS, af_release_array(signal)); ASSERT_EQ(AF_SUCCESS, af_release_array(c_filter)); ASSERT_EQ(AF_SUCCESS, af_release_array(r_filter)); } TEST(Convolve, Separable_DimCheck) { if (noDoubleTests()) return; if (noDoubleTests()) return; using af::dim4; dim4 sDims(10, 1, 1, 1); dim4 fDims(4, 1, 1, 1); vector in(10,1); vector filt(4,1); af_array signal = 0; af_array c_filter = 0; af_array r_filter = 0; af_array outArray = 0; ASSERT_EQ(AF_SUCCESS, af_create_array(&signal, &(in.front()), sDims.ndims(), sDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_SUCCESS, af_create_array(&c_filter, &(filt.front()), fDims.ndims(), fDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_SUCCESS, af_create_array(&r_filter, &(filt.front()), fDims.ndims(), fDims.get(), (af_dtype)af::dtype_traits::af_type)); ASSERT_EQ(AF_ERR_ARG, af_convolve2_sep(&outArray, c_filter, r_filter, signal, AF_CONV_EXPAND)); ASSERT_EQ(AF_SUCCESS, af_release_array(c_filter)); ASSERT_EQ(AF_SUCCESS, af_release_array(r_filter)); ASSERT_EQ(AF_SUCCESS, af_release_array(signal)); } TEST(Convolve1, CPP) { if (noDoubleTests()) return; using af::dim4; vector numDims; vector > in; vector > tests; readTests(string(TEST_DIR"/convolve/vector_same.test"), numDims, in, tests); //![ex_image_convolve1] //vector numDims; //vector > in; af::array signal(numDims[0], &(in[0].front())); //signal dims = [32 1 1 1] af::array filter(numDims[1], &(in[1].front())); //filter dims = [4 1 1 1] af::array output = convolve1(signal, filter, AF_CONV_DEFAULT); //output dims = [32 1 1 1] - same as input since expand(3rd argument is false) //None of the dimensions > 1 has lenght > 1, so no batch mode is activated. //![ex_image_convolve1] vector currGoldBar = tests[0]; size_t nElems = output.elements(); float *outData = new float[nElems]; output.host(outData); for (size_t elIter=0; elIter()) return; using af::dim4; vector numDims; vector > in; vector > tests; readTests(string(TEST_DIR"/convolve/rectangle_same_one2many.test"), numDims, in, tests); //![ex_image_convolve2] //vector numDims; //vector > in; af::array signal(numDims[0], &(in[0].front())); //signal dims = [15 17 1 1] af::array filter(numDims[1], &(in[1].front())); //filter dims = [5 5 2 1] af::array output = convolve2(signal, filter, AF_CONV_DEFAULT); //output dims = [15 17 1 1] - same as input since expand(3rd argument is false) //however, notice that the 3rd dimension of filter is > 1. //So, one to many batch mode will be activated automatically //where the 2d input signal is convolved with each 2d filter //and the result will written corresponding slice in the output 3d array //![ex_image_convolve2] vector currGoldBar = tests[0]; size_t nElems = output.elements(); float *outData = new float[nElems]; output.host(outData); for (size_t elIter=0; elIter()) return; using af::dim4; vector numDims; vector > in; vector > tests; readTests(string(TEST_DIR"/convolve/cuboid_same_many2many.test"), numDims, in, tests); //![ex_image_convolve3] //vector numDims; //vector > in; af::array signal(numDims[0], &(in[0].front())); //signal dims = [10 11 2 2] af::array filter(numDims[1], &(in[1].front())); //filter dims = [4 2 3 2] af::array output = convolve3(signal, filter, AF_CONV_DEFAULT); //output dims = [10 11 2 2] - same as input since expand(3rd argument is false) //however, notice that the 4th dimension is > 1 for both signal //and the filter, therefore many to many batch mode will be //activated where each 3d signal is convolved with the corresponding 3d filter //![ex_image_convolve3] vector currGoldBar = tests[0]; size_t nElems = output.elements(); float *outData = new float[nElems]; output.host(outData); for (size_t elIter=0; elIter()) return; using af::dim4; vector numDims; vector > in; vector > tests; readTests(string(TEST_DIR"/convolve/separable_conv2d_same_rectangle_batch.test"), numDims, in, tests); //![ex_image_conv2_sep] //vector numDims; //vector > in; af::array signal(numDims[0], &(in[0].front())); //signal dims = [3 4 2 1] af::array cFilter(numDims[1], &(in[1].front())); //coloumn filter dims = [2 1 1 1] af::array rFilter(numDims[2], &(in[2].front())); //row filter dims = [3 1 1 1] af::array output = convolve(cFilter, rFilter, signal, AF_CONV_DEFAULT); //output signal dims = [3 4 2 1] - same as input since 'expand = false' //notice that the input signal is 3d array, therefore //batch mode will be automatically activated. //output will be 3d array with result of each 2d array convolution(with same filter) //stacked along the 3rd dimension //![ex_image_conv2_sep] vector currGoldBar = tests[0]; size_t nElems = output.elements(); float *outData = new float[nElems]; output.host((void*)outData); for (size_t elIter=0; elIter(abs(c_ii - b_ii)) < 1E-5, true); } } TEST(GFOR, convolve2_OM) { array A = randu(5, 5); array B = randu(5, 5, 3); array K = randu(3, 3, 3); gfor(seq ii, 3) { B(span, span, ii) = convolve2(A, K(span, span, ii)); } for (int ii = 0; ii < 3; ii++) { array c_ii = convolve2(A, K(span, span, ii)); array b_ii = B(span, span, ii); ASSERT_EQ(max(abs(c_ii - b_ii)) < 1E-5, true); } } TEST(GFOR, convolve2_MM) { array A = randu(5, 5, 3); array B = randu(5, 5, 3); array K = randu(3, 3, 3); gfor(seq ii, 3) { B(span, span, ii) = convolve2(A(span, span, ii), K(span, span, ii)); } for (int ii = 0; ii < 3; ii++) { array c_ii = convolve2(A(span, span, ii), K(span, span, ii)); array b_ii = B(span, span, ii); ASSERT_EQ(max(abs(c_ii - b_ii)) < 1E-5, true); } }