Support Convolution3D layer on IE backend#14301
Conversation
| TEST_P(Test_ONNX_layers, Convolution3D) | ||
| { | ||
| if (backend == DNN_BACKEND_OPENCV || target != DNN_TARGET_CPU) | ||
| throw SkipTestException(""); |
There was a problem hiding this comment.
Let's replace to
if (backend != DNN_BACKEND_INFERENCE_ENGINE || target != DNN_TARGET_CPU)
throw SkipTestException("Only DLIE backend on CPU is supported");| int kernel[] = {layerParams.blobs[0].size[2], layerParams.blobs[0].size[3], layerParams.blobs[0].size[4]}; | ||
| layerParams.set("kernel", DictValue::arrayInt(kernel, 3)); | ||
| setDilations(layerParams, layer); | ||
| } |
There was a problem hiding this comment.
Can we generalize it? In example,
Mat weights = layerParams.blobs[0];
layerParams.set("kernel", DictValue::arrayInt(&weights.size[2], weights.dims - 2));| else if (layerParams.blobs[0].dims == 5) { | ||
| int kernel[] = {layerParams.blobs[0].size[2], layerParams.blobs[0].size[3], layerParams.blobs[0].size[4]}; | ||
| layerParams.set("kernel", DictValue::arrayInt(kernel, 3)); | ||
| setDilations(layerParams, layer); |
There was a problem hiding this comment.
Why we need dilations in case of 5D kernel but not for 4D one?
| #if INF_ENGINE_VER_MAJOR_GE(INF_ENGINE_RELEASE_2018R5) | ||
| InferenceEngine::Builder::ConvolutionLayer ieLayer(name); | ||
|
|
||
| ieLayer.setKernel({(size_t)kernel.get<int>(0), (size_t)kernel.get<int>(1), (size_t)kernel.get<int>(2)}); |
There was a problem hiding this comment.
Please experiment with merging Convolution3D into the Convolution layer. IE backend receives vectors as convolution's hyperparameters so it might looks like:
// std::vector<size_t> kernel: height+width for Convolution and depth+height+width for Convolution3D
ieLayer.setKernel(kernel);
| ieLayer.setStrides(std::vector<size_t>(strides.begin(), strides.end())); | ||
| ieLayer.setDilation(std::vector<size_t>(dilations.begin(), dilations.end())); | ||
| ieLayer.setPaddingsBegin(std::vector<size_t>(pads.begin(), pads.begin() + pads.size() / 2)); | ||
| ieLayer.setPaddingsEnd(std::vector<size_t>(pads.begin() + pads.size() / 2, pads.end())); |
There was a problem hiding this comment.
Can we just use std::vector<size_t> data type for all the kernel_size, pads, strides and dilations?
| CV_Assert(input->dims.size() == 4 || input->dims.size() == 5); | ||
|
|
||
| const int inpCn = input->dims[2]; // NOTE: input->dims are reversed (whcn) | ||
| const int inpCn = input->dims[input->dims.size() - 2]; // NOTE: input->dims are reversed (whcn or whdcn) |
There was a problem hiding this comment.
Please rename whcn to WHIO (and whdcn to WHDIO correspondingly) due there is no batch (n) and channels (c) in the kernel but there are input channels (I) and output channels (O).
| const Mat &input = inputs[0]; | ||
| CV_Assert(input.dims == 4 && (input.type() == CV_32F || input.type() == CV_64F || input.type() == CV_16S)); | ||
| for (size_t i = 0; i < inputs.size(); i++) | ||
| CV_Assert((input.dims == 4 || input.dims == 5) && (input.type() == CV_32F || input.type() == CV_64F || input.type() == CV_16S)); |
There was a problem hiding this comment.
I think that we can remove input.type() == CV_64F check due there is no double precision support.
| CV_Assert(input.dims == 4 && (input.type() == CV_32F || input.type() == CV_64F || input.type() == CV_16S)); | ||
| for (size_t i = 0; i < inputs.size(); i++) | ||
| CV_Assert((input.dims == 4 || input.dims == 5) && (input.type() == CV_32F || input.type() == CV_64F || input.type() == CV_16S)); | ||
| for (int i = 0; i < inputs.size(); i++) |
| out.height = (inpH + 2 * pad.height - (dilation.height * (kernel.height - 1) + 1)) / stride.height + 1; | ||
| out.width = (inpW + 2 * pad.width - (dilation.width * (kernel.width - 1) + 1)) / stride.width + 1; | ||
| for (int i = 0; i < inpShape.size(); i++) | ||
| outShape.push_back((inpShape[i] + pads[i] + pads[i + pads.size() / 2] - dilations[i] * (kernel_size[i] - 1) - 1) / strides[i] + 1); |
There was a problem hiding this comment.
I think it also make sense for us to split paddings vector to begins and ends as IE expects. Can you try?
| adjustPad.height < stride.height); | ||
| adjust_pads.resize(2); | ||
| adjust_pads[0] = params.get<int>("adj_h", 0); | ||
| adjust_pads[1] = params.get<int>("adj_w", 0); |
There was a problem hiding this comment.
I guess that we can have adjust paddings with 3D convolution as well.
There was a problem hiding this comment.
Now Deconvolution layer is supported only for 4D input
| (dilation.height == 1 && dilation.width == 1); | ||
| return (kernel_size.back() == 1 && kernel_size[kernel_size.size() - 2] == 1) && | ||
| (strides.back() == 1 && strides[strides.size() - 2] == 1) && | ||
| (dilations.back() == 1 && dilations[dilations.size() - 2] == 1); |
There was a problem hiding this comment.
Due is1x1 method is called only int the default implementation for 2D convs only we can keep cv::Size checks because they will be actual.
| { | ||
| if (INF_ENGINE_RELEASE >= 2018050000 && (adjustPad.height || adjustPad.width)) | ||
| if (kernel_size.size() == 3) | ||
| return (INF_ENGINE_RELEASE >= 2018050000 && preferableTarget == DNN_TARGET_CPU); |
| if (pads_begin.size() == kernel.size() - 1 && pads_end.size() == kernel.size() - 1) { | ||
| pads_begin.push_back(pads_begin.back()); | ||
| pads_end.push_back(pads_end.back()); | ||
| } |
There was a problem hiding this comment.
I think that we need to remove
if (parameter.size() == 1) {
parameter.push_back(parameter.back());
}above and before the final checks do something like
if (pads_begin.size() == 1) {
pads_begin.resize(kernel.size(), pads_begin[0]);
}| if (kernel_size.size() == 3) | ||
| return false; | ||
|
|
||
| if (INF_ENGINE_RELEASE >= 2018050000 && (adjust_pads[0] || adjust_pads[1])) |
There was a problem hiding this comment.
We can still check adjustPad.height and adjustPad.width and dilation.width with dilation.height here (2D convolution).
| dims.push_back(inputs[0][0]); | ||
| dims.push_back(outCn); | ||
| dims.insert(dims.end(), outShape.begin(), outShape.end()); | ||
| outputs.resize(inputs.size(), shape(&dims[0], dims.size())); |
There was a problem hiding this comment.
Let's push inputs[0][0] and outCn right into outShape at the beginning.
| std::vector<int> inpShape; | ||
| for (int i = 2; i < inputs[0].size(); i++) { | ||
| inpShape.push_back(inputs[0][i]); | ||
| } |
There was a problem hiding this comment.
std::vector<int> inpShape(inputs[0].begin() + 2, inputs[0].end());| return backendId == DNN_BACKEND_OPENCV || | ||
| (backendId == DNN_BACKEND_HALIDE && haveHalide() && | ||
| (type == MAX || (type == AVE && !pad_t && !pad_l && !pad_b && !pad_r))); | ||
| return (kernel_size.size() != 3) && (backendId == DNN_BACKEND_OPENCV || |
There was a problem hiding this comment.
kernel_size.size() == 2to be more certain
There was a problem hiding this comment.
In Layer_Test_ROIPooling.Accuracy "kernel_size.size() = 0
| } | ||
| util::checkSize(size, pads_begin); | ||
| util::checkSize(size, pads_end); | ||
| util::checkSize(size, strides); |
There was a problem hiding this comment.
I think we can align it to kernel size here because getKernelSize already increases it up to 2.
| CV_Assert_N(kernel.size() == pads_begin.size() || pads_begin.size() == 1, pads_begin.size() == pads_end.size()); | ||
| pads_begin.resize(kernel.size(), pads_begin[0]); | ||
| pads_end.resize(kernel.size(), pads_end[0]); | ||
| CV_Assert(pads_begin.size() == pads_end.size() && pads_begin.size() == kernel.size()); |
There was a problem hiding this comment.
It seems to me that at this point kernel.size() must be equal to pads_begin.size() and pads_end.size()`. May you check this?
| if (backendId == DNN_BACKEND_INFERENCE_ENGINE) | ||
| { | ||
| if (kernel_size.size() == 3) | ||
| return false; |
There was a problem hiding this comment.
I think that it's better to have a NotImplemented assertion for kernel_size.size() != 2 at the beginning of supportBackend method.
|
|
||
| pad.width = pad_l; | ||
| pad.height = pad_t; | ||
| std::vector<int> inpShape; |
| if (hasDefault) | ||
| { | ||
| parameterH = parameterW = defaultValue; | ||
| parameter.push_back(defaultValue); |
There was a problem hiding this comment.
The same as above,
parameter.assign(2, defaultValue);A single kernel_size, pad, stride etc. are observed only with Caffe framework which has no 3d convolutions.
|
|
||
| CV_Assert(kernelH > 0 && kernelW > 0); | ||
| if (kernel.size() == 1) | ||
| kernel.resize(2, kernel[0]); |
There was a problem hiding this comment.
Considering proposed changes in the getParameter we won't need any other alignments.
| { | ||
| type = ROI; | ||
| pads_begin.resize(1, 0); | ||
| pads_end.resize(1, 0); |
| { | ||
| type = PSROI; | ||
| pads_begin.resize(1, 0); | ||
| pads_end.resize(1, 0); |
| else | ||
| { | ||
| return false; | ||
| } |
There was a problem hiding this comment.
Please keep
else
{
return false;
}| if (params.has("pad_mode")) | ||
| { | ||
| padMode = params.get<String>("pad_mode"); | ||
| } |
There was a problem hiding this comment.
Please keep
if (params.has("pad_mode"))
{
padMode = params.get<String>("pad_mode");
}| else | ||
| { | ||
| CV_Error(Error::StsError, "Unsupported padding mode"); | ||
| } |
There was a problem hiding this comment.
Please keep
else
{
CV_Error(Error::StsError, "Unsupported padding mode");
}| (type == MAX || (type == AVE && !pad_t && !pad_l && !pad_b && !pad_r))); | ||
| return (kernel_size.empty() || kernel_size.size() == 2) && (backendId == DNN_BACKEND_OPENCV || | ||
| (backendId == DNN_BACKEND_HALIDE && haveHalide() && | ||
| (type == MAX || (type == AVE && !pad_t && !pad_l && !pad_b && !pad_r)))); |
e1b13d8 to
749a9fd
Compare
Merge with extra: opencv/opencv_extra#594