Commit 34f6b054 authored by Lubov Batanina's avatar Lubov Batanina Committed by Alexander Alekhin

Merge pull request #14996 from l-bat:ocv_deconv3d

* Support Deconvolution3D on IE backend

* Add test tag

* Fix tests
parent 8bcd7e12
...@@ -67,7 +67,7 @@ public: ...@@ -67,7 +67,7 @@ public:
BaseConvolutionLayerImpl(const LayerParams &params) BaseConvolutionLayerImpl(const LayerParams &params)
{ {
setParamsFrom(params); setParamsFrom(params);
getConvolutionKernelParams(params, kernel_size, pads_begin, pads_end, strides, dilations, padMode); getConvolutionKernelParams(params, kernel_size, pads_begin, pads_end, strides, dilations, padMode, adjust_pads);
numOutput = params.get<int>("num_output"); numOutput = params.get<int>("num_output");
int ngroups = params.get<int>("group", 1); int ngroups = params.get<int>("group", 1);
...@@ -83,14 +83,14 @@ public: ...@@ -83,14 +83,14 @@ public:
pad = Size(pads_begin[1], pads_begin[0]); pad = Size(pads_begin[1], pads_begin[0]);
dilation = Size(dilations[1], dilations[0]); dilation = Size(dilations[1], dilations[0]);
adjust_pads.push_back(params.get<int>("adj_h", 0));
adjust_pads.push_back(params.get<int>("adj_w", 0));
adjustPad.height = adjust_pads[0]; adjustPad.height = adjust_pads[0];
adjustPad.width = adjust_pads[1]; adjustPad.width = adjust_pads[1];
CV_Assert(adjustPad.width < stride.width &&
adjustPad.height < stride.height);
} }
for (int i = 0; i < adjust_pads.size(); i++) {
CV_Assert(adjust_pads[i] < strides[i]);
}
fusedWeights = false; fusedWeights = false;
fusedBias = false; fusedBias = false;
} }
...@@ -1241,29 +1241,39 @@ public: ...@@ -1241,29 +1241,39 @@ public:
virtual bool supportBackend(int backendId) CV_OVERRIDE virtual bool supportBackend(int backendId) CV_OVERRIDE
{ {
#ifdef HAVE_INF_ENGINE #ifdef HAVE_INF_ENGINE
const int outGroupCn = blobs[0].size[1]; // Weights are in IOHW layout const int outGroupCn = blobs[0].size[1]; // Weights are in IOHW or IODHW layout
const int group = numOutput / outGroupCn; const int group = numOutput / outGroupCn;
if (backendId == DNN_BACKEND_INFERENCE_ENGINE) if (backendId == DNN_BACKEND_INFERENCE_ENGINE)
{ {
if (kernel_size.size() == 3) if (kernel_size.size() == 3 && preferableTarget != DNN_TARGET_CPU) {
CV_Error(Error::StsNotImplemented, "Unsupported deconvolution3D layer"); return false;
}
if (adjustPad.height || adjustPad.width) if (std::accumulate(adjust_pads.begin(), adjust_pads.end(), 0, std::plus<size_t>()) > 0)
{ {
if (padMode.empty()) if (padMode.empty())
{ {
if (preferableTarget != DNN_TARGET_CPU && group != 1) if (preferableTarget != DNN_TARGET_CPU && group != 1)
{ {
if ((adjustPad.height && pad.height) || (adjustPad.width && pad.width)) for (int i = 0; i < adjust_pads.size(); i++) {
if (adjust_pads[i] && pads_begin[i])
return false;
}
}
for (int i = 0; i < adjust_pads.size(); i++) {
if (pads_end[i] < adjust_pads[i])
return false; return false;
} }
return pad.width >= adjustPad.width && pad.height >= adjustPad.height; return true;
} }
else if (padMode == "SAME") else if (padMode == "SAME")
{ {
return kernel.width >= pad.width + 1 + adjustPad.width && for (int i = 0; i < adjust_pads.size(); i++) {
kernel.height >= pad.height + 1 + adjustPad.height; if (kernel_size[i] < pads_begin[i] + 1 + adjust_pads[i])
return false;
}
return true;
} }
else if (padMode == "VALID") else if (padMode == "VALID")
return false; return false;
...@@ -1274,7 +1284,7 @@ public: ...@@ -1274,7 +1284,7 @@ public:
return preferableTarget == DNN_TARGET_CPU; return preferableTarget == DNN_TARGET_CPU;
} }
if (preferableTarget == DNN_TARGET_OPENCL || preferableTarget == DNN_TARGET_OPENCL_FP16) if (preferableTarget == DNN_TARGET_OPENCL || preferableTarget == DNN_TARGET_OPENCL_FP16)
return dilation.width == 1 && dilation.height == 1; return std::accumulate(dilations.begin(), dilations.end(), 1, std::multiplies<size_t>()) == 1;
return true; return true;
} }
else else
...@@ -1861,11 +1871,14 @@ public: ...@@ -1861,11 +1871,14 @@ public:
#ifdef HAVE_INF_ENGINE #ifdef HAVE_INF_ENGINE
virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> > &) CV_OVERRIDE virtual Ptr<BackendNode> initInfEngine(const std::vector<Ptr<BackendWrapper> > &) CV_OVERRIDE
{ {
auto ieWeights = wrapToInfEngineBlob(blobs[0], InferenceEngine::Layout::OIHW); InferenceEngine::Layout layout = blobs[0].dims == 5? InferenceEngine::Layout::NCDHW :
InferenceEngine::Layout::OIHW;
auto ieWeights = wrapToInfEngineBlob(blobs[0], layout);
if (fusedWeights) if (fusedWeights)
{ {
ieWeights = InferenceEngine::make_shared_blob<float>( ieWeights = InferenceEngine::make_shared_blob<float>(
InferenceEngine::Precision::FP32, InferenceEngine::Layout::OIHW, InferenceEngine::Precision::FP32, layout,
ieWeights->dims()); ieWeights->dims());
ieWeights->allocate(); ieWeights->allocate();
...@@ -1874,7 +1887,7 @@ public: ...@@ -1874,7 +1887,7 @@ public:
transpose(weightsMat, newWeights); transpose(weightsMat, newWeights);
} }
const int outGroupCn = blobs[0].size[1]; // Weights are in IOHW layout const int outGroupCn = blobs[0].size[1]; // Weights are in IOHW or OIDHW layout
const int group = numOutput / outGroupCn; const int group = numOutput / outGroupCn;
InferenceEngine::Builder::DeconvolutionLayer ieLayer(name); InferenceEngine::Builder::DeconvolutionLayer ieLayer(name);
...@@ -1886,12 +1899,19 @@ public: ...@@ -1886,12 +1899,19 @@ public:
if (padMode.empty()) if (padMode.empty())
{ {
ieLayer.setPaddingsEnd({pads_end[0] - adjust_pads[0], pads_end[1] - adjust_pads[1]}); std::vector<size_t> paddings_end;
for (int i = 0; i < pads_end.size(); i++) {
paddings_end.push_back(pads_end[i] - adjust_pads[i]);
}
ieLayer.setPaddingsEnd(paddings_end);
} }
else if (padMode == "SAME") else if (padMode == "SAME")
{ {
ieLayer.setPaddingsEnd({kernel_size[0] - pads_begin[0] - 1 - adjust_pads[0], std::vector<size_t> paddings_end;
kernel_size[1] - pads_begin[1] - 1 - adjust_pads[1]}); for (int i = 0; i < pads_begin.size(); i++) {
paddings_end.push_back(kernel_size[i] - pads_begin[i] - 1 - adjust_pads[i]);
}
ieLayer.setPaddingsEnd(paddings_end);
} }
ieLayer.setGroup((size_t)group); ieLayer.setGroup((size_t)group);
ieLayer.setOutDepth((size_t)numOutput); ieLayer.setOutDepth((size_t)numOutput);
...@@ -1911,10 +1931,12 @@ public: ...@@ -1911,10 +1931,12 @@ public:
float flops = 0; float flops = 0;
int outChannels = blobs[0].size[0]; int outChannels = blobs[0].size[0];
size_t karea = std::accumulate(kernel_size.begin(), kernel_size.end(),
1, std::multiplies<size_t>());
for (int i = 0; i < inputs.size(); i++) for (int i = 0; i < inputs.size(); i++)
{ {
flops += CV_BIG_INT(2)*outChannels*kernel.area()*total(inputs[i]); flops += CV_BIG_INT(2)*outChannels*karea*total(inputs[i]);
} }
return flops; return flops;
......
...@@ -175,11 +175,13 @@ void getPoolingKernelParams(const LayerParams &params, std::vector<size_t>& kern ...@@ -175,11 +175,13 @@ void getPoolingKernelParams(const LayerParams &params, std::vector<size_t>& kern
} }
void getConvolutionKernelParams(const LayerParams &params, std::vector<size_t>& kernel, std::vector<size_t>& pads_begin, void getConvolutionKernelParams(const LayerParams &params, std::vector<size_t>& kernel, std::vector<size_t>& pads_begin,
std::vector<size_t>& pads_end, std::vector<size_t>& strides, std::vector<size_t>& dilations, cv::String &padMode) std::vector<size_t>& pads_end, std::vector<size_t>& strides,
std::vector<size_t>& dilations, cv::String &padMode, std::vector<size_t>& adjust_pads)
{ {
util::getKernelSize(params, kernel); util::getKernelSize(params, kernel);
util::getStrideAndPadding(params, pads_begin, pads_end, strides, padMode, kernel.size()); util::getStrideAndPadding(params, pads_begin, pads_end, strides, padMode, kernel.size());
util::getParameter(params, "dilation", "dilation", dilations, true, std::vector<size_t>(kernel.size(), 1)); util::getParameter(params, "dilation", "dilation", dilations, true, std::vector<size_t>(kernel.size(), 1));
util::getParameter(params, "adj", "adj", adjust_pads, true, std::vector<size_t>(kernel.size(), 0));
for (int i = 0; i < dilations.size(); i++) for (int i = 0; i < dilations.size(); i++)
CV_Assert(dilations[i] > 0); CV_Assert(dilations[i] > 0);
......
...@@ -60,7 +60,8 @@ namespace cv ...@@ -60,7 +60,8 @@ namespace cv
namespace dnn namespace dnn
{ {
void getConvolutionKernelParams(const LayerParams &params, std::vector<size_t>& kernel, std::vector<size_t>& pads_begin, void getConvolutionKernelParams(const LayerParams &params, std::vector<size_t>& kernel, std::vector<size_t>& pads_begin,
std::vector<size_t>& pads_end, std::vector<size_t>& strides, std::vector<size_t>& dilations, cv::String &padMode); std::vector<size_t>& pads_end, std::vector<size_t>& strides, std::vector<size_t>& dilations,
cv::String &padMode, std::vector<size_t>& adjust_pads);
void getPoolingKernelParams(const LayerParams &params, std::vector<size_t>& kernel, bool &globalPooling, void getPoolingKernelParams(const LayerParams &params, std::vector<size_t>& kernel, bool &globalPooling,
std::vector<size_t>& pads_begin, std::vector<size_t>& pads_end, std::vector<size_t>& strides, cv::String &padMode); std::vector<size_t>& pads_begin, std::vector<size_t>& pads_end, std::vector<size_t>& strides, cv::String &padMode);
......
...@@ -682,42 +682,37 @@ void ONNXImporter::populateNet(Net dstNet) ...@@ -682,42 +682,37 @@ void ONNXImporter::populateNet(Net dstNet)
layerParams.set("num_output", layerParams.blobs[0].size[1] * layerParams.get<int>("group", 1)); layerParams.set("num_output", layerParams.blobs[0].size[1] * layerParams.get<int>("group", 1));
layerParams.set("bias_term", node_proto.input_size() == 3); layerParams.set("bias_term", node_proto.input_size() == 3);
if (!layerParams.has("kernel_size"))
CV_Error(Error::StsNotImplemented,
"Required attribute 'kernel_size' is not present.");
if (layerParams.has("output_shape")) if (layerParams.has("output_shape"))
{ {
const DictValue& outShape = layerParams.get("output_shape"); const DictValue& outShape = layerParams.get("output_shape");
DictValue strides = layerParams.get("stride");
DictValue kernel = layerParams.get("kernel_size");
if (outShape.size() != 4) String padMode;
CV_Error(Error::StsNotImplemented, "Output shape must have 4 elements."); std::vector<int> adjust_pads;
if (layerParams.has("pad_mode"))
DictValue stride = layerParams.get("stride");
const int strideY = stride.getIntValue(0);
const int strideX = stride.getIntValue(1);
const int outH = outShape.getIntValue(2);
const int outW = outShape.getIntValue(3);
if (layerParams.get<String>("pad_mode") == "SAME")
{ {
layerParams.set("adj_w", (outW - 1) % strideX); padMode = toUpperCase(layerParams.get<String>("pad_mode"));
layerParams.set("adj_h", (outH - 1) % strideY); if (padMode != "SAME" && padMode != "VALID")
} CV_Error(Error::StsError, "Unsupported padding mode " + padMode);
else if (layerParams.get<String>("pad_mode") == "VALID")
{ for (int i = 0; i < strides.size(); i++)
if (!layerParams.has("kernel_size")) {
CV_Error(Error::StsNotImplemented, int sz = outShape.get<int>(2 + i);
"Required attribute 'kernel_size' is not present."); int stride = strides.get<int>(i);
adjust_pads.push_back(padMode == "SAME"? (sz - 1) % stride :
DictValue kernel = layerParams.get("kernel_size"); (sz - kernel.get<int>(i)) % stride);
layerParams.set("adj_h", (outH - kernel.getIntValue(0)) % strideY); }
layerParams.set("adj_w", (outW - kernel.getIntValue(1)) % strideX); layerParams.set("adj", DictValue::arrayInt(&adjust_pads[0], adjust_pads.size()));
} }
} }
else if (layerParams.has("output_padding")) else if (layerParams.has("output_padding"))
{ {
const DictValue& adj_pad = layerParams.get("output_padding"); replaceLayerParam(layerParams, "output_padding", "adj");
if (adj_pad.size() != 2)
CV_Error(Error::StsNotImplemented, "Deconvolution3D layer is not supported");
layerParams.set("adj_w", adj_pad.get<int>(1));
layerParams.set("adj_h", adj_pad.get<int>(0));
} }
} }
else if (layer_type == "Transpose") else if (layer_type == "Transpose")
......
...@@ -127,6 +127,19 @@ TEST_P(Test_ONNX_layers, Deconvolution) ...@@ -127,6 +127,19 @@ TEST_P(Test_ONNX_layers, Deconvolution)
testONNXModels("deconv_adjpad_2d", npy, 0, 0, false, false); testONNXModels("deconv_adjpad_2d", npy, 0, 0, false, false);
} }
TEST_P(Test_ONNX_layers, Deconvolution3D)
{
#if defined(INF_ENGINE_RELEASE)
applyTestTag(CV_TEST_TAG_DNN_SKIP_IE_2018R5);
#endif
if (backend != DNN_BACKEND_INFERENCE_ENGINE || target != DNN_TARGET_CPU)
throw SkipTestException("Only DLIE backend on CPU is supported");
testONNXModels("deconv3d");
testONNXModels("deconv3d_bias");
testONNXModels("deconv3d_pad");
testONNXModels("deconv3d_adjpad");
}
TEST_P(Test_ONNX_layers, Dropout) TEST_P(Test_ONNX_layers, Dropout)
{ {
testONNXModels("dropout"); testONNXModels("dropout");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment