mirror of
https://github.com/opencv/opencv.git
synced 2025-06-17 23:51:16 +08:00
Merge pull request #14996 from l-bat:ocv_deconv3d
* Support Deconvolution3D on IE backend * Add test tag * Fix tests
This commit is contained in:
parent
8bcd7e122a
commit
34f6b05467
@ -67,7 +67,7 @@ public:
|
|||||||
BaseConvolutionLayerImpl(const LayerParams ¶ms)
|
BaseConvolutionLayerImpl(const LayerParams ¶ms)
|
||||||
{
|
{
|
||||||
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:
|
|||||||
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:
|
|||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
return pad.width >= adjustPad.width && pad.height >= adjustPad.height;
|
}
|
||||||
|
for (int i = 0; i < adjust_pads.size(); i++) {
|
||||||
|
if (pads_end[i] < adjust_pads[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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:
|
|||||||
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:
|
|||||||
#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:
|
|||||||
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:
|
|||||||
|
|
||||||
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:
|
|||||||
|
|
||||||
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 ¶ms, std::vector<size_t>& kern
|
|||||||
}
|
}
|
||||||
|
|
||||||
void getConvolutionKernelParams(const LayerParams ¶ms, std::vector<size_t>& kernel, std::vector<size_t>& pads_begin,
|
void getConvolutionKernelParams(const LayerParams ¶ms, 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
|
|||||||
namespace dnn
|
namespace dnn
|
||||||
{
|
{
|
||||||
void getConvolutionKernelParams(const LayerParams ¶ms, std::vector<size_t>& kernel, std::vector<size_t>& pads_begin,
|
void getConvolutionKernelParams(const LayerParams ¶ms, 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 ¶ms, std::vector<size_t>& kernel, bool &globalPooling,
|
void getPoolingKernelParams(const LayerParams ¶ms, 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)
|
|||||||
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("output_shape"))
|
|
||||||
{
|
|
||||||
const DictValue& outShape = layerParams.get("output_shape");
|
|
||||||
|
|
||||||
if (outShape.size() != 4)
|
|
||||||
CV_Error(Error::StsNotImplemented, "Output shape must have 4 elements.");
|
|
||||||
|
|
||||||
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);
|
|
||||||
layerParams.set("adj_h", (outH - 1) % strideY);
|
|
||||||
}
|
|
||||||
else if (layerParams.get<String>("pad_mode") == "VALID")
|
|
||||||
{
|
|
||||||
if (!layerParams.has("kernel_size"))
|
if (!layerParams.has("kernel_size"))
|
||||||
CV_Error(Error::StsNotImplemented,
|
CV_Error(Error::StsNotImplemented,
|
||||||
"Required attribute 'kernel_size' is not present.");
|
"Required attribute 'kernel_size' is not present.");
|
||||||
|
|
||||||
|
if (layerParams.has("output_shape"))
|
||||||
|
{
|
||||||
|
const DictValue& outShape = layerParams.get("output_shape");
|
||||||
|
DictValue strides = layerParams.get("stride");
|
||||||
DictValue kernel = layerParams.get("kernel_size");
|
DictValue kernel = layerParams.get("kernel_size");
|
||||||
layerParams.set("adj_h", (outH - kernel.getIntValue(0)) % strideY);
|
|
||||||
layerParams.set("adj_w", (outW - kernel.getIntValue(1)) % strideX);
|
String padMode;
|
||||||
|
std::vector<int> adjust_pads;
|
||||||
|
if (layerParams.has("pad_mode"))
|
||||||
|
{
|
||||||
|
padMode = toUpperCase(layerParams.get<String>("pad_mode"));
|
||||||
|
if (padMode != "SAME" && padMode != "VALID")
|
||||||
|
CV_Error(Error::StsError, "Unsupported padding mode " + padMode);
|
||||||
|
|
||||||
|
for (int i = 0; i < strides.size(); i++)
|
||||||
|
{
|
||||||
|
int sz = outShape.get<int>(2 + i);
|
||||||
|
int stride = strides.get<int>(i);
|
||||||
|
adjust_pads.push_back(padMode == "SAME"? (sz - 1) % stride :
|
||||||
|
(sz - kernel.get<int>(i)) % stride);
|
||||||
|
}
|
||||||
|
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)
|
|||||||
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");
|
||||||
|
Loading…
Reference in New Issue
Block a user