diff --git a/modules/dnn/src/dnn.cpp b/modules/dnn/src/dnn.cpp index 8182394387..b35dda9ddf 100644 --- a/modules/dnn/src/dnn.cpp +++ b/modules/dnn/src/dnn.cpp @@ -597,29 +597,26 @@ struct DataLayer : public Layer CV_TRACE_FUNCTION(); CV_TRACE_ARG_VALUE(name, "name", name.c_str()); + // FIXIT: add wrapper without exception suppression CV_OCL_RUN(IS_DNN_OPENCL_TARGET(preferableTarget), forward_ocl(inputs_arr, outputs_arr, internals_arr)) - if (outputs_arr.depth() == CV_16S) - { - forward_fallback(inputs_arr, outputs_arr, internals_arr); - return; - } + bool isFP16 = outputs_arr.depth() == CV_16S; std::vector outputs, internals; outputs_arr.getMatVector(outputs); internals_arr.getMatVector(internals); - // Supported modes: - // | Input type | Output type | - // | fp32 | fp32 | - // | uint8 | fp32 | for (int i = 0; i < inputsData.size(); ++i) { double scale = scaleFactors[i]; Scalar& mean = means[i]; + CV_Assert(mean == Scalar() || inputsData[i].size[1] <= 4); - CV_CheckTypeEQ(outputs[i].type(), CV_32FC1, ""); + if (isFP16) + CV_CheckTypeEQ(outputs[i].type(), CV_16SC1, ""); + else + CV_CheckTypeEQ(outputs[i].type(), CV_32FC1, ""); bool singleMean = true; for (int j = 1; j < std::min(4, inputsData[i].size[1]) && singleMean; ++j) @@ -629,34 +626,49 @@ struct DataLayer : public Layer if (singleMean) { - inputsData[i].convertTo(outputs[i], CV_32F, scale, -mean[0] * scale); + if (isFP16) + { + Mat input_f32; + inputsData[i].convertTo(input_f32, CV_32F, scale, -mean[0] * scale); + convertFp16(input_f32, outputs[i]); + } + else + { + inputsData[i].convertTo(outputs[i], CV_32F, scale, -mean[0] * scale); + } } else { for (int n = 0; n < inputsData[i].size[0]; ++n) + { for (int c = 0; c < inputsData[i].size[1]; ++c) { Mat inp = getPlane(inputsData[i], n, c); Mat out = getPlane(outputs[i], n, c); - inp.convertTo(out, CV_32F, scale, -mean[c] * scale); + if (isFP16) + { + Mat input_f32; + inp.convertTo(input_f32, CV_32F, scale, -mean[c] * scale); + convertFp16(input_f32, out); + } + else + { + inp.convertTo(out, CV_32F, scale, -mean[c] * scale); + } } + } } } } #ifdef HAVE_OPENCL - std::vector tmp_expressions; bool forward_ocl(InputArrayOfArrays, OutputArrayOfArrays outputs_, OutputArrayOfArrays internals_) { - // Supported modes: - // | Input type | Output type | - // | fp32 | fp32 | - // | fp32 | fp16 | - // | uint8 | fp32 | + bool isFP16 = outputs_.depth() == CV_16S; + std::vector outputs; outputs_.getUMatVector(outputs); - tmp_expressions.clear(); for (int i = 0; i < inputsData.size(); ++i) { Mat inputData = inputsData[i]; @@ -664,58 +676,55 @@ struct DataLayer : public Layer double scale = scaleFactors[i]; Scalar& mean = means[i]; - CV_Assert(mean == Scalar() || inputsData[i].size[1] <= 4); + CV_Assert(mean == Scalar() || inputData.size[1] <= 4); + if (isFP16) + CV_CheckTypeEQ(outputs[i].type(), CV_16SC1, ""); + else + CV_CheckTypeEQ(outputs[i].type(), CV_32FC1, ""); + bool singleMean = true; - for (int j = 1; j < std::min(4, inputsData[i].size[1]) && singleMean; ++j) + for (int j = 1; j < std::min(4, inputData.size[1]) && singleMean; ++j) { singleMean = mean[j] == mean[j - 1]; } - if (outputs_.depth() == CV_16S) + if (singleMean) { - if (singleMean) + if (isFP16) { - tmp_expressions.push_back(Mat(scale * (inputsData[i] - mean[0]))); - convertFp16(tmp_expressions.back(), outputs[i]); + UMat input_i; + inputData.convertTo(input_i, CV_32F, scale, -mean[0] * scale); + convertFp16(input_i, outputs[i]); } else { - for (int n = 0; n < inputsData[i].size[0]; ++n) - for (int c = 0; c < inputsData[i].size[1]; ++c) - { - Mat inp = getPlane(inputsData[i], n, c); - - std::vector plane(4, Range::all()); - plane[0] = Range(n, n + 1); - plane[1] = Range(c, c + 1); - UMat out = outputs[i](plane).reshape(1, inp.dims, inp.size); - - tmp_expressions.push_back(scale * (inp - mean[c])); - convertFp16(tmp_expressions.back(), out); - } + inputData.convertTo(outputs[i], CV_32F, scale, -mean[0] * scale); } } else { - CV_Assert(outputs_.depth() == CV_32F); - if (singleMean) - { - inputsData[i].convertTo(outputs[i], CV_32F, scale, -mean[0] * scale); - } - else + for (int n = 0; n < inputData.size[0]; ++n) { - for (int n = 0; n < inputsData[i].size[0]; ++n) - for (int c = 0; c < inputsData[i].size[1]; ++c) - { - Mat inp = getPlane(inputsData[i], n, c); + for (int c = 0; c < inputData.size[1]; ++c) + { + Mat inp = getPlane(inputData, n, c); - std::vector plane(4, Range::all()); - plane[0] = Range(n, n + 1); - plane[1] = Range(c, c + 1); - UMat out = outputs[i](plane).reshape(1, inp.dims, inp.size); + std::vector plane(4, Range::all()); + plane[0] = Range(n, n + 1); + plane[1] = Range(c, c + 1); + UMat out = outputs[i](plane).reshape(1, inp.dims, inp.size); + if (isFP16) + { + UMat input_i; + inp.convertTo(input_i, CV_32F, scale, -mean[c] * scale); + convertFp16(input_i, out); + } + else + { inp.convertTo(out, CV_32F, scale, -mean[c] * scale); } + } } } } diff --git a/modules/dnn/test/test_layers.cpp b/modules/dnn/test/test_layers.cpp index 836b0aab9a..e61fd733f9 100644 --- a/modules/dnn/test/test_layers.cpp +++ b/modules/dnn/test/test_layers.cpp @@ -1380,57 +1380,6 @@ INSTANTIATE_TEST_CASE_P(/*nothing*/, Test_DLDT_two_inputs_3dim, Combine( testing::ValuesIn(list_sizes) )); -typedef testing::TestWithParam > > Test_DLDT_two_inputs; -TEST_P(Test_DLDT_two_inputs, as_backend) -{ - 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())); - - 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}; - Mat firstInp(4, &inpSize[0], get<0>(GetParam())); - Mat secondInp(4, &inpSize[0], get<1>(GetParam())); - randu(firstInp, 0, 255); - randu(secondInp, 0, 255); - - net.setInputsNames({"data", "second_input"}); - 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); - // Output values are in range [0, 637.5]. - double l1 = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 0.06 : 1e-6; - double lInf = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 0.3 : 1e-5; - 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_DLDT_two_inputs, Combine( - Values(CV_8U, CV_32F), Values(CV_8U, CV_32F), - dnnBackendsAndTargets() -)); - class UnsupportedLayer : public Layer { public: diff --git a/modules/dnn/test/test_misc.cpp b/modules/dnn/test/test_misc.cpp index 11e0f0ec2d..9971450478 100644 --- a/modules/dnn/test/test_misc.cpp +++ b/modules/dnn/test/test_misc.cpp @@ -828,4 +828,64 @@ INSTANTIATE_TEST_CASE_P(/**/, Test_Model_Optimizer, #endif // HAVE_INF_ENGINE +typedef testing::TestWithParam > > 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())); + + 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}; + Mat firstInp(4, &inpSize[0], get<0>(GetParam())); + Mat secondInp(4, &inpSize[0], get<1>(GetParam())); + randu(firstInp, 0, 100); + randu(secondInp, 0, 100); + +#ifndef CV_CXX11 + std::vector 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); + + double l1 = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 0.06 : 1e-6; + double lInf = (targetId == DNN_TARGET_OPENCL_FP16 || targetId == DNN_TARGET_MYRIAD) ? 0.3 : 1e-5; + 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() +)); + }} // namespace