diff --git a/modules/dnn/include/opencv2/dnn/shape_utils.hpp b/modules/dnn/include/opencv2/dnn/shape_utils.hpp new file mode 100644 index 000000000..0f83416f0 --- /dev/null +++ b/modules/dnn/include/opencv2/dnn/shape_utils.hpp @@ -0,0 +1,135 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +//M*/ + +#ifndef __OPENCV_DNN_DNN_SHAPE_UTILS_HPP__ +#define __OPENCV_DNN_DNN_SHAPE_UTILS_HPP__ + +#include +#include + +namespace cv { +namespace dnn { + +std::ostream &operator<< (std::ostream &s, cv::Range &r) +{ + return s << "[" << r.start << ", " << r.end << ")"; +} + +//Reshaping + +template +void reshape(Mat &m, const BlobShape &shape) +{ + m = m.reshape(1, shape.dims(), shape.ptr()); +} + +template +Mat reshaped(const Mat &m, const BlobShape &shape) +{ + return m.reshape(1, shape.dims(), shape.ptr()); +} + + +//Slicing + +struct _Range : public cv::Range +{ + _Range(const Range &r) : cv::Range(r) {} + _Range(int start, int size = 1) : cv::Range(start, start + size) {} +}; + +template +Mat slice(const Mat &m, const _Range &r0) +{ + //CV_Assert(m.dims >= 1); + cv::AutoBuffer ranges(m.dims); + for (int i = 1; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + return m(&ranges[0]); +} + +template +Mat slice(const Mat &m, const _Range &r0, const _Range &r1) +{ + CV_Assert(m.dims >= 2); + cv::AutoBuffer ranges(m.dims); + for (int i = 2; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + ranges[1] = r1; +// for (int i = 0; i < m.dims; i++) +// std::cout << ranges[i] << "\n"; + return m(&ranges[0]); +} + +template +Mat slice(const Mat &m, const _Range &r0, const _Range &r1, const _Range &r2) +{ + CV_Assert(m.dims <= 3); + cv::AutoBuffer ranges(m.dims); + for (int i = 3; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + ranges[1] = r1; + ranges[2] = r2; + return m(&ranges[0]); +} + +template +Mat slice(const Mat &m, const _Range &r0, const _Range &r1, const _Range &r2, const _Range &r3) +{ + CV_Assert(m.dims <= 4); + cv::AutoBuffer ranges(m.dims); + for (int i = 4; i < m.dims; i++) + ranges[i] = Range::all(); + ranges[0] = r0; + ranges[1] = r1; + ranges[2] = r2; + ranges[3] = r3; + return m(&ranges[0]); +} + +} + +} + +#endif diff --git a/modules/dnn/src/layers/convolution_layer.cpp b/modules/dnn/src/layers/convolution_layer.cpp index e6f0b02eb..903e925ad 100644 --- a/modules/dnn/src/layers/convolution_layer.cpp +++ b/modules/dnn/src/layers/convolution_layer.cpp @@ -45,6 +45,7 @@ #include "convolution_layer.hpp" #include "op_im2col.hpp" #include "op_blas.hpp" +#include #include namespace cv @@ -54,18 +55,6 @@ namespace dnn typedef BlobShape Shape; -template -void reshape(Mat &m, const BlobShape &shape) -{ - m = m.reshape(1, shape.dims(), shape.ptr()); -} - -template -Mat reshaped(const Mat &m, const BlobShape &shape) -{ - return m.reshape(1, shape.dims(), shape.ptr()); -} - ConvolutionLayer::ConvolutionLayer(LayerParams ¶ms) : Layer(params) { getKernelParams(params, kerH, kerW, padH, padW, strideH, strideW); @@ -122,12 +111,7 @@ void ConvolutionLayer::allocate(const std::vector &inputs, std::vectornum(), topCn, topH, topW)); } - #ifdef HAVE_OPENCL useOpenCL = ocl::useOpenCL() && tryUseOpenCL; - #else - useOpenCL = false; - #endif - int allocFlags = useOpenCL ? Blob::ALLOC_BOTH : Blob::ALLOC_MAT; if (!is1x1()) @@ -149,33 +133,31 @@ inline bool ConvolutionLayer::is1x1() const return (kerH == 1 && kerW == 1) && (strideW == 1 && strideH == 1); //hotfix with stride } -template +template void ConvolutionLayer::forward_(std::vector &inputs, std::vector &outputs) { - Mat weightsMat = reshaped(blobs[0].getRefConst(), Shape(outCn, ksize)); - Mat biasesMat = reshaped(blobs[1].getRefConst(), Shape(outCn, 1)); + XMat weightsMat = reshaped(blobs[0].getRefConst(), Shape(outCn, ksize)); + XMat biasesMat = reshaped(blobs[1].getRefConst(), Shape(outCn, 1)); for (size_t ii = 0; ii < outputs.size(); ii++) { Blob &inpBlob = *inputs[ii]; Blob &outBlob = outputs[ii]; - Mat inpMat = inpBlob.getRefConst(); - Mat outMat = reshaped(outBlob.getRef(), Shape(inpBlob.num()*group*outGroupCn, outH*outW)); + XMat inpMat = inpBlob.getRefConst(); + XMat outMat = reshaped(outBlob.getRef(), Shape(inpBlob.num()*group*outGroupCn, outH*outW)); - int outCurrCn = 0; for (int n = 0; n < inpBlob.num(); n++) { - int kerCurrCn = 0; for (int g = 0; g < group; g++) { - im2col(inpBlob, n, g, colBlob); - const Mat &colMat = colBlob.getRefConst(); + XMat colMat, curInp = slice(inpMat, n, _Range(g * inpGroupCn, inpGroupCn)); + im2col(curInp, colMat); - Range kerRange(kerCurrCn, kerCurrCn + outGroupCn); - Mat kerMat = weightsMat.rowRange(kerRange); + _Range kerRange(g * outGroupCn, outGroupCn); + XMat kerMat = weightsMat.rowRange(kerRange); - Range outRange(outCurrCn, outCurrCn + outGroupCn); - Mat dstMat = outMat.rowRange(outRange); + _Range outRange((g + n * group) * outGroupCn, outGroupCn); + XMat dstMat = outMat.rowRange(outRange); dnn::gemm(kerMat, colMat, 1, dstMat, 0); @@ -183,9 +165,6 @@ void ConvolutionLayer::forward_(std::vector &inputs, std::vector &o { dnn::gemm(biasesMat.rowRange(kerRange), biasOnesMat, 1, dstMat, 1); } - - kerCurrCn += outGroupCn; - outCurrCn += outGroupCn; } } } @@ -199,35 +178,39 @@ void ConvolutionLayer::forward(std::vector &inputs, std::vector &ou forward_(inputs, outputs); } -void ConvolutionLayer::im2col(Blob &inpBlob, int imNum, int cnGroup, Blob &colBlob) +void ConvolutionLayer::im2col(const UMat &srcImg, UMat &dstCol) { #ifdef HAVE_OPENCL - if (useOpenCL) + if (!is1x1()) { - std::vector ranges(4, Range::all()); - ranges[0] = Range(imNum, imNum+1); - ranges[1] = Range(cnGroup*inpGroupCn, (cnGroup + 1)*inpGroupCn); - - UMat src = inpBlob.umatRef()(&ranges[0]); - UMat &dst = colBlob.umatRef(); - im2col_ocl(src, inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, dst); - return; + im2col_ocl(srcImg, inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, this->colBlob.umatRef()); + dstCol = this->colBlob.umatRefConst(); } -#endif // HAVE_OPENCL - - Mat &colMat = colBlob.matRef(); - uchar *srcPtr = inpBlob.ptr(imNum, cnGroup*inpGroupCn); + else + { + dstCol = reshaped(srcImg, Shape(ksize, outH*outW)); + } +#else + CV_Error(Error::StsInternal, ""); + dstCol = srcImg; //supress warning +#endif +} +void ConvolutionLayer::im2col(const Mat &srcImg, Mat &dstCol) +{ if (is1x1()) { - colMat = Mat(ksize, inpBlob.rows()*inpBlob.cols(), inpBlob.type(), srcPtr); + dstCol = reshaped(srcImg, Shape(ksize, outH*outW)); return; } - if (inpBlob.type() == CV_32F) - im2col_CpuPBody::run((float*)srcPtr, inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, colMat.ptr()); - if (inpBlob.type() == CV_64F) - im2col_CpuPBody::run((double*)srcPtr, inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, colMat.ptr()); + Mat &colMat = colBlob.matRef(); + if (srcImg.type() == CV_32F) + im2col_CpuPBody::run(srcImg.ptr(), inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, colMat.ptr()); + if (srcImg.type() == CV_64F) + im2col_CpuPBody::run(srcImg.ptr(), inpGroupCn, inpH, inpW, kerH, kerW, padH, padW, strideH, strideW, colMat.ptr()); + + dstCol = colMat; } void ConvolutionLayer::computeInpOutShape(const Blob &inpBlob) diff --git a/modules/dnn/src/layers/convolution_layer.hpp b/modules/dnn/src/layers/convolution_layer.hpp index 03e3a334c..c94b57d1f 100644 --- a/modules/dnn/src/layers/convolution_layer.hpp +++ b/modules/dnn/src/layers/convolution_layer.hpp @@ -70,7 +70,9 @@ namespace dnn inline bool is1x1() const; virtual void computeInpOutShape(const Blob &inpBlob); - void im2col(Blob &inpBlob, int imNum, int cnGroup, Blob &colBlob); + + void im2col(const Mat &srcImg, Mat &dstCol); + void im2col(const UMat &srcImg, UMat &dstCol); public: ConvolutionLayer() {} diff --git a/modules/dnn/src/layers/op_blas.cpp b/modules/dnn/src/layers/op_blas.cpp index c0eb20367..079e253d7 100644 --- a/modules/dnn/src/layers/op_blas.cpp +++ b/modules/dnn/src/layers/op_blas.cpp @@ -16,10 +16,7 @@ void gemm(InputArray A, InputArray B, double alpha, InputOutputArray C, double b if (C.isMat()) gemmCPU(A.getMat(), B.getMat(), alpha, C.getMatRef(), beta, flags); else - { cv::gemm(A, B, alpha, C, beta, C, flags); - std::cout << "OCL gemm\n"; - } } inline void SwapRowCols(const Mat &A, int &rows, int &cols, bool isTrans) diff --git a/modules/dnn/src/layers/op_im2col.cpp b/modules/dnn/src/layers/op_im2col.cpp index b629451ee..07b79d71d 100644 --- a/modules/dnn/src/layers/op_im2col.cpp +++ b/modules/dnn/src/layers/op_im2col.cpp @@ -40,9 +40,8 @@ //M*/ #include "../precomp.hpp" -#include -#include "op_im2col.hpp" #include "opencl_kernels_dnn.hpp" +#include "op_im2col.hpp" namespace cv { @@ -50,7 +49,7 @@ namespace dnn { #ifdef HAVE_OPENCL -void im2col_ocl(UMat &img, +void im2col_ocl(const UMat &img, int channels, int height, int width, int kernel_h, int kernel_w, int pad_h, int pad_w, @@ -79,7 +78,7 @@ void im2col_ocl(UMat &img, CV_Assert(im2col_ker.run(1, &globalSize, &localSize, true)); } -#endif // HAVE_OPENCL +#endif } } diff --git a/modules/dnn/src/layers/op_im2col.hpp b/modules/dnn/src/layers/op_im2col.hpp index 72f1b8bcb..ac3d0b4eb 100644 --- a/modules/dnn/src/layers/op_im2col.hpp +++ b/modules/dnn/src/layers/op_im2col.hpp @@ -148,7 +148,7 @@ void col2im_cpu(const Dtype* data_col, } #ifdef HAVE_OPENCL -void im2col_ocl(UMat &img, +void im2col_ocl(const UMat &img, int channels, int height, int width, int kernel_h, int kernel_w, int pad_h, int pad_w, diff --git a/modules/dnn/src/precomp.hpp b/modules/dnn/src/precomp.hpp index 8639e45f8..6932bc8e5 100644 --- a/modules/dnn/src/precomp.hpp +++ b/modules/dnn/src/precomp.hpp @@ -40,4 +40,5 @@ //M*/ #include +#include "cvconfig.h" #include diff --git a/modules/dnn/test/test_googlenet.cpp b/modules/dnn/test/test_googlenet.cpp index 0bc7e01d9..6adf321da 100644 --- a/modules/dnn/test/test_googlenet.cpp +++ b/modules/dnn/test/test_googlenet.cpp @@ -43,6 +43,7 @@ #include "test_precomp.hpp" #include "npy_blob.hpp" #include +#include namespace cvtest { @@ -56,7 +57,7 @@ static std::string _tf(TString filename) return (getOpenCVExtraDir() + "/dnn/") + filename; } -TEST(Reproducibility_GoogLeNet, Accuracy) +static void launchGoogleNetTest() { Net net; { @@ -78,5 +79,16 @@ TEST(Reproducibility_GoogLeNet, Accuracy) normAssert(out, ref); } +TEST(Reproducibility_GoogLeNet, Accuracy) +{ + OCL_OFF(launchGoogleNetTest()); +} + +OCL_TEST(Reproducibility_GoogLeNet, Accuracy) +{ + OCL_ON(launchGoogleNetTest()); + OCL_OFF(); +} + } #endif diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 5e9171265..b8dbf887d 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -44,6 +44,7 @@ #include #include "npy_blob.hpp" #include +#include namespace cvtest { @@ -57,7 +58,7 @@ static String _tf(TString filename) return (getOpenCVExtraDir() + "/dnn/layers/") + filename; } -static void testLayer(String basename, bool useCaffeModel = false, bool useCommonInputBlob = true) +void testLayerUsingCaffeModels(String basename, bool useCaffeModel = false, bool useCommonInputBlob = true) { String prototxt = _tf(basename + ".prototxt"); String caffemodel = _tf(basename + ".caffemodel"); @@ -86,58 +87,62 @@ static void testLayer(String basename, bool useCaffeModel = false, bool useCommo TEST(Layer_Test_Softmax, Accuracy) { - testLayer("layer_softmax"); + testLayerUsingCaffeModels("layer_softmax"); +} +OCL_TEST(Layer_Test_Softmax, Accuracy) +{ + OCL_ON(testLayerUsingCaffeModels("layer_softmax")); + OCL_OFF(); } TEST(Layer_Test_LRN_spatial, Accuracy) { - testLayer("layer_lrn_spatial"); + testLayerUsingCaffeModels("layer_lrn_spatial"); } TEST(Layer_Test_LRN_channels, Accuracy) { - testLayer("layer_lrn_channels"); + testLayerUsingCaffeModels("layer_lrn_channels"); } TEST(Layer_Test_Convolution, Accuracy) { - testLayer("layer_convolution", true); + testLayerUsingCaffeModels("layer_convolution", true); +} +OCL_TEST(Layer_Test_Convolution, Accuracy) +{ + OCL_ON(testLayerUsingCaffeModels("layer_convolution", true)); + OCL_OFF(); } -//TODO: move this test into separate file -TEST(Layer_Test_Convolution, AccuracyOCL) +TEST(Layer_Test_DeConvolution, Accuracy) { - if (cv::ocl::haveOpenCL()) - { - cv::ocl::setUseOpenCL(true); - testLayer("layer_convolution", true); - cv::ocl::setUseOpenCL(false); - } + testLayerUsingCaffeModels("layer_deconvolution", true, false); +} +OCL_TEST(Layer_Test_DeConvolution, Accuracy) +{ + OCL_ON(testLayerUsingCaffeModels("layer_deconvolution", true, false);); + OCL_OFF(); } TEST(Layer_Test_InnerProduct, Accuracy) { - testLayer("layer_inner_product", true); + testLayerUsingCaffeModels("layer_inner_product", true); } TEST(Layer_Test_Pooling_max, Accuracy) { - testLayer("layer_pooling_max"); + testLayerUsingCaffeModels("layer_pooling_max"); } TEST(Layer_Test_Pooling_ave, Accuracy) { - testLayer("layer_pooling_ave"); -} - -TEST(Layer_Test_DeConvolution, Accuracy) -{ - testLayer("layer_deconvolution", true, false); + testLayerUsingCaffeModels("layer_pooling_ave"); } TEST(Layer_Test_MVN, Accuracy) { - testLayer("layer_mvn"); + testLayerUsingCaffeModels("layer_mvn"); } TEST(Layer_Test_Reshape, squeeze)