2017-10-27 19:06:53 +08:00
|
|
|
// This file is part of OpenCV project.
|
|
|
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
|
|
|
// of this distribution and at http://opencv.org/license.html.
|
|
|
|
//
|
|
|
|
// Copyright (C) 2017, Intel Corporation, all rights reserved.
|
|
|
|
// Third party copyrights are property of their respective owners.
|
|
|
|
|
|
|
|
#include "test_precomp.hpp"
|
2023-10-20 16:49:27 +08:00
|
|
|
#include "npy_blob.hpp"
|
2018-09-06 18:26:47 +08:00
|
|
|
#include <opencv2/core/ocl.hpp>
|
|
|
|
#include <opencv2/core/opencl/ocl_defs.hpp>
|
2018-04-24 19:59:59 +08:00
|
|
|
#include <opencv2/dnn/layer.details.hpp> // CV_DNN_REGISTER_LAYER_CLASS
|
|
|
|
|
2017-11-05 21:48:40 +08:00
|
|
|
namespace opencv_test { namespace {
|
2017-10-27 19:06:53 +08:00
|
|
|
|
|
|
|
TEST(blobFromImage_4ch, Regression)
|
|
|
|
{
|
|
|
|
Mat ch[4];
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
ch[i] = Mat::ones(10, 10, CV_8U)*i;
|
|
|
|
|
|
|
|
Mat img;
|
|
|
|
merge(ch, 4, img);
|
|
|
|
Mat blob = dnn::blobFromImage(img, 1., Size(), Scalar(), false, false);
|
|
|
|
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
ch[i] = Mat(img.rows, img.cols, CV_32F, blob.ptr(0, i));
|
|
|
|
ASSERT_DOUBLE_EQ(cvtest::norm(ch[i], cv::NORM_INF), i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-13 23:17:56 +08:00
|
|
|
TEST(blobFromImage, allocated)
|
|
|
|
{
|
|
|
|
int size[] = {1, 3, 4, 5};
|
|
|
|
Mat img(size[2], size[3], CV_32FC(size[1]));
|
|
|
|
Mat blob(4, size, CV_32F);
|
|
|
|
void* blobData = blob.data;
|
|
|
|
dnn::blobFromImage(img, blob, 1.0 / 255, Size(), Scalar(), false, false);
|
|
|
|
ASSERT_EQ(blobData, blob.data);
|
|
|
|
}
|
|
|
|
|
2018-02-12 19:51:07 +08:00
|
|
|
TEST(imagesFromBlob, Regression)
|
|
|
|
{
|
|
|
|
int nbOfImages = 8;
|
|
|
|
|
|
|
|
std::vector<cv::Mat> inputImgs(nbOfImages);
|
|
|
|
for (int i = 0; i < nbOfImages; i++)
|
|
|
|
{
|
|
|
|
inputImgs[i] = cv::Mat::ones(100, 100, CV_32FC3);
|
|
|
|
cv::randu(inputImgs[i], cv::Scalar::all(0), cv::Scalar::all(1));
|
|
|
|
}
|
|
|
|
|
|
|
|
cv::Mat blob = cv::dnn::blobFromImages(inputImgs, 1., cv::Size(), cv::Scalar(), false, false);
|
|
|
|
std::vector<cv::Mat> outputImgs;
|
|
|
|
cv::dnn::imagesFromBlob(blob, outputImgs);
|
|
|
|
|
|
|
|
for (int i = 0; i < nbOfImages; i++)
|
|
|
|
{
|
2020-02-24 01:05:05 +08:00
|
|
|
EXPECT_EQ(0, cvtest::norm(inputImgs[i], outputImgs[i], NORM_INF))
|
|
|
|
<< "i=" << i
|
|
|
|
<< " inputImgs[i]=" << inputImgs[i].size
|
|
|
|
<< " outputImgs[i]=" << outputImgs[i].size;
|
2018-02-12 19:51:07 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-22 00:10:17 +08:00
|
|
|
TEST(blobFromImageWithParams_4ch, NHWC_scalar_scale)
|
|
|
|
{
|
|
|
|
Mat img(10, 10, CV_8UC4, cv::Scalar(0,1,2,3));
|
|
|
|
std::vector<double> factorVec = {0.1, 0.2, 0.3, 0.4};
|
|
|
|
|
|
|
|
Scalar scalefactor(factorVec[0], factorVec[1], factorVec[2], factorVec[3]);
|
|
|
|
|
|
|
|
Image2BlobParams param;
|
|
|
|
param.scalefactor = scalefactor;
|
|
|
|
param.datalayout = DNN_LAYOUT_NHWC;
|
|
|
|
Mat blob = dnn::blobFromImageWithParams(img, param); // [1, 10, 10, 4]
|
|
|
|
|
|
|
|
float* blobPtr = blob.ptr<float>(0);
|
|
|
|
std::vector<float> targetVec = {(float )factorVec[0] * 0, (float )factorVec[1] * 1, (float )factorVec[2] * 2, (float )factorVec[3] * 3}; // Target Value.
|
|
|
|
for (int hi = 0; hi < 10; hi++)
|
|
|
|
{
|
|
|
|
for (int wi = 0; wi < 10; wi++)
|
|
|
|
{
|
|
|
|
float* hwPtr = blobPtr + hi * 10 * 4 + wi * 4;
|
|
|
|
|
|
|
|
// Check equal
|
|
|
|
EXPECT_NEAR(hwPtr[0], targetVec[0], 1e-5);
|
|
|
|
EXPECT_NEAR(hwPtr[1], targetVec[1], 1e-5);
|
|
|
|
EXPECT_NEAR(hwPtr[2], targetVec[2], 1e-5);
|
|
|
|
EXPECT_NEAR(hwPtr[3], targetVec[3], 1e-5);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-28 16:54:09 +08:00
|
|
|
TEST(blobFromImageWithParams_CustomPadding, letter_box)
|
|
|
|
{
|
|
|
|
Mat img(40, 20, CV_8UC4, Scalar(0, 1, 2, 3));
|
|
|
|
|
|
|
|
// Custom padding value that you have added
|
|
|
|
Scalar customPaddingValue(5, 6, 7, 8); // Example padding value
|
|
|
|
|
|
|
|
Size targetSize(20, 20);
|
|
|
|
|
|
|
|
Mat targetImg = img.clone();
|
|
|
|
|
|
|
|
cv::copyMakeBorder(
|
|
|
|
targetImg, targetImg, 0, 0,
|
|
|
|
targetSize.width / 2,
|
|
|
|
targetSize.width / 2,
|
|
|
|
BORDER_CONSTANT,
|
|
|
|
customPaddingValue);
|
|
|
|
|
|
|
|
// Set up Image2BlobParams with your new functionality
|
|
|
|
Image2BlobParams param;
|
|
|
|
param.size = targetSize;
|
|
|
|
param.paddingmode = DNN_PMODE_LETTERBOX;
|
|
|
|
param.borderValue = customPaddingValue; // Use your new feature here
|
|
|
|
|
|
|
|
// Create blob with custom padding
|
|
|
|
Mat blob = dnn::blobFromImageWithParams(img, param);
|
|
|
|
|
|
|
|
// Create target blob for comparison
|
|
|
|
Mat targetBlob = dnn::blobFromImage(targetImg, 1.0, targetSize);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, cvtest::norm(targetBlob, blob, NORM_INF));
|
|
|
|
}
|
|
|
|
|
2023-04-22 00:10:17 +08:00
|
|
|
TEST(blobFromImageWithParams_4ch, letter_box)
|
|
|
|
{
|
|
|
|
Mat img(40, 20, CV_8UC4, cv::Scalar(0,1,2,3));
|
|
|
|
|
|
|
|
// Construct target mat.
|
|
|
|
Mat targetCh[4];
|
|
|
|
// The letterbox will add zero at the left and right of output blob.
|
|
|
|
// After the letterbox, every row data would have same value showing as valVec.
|
|
|
|
std::vector<uint8_t> valVec = {0,0,0,0,0, 1,1,1,1,1,1,1,1,1,1, 0,0,0,0,0};
|
|
|
|
Mat rowM(1, 20, CV_8UC1, valVec.data());
|
|
|
|
|
|
|
|
for(int i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
targetCh[i] = rowM * i;
|
|
|
|
}
|
|
|
|
|
|
|
|
Mat targetImg;
|
|
|
|
merge(targetCh, 4, targetImg);
|
|
|
|
Size targeSize(20, 20);
|
|
|
|
|
|
|
|
Image2BlobParams param;
|
|
|
|
param.size = targeSize;
|
|
|
|
param.paddingmode = DNN_PMODE_LETTERBOX;
|
|
|
|
Mat blob = dnn::blobFromImageWithParams(img, param);
|
|
|
|
Mat targetBlob = dnn::blobFromImage(targetImg, 1.0, targeSize); // only convert data from uint8 to float32.
|
|
|
|
EXPECT_EQ(0, cvtest::norm(targetBlob, blob, NORM_INF));
|
|
|
|
}
|
|
|
|
|
2023-08-08 19:31:32 +08:00
|
|
|
TEST(blobFromImagesWithParams_4ch, multi_image)
|
|
|
|
{
|
|
|
|
Mat img(10, 10, CV_8UC4, cv::Scalar(0, 1, 2, 3));
|
|
|
|
Scalar scalefactor(0.1, 0.2, 0.3, 0.4);
|
|
|
|
|
|
|
|
Image2BlobParams param;
|
|
|
|
param.scalefactor = scalefactor;
|
|
|
|
param.datalayout = DNN_LAYOUT_NHWC;
|
|
|
|
|
|
|
|
Mat blobs = blobFromImagesWithParams(std::vector<Mat> { img, 2*img }, param);
|
|
|
|
vector<Range> ranges;
|
|
|
|
ranges.push_back(Range(0, 1));
|
|
|
|
ranges.push_back(Range(0, blobs.size[1]));
|
|
|
|
ranges.push_back(Range(0, blobs.size[2]));
|
|
|
|
ranges.push_back(Range(0, blobs.size[3]));
|
|
|
|
Mat blob0 = blobs(ranges);
|
|
|
|
ranges[0] = Range(1, 2);
|
|
|
|
Mat blob1 = blobs(ranges);
|
|
|
|
|
|
|
|
EXPECT_EQ(0, cvtest::norm(2*blob0, blob1, NORM_INF));
|
|
|
|
}
|
|
|
|
|
2018-03-04 00:29:37 +08:00
|
|
|
TEST(readNet, Regression)
|
|
|
|
{
|
2019-06-20 21:43:28 +08:00
|
|
|
Net net = readNet(findDataFile("dnn/squeezenet_v1.1.prototxt"),
|
2018-03-04 00:29:37 +08:00
|
|
|
findDataFile("dnn/squeezenet_v1.1.caffemodel", false));
|
|
|
|
EXPECT_FALSE(net.empty());
|
|
|
|
net = readNet(findDataFile("dnn/opencv_face_detector.caffemodel", false),
|
2019-06-20 21:43:28 +08:00
|
|
|
findDataFile("dnn/opencv_face_detector.prototxt"));
|
2018-03-04 00:29:37 +08:00
|
|
|
EXPECT_FALSE(net.empty());
|
|
|
|
net = readNet(findDataFile("dnn/openface_nn4.small2.v1.t7", false));
|
|
|
|
EXPECT_FALSE(net.empty());
|
2019-06-20 21:43:28 +08:00
|
|
|
net = readNet(findDataFile("dnn/tiny-yolo-voc.cfg"),
|
2018-03-04 00:29:37 +08:00
|
|
|
findDataFile("dnn/tiny-yolo-voc.weights", false));
|
|
|
|
EXPECT_FALSE(net.empty());
|
2019-06-20 21:43:28 +08:00
|
|
|
net = readNet(findDataFile("dnn/ssd_mobilenet_v1_coco.pbtxt"),
|
2018-03-04 00:29:37 +08:00
|
|
|
findDataFile("dnn/ssd_mobilenet_v1_coco.pb", false));
|
|
|
|
EXPECT_FALSE(net.empty());
|
|
|
|
}
|
|
|
|
|
2020-02-22 03:39:54 +08:00
|
|
|
TEST(readNet, do_not_call_setInput) // https://github.com/opencv/opencv/issues/16618
|
|
|
|
{
|
|
|
|
// 1. load network
|
|
|
|
const string proto = findDataFile("dnn/squeezenet_v1.1.prototxt");
|
|
|
|
const string model = findDataFile("dnn/squeezenet_v1.1.caffemodel", false);
|
|
|
|
Net net = readNetFromCaffe(proto, model);
|
|
|
|
|
|
|
|
// 2. mistake: no inputs are specified through .setInput()
|
|
|
|
|
|
|
|
// 3. try inference
|
|
|
|
Mat res;
|
|
|
|
EXPECT_THROW(
|
|
|
|
{
|
|
|
|
res = net.forward(); // no inputs after loading => should fail
|
|
|
|
}, cv::Exception);
|
|
|
|
EXPECT_TRUE(res.empty()) << res.size;
|
|
|
|
}
|
|
|
|
|
2020-10-05 14:23:47 +08:00
|
|
|
TEST(Net, empty_forward_18392)
|
|
|
|
{
|
|
|
|
cv::dnn::Net net;
|
|
|
|
Mat image(Size(512, 512), CV_8UC3, Scalar::all(0));
|
|
|
|
Mat inputBlob = cv::dnn::blobFromImage(image, 1.0, Size(512, 512), Scalar(0,0,0), true, false);
|
|
|
|
net.setInput(inputBlob);
|
|
|
|
EXPECT_ANY_THROW(Mat output = net.forward());
|
|
|
|
}
|
|
|
|
|
2020-02-22 03:39:54 +08:00
|
|
|
#ifdef HAVE_INF_ENGINE
|
|
|
|
static
|
|
|
|
void test_readNet_IE_do_not_call_setInput(Backend backendId)
|
|
|
|
{
|
|
|
|
const Target targetId = DNN_TARGET_CPU;
|
|
|
|
|
|
|
|
const std::string& model = findDataFile("dnn/layers/layer_convolution.bin");
|
|
|
|
const std::string& proto = findDataFile("dnn/layers/layer_convolution.xml");
|
|
|
|
|
2022-02-09 22:25:08 +08:00
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
2020-02-22 03:39:54 +08:00
|
|
|
|
|
|
|
Net net = readNet(model, proto);
|
|
|
|
net.setPreferableBackend(backendId);
|
|
|
|
net.setPreferableTarget(targetId);
|
|
|
|
|
|
|
|
// 2. mistake: no inputs are specified through .setInput()
|
|
|
|
|
|
|
|
// 3. try inference
|
|
|
|
Mat res;
|
|
|
|
EXPECT_THROW(
|
|
|
|
{
|
|
|
|
res = net.forward(); // no inputs after loading => should fail
|
|
|
|
}, cv::Exception);
|
|
|
|
EXPECT_TRUE(res.empty()) << res.size;
|
|
|
|
}
|
|
|
|
|
2020-02-27 21:02:32 +08:00
|
|
|
#ifdef HAVE_DNN_IE_NN_BUILDER_2019
|
2020-02-22 03:39:54 +08:00
|
|
|
TEST(readNet, do_not_call_setInput_IE_NN_BUILDER_2019)
|
|
|
|
{
|
|
|
|
test_readNet_IE_do_not_call_setInput(DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019);
|
|
|
|
}
|
2020-02-27 21:02:32 +08:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_DNN_NGRAPH
|
2020-02-22 03:39:54 +08:00
|
|
|
TEST(readNet, do_not_call_setInput_IE_NGRAPH)
|
|
|
|
{
|
|
|
|
test_readNet_IE_do_not_call_setInput(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH);
|
|
|
|
}
|
2020-02-27 21:02:32 +08:00
|
|
|
#endif
|
2020-02-22 03:39:54 +08:00
|
|
|
#endif // HAVE_INF_ENGINE
|
|
|
|
|
2019-07-18 23:41:08 +08:00
|
|
|
typedef testing::TestWithParam<tuple<Backend, Target> > dump;
|
|
|
|
TEST_P(dump, Regression)
|
|
|
|
{
|
|
|
|
const int backend = get<0>(GetParam());
|
|
|
|
const int target = get<1>(GetParam());
|
|
|
|
Net net = readNet(findDataFile("dnn/squeezenet_v1.1.prototxt"),
|
|
|
|
findDataFile("dnn/squeezenet_v1.1.caffemodel", false));
|
|
|
|
|
2019-11-07 02:05:35 +08:00
|
|
|
ASSERT_EQ(net.getLayerInputs(net.getLayerId("fire2/concat")).size(), 2);
|
|
|
|
|
2019-07-18 23:41:08 +08:00
|
|
|
int size[] = {1, 3, 227, 227};
|
|
|
|
Mat input = cv::Mat::ones(4, size, CV_32F);
|
|
|
|
net.setInput(input);
|
|
|
|
net.setPreferableBackend(backend);
|
|
|
|
net.setPreferableTarget(target);
|
|
|
|
EXPECT_FALSE(net.dump().empty());
|
|
|
|
net.forward();
|
|
|
|
EXPECT_FALSE(net.dump().empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(/**/, dump, dnnBackendsAndTargets());
|
|
|
|
|
2018-04-24 19:59:59 +08:00
|
|
|
class FirstCustomLayer CV_FINAL : public Layer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
FirstCustomLayer(const LayerParams ¶ms) : Layer(params) {}
|
|
|
|
|
|
|
|
static Ptr<Layer> create(LayerParams& params)
|
|
|
|
{
|
|
|
|
return Ptr<Layer>(new FirstCustomLayer(params));
|
|
|
|
}
|
|
|
|
|
2018-09-06 18:26:47 +08:00
|
|
|
void forward(InputArrayOfArrays, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays) CV_OVERRIDE
|
2018-04-24 19:59:59 +08:00
|
|
|
{
|
2018-09-06 18:26:47 +08:00
|
|
|
CV_TRACE_FUNCTION();
|
|
|
|
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
|
|
|
|
|
|
|
|
std::vector<Mat> outputs;
|
|
|
|
outputs_arr.getMatVector(outputs);
|
2018-04-24 19:59:59 +08:00
|
|
|
outputs[0].setTo(1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class SecondCustomLayer CV_FINAL : public Layer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SecondCustomLayer(const LayerParams ¶ms) : Layer(params) {}
|
|
|
|
|
|
|
|
static Ptr<Layer> create(LayerParams& params)
|
|
|
|
{
|
|
|
|
return Ptr<Layer>(new SecondCustomLayer(params));
|
|
|
|
}
|
|
|
|
|
2018-09-06 18:26:47 +08:00
|
|
|
void forward(InputArrayOfArrays, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays) CV_OVERRIDE
|
2018-04-24 19:59:59 +08:00
|
|
|
{
|
2018-09-06 18:26:47 +08:00
|
|
|
CV_TRACE_FUNCTION();
|
|
|
|
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
|
|
|
|
|
|
|
|
std::vector<Mat> outputs;
|
|
|
|
outputs_arr.getMatVector(outputs);
|
2018-04-24 19:59:59 +08:00
|
|
|
outputs[0].setTo(2);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TEST(LayerFactory, custom_layers)
|
|
|
|
{
|
|
|
|
LayerParams lp;
|
|
|
|
lp.name = "name";
|
|
|
|
lp.type = "CustomType";
|
|
|
|
|
|
|
|
Mat inp(1, 1, CV_32FC1);
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
|
|
{
|
|
|
|
if (i == 0) { CV_DNN_REGISTER_LAYER_CLASS(CustomType, FirstCustomLayer); }
|
|
|
|
else if (i == 1) { CV_DNN_REGISTER_LAYER_CLASS(CustomType, SecondCustomLayer); }
|
|
|
|
else if (i == 2) { LayerFactory::unregisterLayer("CustomType"); }
|
|
|
|
|
|
|
|
Net net;
|
|
|
|
net.addLayerToPrev(lp.name, lp.type, lp);
|
|
|
|
|
|
|
|
net.setInput(inp);
|
2018-06-01 15:54:12 +08:00
|
|
|
net.setPreferableBackend(DNN_BACKEND_OPENCV);
|
2018-04-24 19:59:59 +08:00
|
|
|
Mat output = net.forward();
|
|
|
|
|
2018-11-15 04:25:23 +08:00
|
|
|
if (i == 0) { EXPECT_EQ(output.at<float>(0), 1); }
|
|
|
|
else if (i == 1) { EXPECT_EQ(output.at<float>(0), 2); }
|
|
|
|
else if (i == 2) { EXPECT_EQ(output.at<float>(0), 1); }
|
2018-04-24 19:59:59 +08:00
|
|
|
}
|
|
|
|
LayerFactory::unregisterLayer("CustomType");
|
|
|
|
}
|
|
|
|
|
2018-06-05 04:51:28 +08:00
|
|
|
typedef testing::TestWithParam<tuple<float, Vec3f, int, tuple<Backend, Target> > > setInput;
|
|
|
|
TEST_P(setInput, normalization)
|
|
|
|
{
|
|
|
|
const float kScale = get<0>(GetParam());
|
|
|
|
const Scalar kMean = get<1>(GetParam());
|
|
|
|
const int dtype = get<2>(GetParam());
|
|
|
|
const int backend = get<0>(get<3>(GetParam()));
|
|
|
|
const int target = get<1>(get<3>(GetParam()));
|
|
|
|
const bool kSwapRB = true;
|
|
|
|
|
Merge pull request #14827 from YashasSamaga:cuda4dnn-csl-low
CUDA backend for the DNN module
* stub cuda4dnn design
* minor fixes for tests and doxygen
* add csl public api directory to module headers
* add low-level CSL components
* add high-level CSL components
* integrate csl::Tensor into backbone code
* switch to CPU iff unsupported; otherwise, fail on error
* add fully connected layer
* add softmax layer
* add activation layers
* support arbitary rank TensorDescriptor
* pass input wrappers to `initCUDA()`
* add 1d/2d/3d-convolution
* add pooling layer
* reorganize and refactor code
* fixes for gcc, clang and doxygen; remove cxx14/17 code
* add blank_layer
* add LRN layer
* add rounding modes for pooling layer
* split tensor.hpp into tensor.hpp and tensor_ops.hpp
* add concat layer
* add scale layer
* add batch normalization layer
* split math.cu into activations.cu and math.hpp
* add eltwise layer
* add flatten layer
* add tensor transform api
* add asymmetric padding support for convolution layer
* add reshape layer
* fix rebase issues
* add permute layer
* add padding support for concat layer
* refactor and reorganize code
* add normalize layer
* optimize bias addition in scale layer
* add prior box layer
* fix and optimize normalize layer
* add asymmetric padding support for pooling layer
* add event API
* improve pooling performance for some padding scenarios
* avoid over-allocation of compute resources to kernels
* improve prior box performance
* enable layer fusion
* add const layer
* add resize layer
* add slice layer
* add padding layer
* add deconvolution layer
* fix channelwise ReLU initialization
* add vector traits
* add vectorized versions of relu, clipped_relu, power
* add vectorized concat kernels
* improve concat_with_offsets performance
* vectorize scale and bias kernels
* add support for multi-billion element tensors
* vectorize prior box kernels
* fix address alignment check
* improve bias addition performance of conv/deconv/fc layers
* restructure code for supporting multiple targets
* add DNN_TARGET_CUDA_FP64
* add DNN_TARGET_FP16
* improve vectorization
* add region layer
* improve tensor API, add dynamic ranks
1. use ManagedPtr instead of a Tensor in backend wrapper
2. add new methods to tensor classes
- size_range: computes the combined size of for a given axis range
- tensor span/view can be constructed from a raw pointer and shape
3. the tensor classes can change their rank at runtime (previously rank was fixed at compile-time)
4. remove device code from tensor classes (as they are unused)
5. enforce strict conditions on tensor class APIs to improve debugging ability
* fix parametric relu activation
* add squeeze/unsqueeze tensor API
* add reorg layer
* optimize permute and enable 2d permute
* enable 1d and 2d slice
* add split layer
* add shuffle channel layer
* allow tensors of different ranks in reshape primitive
* patch SliceOp to allow Crop Layer
* allow extra shape inputs in reshape layer
* use `std::move_backward` instead of `std::move` for insert in resizable_static_array
* improve workspace management
* add spatial LRN
* add nms (cpu) to region layer
* add max pooling with argmax ( and a fix to limits.hpp)
* add max unpooling layer
* rename DNN_TARGET_CUDA_FP32 to DNN_TARGET_CUDA
* update supportBackend to be more rigorous
* remove stray include from preventing non-cuda build
* include op_cuda.hpp outside condition #if
* refactoring, fixes and many optimizations
* drop DNN_TARGET_CUDA_FP64
* fix gcc errors
* increase max. tensor rank limit to six
* add Interp layer
* drop custom layers; use BackendNode
* vectorize activation kernels
* fixes for gcc
* remove wrong assertion
* fix broken assertion in unpooling primitive
* fix build errors in non-CUDA build
* completely remove workspace from public API
* fix permute layer
* enable accuracy and perf. tests for DNN_TARGET_CUDA
* add asynchronous forward
* vectorize eltwise ops
* vectorize fill kernel
* fixes for gcc
* remove CSL headers from public API
* remove csl header source group from cmake
* update min. cudnn version in cmake
* add numerically stable FP32 log1pexp
* refactor code
* add FP16 specialization to cudnn based tensor addition
* vectorize scale1 and bias1 + minor refactoring
* fix doxygen build
* fix invalid alignment assertion
* clear backend wrappers before allocateLayers
* ignore memory lock failures
* do not allocate internal blobs
* integrate NVTX
* add numerically stable half precision log1pexp
* fix indentation, following coding style, improve docs
* remove accidental modification of IE code
* Revert "add asynchronous forward"
This reverts commit 1154b9da9da07e9b52f8a81bdcea48cf31c56f70.
* [cmake] throw error for unsupported CC versions
* fix rebase issues
* add more docs, refactor code, fix bugs
* minor refactoring and fixes
* resolve warnings/errors from clang
* remove haveCUDA() checks from supportBackend()
* remove NVTX integration
* changes based on review comments
* avoid exception when no CUDA device is present
* add color code for CUDA in Net::dump
2019-10-21 19:28:00 +08:00
|
|
|
if(backend == DNN_BACKEND_CUDA)
|
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_CUDA);
|
2018-06-05 04:51:28 +08:00
|
|
|
if (backend == DNN_BACKEND_OPENCV && target == DNN_TARGET_OPENCL_FP16 && dtype != CV_32F)
|
2019-06-15 20:17:25 +08:00
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_OPENCL_FP16);
|
Merge pull request #12703 from wzw-intel:vkcom
* dnn: Add a Vulkan based backend
This commit adds a new backend "DNN_BACKEND_VKCOM" and a
new target "DNN_TARGET_VULKAN". VKCOM means vulkan based
computation library.
This backend uses Vulkan API and SPIR-V shaders to do
the inference computation for layers. The layer types
that implemented in DNN_BACKEND_VKCOM include:
Conv, Concat, ReLU, LRN, PriorBox, Softmax, MaxPooling,
AvePooling, Permute
This is just a beginning work for Vulkan in OpenCV DNN,
more layer types will be supported and performance
tuning is on the way.
Signed-off-by: Wu Zhiwen <zhiwen.wu@intel.com>
* dnn/vulkan: Add FindVulkan.cmake to detect Vulkan SDK
In order to build dnn with Vulkan support, need installing
Vulkan SDK and setting environment variable "VULKAN_SDK" and
add "-DWITH_VULKAN=ON" to cmake command.
You can download Vulkan SDK from:
https://vulkan.lunarg.com/sdk/home#linux
For how to install, see
https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html
https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html
https://vulkan.lunarg.com/doc/sdk/latest/mac/getting_started.html
respectively for linux, windows and mac.
To run the vulkan backend, also need installing mesa driver.
On Ubuntu, use this command 'sudo apt-get install mesa-vulkan-drivers'
To test, use command '$BUILD_DIR/bin/opencv_test_dnn --gtest_filter=*VkCom*'
Signed-off-by: Wu Zhiwen <zhiwen.wu@intel.com>
* dnn/Vulkan: dynamically load Vulkan runtime
No compile-time dependency on Vulkan library.
If Vulkan runtime is unavailable, fallback to CPU path.
Use environment "OPENCL_VULKAN_RUNTIME" to specify path to your
own vulkan runtime library.
Signed-off-by: Wu Zhiwen <zhiwen.wu@intel.com>
* dnn/Vulkan: Add a python script to compile GLSL shaders to SPIR-V shaders
The SPIR-V shaders are in format of text-based 32-bit hexadecimal
numbers, and inserted into .cpp files as unsigned int32 array.
* dnn/Vulkan: Put Vulkan headers into 3rdparty directory and some other fixes
Vulkan header files are copied from
https://github.com/KhronosGroup/Vulkan-Docs/tree/master/include/vulkan
to 3rdparty/include
Fix the Copyright declaration issue.
Refine OpenCVDetectVulkan.cmake
* dnn/Vulkan: Add vulkan backend tests into existing ones.
Also fixed some test failures.
- Don't use bool variable as uniform for shader
- Fix dispathed group number beyond max issue
- Bypass "group > 1" convolution. This should be support in future.
* dnn/Vulkan: Fix multiple initialization in one thread.
2018-10-29 22:51:26 +08:00
|
|
|
if (backend == DNN_BACKEND_VKCOM && dtype != CV_32F)
|
2019-12-02 23:22:10 +08:00
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_VULKAN);
|
2018-06-05 04:51:28 +08:00
|
|
|
|
|
|
|
Mat inp(5, 5, CV_8UC3);
|
|
|
|
randu(inp, 0, 255);
|
|
|
|
Mat ref = blobFromImage(inp, kScale, Size(), kMean, kSwapRB, /*crop*/false);
|
|
|
|
|
|
|
|
LayerParams lp;
|
|
|
|
Net net;
|
|
|
|
net.addLayerToPrev("testLayer", "Identity", lp);
|
|
|
|
net.setPreferableBackend(backend);
|
|
|
|
net.setPreferableTarget(target);
|
|
|
|
|
|
|
|
Mat blob = blobFromImage(inp, 1.0, Size(), Scalar(), kSwapRB, /*crop*/false, dtype);
|
|
|
|
ASSERT_EQ(blob.type(), dtype);
|
|
|
|
net.setInput(blob, "", kScale, kMean);
|
|
|
|
Mat out = net.forward();
|
|
|
|
ASSERT_EQ(out.type(), CV_32F);
|
|
|
|
normAssert(ref, out, "", 4e-4, 1e-3);
|
|
|
|
}
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(/**/, setInput, Combine(
|
|
|
|
Values(1.0f, 1.0 / 127.5),
|
|
|
|
Values(Vec3f(), Vec3f(50, 50, 50), Vec3f(10, 50, 140)),
|
|
|
|
Values(CV_32F, CV_8U),
|
|
|
|
dnnBackendsAndTargets()
|
|
|
|
));
|
|
|
|
|
2018-09-06 18:26:47 +08:00
|
|
|
class CustomLayerWithDeprecatedForward CV_FINAL : public Layer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CustomLayerWithDeprecatedForward(const LayerParams ¶ms) : Layer(params) {}
|
|
|
|
|
|
|
|
static Ptr<Layer> create(LayerParams& params)
|
|
|
|
{
|
|
|
|
return Ptr<Layer>(new CustomLayerWithDeprecatedForward(params));
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals) CV_OVERRIDE
|
|
|
|
{
|
|
|
|
CV_Assert_N(inputs[0]->depth() == CV_32F, outputs[0].depth() == CV_32F);
|
|
|
|
cv::add(*inputs[0], 0.5f, outputs[0]);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class CustomLayerWithDeprecatedForwardAndFallback CV_FINAL : public Layer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CustomLayerWithDeprecatedForwardAndFallback(const LayerParams ¶ms) : Layer(params) {}
|
|
|
|
|
|
|
|
static Ptr<Layer> create(LayerParams& params)
|
|
|
|
{
|
|
|
|
return Ptr<Layer>(new CustomLayerWithDeprecatedForwardAndFallback(params));
|
|
|
|
}
|
|
|
|
|
|
|
|
void forward(InputArrayOfArrays inputs, OutputArrayOfArrays outputs, OutputArrayOfArrays internals) CV_OVERRIDE
|
|
|
|
{
|
|
|
|
CV_TRACE_FUNCTION();
|
|
|
|
CV_TRACE_ARG_VALUE(name, "name", name.c_str());
|
|
|
|
|
|
|
|
CV_OCL_RUN(preferableTarget == DNN_TARGET_OPENCL || preferableTarget == DNN_TARGET_OPENCL_FP16,
|
|
|
|
forward_ocl(inputs, outputs, internals));
|
|
|
|
|
|
|
|
Layer::forward_fallback(inputs, outputs, internals);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void forward(std::vector<Mat*> &inputs, std::vector<Mat> &outputs, std::vector<Mat> &internals) CV_OVERRIDE
|
|
|
|
{
|
|
|
|
CV_Assert_N(inputs[0]->depth() == CV_32F, outputs[0].depth() == CV_32F);
|
|
|
|
cv::add(*inputs[0], 0.5f, outputs[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_OPENCL
|
|
|
|
bool forward_ocl(InputArrayOfArrays inputs_arr, OutputArrayOfArrays outputs_arr, OutputArrayOfArrays internals_arr)
|
|
|
|
{
|
|
|
|
if (inputs_arr.depth() != CV_32F)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
std::vector<UMat> inputs;
|
|
|
|
std::vector<UMat> outputs;
|
|
|
|
inputs_arr.getUMatVector(inputs);
|
|
|
|
outputs_arr.getUMatVector(outputs);
|
|
|
|
cv::add(inputs[0], 0.5f, outputs[0]);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef testing::TestWithParam<tuple<Backend, Target> > DeprecatedForward;
|
|
|
|
TEST_P(DeprecatedForward, CustomLayer)
|
|
|
|
{
|
|
|
|
const int backend = get<0>(GetParam());
|
|
|
|
const int target = get<1>(GetParam());
|
|
|
|
|
|
|
|
Mat inp(5, 5, CV_32FC1);
|
|
|
|
randu(inp, -1.0f, 1.0f);
|
|
|
|
inp = blobFromImage(inp);
|
|
|
|
|
|
|
|
CV_DNN_REGISTER_LAYER_CLASS(CustomType, CustomLayerWithDeprecatedForward);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
LayerParams lp;
|
|
|
|
Net net;
|
|
|
|
net.addLayerToPrev("testLayer", "CustomType", lp);
|
|
|
|
net.setPreferableBackend(backend);
|
|
|
|
net.setPreferableTarget(target);
|
|
|
|
net.setInput(inp);
|
|
|
|
Mat out = net.forward();
|
|
|
|
normAssert(out, inp + 0.5f, "", 2e-4, 7e-4);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
LayerFactory::unregisterLayer("CustomType");
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
LayerFactory::unregisterLayer("CustomType");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_P(DeprecatedForward, CustomLayerWithFallback)
|
|
|
|
{
|
|
|
|
const int backend = get<0>(GetParam());
|
|
|
|
const int target = get<1>(GetParam());
|
|
|
|
|
|
|
|
Mat inp(5, 5, CV_32FC1);
|
|
|
|
randu(inp, -1.0f, 1.0f);
|
|
|
|
inp = blobFromImage(inp);
|
|
|
|
|
|
|
|
CV_DNN_REGISTER_LAYER_CLASS(CustomType, CustomLayerWithDeprecatedForwardAndFallback);
|
|
|
|
try
|
|
|
|
{
|
|
|
|
LayerParams lp;
|
|
|
|
Net net;
|
|
|
|
net.addLayerToPrev("testLayer", "CustomType", lp);
|
|
|
|
net.setPreferableBackend(backend);
|
|
|
|
net.setPreferableTarget(target);
|
|
|
|
net.setInput(inp);
|
|
|
|
Mat out = net.forward();
|
|
|
|
normAssert(out, inp + 0.5f, "", 2e-4, 7e-4);
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
LayerFactory::unregisterLayer("CustomType");
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
LayerFactory::unregisterLayer("CustomType");
|
|
|
|
}
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(/**/, DeprecatedForward, dnnBackendsAndTargets());
|
|
|
|
|
2019-01-28 23:44:31 +08:00
|
|
|
TEST(Net, forwardAndRetrieve)
|
|
|
|
{
|
|
|
|
std::string prototxt =
|
|
|
|
"input: \"data\"\n"
|
|
|
|
"layer {\n"
|
|
|
|
" name: \"testLayer\"\n"
|
|
|
|
" type: \"Slice\"\n"
|
|
|
|
" bottom: \"data\"\n"
|
|
|
|
" top: \"firstCopy\"\n"
|
|
|
|
" top: \"secondCopy\"\n"
|
|
|
|
" slice_param {\n"
|
|
|
|
" axis: 0\n"
|
|
|
|
" slice_point: 2\n"
|
|
|
|
" }\n"
|
|
|
|
"}";
|
|
|
|
Net net = readNetFromCaffe(&prototxt[0], prototxt.size());
|
|
|
|
net.setPreferableBackend(DNN_BACKEND_OPENCV);
|
|
|
|
|
|
|
|
Mat inp(4, 5, CV_32F);
|
|
|
|
randu(inp, -1, 1);
|
|
|
|
net.setInput(inp);
|
|
|
|
|
|
|
|
std::vector<String> outNames;
|
|
|
|
outNames.push_back("testLayer");
|
|
|
|
std::vector<std::vector<Mat> > outBlobs;
|
|
|
|
|
|
|
|
net.forward(outBlobs, outNames);
|
|
|
|
|
|
|
|
EXPECT_EQ(outBlobs.size(), 1);
|
|
|
|
EXPECT_EQ(outBlobs[0].size(), 2);
|
|
|
|
normAssert(outBlobs[0][0], inp.rowRange(0, 2), "first part");
|
|
|
|
normAssert(outBlobs[0][1], inp.rowRange(2, 4), "second part");
|
|
|
|
}
|
|
|
|
|
2019-04-20 02:01:19 +08:00
|
|
|
#ifdef HAVE_INF_ENGINE
|
2019-10-01 18:31:57 +08:00
|
|
|
static const std::chrono::milliseconds async_timeout(10000);
|
2019-05-01 19:51:12 +08:00
|
|
|
|
2019-04-20 02:01:19 +08:00
|
|
|
// This test runs network in synchronous mode for different inputs and then
|
|
|
|
// runs the same model asynchronously for the same inputs.
|
2019-12-02 21:16:06 +08:00
|
|
|
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Async;
|
|
|
|
TEST_P(Async, model_optimizer_pipeline_set_and_forward_single)
|
2019-04-20 02:01:19 +08:00
|
|
|
{
|
2019-05-05 17:49:38 +08:00
|
|
|
const int dtype = get<0>(GetParam());
|
2019-12-02 21:16:06 +08:00
|
|
|
const Backend backendId = get<0>(get<1>(GetParam()));
|
|
|
|
const Target targetId = get<1>(get<1>(GetParam()));
|
2019-04-20 02:01:19 +08:00
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && targetId == DNN_TARGET_MYRIAD)
|
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
|
|
|
|
|
2019-12-02 21:16:06 +08:00
|
|
|
if (backendId != DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && backendId != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
|
|
|
|
throw SkipTestException("No support for async forward");
|
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
const std::string& model = findDataFile("dnn/layers/layer_convolution.bin");
|
|
|
|
const std::string& proto = findDataFile("dnn/layers/layer_convolution.xml");
|
2019-04-20 02:01:19 +08:00
|
|
|
|
2022-02-09 22:25:08 +08:00
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
2019-12-02 21:16:06 +08:00
|
|
|
|
2019-04-20 02:01:19 +08:00
|
|
|
Net netSync = readNet(model, proto);
|
2019-12-02 21:16:06 +08:00
|
|
|
netSync.setPreferableBackend(backendId);
|
|
|
|
netSync.setPreferableTarget(targetId);
|
2019-04-20 02:01:19 +08:00
|
|
|
|
|
|
|
Net netAsync = readNet(model, proto);
|
2019-12-02 21:16:06 +08:00
|
|
|
netAsync.setPreferableBackend(backendId);
|
|
|
|
netAsync.setPreferableTarget(targetId);
|
2019-04-20 02:01:19 +08:00
|
|
|
|
|
|
|
// Generate inputs.
|
|
|
|
const int numInputs = 10;
|
|
|
|
std::vector<Mat> inputs(numInputs);
|
|
|
|
int blobSize[] = {2, 6, 75, 113};
|
|
|
|
for (int i = 0; i < numInputs; ++i)
|
|
|
|
{
|
2019-05-05 17:49:38 +08:00
|
|
|
inputs[i].create(4, &blobSize[0], dtype);
|
|
|
|
randu(inputs[i], 0, 255);
|
2019-04-20 02:01:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Run synchronously.
|
|
|
|
std::vector<Mat> refs(numInputs);
|
|
|
|
for (int i = 0; i < numInputs; ++i)
|
|
|
|
{
|
|
|
|
netSync.setInput(inputs[i]);
|
|
|
|
refs[i] = netSync.forward().clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run asynchronously. To make test more robust, process inputs in the reversed order.
|
|
|
|
for (int i = numInputs - 1; i >= 0; --i)
|
|
|
|
{
|
|
|
|
netAsync.setInput(inputs[i]);
|
|
|
|
|
2019-05-01 19:51:12 +08:00
|
|
|
AsyncArray out = netAsync.forwardAsync();
|
|
|
|
ASSERT_TRUE(out.valid());
|
|
|
|
Mat result;
|
|
|
|
EXPECT_TRUE(out.get(result, async_timeout));
|
|
|
|
normAssert(refs[i], result, format("Index: %d", i).c_str(), 0, 0);
|
2019-04-20 02:01:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 21:16:06 +08:00
|
|
|
TEST_P(Async, model_optimizer_pipeline_set_and_forward_all)
|
2019-04-20 02:01:19 +08:00
|
|
|
{
|
2019-05-05 17:49:38 +08:00
|
|
|
const int dtype = get<0>(GetParam());
|
2019-12-02 21:16:06 +08:00
|
|
|
const Backend backendId = get<0>(get<1>(GetParam()));
|
|
|
|
const Target targetId = get<1>(get<1>(GetParam()));
|
2019-04-20 02:01:19 +08:00
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && targetId == DNN_TARGET_MYRIAD)
|
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
|
|
|
|
|
2019-12-02 21:16:06 +08:00
|
|
|
if (backendId != DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && backendId != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
|
|
|
|
throw SkipTestException("No support for async forward");
|
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
const std::string& model = findDataFile("dnn/layers/layer_convolution.bin");
|
|
|
|
const std::string& proto = findDataFile("dnn/layers/layer_convolution.xml");
|
2019-04-20 02:01:19 +08:00
|
|
|
|
2022-02-09 22:25:08 +08:00
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
2019-04-20 02:01:19 +08:00
|
|
|
|
|
|
|
Net netSync = readNet(model, proto);
|
2019-12-02 21:16:06 +08:00
|
|
|
netSync.setPreferableBackend(backendId);
|
|
|
|
netSync.setPreferableTarget(targetId);
|
2019-04-20 02:01:19 +08:00
|
|
|
|
|
|
|
Net netAsync = readNet(model, proto);
|
2019-12-02 21:16:06 +08:00
|
|
|
netAsync.setPreferableBackend(backendId);
|
|
|
|
netAsync.setPreferableTarget(targetId);
|
2019-04-20 02:01:19 +08:00
|
|
|
|
|
|
|
// Generate inputs.
|
|
|
|
const int numInputs = 10;
|
|
|
|
std::vector<Mat> inputs(numInputs);
|
|
|
|
int blobSize[] = {2, 6, 75, 113};
|
|
|
|
for (int i = 0; i < numInputs; ++i)
|
|
|
|
{
|
2019-05-05 17:49:38 +08:00
|
|
|
inputs[i].create(4, &blobSize[0], dtype);
|
|
|
|
randu(inputs[i], 0, 255);
|
2019-04-20 02:01:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Run synchronously.
|
|
|
|
std::vector<Mat> refs(numInputs);
|
|
|
|
for (int i = 0; i < numInputs; ++i)
|
|
|
|
{
|
|
|
|
netSync.setInput(inputs[i]);
|
|
|
|
refs[i] = netSync.forward().clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run asynchronously. To make test more robust, process inputs in the reversed order.
|
2019-05-01 19:51:12 +08:00
|
|
|
std::vector<AsyncArray> outs(numInputs);
|
2019-04-20 02:01:19 +08:00
|
|
|
for (int i = numInputs - 1; i >= 0; --i)
|
|
|
|
{
|
|
|
|
netAsync.setInput(inputs[i]);
|
|
|
|
outs[i] = netAsync.forwardAsync();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = numInputs - 1; i >= 0; --i)
|
|
|
|
{
|
2019-05-01 19:51:12 +08:00
|
|
|
ASSERT_TRUE(outs[i].valid());
|
|
|
|
Mat result;
|
|
|
|
EXPECT_TRUE(outs[i].get(result, async_timeout));
|
|
|
|
normAssert(refs[i], result, format("Index: %d", i).c_str(), 0, 0);
|
2019-04-20 02:01:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-02 21:16:06 +08:00
|
|
|
TEST_P(Async, create_layer_pipeline_set_and_forward_all)
|
|
|
|
{
|
|
|
|
const int dtype = get<0>(GetParam());
|
|
|
|
const Backend backendId = get<0>(get<1>(GetParam()));
|
|
|
|
const Target targetId = get<1>(get<1>(GetParam()));
|
|
|
|
|
|
|
|
if (backendId != DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && backendId != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
|
|
|
|
throw SkipTestException("No support for async forward");
|
|
|
|
|
2021-11-30 20:08:35 +08:00
|
|
|
// Exception: Default implementation fallbacks in asynchronous mode
|
|
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && dtype == CV_8U)
|
2020-02-07 21:40:50 +08:00
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH);
|
|
|
|
|
2022-02-09 22:25:08 +08:00
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
2019-12-02 21:16:06 +08:00
|
|
|
|
|
|
|
Net netSync;
|
|
|
|
Net netAsync;
|
|
|
|
{
|
|
|
|
int inChannels = 4;
|
|
|
|
int outChannels = 12;
|
|
|
|
int group = 3;
|
|
|
|
Size inSize(113, 75);
|
|
|
|
Size kernel(4, 5);
|
|
|
|
Size stride(2, 3);
|
|
|
|
Size pad(0, 1);
|
|
|
|
Size dilation(1, 1);
|
|
|
|
bool hasBias = true;
|
|
|
|
|
|
|
|
int sz[] = {outChannels, inChannels / group, kernel.height, kernel.width};
|
|
|
|
Mat weights(4, &sz[0], CV_32F);
|
|
|
|
randu(weights, -1.0f, 1.0f);
|
|
|
|
|
|
|
|
LayerParams lp;
|
|
|
|
lp.set("kernel_w", kernel.width);
|
|
|
|
lp.set("kernel_h", kernel.height);
|
|
|
|
lp.set("pad_w", pad.width);
|
|
|
|
lp.set("pad_h", pad.height);
|
|
|
|
lp.set("stride_w", stride.width);
|
|
|
|
lp.set("stride_h", stride.height);
|
|
|
|
lp.set("dilation_w", dilation.width);
|
|
|
|
lp.set("dilation_h", dilation.height);
|
|
|
|
lp.set("num_output", outChannels);
|
|
|
|
lp.set("group", group);
|
|
|
|
lp.set("bias_term", hasBias);
|
|
|
|
lp.type = "Convolution";
|
|
|
|
lp.name = "testLayer";
|
|
|
|
lp.blobs.push_back(weights);
|
|
|
|
if (hasBias)
|
|
|
|
{
|
|
|
|
Mat bias(1, outChannels, CV_32F);
|
|
|
|
randu(bias, -1.0f, 1.0f);
|
|
|
|
lp.blobs.push_back(bias);
|
|
|
|
}
|
|
|
|
int inpSz[] = {1, inChannels, inSize.height, inSize.width};
|
|
|
|
Mat input(4, &inpSz[0], CV_32F);
|
|
|
|
|
|
|
|
netSync.addLayerToPrev(lp.name, lp.type, lp);
|
|
|
|
|
|
|
|
netAsync.addLayerToPrev(lp.name, lp.type, lp);
|
|
|
|
}
|
|
|
|
|
|
|
|
netSync.setPreferableBackend(backendId);
|
|
|
|
netSync.setPreferableTarget(targetId);
|
|
|
|
|
|
|
|
netAsync.setPreferableBackend(backendId);
|
|
|
|
netAsync.setPreferableTarget(targetId);
|
|
|
|
|
|
|
|
// Generate inputs.
|
|
|
|
const int numInputs = 10;
|
|
|
|
std::vector<Mat> inputs(numInputs);
|
|
|
|
int blobSize[] = {1, 4, 75, 113};
|
|
|
|
for (int i = 0; i < numInputs; ++i)
|
|
|
|
{
|
|
|
|
inputs[i].create(4, &blobSize[0], dtype);
|
|
|
|
randu(inputs[i], 0, 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run synchronously.
|
|
|
|
std::vector<Mat> refs(numInputs);
|
|
|
|
for (int i = 0; i < numInputs; ++i)
|
|
|
|
{
|
|
|
|
netSync.setInput(inputs[i]);
|
|
|
|
refs[i] = netSync.forward().clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run asynchronously. To make test more robust, process inputs in the reversed order.
|
|
|
|
std::vector<AsyncArray> outs(numInputs);
|
|
|
|
for (int i = numInputs - 1; i >= 0; --i)
|
|
|
|
{
|
|
|
|
netAsync.setInput(inputs[i]);
|
|
|
|
outs[i] = netAsync.forwardAsync();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = numInputs - 1; i >= 0; --i)
|
|
|
|
{
|
|
|
|
ASSERT_TRUE(outs[i].valid());
|
|
|
|
Mat result;
|
|
|
|
EXPECT_TRUE(outs[i].get(result, async_timeout));
|
|
|
|
normAssert(refs[i], result, format("Index: %d", i).c_str(), 0, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-05 17:49:38 +08:00
|
|
|
INSTANTIATE_TEST_CASE_P(/**/, Async, Combine(
|
2019-12-02 21:16:06 +08:00
|
|
|
Values(CV_32F, CV_8U),
|
|
|
|
dnnBackendsAndTargetsIE()
|
2019-05-05 17:49:38 +08:00
|
|
|
));
|
2019-08-07 03:20:26 +08:00
|
|
|
|
2019-12-02 21:16:06 +08:00
|
|
|
typedef testing::TestWithParam<tuple<Backend, Target> > Test_Model_Optimizer;
|
2019-08-07 03:20:26 +08:00
|
|
|
TEST_P(Test_Model_Optimizer, forward_two_nets)
|
|
|
|
{
|
2019-12-02 21:16:06 +08:00
|
|
|
const Backend backendId = get<0>(GetParam());
|
|
|
|
const Target targetId = get<1>(GetParam());
|
2019-08-07 03:20:26 +08:00
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && targetId == DNN_TARGET_MYRIAD)
|
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
|
|
|
|
|
|
|
|
const std::string& model = findDataFile("dnn/layers/layer_convolution.bin");
|
|
|
|
const std::string& proto = findDataFile("dnn/layers/layer_convolution.xml");
|
2019-08-07 03:20:26 +08:00
|
|
|
|
2022-02-09 22:25:08 +08:00
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
2019-12-02 21:16:06 +08:00
|
|
|
|
2019-08-07 03:20:26 +08:00
|
|
|
Net net0 = readNet(model, proto);
|
2019-12-02 21:16:06 +08:00
|
|
|
net0.setPreferableTarget(targetId);
|
2019-08-07 03:20:26 +08:00
|
|
|
|
|
|
|
Net net1 = readNet(model, proto);
|
2019-12-02 21:16:06 +08:00
|
|
|
net1.setPreferableTarget(targetId);
|
2019-08-07 03:20:26 +08:00
|
|
|
|
|
|
|
// Generate inputs.
|
|
|
|
int blobSize[] = {2, 6, 75, 113};
|
|
|
|
Mat input(4, &blobSize[0], CV_32F);
|
|
|
|
randu(input, 0, 255);
|
|
|
|
|
|
|
|
net0.setInput(input);
|
|
|
|
Mat ref0 = net0.forward().clone();
|
|
|
|
|
|
|
|
net1.setInput(input);
|
|
|
|
Mat ref1 = net1.forward();
|
|
|
|
|
|
|
|
net0.setInput(input);
|
|
|
|
Mat ref2 = net0.forward();
|
|
|
|
|
|
|
|
normAssert(ref0, ref2, 0, 0);
|
|
|
|
}
|
2019-11-27 22:31:38 +08:00
|
|
|
|
|
|
|
TEST_P(Test_Model_Optimizer, readFromBuffer)
|
|
|
|
{
|
|
|
|
const Backend backendId = get<0>(GetParam());
|
|
|
|
const Target targetId = get<1>(GetParam());
|
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && targetId == DNN_TARGET_MYRIAD)
|
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
|
|
|
|
|
2019-11-27 22:31:38 +08:00
|
|
|
if (backendId != DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && backendId != DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
|
|
|
|
throw SkipTestException("No support for async forward");
|
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
const std::string& weightsFile = findDataFile("dnn/layers/layer_convolution.bin");
|
|
|
|
const std::string& modelFile = findDataFile("dnn/layers/layer_convolution.xml");
|
2019-11-27 22:31:38 +08:00
|
|
|
|
2022-02-09 22:25:08 +08:00
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
2019-11-27 22:31:38 +08:00
|
|
|
|
|
|
|
Net net1 = readNetFromModelOptimizer(modelFile, weightsFile);
|
|
|
|
net1.setPreferableBackend(backendId);
|
|
|
|
net1.setPreferableTarget(targetId);
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<char> modelConfig;
|
|
|
|
readFileContent(modelFile, modelConfig);
|
|
|
|
std::vector<char> weights;
|
|
|
|
readFileContent(weightsFile, weights);
|
|
|
|
|
|
|
|
Net net2 = readNetFromModelOptimizer(
|
|
|
|
(const uchar*)modelConfig.data(), modelConfig.size(),
|
|
|
|
(const uchar*)weights.data(), weights.size()
|
|
|
|
);
|
|
|
|
net2.setPreferableBackend(backendId);
|
|
|
|
net2.setPreferableTarget(targetId);
|
|
|
|
|
|
|
|
int blobSize[] = {2, 6, 75, 113};
|
|
|
|
Mat input(4, &blobSize[0], CV_32F);
|
|
|
|
randu(input, 0, 255);
|
|
|
|
|
|
|
|
Mat ref, actual;
|
|
|
|
{
|
|
|
|
net1.setInput(input);
|
|
|
|
ref = net1.forward();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
net2.setInput(input);
|
|
|
|
actual = net2.forward();
|
|
|
|
}
|
|
|
|
|
|
|
|
normAssert(ref, actual, "", 0, 0);
|
|
|
|
}
|
|
|
|
|
2020-04-19 00:42:48 +08:00
|
|
|
TEST_P(Test_Model_Optimizer, flexible_inputs)
|
|
|
|
{
|
|
|
|
const Backend backendId = get<0>(GetParam());
|
|
|
|
const Target targetId = get<1>(GetParam());
|
|
|
|
|
2020-07-30 23:04:22 +08:00
|
|
|
if (backendId == DNN_BACKEND_INFERENCE_ENGINE_NN_BUILDER_2019 && targetId == DNN_TARGET_MYRIAD)
|
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_MYRIAD, CV_TEST_TAG_DNN_SKIP_IE_NN_BUILDER);
|
|
|
|
|
|
|
|
const std::string& model = findDataFile("dnn/layers/layer_convolution.bin");
|
|
|
|
const std::string& proto = findDataFile("dnn/layers/layer_convolution.xml");
|
2020-04-19 00:42:48 +08:00
|
|
|
|
2022-02-09 22:25:08 +08:00
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
2020-04-19 00:42:48 +08:00
|
|
|
|
|
|
|
Net net0 = readNet(model, proto);
|
|
|
|
net0.setPreferableTarget(targetId);
|
|
|
|
|
|
|
|
Net net1 = readNet(model, proto);
|
|
|
|
net1.setPreferableTarget(targetId);
|
|
|
|
|
|
|
|
// Generate inputs.
|
|
|
|
int blobSize0[] = {2, 6, 75, 113};
|
|
|
|
Mat input0(4, &blobSize0[0], CV_32F);
|
|
|
|
randu(input0, 0, 255);
|
|
|
|
|
|
|
|
net0.setInput(input0);
|
|
|
|
Mat ref = net0.forward().clone();
|
|
|
|
|
|
|
|
int blobSize1[] = {1, 6, 10, 9};
|
|
|
|
Mat input1(4, &blobSize1[0], CV_32F);
|
|
|
|
randu(input1, 0, 255);
|
|
|
|
|
|
|
|
net1.setInput(input1);
|
|
|
|
Mat out = net1.forward();
|
|
|
|
EXPECT_NE(out.size, ref.size);
|
|
|
|
|
|
|
|
net1.setInput(input0);
|
|
|
|
out = net1.forward();
|
|
|
|
normAssert(ref, out, 0, 0);
|
|
|
|
}
|
|
|
|
|
2023-10-20 16:49:27 +08:00
|
|
|
TEST_P(Test_Model_Optimizer, readONNX)
|
|
|
|
{
|
|
|
|
const Backend backendId = get<0>(GetParam());
|
|
|
|
const Target targetId = get<1>(GetParam());
|
|
|
|
|
|
|
|
ASSERT_EQ(DNN_BACKEND_INFERENCE_ENGINE_NGRAPH, backendId);
|
|
|
|
|
|
|
|
const std::string& model = findDataFile("dnn/onnx/models/convolution.onnx");
|
|
|
|
|
|
|
|
std::vector<Net> nets = {
|
|
|
|
// Old API
|
|
|
|
readNetFromModelOptimizer(model, ""),
|
|
|
|
readNet("", model, "dldt"),
|
|
|
|
// New API
|
|
|
|
readNetFromModelOptimizer(model),
|
|
|
|
readNet(model, "", "openvino")
|
|
|
|
};
|
|
|
|
|
|
|
|
Mat inp = blobFromNPY(findDataFile("dnn/onnx/data/input_convolution.npy"));
|
|
|
|
Mat ref = blobFromNPY(findDataFile("dnn/onnx/data/output_convolution.npy"));
|
|
|
|
|
|
|
|
for (int i = 0; i < nets.size(); ++i) {
|
|
|
|
nets[i].setPreferableTarget(targetId);
|
|
|
|
nets[i].setInput(inp);
|
|
|
|
Mat out = nets[i].forward();
|
|
|
|
normAssert(out, ref, format("Index: %d", i).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-07 03:20:26 +08:00
|
|
|
INSTANTIATE_TEST_CASE_P(/**/, Test_Model_Optimizer,
|
2019-12-02 21:16:06 +08:00
|
|
|
dnnBackendsAndTargetsIE()
|
2019-08-07 03:20:26 +08:00
|
|
|
);
|
|
|
|
|
2019-04-20 02:01:19 +08:00
|
|
|
#endif // HAVE_INF_ENGINE
|
|
|
|
|
2021-11-27 10:51:57 +08:00
|
|
|
typedef testing::TestWithParam<tuple<MatDepth, MatDepth, tuple<Backend, Target> > > Test_two_inputs;
|
|
|
|
TEST_P(Test_two_inputs, basic)
|
|
|
|
{
|
|
|
|
static const float kScale = 0.5f;
|
|
|
|
static const float kScaleInv = 1.0f / kScale;
|
|
|
|
|
|
|
|
Backend backendId = get<0>(get<2>(GetParam()));
|
|
|
|
Target targetId = get<1>(get<2>(GetParam()));
|
|
|
|
|
2021-12-17 21:28:34 +08:00
|
|
|
int type1 = get<0>(GetParam());
|
|
|
|
int type2 = get<1>(GetParam());
|
|
|
|
|
|
|
|
if (backendId == DNN_BACKEND_VKCOM && !(type1 == CV_32F && type2 == CV_32F))
|
|
|
|
applyTestTag(CV_TEST_TAG_DNN_SKIP_VULKAN);
|
|
|
|
|
2021-11-27 10:51:57 +08:00
|
|
|
Net net;
|
|
|
|
LayerParams lp;
|
|
|
|
lp.type = "Eltwise";
|
|
|
|
lp.name = "testLayer";
|
|
|
|
lp.set("operation", "sum");
|
|
|
|
int eltwiseId = net.addLayerToPrev(lp.name, lp.type, lp); // connect to a first input
|
|
|
|
net.connect(0, 1, eltwiseId, 1); // connect to a second input
|
|
|
|
|
|
|
|
int inpSize[] = {1, 2, 3, 4};
|
2021-12-17 21:28:34 +08:00
|
|
|
Mat firstInp(4, &inpSize[0], type1);
|
|
|
|
Mat secondInp(4, &inpSize[0], type2);
|
2021-11-27 10:51:57 +08:00
|
|
|
randu(firstInp, 0, 100);
|
|
|
|
randu(secondInp, 0, 100);
|
|
|
|
|
|
|
|
#ifndef CV_CXX11
|
|
|
|
std::vector<String> input_names;
|
|
|
|
input_names.push_back("data");
|
|
|
|
input_names.push_back("second_input");
|
|
|
|
net.setInputsNames(input_names);
|
|
|
|
#else
|
|
|
|
net.setInputsNames({"data", "second_input"});
|
|
|
|
#endif
|
|
|
|
net.setInput(firstInp, "data", kScale);
|
|
|
|
net.setInput(secondInp, "second_input", kScaleInv);
|
|
|
|
net.setPreferableBackend(backendId);
|
|
|
|
net.setPreferableTarget(targetId);
|
|
|
|
Mat out = net.forward();
|
|
|
|
|
|
|
|
Mat ref;
|
|
|
|
addWeighted(firstInp, kScale, secondInp, kScaleInv, 0, ref, CV_32F);
|
|
|
|
|
2022-04-20 00:40:25 +08:00
|
|
|
double l1 = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD || targetId == DNN_TARGET_CUDA_FP16) ? 0.06 : 1e-6;
|
|
|
|
double lInf = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD || targetId == DNN_TARGET_CUDA_FP16) ? 0.3 : 1e-5;
|
|
|
|
|
2021-11-27 10:51:57 +08:00
|
|
|
normAssert(out, ref, "", l1, lInf);
|
|
|
|
|
|
|
|
if (cvtest::debugLevel > 0 || HasFailure())
|
|
|
|
{
|
|
|
|
std::cout << "input1 scale=" << kScale << " input2 scale=" << kScaleInv << std::endl;
|
|
|
|
std::cout << "input1: " << firstInp.size << " " << firstInp.reshape(1, 1) << std::endl;
|
|
|
|
std::cout << "input2: " << secondInp.size << " " << secondInp.reshape(1, 1) << std::endl;
|
|
|
|
std::cout << "ref: " << ref.reshape(1, 1) << std::endl;
|
|
|
|
std::cout << "out: " << out.reshape(1, 1) << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
INSTANTIATE_TEST_CASE_P(/*nothing*/, Test_two_inputs, Combine(
|
|
|
|
Values(CV_32F, CV_8U),
|
|
|
|
Values(CV_32F, CV_8U),
|
|
|
|
dnnBackendsAndTargets()
|
|
|
|
));
|
|
|
|
|
2017-11-05 21:48:40 +08:00
|
|
|
}} // namespace
|