fix bug: wrong output dimension when "keep_dims" is false in pooling layer.#20904
fix bug: wrong output dimension when "keep_dims" is false in pooling layer.#20904alalek merged 8 commits intoopencv:3.4from
Conversation
|
I checked the build results. "Test_TensorFlow_layers.reduce_sum/0" failed because I connect a permute layer after "squeeze". So the output dimension from "nwc" change to "ncw". But I think it is necessary to add it. Because we may do some other operations (like "concat" in this model) after pooling. |
| connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0); | ||
|
|
||
| if (!keepDims) | ||
| if (keepDims) { |
There was a problem hiding this comment.
Test data sum_pool_by_axis_out.npy is generated by this code through original framework.
So changing the "output" only looks very strange (sum_pool_by_axis_out.npy in opencv_extra PR) and would conflict with framework results (we must avoid such conflicts).
Is there any information about processing/behavior changes between TF 1.x / TF 2.x?
If so we need to properly handle min_consumer TF versions here (but sum_pool_by_axis_net.pb file doesn't contain versions information).
There was a problem hiding this comment.
Thanks for your reply!
I think TF 1.x/ TF 2.x both produce the same output data.
|
@asmorkalov Hello, anything else do I need to do? |
rogday
left a comment
There was a problem hiding this comment.
Thank you for your contribution! IIRC, bugfixes should go to 3.4 branch and not 4.x, so, please, rebase.
I think, there is more to it. Could you check other cases as well? I used +1 instead of ExpandDims to avoid more issues with dimensions.
I used the following code for tests, it shows errors with axis=[0], [3](keepdims true and false), [1,2]:
axises = [[0], [1], [2], [3], [1, 2]]
for axis in axises:
for keepdims in [False, True]:
inp = tf.placeholder(tf.float32, [2, 3, 4, 1])
biasadd = tf.nn.bias_add(inp, [1], data_format='NHWC')
print(axis, keepdims)
reduced = tf.reduce_sum(biasadd, axis=axis, keepdims=keepdims)
save(inp, reduced + 1, f'reduce_sum_{axis}_{keepdims}')
TEST_P(Test_TensorFlow_layers, pooling_reduce_sum3)
{
std::vector<std::vector<int>> axises = {{0}, {1}, {2}, {3}, {1, 2}};
for (const auto& axis : axises)
{
for (int keepdims = 0; keepdims <= 1; ++keepdims)
{
std::stringstream ss;
ss << "reduce_sum_[" << axis[0];
if (axis.size() > 1)
{
ss << ", " << axis[1];
}
ss << "]_" << (keepdims ? "True" : "False");
std::cout << ss.str() << std::endl;
try
{
runTensorFlowNet(ss.str());
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
}
}
| layerParams.set("pool", pool_type); | ||
| layerParams.set(axis == 2 ? "kernel_w" : "kernel_h", 1); | ||
| layerParams.set(axis == 2 ? "global_pooling_h" : "global_pooling_w", true); |
There was a problem hiding this comment.
Seems like this bit of code can be extracted from the if body.
75a7e93 to
18b8102
Compare
| else | ||
| { | ||
| // To keep correct order after squeeze dims we first need to change layout from NCHW to NHWC | ||
| std::string poolingName = name+"/Pooling"; |
There was a problem hiding this comment.
Please, add spaces around plus sign.
|
|
||
| LayerParams squeezeLp; | ||
| std::string squeezeName = name + "/squeeze"; | ||
| std::string squeezeName = name; |
There was a problem hiding this comment.
Please, use const std::string&, since you aren't modifying the variable.
| int id = dstNet.addLayer(name, "Pooling", layerParams); | ||
| layer_id[name] = id; | ||
| connect(layer_id, dstNet, inpId, id, 0); | ||
| std::string poolingName = name+"/Pooling"; |
There was a problem hiding this comment.
Please, add spaces around the plus sign and a check, that the layer with that name doesn't exist yet: CV_Assert(layer_id.find(poolingName) == layer_id.end());
| LayerParams squeezeLp; | ||
| std::string squeezeName = name + "/squeeze"; | ||
| std::string squeezeName = name; | ||
| CV_Assert(layer_id.find(squeezeName) == layer_id.end()); |
There was a problem hiding this comment.
This check is not required anymore(we aren't giving new name to the layer).
| } | ||
| else | ||
| { | ||
| std::string poolingName = name+"/Pooling"; |
There was a problem hiding this comment.
Please, add spaces around the plus sign and a check, that the layer with that name doesn't exist yet: CV_Assert(layer_id.find(poolingName) == layer_id.end());
| std::string flattenName = name; | ||
| CV_Assert(layer_id.find(flattenName) == layer_id.end()); |
There was a problem hiding this comment.
Consider using const std::string& and removing the assert.
| std::string squeezeName = name; | ||
| CV_Assert(layer_id.find(squeezeName) == layer_id.end()); |
There was a problem hiding this comment.
Consider changing the type to const std::string& and removing the assert.
| TEST_P(Test_TensorFlow_layers, pooling_reduce_sum2) | ||
| { | ||
| int axises[] = {0, 1, 2, 3}; | ||
| for (int i = 0; i<sizeof(axises)/sizeof(axises[0]); i++) | ||
| { | ||
| for (int keepdims = 0; keepdims <= 1; ++keepdims) | ||
| { | ||
| std::stringstream ss; | ||
| ss << "reduce_sum_[" << axises[i] << "]_" << (keepdims ? "True" : "False"); | ||
| std::cout << ss.str() << std::endl; | ||
| try | ||
| { | ||
| runTensorFlowNet(ss.str()); | ||
| } | ||
| catch (const std::exception& e) | ||
| { | ||
| std::cout << e.what() << std::endl; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| TEST_P(Test_TensorFlow_layers, pooling_reduce_sum3) | ||
| { | ||
| int axises[][2] = {{1, 2}}; // two axises | ||
| for (int i = 0; i<sizeof(axises)/sizeof(axises[0]); i++) | ||
| { | ||
| for (int keepdims = 0; keepdims <= 1; ++keepdims) | ||
| { | ||
| std::stringstream ss; | ||
| ss << "reduce_sum_[" << axises[i][0] << ", " << axises[i][1] << "]_" << (keepdims ? "True" : "False"); | ||
| std::cout << ss.str() << std::endl; | ||
| try | ||
| { | ||
| runTensorFlowNet(ss.str()); | ||
| } | ||
| catch (const std::exception& e) | ||
| { | ||
| std::cout << e.what() << std::endl; | ||
| } | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
My proposed solution was a draft, which helps debugging the problem.
Consider this instead:
TEST_P(Test_TensorFlow_layers, pooling_reduce_sum2)
{
int axises[] = {0, 1, 2, 3};
for (int keepdims = 0; keepdims <= 1; ++keepdims)
{
for (int i = 0; i < sizeof(axises)/sizeof(axises[0]); ++i)
{
runTensorFlowNet(cv::format("reduce_sum_[%d]_%s", axises[i], keepdims ? "True" : "False"));
}
runTensorFlowNet(cv::format("reduce_sum_[1, 2]_%s", keepdims ? "True" : "False"));
}
}
| { | ||
| runTensorFlowNet(cv::format("reduce_sum_[%d]_%s", axises[i], (keepdims ? "True" : "False"))); | ||
| } | ||
| runTensorFlowNet(cv::format("reduce_sum_[1, 2]_%s", keepdims ? "True" : "False")); |
There was a problem hiding this comment.
'['
']'
','
' '
Could you please use sanitized file names? (please use _ instead of these symbols or space)

Merge with extra: opencv/opencv_extra#932
Pull Request Readiness Checklist
Fixed bug in #20896:When parsing a pooling layer in dnn/tensorflow. If keep_dims is false, the additional "nhwc" layer and "squeeze" layer will be lost. Because the final "squeeze" layer name is not the original layer name.
Solution:
Change the final output layer's name to the orignal pooling layer's name.
Patch to opencv_extra has the same branch name.