mirror of
https://github.com/opencv/opencv.git
synced 2024-12-15 01:39:10 +08:00
Merge pull request #24977 from Abdurrahheem:ash/primitive_1d_tests
Primitive 1D Tests #24977 This PR is designed to add tests for 1D inputs for layer, which is required after introducing 1d support in 5.x. Currently tests are written for following layers: - [x] `Add`, `Sub` - [x] `Product`, `Div` - [x] `Min`, `Max` - [x] `Argmin`, `Argmax` - [x] `Gather` This list is to be extended for more layer such `gemm`, `conv` etc. ### 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 - [x] There is a reference to the original bug report and related work - [x] 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
This commit is contained in:
parent
a0df2f5328
commit
093ed08892
@ -191,19 +191,19 @@ public:
|
|||||||
std::vector<MatShape> &internals) const CV_OVERRIDE
|
std::vector<MatShape> &internals) const CV_OVERRIDE
|
||||||
{
|
{
|
||||||
CV_Assert(inputs.size() >= 2);
|
CV_Assert(inputs.size() >= 2);
|
||||||
CV_Assert(inputs[0].size() >= 2);
|
CV_Assert(inputs[0].size() >= 1);
|
||||||
CV_Assert(coeffs.size() == 0 || coeffs.size() == inputs.size());
|
CV_Assert(coeffs.size() == 0 || coeffs.size() == inputs.size());
|
||||||
CV_Assert(op == SUM || coeffs.size() == 0);
|
CV_Assert(op == SUM || coeffs.size() == 0);
|
||||||
|
|
||||||
int dims = inputs[0].size();
|
int dims = inputs[0].size();
|
||||||
// Number of channels in output shape is determined by the first input tensor.
|
// Number of channels in output shape is determined by the first input tensor.
|
||||||
bool variableChannels = false;
|
bool variableChannels = false;
|
||||||
int numChannels = inputs[0][1];
|
int numChannels = (dims == 1) ? inputs[0][0] : inputs[0][1];
|
||||||
for (size_t i = 1; i < inputs.size(); i++)
|
for (size_t i = 1; i < inputs.size(); i++)
|
||||||
{
|
{
|
||||||
CV_Assert(inputs[0][0] == inputs[i][0]); // batch sizes are equal
|
CV_Assert(inputs[0][0] == inputs[i][0]); // batch sizes are equal
|
||||||
|
|
||||||
int input_channels = inputs[i][1];
|
int input_channels = (dims == 1) ? inputs[i][0] : inputs[i][1];
|
||||||
if (numChannels != input_channels)
|
if (numChannels != input_channels)
|
||||||
variableChannels = true;
|
variableChannels = true;
|
||||||
|
|
||||||
@ -235,13 +235,13 @@ public:
|
|||||||
outputs.assign(1, inputs[0]);
|
outputs.assign(1, inputs[0]);
|
||||||
outputs[0][1] = numChannels;
|
outputs[0][1] = numChannels;
|
||||||
|
|
||||||
if (dims > 2)
|
if (dims >= 1)
|
||||||
{
|
{
|
||||||
size_t vecIdx = 0;
|
size_t vecIdx = 0;
|
||||||
bool isVecFound = false;
|
bool isVecFound = false;
|
||||||
for (size_t i = 0; i < inputs.size(); i++)
|
for (size_t i = 0; i < inputs.size(); i++)
|
||||||
{
|
{
|
||||||
bool allOnes = isAllOnes(inputs[i], 2, dims);
|
bool allOnes = isAllOnes(inputs[i], (dims != 1) ? 2 : 1, dims);
|
||||||
if (!allOnes && !isVecFound)
|
if (!allOnes && !isVecFound)
|
||||||
{
|
{
|
||||||
vecIdx = i;
|
vecIdx = i;
|
||||||
@ -277,7 +277,7 @@ public:
|
|||||||
for (size_t i = 0; i < inputs.size(); i++)
|
for (size_t i = 0; i < inputs.size(); i++)
|
||||||
{
|
{
|
||||||
MatShape inpShape = shape(inputs[i].size);
|
MatShape inpShape = shape(inputs[i].size);
|
||||||
if (isAllOnes(inpShape, 2, inputs[i].dims))
|
if (isAllOnes(inpShape, 0, inputs[i].dims))
|
||||||
{
|
{
|
||||||
hasVecInput = true;
|
hasVecInput = true;
|
||||||
return;
|
return;
|
||||||
@ -310,10 +310,13 @@ public:
|
|||||||
int nstripes)
|
int nstripes)
|
||||||
{
|
{
|
||||||
const EltwiseOp op = self.op;
|
const EltwiseOp op = self.op;
|
||||||
CV_Check(dst.dims, 1 < dst.dims && dst.dims <= 5, ""); CV_CheckTypeEQ(dst.type(), CV_32FC1, ""); CV_Assert(dst.isContinuous());
|
CV_Check(dst.dims, 1 <= dst.dims && dst.dims <= 5, "");
|
||||||
|
CV_CheckTypeEQ(dst.type(), CV_32FC1, "");
|
||||||
|
CV_Assert(dst.isContinuous());
|
||||||
CV_Assert(self.coeffs.empty() || self.coeffs.size() == (size_t)nsrcs);
|
CV_Assert(self.coeffs.empty() || self.coeffs.size() == (size_t)nsrcs);
|
||||||
CV_CheckGE(nsrcs, 2, "");
|
CV_CheckGE(nsrcs, 2, "");
|
||||||
|
|
||||||
|
if (dst.dims != 1)
|
||||||
CV_Assert(self.outputChannels == dst.size[1]);
|
CV_Assert(self.outputChannels == dst.size[1]);
|
||||||
|
|
||||||
EltwiseInvoker p(self);
|
EltwiseInvoker p(self);
|
||||||
|
@ -618,6 +618,204 @@ TEST(Layer_LSTM_Test_Accuracy_with_, HiddenParams)
|
|||||||
normAssert(h_t_reference, outputs[0]);
|
normAssert(h_t_reference, outputs[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef testing::TestWithParam<tuple<int, int>> Layer_Gather_1d_Test;
|
||||||
|
TEST_P(Layer_Gather_1d_Test, Accuracy) {
|
||||||
|
|
||||||
|
int batch_size = get<0>(GetParam());
|
||||||
|
int axis = get<1>(GetParam());
|
||||||
|
|
||||||
|
LayerParams lp;
|
||||||
|
lp.type = "Gather";
|
||||||
|
lp.name = "gatherLayer";
|
||||||
|
lp.set("axis", axis);
|
||||||
|
lp.set("real_ndims", 1);
|
||||||
|
|
||||||
|
Ptr<GatherLayer> layer = GatherLayer::create(lp);
|
||||||
|
|
||||||
|
std::vector<int> input_shape = {batch_size, 1};
|
||||||
|
std::vector<int> indices_shape = {1, 1};
|
||||||
|
std::vector<int> output_shape = {batch_size, 1};
|
||||||
|
|
||||||
|
if (batch_size == 0){
|
||||||
|
input_shape.erase(input_shape.begin());
|
||||||
|
indices_shape.erase(indices_shape.begin());
|
||||||
|
output_shape.erase(output_shape.begin());
|
||||||
|
} else if (axis == 0) {
|
||||||
|
output_shape[0] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat input = cv::Mat(input_shape, CV_32F, 1.0);
|
||||||
|
cv::randu(input, 0.0, 1.0);
|
||||||
|
cv::Mat indices = cv::Mat(indices_shape, CV_32F, 0.0);
|
||||||
|
cv::Mat output_ref = cv::Mat(output_shape, CV_32F, input(cv::Range::all(), cv::Range(0, 1)).data);
|
||||||
|
|
||||||
|
std::vector<Mat> inputs{input, indices};
|
||||||
|
std::vector<Mat> outputs;
|
||||||
|
|
||||||
|
runLayer(layer, inputs, outputs);
|
||||||
|
ASSERT_EQ(shape(output_ref), shape(outputs[0]));
|
||||||
|
normAssert(output_ref, outputs[0]);
|
||||||
|
}
|
||||||
|
INSTANTIATE_TEST_CASE_P(/*nothing*/, Layer_Gather_1d_Test, Combine(
|
||||||
|
/*input blob shape*/ Values(0, 1, 2, 3),
|
||||||
|
/*operation*/ Values(0, 1)
|
||||||
|
));
|
||||||
|
|
||||||
|
typedef testing::TestWithParam<tuple<int, int, std::string>> Layer_Arg_1d_Test;
|
||||||
|
TEST_P(Layer_Arg_1d_Test, Accuracy) {
|
||||||
|
|
||||||
|
int batch_size = get<0>(GetParam());
|
||||||
|
int axis = get<1>(GetParam());
|
||||||
|
std::string operation = get<2>(GetParam());
|
||||||
|
|
||||||
|
LayerParams lp;
|
||||||
|
lp.type = "Arg";
|
||||||
|
lp.name = "arg" + operation + "_Layer";
|
||||||
|
lp.set("op", operation);
|
||||||
|
lp.set("axis", axis);
|
||||||
|
lp.set("keepdims", 1);
|
||||||
|
lp.set("select_last_index", 0);
|
||||||
|
|
||||||
|
Ptr<ArgLayer> layer = ArgLayer::create(lp);
|
||||||
|
|
||||||
|
std::vector<int> input_shape = {batch_size, 1};
|
||||||
|
std::vector<int> output_shape = {1, 1};
|
||||||
|
|
||||||
|
if (batch_size == 0){
|
||||||
|
input_shape.erase(input_shape.begin());
|
||||||
|
output_shape.erase(output_shape.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (axis != 0 && batch_size != 0){
|
||||||
|
output_shape[0] = batch_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
cv::Mat input = cv::Mat(input_shape, CV_32F, 1);
|
||||||
|
cv::Mat output_ref = cv::Mat(output_shape, CV_32F, 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < batch_size; ++i)
|
||||||
|
input.at<float>(i, 0) = static_cast<float>(i + 1);
|
||||||
|
|
||||||
|
std::vector<Mat> inputs{input};
|
||||||
|
std::vector<Mat> outputs;
|
||||||
|
|
||||||
|
runLayer(layer, inputs, outputs);
|
||||||
|
ASSERT_EQ(shape(output_ref), shape(outputs[0]));
|
||||||
|
normAssert(output_ref, outputs[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(/*nothing*/, Layer_Arg_1d_Test, Combine(
|
||||||
|
/*input blob shape*/ Values(0, 1, 2, 3),
|
||||||
|
/*operation*/ Values(0, 1),
|
||||||
|
/*operation*/ Values( "max", "min")
|
||||||
|
));
|
||||||
|
|
||||||
|
typedef testing::TestWithParam<tuple<int, std::string>> Layer_NaryElemwise_1d_Test;
|
||||||
|
TEST_P(Layer_NaryElemwise_1d_Test, Accuracy) {
|
||||||
|
|
||||||
|
int batch_size = get<0>(GetParam());
|
||||||
|
std::string operation = get<1>(GetParam());
|
||||||
|
|
||||||
|
LayerParams lp;
|
||||||
|
lp.type = "Eltwise";
|
||||||
|
lp.name = operation + "_Layer";
|
||||||
|
lp.set("operation", operation);
|
||||||
|
Ptr<NaryEltwiseLayer> layer = NaryEltwiseLayer::create(lp);
|
||||||
|
|
||||||
|
std::vector<int> input_shape = {batch_size, 1};
|
||||||
|
if (batch_size == 0)
|
||||||
|
input_shape.erase(input_shape.begin());
|
||||||
|
|
||||||
|
cv::Mat input1 = cv::Mat(input_shape, CV_32F, 0.0);
|
||||||
|
cv::Mat input2 = cv::Mat(input_shape, CV_32F, 0.0);
|
||||||
|
cv::randu(input1, 0.0, 1.0);
|
||||||
|
cv::randu(input2, 0.0, 1.0);
|
||||||
|
|
||||||
|
cv::Mat output_ref;
|
||||||
|
if (operation == "sum") {
|
||||||
|
output_ref = input1 + input2;
|
||||||
|
} else if (operation == "mul") {
|
||||||
|
output_ref = input1.mul(input2);
|
||||||
|
} else if (operation == "div") {
|
||||||
|
output_ref = input1 / input2;
|
||||||
|
} else if (operation == "sub") {
|
||||||
|
output_ref = input1 - input2;
|
||||||
|
} else {
|
||||||
|
output_ref = cv::Mat();
|
||||||
|
}
|
||||||
|
std::vector<Mat> inputs{input1, input2};
|
||||||
|
std::vector<Mat> outputs;
|
||||||
|
|
||||||
|
runLayer(layer, inputs, outputs);
|
||||||
|
if (!output_ref.empty()) {
|
||||||
|
ASSERT_EQ(shape(output_ref), shape(outputs[0]));
|
||||||
|
normAssert(output_ref, outputs[0]);
|
||||||
|
} else {
|
||||||
|
CV_Error(Error::StsAssert, "Provided operation: " + operation + " is not supported. Please check the test instantiation.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(/*nothing*/, Layer_NaryElemwise_1d_Test, Combine(
|
||||||
|
/*input blob shape*/ Values(0, 1),
|
||||||
|
/*operation*/ Values("div", "mul", "sum", "sub")
|
||||||
|
));
|
||||||
|
|
||||||
|
typedef testing::TestWithParam<tuple<int, std::string>> Layer_Elemwise_1d_Test;
|
||||||
|
TEST_P(Layer_Elemwise_1d_Test, Accuracy) {
|
||||||
|
|
||||||
|
int batch_size = get<0>(GetParam());
|
||||||
|
std::string operation = get<1>(GetParam());
|
||||||
|
|
||||||
|
LayerParams lp;
|
||||||
|
lp.type = "Eltwise";
|
||||||
|
lp.name = operation + "_Layer";
|
||||||
|
lp.set("operation", operation);
|
||||||
|
Ptr<EltwiseLayer> layer = EltwiseLayer::create(lp);
|
||||||
|
|
||||||
|
std::vector<int> input_shape = {batch_size, 1};
|
||||||
|
if (batch_size == 0)
|
||||||
|
input_shape.erase(input_shape.begin());
|
||||||
|
|
||||||
|
cv::Mat input1 = cv::Mat(input_shape, CV_32F, 1.0);
|
||||||
|
cv::Mat input2 = cv::Mat(input_shape, CV_32F, 1.0);
|
||||||
|
cv::randu(input1, 0.0, 1.0);
|
||||||
|
cv::randu(input2, 0.0, 1.0);
|
||||||
|
|
||||||
|
// Dynamically select the operation
|
||||||
|
cv::Mat output_ref;
|
||||||
|
if (operation == "sum") {
|
||||||
|
output_ref = input1 + input2;
|
||||||
|
} else if (operation == "max") {
|
||||||
|
output_ref = cv::max(input1, input2);
|
||||||
|
} else if (operation == "min") {
|
||||||
|
output_ref = cv::min(input1, input2);
|
||||||
|
} else if (operation == "prod") {
|
||||||
|
output_ref = input1.mul(input2);
|
||||||
|
} else if (operation == "div") {
|
||||||
|
output_ref = input1 / input2;
|
||||||
|
} else {
|
||||||
|
output_ref = cv::Mat();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Mat> inputs{input1, input2};
|
||||||
|
std::vector<Mat> outputs;
|
||||||
|
|
||||||
|
runLayer(layer, inputs, outputs);
|
||||||
|
|
||||||
|
if (!output_ref.empty()) {
|
||||||
|
ASSERT_EQ(shape(output_ref), shape(outputs[0]));
|
||||||
|
normAssert(output_ref, outputs[0]);
|
||||||
|
} else {
|
||||||
|
CV_Error(Error::StsAssert, "Provided operation: " + operation + " is not supported. Please check the test instantiation.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(/*nothing*/, Layer_Elemwise_1d_Test, Combine(
|
||||||
|
/*input blob shape*/ Values(0, 1, 2, 3),
|
||||||
|
/*operation*/ Values("div", "prod", "max", "min", "sum")
|
||||||
|
));
|
||||||
|
|
||||||
TEST(Layer_GRU_Test_Accuracy_with_, Pytorch)
|
TEST(Layer_GRU_Test_Accuracy_with_, Pytorch)
|
||||||
{
|
{
|
||||||
Mat Wx = blobFromNPY(_tf("gru.W.npy"));
|
Mat Wx = blobFromNPY(_tf("gru.W.npy"));
|
||||||
|
Loading…
Reference in New Issue
Block a user