opencv/modules/dnn/test/test_int.cpp
alexlyulkov 12b8ed1443
Merge pull request #25755 from alexlyulkov:al/more-types
Added more types support to dnn layers #25755

Added support of more types to dnn layers for CPU, CUDA and OpenVINO backends.
Now most of the multi-type layers support uint8, int8, int32, int64, float32, float16, bool types.

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
2024-06-28 09:02:15 +03:00

1259 lines
39 KiB
C++

// 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"
#include <opencv2/dnn/shape_utils.hpp>
namespace opencv_test { namespace {
int64_t getValueAt(const Mat &m, const int *indices)
{
if (m.type() == CV_Bool)
return m.at<bool>(indices);
else if (m.type() == CV_8U)
return m.at<uint8_t>(indices);
else if (m.type() == CV_8S)
return m.at<int8_t>(indices);
else if (m.type() == CV_32S)
return m.at<int32_t>(indices);
else if (m.type() == CV_64S)
return m.at<int64_t>(indices);
else
CV_Error(Error::BadDepth, "Unsupported type");
return -1;
}
int64_t getValueAt(const Mat &m, int index)
{
if (m.type() == CV_Bool)
return m.ptr<bool>()[index];
else if (m.type() == CV_8U)
return m.ptr<uint8_t>()[index];
else if (m.type() == CV_8S)
return m.ptr<int8_t>()[index];
else if (m.type() == CV_32S)
return m.ptr<int32_t>()[index];
else if (m.type() == CV_64S)
return m.ptr<int64_t>()[index];
else
CV_Error(Error::BadDepth, "Unsupported type");
return -1;
}
void fillRandom(Mat& m, int matType, Backend backend)
{
if (matType == CV_64S && backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
cv::randu(m, 1000000000, 1000000100); // Looks like OpenVINO uses int32 internal values for int64 operations
else if (matType == CV_64S)
cv::randu(m, 1000000000000000ll, 1000000000000100ll);
else if (matType == CV_32S)
cv::randu(m, 1000000000, 1000000100);
else if (matType == CV_8S)
cv::randu(m, -50, 50);
else if (matType == CV_8U)
cv::randu(m, 0, 100);
else if (matType == CV_Bool)
cv::randu(m, 0, 2);
else
CV_Error(Error::BadDepth, "Unsupported type");
}
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_NaryEltwise_Int;
TEST_P(Test_NaryEltwise_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input1(inShape, matType);
Mat input2(inShape, matType);
fillRandom(input1, matType, backend);
fillRandom(input2, matType, backend);
Net net;
LayerParams lp;
lp.type = "NaryEltwise";
lp.name = "testLayer";
if (matType == CV_Bool)
lp.set("operation", "or");
else
lp.set("operation", "add");
int id = net.addLayerToPrev(lp.name, lp.type, lp);
net.connect(0, 1, id, 1);
vector<String> inpNames(2);
inpNames[0] = "input1";
inpNames[1] = "input2";
net.setInputsNames(inpNames);
net.setInput(input1, inpNames[0]);
net.setInput(input2, inpNames[1]);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], input1.size[0]);
EXPECT_EQ(re.size[1], input1.size[1]);
EXPECT_EQ(re.size[2], input1.size[2]);
EXPECT_EQ(re.size[3], input1.size[3]);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
reIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
reIndices[2] = i2;
for (int i3 = 0; i3 < re.size[3]; ++i3)
{
reIndices[3] = i3;
if (matType == CV_Bool)
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input1, reIndices.data()) | getValueAt(input2, reIndices.data()));
else
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input1, reIndices.data()) + getValueAt(input2, reIndices.data()));
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_NaryEltwise_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Const_Int;
TEST_P(Test_Const_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input1(inShape, matType);
Mat inputConst(inShape, matType);
fillRandom(input1, matType, backend);
fillRandom(inputConst, matType, backend);
Net net;
LayerParams lpConst;
lpConst.type = "Const";
lpConst.name = "constLayer";
lpConst.blobs.push_back(inputConst);
int idConst = net.addLayer(lpConst.name, lpConst.type, lpConst);
LayerParams lp;
lp.type = "NaryEltwise";
lp.name = "testLayer";
if (matType == CV_Bool)
lp.set("operation", "or");
else
lp.set("operation", "add");
int idSum = net.addLayer(lp.name, lp.type, lp);
net.connect(0, 0, idSum, 0);
net.connect(idConst, 0, idSum, 1);
net.setInput(input1);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], input1.size[0]);
EXPECT_EQ(re.size[1], input1.size[1]);
EXPECT_EQ(re.size[2], input1.size[2]);
EXPECT_EQ(re.size[3], input1.size[3]);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
reIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
reIndices[2] = i2;
for (int i3 = 0; i3 < re.size[3]; ++i3)
{
reIndices[3] = i3;
if (matType == CV_Bool)
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input1, reIndices.data()) | getValueAt(inputConst, reIndices.data()));
else
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input1, reIndices.data()) + getValueAt(inputConst, reIndices.data()));
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Const_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, int, tuple<Backend, Target> > > Test_ScatterND_Int;
TEST_P(Test_ScatterND_Int, random)
{
int matType = get<0>(GetParam());
int indicesType = get<1>(GetParam());
tuple<Backend, Target> backend_target= get<2>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
std::vector<int64_t> indicesValues{0, 1, 2, 3,
1, 2, 3, 4};
std::vector<int64_t> updatesValues{25, 35};
if (matType == CV_Bool)
{
updatesValues[0] = 1;
updatesValues[1] = 0;
}
Mat indices(2, 4, indicesType);
std::vector<int> updatesShape{2};
Mat updates(updatesShape, matType);
for (int i = 0; i < indicesValues.size(); ++i)
{
if (indicesType == CV_32S)
indices.ptr<int32_t>()[i] = indicesValues[i];
else
indices.ptr<int64_t>()[i] = indicesValues[i];
}
for (int i = 0; i < updatesValues.size(); ++i)
{
if (matType == CV_32S)
updates.ptr<int32_t>()[i] = updatesValues[i];
else if (matType == CV_64S)
updates.ptr<int64_t>()[i] = updatesValues[i];
else if (matType == CV_8S)
updates.ptr<int8_t>()[i] = updatesValues[i];
else if (matType == CV_8U)
updates.ptr<uint8_t>()[i] = updatesValues[i];
else if (matType == CV_Bool)
updates.ptr<bool>()[i] = updatesValues[i];
}
Net net;
LayerParams lp;
lp.type = "ScatterND";
lp.name = "testLayer";
int id = net.addLayerToPrev(lp.name, lp.type, lp);
net.connect(0, 1, id, 1);
net.connect(0, 2, id, 2);
std::vector<String> inpNames(3);
inpNames[0] = "scattedND_input";
inpNames[1] = "scatterND_indices";
inpNames[2] = "scatterND_updates";
net.setInputsNames(inpNames);
net.setInput(input, inpNames[0]);
net.setInput(indices, inpNames[1]);
net.setInput(updates, inpNames[2]);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
ASSERT_EQ(shape(input), shape(re));
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < input.size[0]; ++i0)
{
reIndices[0] = i0;
for (int i1 = 0; i1 < input.size[1]; ++i1)
{
reIndices[1] = i1;
for (int i2 = 0; i2 < input.size[2]; ++i2)
{
reIndices[2] = i2;
for (int i3 = 0; i3 < input.size[3]; ++i3)
{
reIndices[3] = i3;
if (reIndices[0] == indicesValues[0] &&
reIndices[1] == indicesValues[1] &&
reIndices[2] == indicesValues[2] &&
reIndices[3] == indicesValues[3])
{
EXPECT_EQ(getValueAt(re, reIndices.data()), updatesValues[0]);
}
else if (reIndices[0] == indicesValues[4] &&
reIndices[1] == indicesValues[5] &&
reIndices[2] == indicesValues[6] &&
reIndices[3] == indicesValues[7])
{
EXPECT_EQ(getValueAt(re, reIndices.data()), updatesValues[1]);
}
else
{
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input, reIndices.data()));
}
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_ScatterND_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
testing::Values(CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Concat_Int;
TEST_P(Test_Concat_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape1{2, 3, 4, 5};
Mat input1(inShape1, matType);
fillRandom(input1, matType, backend);
std::vector<int> inShape2{2, 2, 4, 5};
Mat input2(inShape2, matType);
fillRandom(input2, matType, backend);
Net net;
LayerParams lp;
lp.type = "Concat";
lp.name = "testLayer";
lp.set<int>("axis", 1);
int id = net.addLayerToPrev(lp.name, lp.type, lp);
net.connect(0, 1, id, 1);
vector<String> inpNames(2);
inpNames[0] = "input1";
inpNames[1] = "input2";
net.setInputsNames(inpNames);
net.setInput(input1, inpNames[0]);
net.setInput(input2, inpNames[1]);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], input1.size[0]);
EXPECT_EQ(re.size[1], input1.size[1] + input2.size[1]);
EXPECT_EQ(re.size[2], input1.size[2]);
EXPECT_EQ(re.size[3], input1.size[3]);
std::vector<int> inIndices(4);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
reIndices[0] = i0;
inIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
reIndices[1] = i1;
if (i1 < input1.size[1])
inIndices[1] = i1;
else
inIndices[1] = i1 - input1.size[1];
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
reIndices[2] = i2;
inIndices[2] = i2;
for (int i3 = 0; i3 < re.size[3]; ++i3)
{
reIndices[3] = i3;
inIndices[3] = i3;
if (i1 < input1.size[1])
{
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input1, inIndices.data()));
}
else
{
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input2, inIndices.data()));
}
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Concat_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_ArgMax_Int;
TEST_P(Test_ArgMax_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); // There is a problem with OpenVINO and custom int64 layers. After model compilation the output tensor type changes from int64 to int32
std::vector<int> inShape{5, 4, 3, 2};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
Net net;
LayerParams lp;
lp.type = "Arg";
lp.name = "testLayer";
lp.set("op", "max");
lp.set<int>("keepdims", 0);
lp.set<int>("axis", 1);
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), CV_64S);
EXPECT_EQ(re.size.dims(), 3);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[2]);
EXPECT_EQ(re.size[2], inShape[3]);
std::vector<int> inIndices(4);
std::vector<int> reIndices(3);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
inIndices[0] = i0;
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
inIndices[2] = i1;
reIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
inIndices[3] = i2;
reIndices[2] = i2;
int64_t max_value = -1000000000000000000l;
int64_t index = 0;
for (int j = 0; j < input.size[1]; ++j)
{
inIndices[1] = j;
int64_t cur_value = getValueAt(input, inIndices.data());
if (cur_value > max_value)
{
max_value = cur_value;
index = j;
}
}
EXPECT_EQ(getValueAt(re, reIndices.data()), index);
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_ArgMax_Int, Combine(
testing::Values(CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Blank_Int;
TEST_P(Test_Blank_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
Net net;
LayerParams lp;
lp.type = "Identity";
lp.name = "testLayer";
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 3);
EXPECT_EQ(re.size[2], 4);
EXPECT_EQ(re.size[3], 5);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
reIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
reIndices[2] = i2;
for (int i3 = 0; i3 < re.size[3]; ++i3)
{
reIndices[3] = i3;
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input, reIndices.data()));
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Blank_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Expand_Int;
TEST_P(Test_Expand_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 1, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
std::vector<int> outShape{2, 1, 4, 5};
Net net;
LayerParams lp;
lp.type = "Expand";
lp.name = "testLayer";
lp.set("shape", DictValue::arrayInt<int*>(&outShape[0], outShape.size()));
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 3);
EXPECT_EQ(re.size[2], 4);
EXPECT_EQ(re.size[3], 5);
std::vector<int> inIndices(4);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
inIndices[0] = i0 % inShape[0];
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
inIndices[1] = i1 % inShape[1];
reIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
inIndices[2] = i2 % inShape[2];
reIndices[2] = i2;
for (int i3 = 0; i3 < re.size[3]; ++i3)
{
inIndices[3] = i3 % inShape[3];
reIndices[3] = i3;
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input, inIndices.data()));
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Expand_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Permute_Int;
TEST_P(Test_Permute_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
std::vector<int> order{0, 2, 3, 1};
Net net;
LayerParams lp;
lp.type = "Permute";
lp.name = "testLayer";
lp.set("order", DictValue::arrayInt<int*>(&order[0], order.size()));
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 4);
EXPECT_EQ(re.size[2], 5);
EXPECT_EQ(re.size[3], 3);
std::vector<int> inIndices(4);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < input.size[0]; ++i0)
{
inIndices[0] = i0;
reIndices[0] = i0;
for (int i1 = 0; i1 < input.size[1]; ++i1)
{
inIndices[1] = i1;
reIndices[3] = i1;
for (int i2 = 0; i2 < input.size[2]; ++i2)
{
inIndices[2] = i2;
reIndices[1] = i2;
for (int i3 = 0; i3 < input.size[3]; ++i3)
{
inIndices[3] = i3;
reIndices[2] = i3;
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input, inIndices.data()));
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Permute_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, int, tuple<Backend, Target> > > Test_GatherElements_Int;
TEST_P(Test_GatherElements_Int, random)
{
int matType = get<0>(GetParam());
int indicesType = get<1>(GetParam());
tuple<Backend, Target> backend_target= get<2>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
std::vector<int> indicesShape{2, 3, 10, 5};
Mat indicesMat(indicesShape, indicesType);
cv::randu(indicesMat, 0, 4);
Net net;
LayerParams lp;
lp.type = "GatherElements";
lp.name = "testLayer";
lp.set("axis", 2);
int id = net.addLayerToPrev(lp.name, lp.type, lp);
net.connect(0, 1, id, 1);
std::vector<String> inpNames(2);
inpNames[0] = "gather_input";
inpNames[1] = "gather_indices";
net.setInputsNames(inpNames);
net.setInput(input, inpNames[0]);
net.setInput(indicesMat, inpNames[1]);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
ASSERT_EQ(shape(indicesMat), shape(re));
std::vector<int> inIndices(4);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < input.size[0]; ++i0)
{
inIndices[0] = i0;
reIndices[0] = i0;
for (int i1 = 0; i1 < input.size[1]; ++i1)
{
inIndices[1] = i1;
reIndices[1] = i1;
for (int i2 = 0; i2 < indicesMat.size[2]; ++i2)
{
reIndices[2] = i2;
for (int i3 = 0; i3 < input.size[3]; ++i3)
{
inIndices[3] = i3;
reIndices[3] = i3;
inIndices[2] = getValueAt(indicesMat, reIndices.data());
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input, inIndices.data()));
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_GatherElements_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
testing::Values(CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, int, tuple<Backend, Target> > > Test_Gather_Int;
TEST_P(Test_Gather_Int, random)
{
int matType = get<0>(GetParam());
int indicesType = get<1>(GetParam());
tuple<Backend, Target> backend_target= get<2>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{5, 1};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
std::vector<int> indices_shape = {1, 1};
Mat indicesMat = cv::Mat(indices_shape, indicesType, 0.0);
std::vector<int> output_shape = {5, 1};
cv::Mat outputRef = cv::Mat(output_shape, matType, input(cv::Range::all(), cv::Range(0, 1)).data);
Net net;
LayerParams lp;
lp.type = "Gather";
lp.name = "testLayer";
lp.set("axis", 1);
lp.set("real_ndims", 1);
int id = net.addLayerToPrev(lp.name, lp.type, lp);
net.connect(0, 1, id, 1);
std::vector<String> inpNames(2);
inpNames[0] = "gather_input";
inpNames[1] = "gather_indices";
net.setInputsNames(inpNames);
net.setInput(input, inpNames[0]);
net.setInput(indicesMat, inpNames[1]);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
ASSERT_EQ(shape(outputRef), shape(re));
normAssert(outputRef, re);
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Gather_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
testing::Values(CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, int, tuple<Backend, Target> > > Test_Cast_Int;
TEST_P(Test_Cast_Int, random)
{
int inMatType = get<0>(GetParam());
int outMatType = get<1>(GetParam());
tuple<Backend, Target> backend_target= get<2>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, inMatType);
if (inMatType == CV_Bool || outMatType == CV_Bool)
cv::randu(input, 0, 1.1);
else
cv::randu(input, 0, 100);
Mat outputRef;
input.convertTo(outputRef, outMatType);
Net net;
LayerParams lp;
lp.type = "Cast";
lp.name = "testLayer";
lp.set("outputType", outMatType);
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), outMatType);
EXPECT_EQ(re.size.dims(), 4);
ASSERT_EQ(shape(input), shape(re));
normAssert(outputRef, re);
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Cast_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Pad_Int;
TEST_P(Test_Pad_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
std::vector<int> paddings{0, 0, 0, 0, 1, 0, 0, 1};
int64_t padValue = matType == CV_Bool ? 1 : 25;
Net net;
LayerParams lp;
lp.type = "Padding";
lp.name = "testLayer";
lp.set("paddings", DictValue::arrayInt<int*>(&paddings[0], paddings.size()));
lp.set<double>("value", padValue);
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], 2);
EXPECT_EQ(re.size[1], 3);
EXPECT_EQ(re.size[2], 5);
EXPECT_EQ(re.size[3], 6);
std::vector<int> reIndices(4);
std::vector<int> inIndices(4);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
reIndices[0] = i0;
inIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
reIndices[1] = i1;
inIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
reIndices[2] = i2;
inIndices[2] = i2 - 1;
for (int i3 = 0; i3 < re.size[3]; ++i3)
{
reIndices[3] = i3;
inIndices[3] = i3;
if (i2 < 1 || i3 >= input.size[3])
{
EXPECT_EQ(getValueAt(re, reIndices.data()), padValue);
}
else
{
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input, inIndices.data()));
}
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Pad_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Slice_Int;
TEST_P(Test_Slice_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inputShape{1, 16, 6, 8};
std::vector<int> begin{0, 4, 0, 0};
std::vector<int> end{1, 8, 6, 8};
Mat input(inputShape, matType);
fillRandom(input, matType, backend);
std::vector<Range> range(4);
for (int i = 0; i < 4; ++i)
range[i] = Range(begin[i], end[i]);
Net net;
LayerParams lp;
lp.type = "Slice";
lp.name = "testLayer";
lp.set("begin", DictValue::arrayInt<int*>(&(begin[0]), 4));
lp.set("end", DictValue::arrayInt<int*>(&(end[0]), 4));
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat out = net.forward();
Mat gt = input(range);
EXPECT_EQ(out.size.dims(), 4);
EXPECT_EQ(out.size[0], gt.size[0]);
EXPECT_EQ(out.size[1], gt.size[1]);
EXPECT_EQ(out.size[2], gt.size[2]);
EXPECT_EQ(out.size[3], gt.size[3]);
for (int i = 0; i < out.total(); ++i)
EXPECT_EQ(getValueAt(out, i), getValueAt(gt, i));
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Slice_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Reshape_Int;
TEST_P(Test_Reshape_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
std::vector<int> outShape{2, 3, 2, 10};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
Net net;
LayerParams lp;
lp.type = "Reshape";
lp.name = "testLayer";
lp.set("dim", DictValue::arrayInt<int*>(&outShape[0], outShape.size()));
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], outShape[0]);
EXPECT_EQ(re.size[1], outShape[1]);
EXPECT_EQ(re.size[2], outShape[2]);
EXPECT_EQ(re.size[3], outShape[3]);
for (int i = 0; i < input.total(); ++i)
EXPECT_EQ(getValueAt(re, i), getValueAt(input, i));
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Reshape_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Flatten_Int;
TEST_P(Test_Flatten_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
Net net;
LayerParams lp;
lp.type = "Flatten";
lp.name = "testLayer";
lp.set("axis", 1);
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 2);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[1] * inShape[2] * inShape[3]);
for (int i = 0; i < input.total(); ++i)
EXPECT_EQ(getValueAt(re, i), getValueAt(input, i));
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Flatten_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Tile_Int;
TEST_P(Test_Tile_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
std::vector<int> inShape{2, 3, 4, 5};
Mat input(inShape, matType);
fillRandom(input, matType, backend);
std::vector<int> repeats{1, 1, 2, 3};
Net net;
LayerParams lp;
lp.type = "Tile";
lp.name = "testLayer";
lp.set("repeats", DictValue::arrayInt<int*>(repeats.data(), repeats.size()));
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 4);
EXPECT_EQ(re.size[0], inShape[0] * repeats[0]);
EXPECT_EQ(re.size[1], inShape[1] * repeats[1]);
EXPECT_EQ(re.size[2], inShape[2] * repeats[2]);
EXPECT_EQ(re.size[3], inShape[3] * repeats[3]);
std::vector<int> inIndices(4);
std::vector<int> reIndices(4);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
inIndices[0] = i0 % inShape[0];
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
inIndices[1] = i1 % inShape[1];
reIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
inIndices[2] = i2 % inShape[2];
reIndices[2] = i2;
for (int i3 = 0; i3 < re.size[3]; ++i3)
{
inIndices[3] = i3 % inShape[3];
reIndices[3] = i3;
EXPECT_EQ(getValueAt(re, reIndices.data()), getValueAt(input, inIndices.data()));
}
}
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Tile_Int, Combine(
testing::Values(CV_Bool, CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Reduce_Int;
TEST_P(Test_Reduce_Int, random)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && matType == CV_64S)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); // There is a problem with OpenVINO and custom int64 layers. After model compilation the output tensor type changes from int64 to int32
std::vector<int> inShape{5, 4, 3, 2};
Mat input(inShape, matType);
if (matType == CV_64S && backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
cv::randu(input, 100000000, 100000100); // Looks like OpenVINO uses int32 internal values for int64 operations
else if (matType == CV_64S)
cv::randu(input, 1000000000000000ll, 1000000000000100ll);
else if (matType == CV_32S)
cv::randu(input, 100000000, 100000100);
else if (matType == CV_8S)
cv::randu(input, -25, 25);
else if (matType == CV_8U)
cv::randu(input, 0, 50);
else
CV_Error(Error::BadDepth, "Unsupported type");
std::vector<int> axes{1};
Net net;
LayerParams lp;
lp.type = "Reduce";
lp.name = "testLayer";
lp.set("reduce", "SUM");
lp.set("keepdims", false);
lp.set("axes", DictValue::arrayInt<int*>(axes.data(), axes.size()));
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 3);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[2]);
EXPECT_EQ(re.size[2], inShape[3]);
std::vector<int> inIndices(4);
std::vector<int> reIndices(3);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
inIndices[0] = i0;
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
inIndices[2] = i1;
reIndices[1] = i1;
for (int i2 = 0; i2 < re.size[2]; ++i2)
{
inIndices[3] = i2;
reIndices[2] = i2;
int64_t value = 0;
for (int j = 0; j < input.size[1]; ++j)
{
inIndices[1] = j;
value += getValueAt(input, inIndices.data());
}
EXPECT_EQ(getValueAt(re, reIndices.data()), value);
}
}
}
}
typedef testing::TestWithParam<tuple<int, tuple<Backend, Target> > > Test_Reduce_Int;
TEST_P(Test_Reduce_Int, two_axes)
{
int matType = get<0>(GetParam());
tuple<Backend, Target> backend_target= get<1>(GetParam());
Backend backend = get<0>(backend_target);
Target target = get<1>(backend_target);
if (backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH && matType == CV_64S)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_NGRAPH); // There is a problem with OpenVINO and custom int64 layers. After model compilation the output tensor type changes from int64 to int32
std::vector<int> inShape{5, 4, 3, 2};
Mat input(inShape, matType);
if (matType == CV_64S && backend == DNN_BACKEND_INFERENCE_ENGINE_NGRAPH)
cv::randu(input, 100000000, 100000100); // Looks like OpenVINO uses int32 internal values for int64 operations
else if (matType == CV_64S)
cv::randu(input, 1000000000000000ll, 1000000000000100ll);
else if (matType == CV_32S)
cv::randu(input, 100000000, 100000100);
else if (matType == CV_8S)
cv::randu(input, -15, 15);
else if (matType == CV_8U)
cv::randu(input, 0, 30);
else
CV_Error(Error::BadDepth, "Unsupported type");
std::vector<int> axes{1, 3};
Net net;
LayerParams lp;
lp.type = "Reduce";
lp.name = "testLayer";
lp.set("reduce", "SUM");
lp.set("keepdims", false);
lp.set("axes", DictValue::arrayInt<int*>(axes.data(), axes.size()));
net.addLayerToPrev(lp.name, lp.type, lp);
net.setInput(input);
net.setPreferableBackend(backend);
net.setPreferableTarget(target);
Mat re;
re = net.forward();
EXPECT_EQ(re.depth(), matType);
EXPECT_EQ(re.size.dims(), 2);
EXPECT_EQ(re.size[0], inShape[0]);
EXPECT_EQ(re.size[1], inShape[2]);
std::vector<int> inIndices(4);
std::vector<int> reIndices(2);
for (int i0 = 0; i0 < re.size[0]; ++i0)
{
inIndices[0] = i0;
reIndices[0] = i0;
for (int i1 = 0; i1 < re.size[1]; ++i1)
{
inIndices[2] = i1;
reIndices[1] = i1;
int64_t value = 0;
for (int i2 = 0; i2 < input.size[3]; ++i2)
{
inIndices[3] = i2;
for (int j = 0; j < input.size[1]; ++j)
{
inIndices[1] = j;
value += getValueAt(input, inIndices.data());
}
}
EXPECT_EQ(getValueAt(re, reIndices.data()), value);
}
}
}
INSTANTIATE_TEST_CASE_P(/**/, Test_Reduce_Int, Combine(
testing::Values(CV_8U, CV_8S, CV_32S, CV_64S),
dnnBackendsAndTargets()
));
}} // namespace