-
-
Notifications
You must be signed in to change notification settings - Fork 56.2k
fix bug: wrong output dimension when "keep_dims" is false in pooling layer. #20904
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for contribution!
connect(layer_id, dstNet, parsePin(layer.input(0)), id, 0); | ||
|
||
if (!keepDims) | ||
if (keepDims) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this bit of code can be extracted from the if body.
75a7e93
to
18b8102
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good work! 👍
{ | ||
// 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, add spaces around plus sign.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
addPermuteLayer(order, permName, inpId); | ||
|
||
LayerParams squeezeLp; | ||
std::string squeezeName = name + "/squeeze"; | ||
std::string squeezeName = name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please, use const std::string&
, since you aren't modifying the variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
addPermuteLayer(order, permName, inpId); | ||
|
||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check is not required anymore(we aren't giving new name to the layer).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
} | ||
else | ||
{ | ||
std::string poolingName = name+"/Pooling"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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());
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
std::string flattenName = name; | ||
CV_Assert(layer_id.find(flattenName) == layer_id.end()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using const std::string&
and removing the assert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
std::string squeezeName = name; | ||
CV_Assert(layer_id.find(squeezeName) == layer_id.end()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider changing the type to const std::string&
and removing the assert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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"));
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
{ | ||
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'['
']'
','
' '
Could you please use sanitized file names? (please use _
instead of these symbols or space)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
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.