diff --git a/modules/dnn/src/layers/layers_common.cpp b/modules/dnn/src/layers/layers_common.cpp index f26c9778ec..4675a380d4 100644 --- a/modules/dnn/src/layers/layers_common.cpp +++ b/modules/dnn/src/layers/layers_common.cpp @@ -157,27 +157,86 @@ void getPoolingKernelParams(const LayerParams ¶ms, std::vector& kern if (params.has("global_pooling_w")) globalPooling[2] = params.get("global_pooling_w"); - if (is_global) - { - util::getStrideAndPadding(params, pads_begin, pads_end, strides, padMode); - if(params.has("kernel_h") || params.has("kernel_w") || params.has("kernel_size")) - { - CV_Error(cv::Error::StsBadArg, "In global_pooling mode, kernel_size (or kernel_h and kernel_w) cannot be specified"); - } - for (int i = 0; i < pads_begin.size(); i++) { - if (pads_begin[i] != 0 || pads_end[i] != 0) - CV_Error(cv::Error::StsBadArg, "In global_pooling mode, pads must be = 0"); - } - for (int i = 0; i < strides.size(); i++) { - if (strides[i] != 1) - CV_Error(cv::Error::StsBadArg, "In global_pooling mode, strides must be = 1"); - } - } - else + is_global = globalPooling[0] || globalPooling[1] || globalPooling[2]; + if (!is_global) { util::getKernelSize(params, kernel); util::getStrideAndPadding(params, pads_begin, pads_end, strides, padMode, kernel.size()); } + else + { + if ((globalPooling[0] && params.has("kernel_d")) || + (globalPooling[1] && params.has("kernel_h")) || + (globalPooling[2] && params.has("kernel_w")) || + params.has("kernel_size")) { + CV_Error(cv::Error::StsBadArg, "In global_pooling mode, kernel_size (or kernel_h and kernel_w) cannot be specified"); + } + + kernel.resize(3, 1); + pads_begin.resize(3, 0); + pads_end.resize(3, 0); + strides.resize(3, 1); + if (params.has("kernel_d")) + kernel[0] = params.get("kernel_d"); + if (params.has("kernel_h")) + kernel[1] = params.get("kernel_h"); + if (params.has("kernel_w")) + kernel[2] = params.get("kernel_w"); + + if (params.has("pad_t")) + pads_begin[1] = params.get("pad_t"); + if (params.has("pad_l")) + pads_begin[2] = params.get("pad_l"); + if (params.has("pad_b")) + pads_end[1] = params.get("pad_b"); + if (params.has("pad_r")) + pads_end[2] = params.get("pad_r"); + if (params.has("pad_h")) { + pads_begin[1] = params.get("pad_h"); + pads_end[1] = params.get("pad_h"); + } + if (params.has("pad_w")) { + pads_begin[2] = params.get("pad_w"); + pads_end[2] = params.get("pad_w"); + } + if (params.has("pad")) { + DictValue param = params.get("pad"); + if (param.size() == 1) { + std::fill(pads_begin.begin(), pads_begin.end(), param.get(0)); + pads_end = pads_begin; + } else if (param.size() <= pads_begin.size()) { + for (int i = param.size() - 1, j = pads_begin.size() - 1; i >= 0; i--, j--) { + pads_begin[j] = param.get(i); + } + pads_end = pads_begin; + } else { + for (int i = param.size() - 1, j = pads_begin.size() - 1; i >= param.size() / 2; i--, j--) { + pads_begin[j] = param.get(i); + } + for (int i = param.size() / 2 - 1, j = pads_end.size() / 2 - 1; i >= 0; i--, j--) { + pads_end[j] = param.get(i); + } + } + } + + if (params.has("stride_h")) + strides[1] = params.get("stride_h"); + if (params.has("stride_w")) + strides[2] = params.get("stride_w"); + if (params.has("stride")) { + DictValue param = params.get("stride"); + for (int i = param.size() - 1, j = strides.size() - 1; i >= 0; i--, j--) { + strides[j] = param.get(i); + } + if (param.size() == 1) + std::fill(strides.begin() + 1, strides.end(), strides[0]); + } + + for (int i = 0; i < pads_begin.size(); i++) { + if ((pads_begin[i] != 0 || pads_end[i] != 0 || strides[i] != 1) && globalPooling[i]) + CV_Error(cv::Error::StsBadArg, "In global_pooling mode, pads must be = 0 and strides must be = 1"); + } + } } void getConvolutionKernelParams(const LayerParams ¶ms, std::vector& kernel, std::vector& pads_begin, diff --git a/modules/dnn/src/layers/pooling_layer.cpp b/modules/dnn/src/layers/pooling_layer.cpp index 1fec982dea..eef091dd42 100644 --- a/modules/dnn/src/layers/pooling_layer.cpp +++ b/modules/dnn/src/layers/pooling_layer.cpp @@ -148,17 +148,24 @@ public: inp.push_back(inputs[0].size[i]); out.push_back(outputs[0].size[i]); } - kernel_size.resize(out.size()); - for (int i = 0; i < kernel_size.size(); i++) - { - int pool_idx = isGlobalPooling.size() - 1 - i; - int kernel_idx = kernel_size.size() - 1 - i; - if (isGlobalPooling[pool_idx]) - kernel_size[kernel_idx] = inp[kernel_idx]; - } - kernel = Size(kernel_size[1], kernel_size[0]); + if (kernel_size.size() > inp.size()) { + kernel_size.erase(kernel_size.begin()); + strides.erase(strides.begin()); + pads_begin.erase(pads_begin.begin()); + pads_end.erase(pads_end.begin()); + } + kernel_size.resize(out.size()); + + for (int i = 0; i < inp.size(); i++) + { + int idx = isGlobalPooling.size() - inp.size() + i; + if (isGlobalPooling[idx]) + kernel_size[i] = inp[i]; + } + kernel = Size(kernel_size.back(), kernel_size[kernel_size.size() - 2]); getConvPoolPaddings(inp, kernel_size, strides, padMode, pads_begin, pads_end); + if (pads_begin.size() == 2) { pad_t = pads_begin[0]; pad_l = pads_begin[1]; @@ -1005,15 +1012,11 @@ virtual Ptr initNgraph(const std::vector >& inp std::vector local_kernel = kernel_size.empty() ? std::vector(inpShape.begin(), inpShape.end()) : kernel_size; - for (int i = 0; i < local_kernel.size(); i++) - { - int pool_idx = isGlobalPooling.size() - 1 - i; - int kernel_idx = local_kernel.size() - 1 - i; - if (isGlobalPooling[pool_idx]) - local_kernel[kernel_idx] = inpShape[kernel_idx]; + for (int i = 0, j = local_kernel.size() - inpShape.size(); i < inpShape.size(); i++, j++) { + if (isGlobalPooling[j]) + local_kernel[j] = inpShape[i]; } - if (type == ROI || type == PSROI) { outShape.push_back(pooledSize.height); @@ -1021,17 +1024,17 @@ virtual Ptr initNgraph(const std::vector >& inp } else if (padMode.empty()) { - for (int i = 0; i < local_kernel.size(); i++) { - float dst = (float)(inpShape[i] + pads_begin[i] + pads_end[i] - local_kernel[i]) / strides[i]; + for (int i = 0, j = local_kernel.size() - inpShape.size(); i < inpShape.size(); i++, j++) { + float dst = (float)(inpShape[i] + pads_begin[j] + pads_end[j] - local_kernel[j]) / strides[j]; outShape.push_back(1 + (ceilMode ? ceil(dst) : floor(dst))); } // If we have padding, ensure that the last pooling starts strictly // inside the image (instead of at the padding); otherwise clip the last. - for (int i = 0; i < pads_end.size(); i++) { - if (pads_end[i] && (outShape[2 + i] - 1) * strides[i] >= inpShape[i] + pads_end[i]) { + for (int i = 0, j = local_kernel.size() - inpShape.size(); i < inpShape.size(); i++, j++) { + if (pads_end[j] && (outShape[2 + i] - 1) * strides[j] >= inpShape[i] + pads_end[j]) { --outShape[2 + i]; - CV_Assert((outShape[2 + i] - 1) * strides[i] < inpShape[i] + pads_end[i]); + CV_Assert((outShape[2 + i] - 1) * strides[j] < inpShape[i] + pads_end[j]); } } } diff --git a/modules/dnn/src/tensorflow/tf_importer.cpp b/modules/dnn/src/tensorflow/tf_importer.cpp index b3527d1092..fe8eb4a637 100644 --- a/modules/dnn/src/tensorflow/tf_importer.cpp +++ b/modules/dnn/src/tensorflow/tf_importer.cpp @@ -1982,7 +1982,7 @@ void TFImporter::populateNet(Net dstNet) avgLp.set("pool", "ave"); // pooling kernel H x 1 avgLp.set("global_pooling_h", true); - avgLp.set("kernel_size", 1); + avgLp.set("kernel_w", 1); int avgId = dstNet.addLayer(avgName, "Pooling", avgLp); layer_id[avgName] = avgId; connect(layer_id, dstNet, Pin(reshapeName), avgId, 0);