Skip to content

[TF-TRT] Fix TopK Combined NMS - #40062

Merged
copybara-service[bot] merged 1 commit into
tensorflow:masterfrom
DEKHTIARJonathan:tftrt/topk_combined_nms_fix
Jan 13, 2021
Merged

copybara-service[bot] merged 1 commit into
tensorflow:masterfrom
DEKHTIARJonathan:tftrt/topk_combined_nms_fix

Conversation

@DEKHTIARJonathan

Copy link
Copy Markdown
Contributor

CC: @bixia1

in tftrt, the tf.image.combined_non_max_suppression op is replaced by a trt engine using batchedNMSplugin, with the minimal reproducible code piece, there's something not aligned.

TRT nms plugin has argument "topK", and we will only do IOU operation on the topK box in each class, so we set topK to boxes count in each class, to fix mismatch between TF and TRT.

@google-ml-butler google-ml-butler Bot added the size:XS CL Change Size: Extra Small label Jun 1, 2020
@google-ml-butler
google-ml-butler Bot requested a review from joker-eph June 1, 2020 19:17
@gbaned gbaned self-assigned this Jun 2, 2020
@gbaned gbaned added the comp:gpu:tensorrt Issues specific to TensorRT label Jun 2, 2020
@gbaned
gbaned requested a review from bixia1 June 2, 2020 04:18
bool share_location = (boxes_dims.d[1] == 1);
const bool pad_per_class = attrs.get<bool>("pad_per_class");
int top_k;
const int top_k = boxes_dims.d[0];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you think of a way to show the effect of this change, such as modifying OpConverterTest.ConvertCombinedNMS?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a test case that shows the error, but it's a bit convoluted and complex to be packaged in a unittest. I'll try to see what I can do ;)

@DEKHTIARJonathan

Copy link
Copy Markdown
Contributor Author

@bixia1 as requested here is a small script to reproduce the issue:

import os
import time

os.environ["TF_CPP_MIN_LOG_LEVEL"]="3"

import numpy as np
import tensorflow.compat.v1 as tf

tf.disable_v2_behavior()

tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)


N = 2048
num_classes = 90

pre_nms_boxes = tf.placeholder(tf.float32, name='boxes', shape=[1, N, 1, 4])
pre_nms_scores = tf.placeholder(tf.float32, name='scores', shape=[1, N, num_classes])
max_detetion_points = N
max_boxes_to_draw = 30
iou_threshold = 0.1
min_score_thresh = 0.001

post_nms_boxes, post_nms_scores, post_nms_classes, post_nms_num_valid_boxes = \
    tf.image.combined_non_max_suppression(
        pre_nms_boxes,
        pre_nms_scores,
        max_output_size_per_class=max_detetion_points,
        max_total_size=max_boxes_to_draw,
        iou_threshold=iou_threshold,
        score_threshold=min_score_thresh,
        pad_per_class=False
    )

np.random.seed(666)
np_boxes = np.random.rand(1, 2048, 1, 4)
np_scores = np.random.rand(1, 2048, 90)

with tf.Session() as sess:
    tf_output = sess.run([
            post_nms_boxes,
            post_nms_scores,
            post_nms_classes,
            post_nms_num_valid_boxes
        ],
        feed_dict={pre_nms_boxes: np_boxes, pre_nms_scores: np_scores}
    )

with tf.Session() as sess:
    output = [
        tf.identity(i)
        for i in [
            post_nms_boxes,
            post_nms_scores,
            post_nms_classes,
            post_nms_num_valid_boxes
        ]
    ]

    output_node_names = [node.name.split(':')[0] for node in output]

    graphdef = tf.graph_util.convert_variables_to_constants(
        sess, sess.graph_def, output_node_names
    )

    fetches = [pre_nms_boxes.name, pre_nms_scores.name] + [i.name for i in output]

    from tensorflow.python.compiler.tensorrt import trt_convert as trt

    converter = trt.TrtGraphConverter(
        nodes_blacklist=[t.split(':')[0] for t in fetches],
        input_graph_def=graphdef,
        max_workspace_size_bytes=1 << 32,    # 4Gb
        minimum_segment_size=1,
        precision_mode='FP32')
    infer_graph = converter.convert()

    goutput = tf.import_graph_def(infer_graph, return_elements=fetches)

    inputs, output = goutput[:2], goutput[2:]

    trt_output = sess.run(
        output,
        feed_dict={inputs[0]: np_boxes, inputs[1]: np_scores}
    )


print("tf_output  - post_nms_classes:", tf_output[2])
print("trt_output - post_nms_classes:", trt_output[2])

If you run with current upstream tensorflow:

$ python main.py 

WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow_core/python/compat/v2_compat.py:88: disable_resource_variables (from tensorflow.python.ops.variable_scope) is deprecated and will be removed in a future version.
Instructions for updating:
non-resource variables are not supported in the long term
tf_output - post_nms_classes: [[89.  6. 85. 51. 68.  1.  1. 78. 51. 27. 61. 63. 30. 49. 78. 45.  8. 46.
  76. 10. 35. 37. 24. 77. 13. 16. 35. 27. 28. 25.]]
trt_output - post_nms_classes: [[89.  6. 85. 51. 68.  1.  1.  1. 78. 51. 27. 85. 61. 63. 30. 49. 78. 45.
   8. 46. 76. 10. 35. 37. 24. 77. 13. 16. 35. 27.]]

As you can see the two results are different.

$ python main.py 

WARNING:tensorflow:From /usr/local/lib/python3.6/dist-packages/tensorflow/python/compat/v2_compat.py:96: disable_resource_variables (from tensorflow.python.ops.variable_scope) is deprecated and will be removed in a future version.
Instructions for updating:
non-resource variables are not supported in the long term
tf_output  - post_nms_classes: [[89.  6. 85. 51. 68.  1.  1. 78. 51. 27. 61. 63. 30. 49. 78. 45.  8. 46.
  76. 10. 35. 37. 24. 77. 13. 16. 35. 27. 28. 25.]]
trt_output - post_nms_classes: [[89.  6. 85. 51. 68.  1.  1. 78. 51. 27. 61. 63. 30. 49. 78. 45.  8. 46.
  76. 10. 35. 37. 24. 77. 13. 16. 35. 27. 28. 25.]]

And now with this change we are good ;)

@bixia1

bixia1 commented Jun 4, 2020

Copy link
Copy Markdown
Contributor

Thanks for the test case. Can we find a way to turn in into a test in the tree?

@gbaned

gbaned commented Jun 8, 2020

Copy link
Copy Markdown
Contributor

@DEKHTIARJonathan Can you please check @bixia1's comments and keep us posted. Thanks!

@gbaned gbaned added the stat:awaiting response Status - Awaiting response from author label Jun 8, 2020
bixia1
bixia1 previously approved these changes Jun 10, 2020
@google-ml-butler google-ml-butler Bot added kokoro:force-run Tests on submitted change ready to pull PR ready for merge process labels Jun 10, 2020
@kokoro-team kokoro-team removed the kokoro:force-run Tests on submitted change label Jun 10, 2020
@gbaned

gbaned commented Jun 11, 2020

Copy link
Copy Markdown
Contributor

@DEKHTIARJonathan Can you please address Ubuntu Sanity errors? Thanks!

@gbaned gbaned removed the ready to pull PR ready for merge process label Jun 11, 2020
@DEKHTIARJonathan

Copy link
Copy Markdown
Contributor Author

@gbaned styling fixed ;)

bixia1
bixia1 previously approved these changes Jun 11, 2020
@google-ml-butler google-ml-butler Bot added kokoro:force-run Tests on submitted change ready to pull PR ready for merge process labels Jun 11, 2020
@kokoro-team kokoro-team removed the kokoro:force-run Tests on submitted change label Jun 11, 2020
@google-ml-butler google-ml-butler Bot removed the ready to pull PR ready for merge process label Jun 11, 2020
@gbaned
gbaned requested a review from bixia1 June 12, 2020 10:09
@gbaned gbaned added awaiting review Pull request awaiting review and removed stat:awaiting response Status - Awaiting response from author labels Jun 12, 2020
@googlebot

Copy link
Copy Markdown

All (the pull request submitter and all commit authors) CLAs are signed, but one or more commits were authored or co-authored by someone other than the pull request submitter.

We need to confirm that all authors are ok with their commits being contributed to this project. Please have them confirm that by leaving a comment that contains only @googlebot I consent. in this pull request.

Note to project maintainer: There may be cases where the author cannot leave a comment, or the comment is not properly detected as consent. In those cases, you can manually confirm consent of the commit author(s), and set the cla label to yes (if enabled on your project).

ℹ️ Googlers: Go here for more info.

@bixia1

bixia1 commented Nov 6, 2020

Copy link
Copy Markdown
Contributor

One more test failure, tensorflow/python/compiler/tensorrt:combined_nms_test with TRT 7.1.3:

Traceback (most recent call last):
File "/build/work/12b5ec9ab1fdb4841ff23eda896242132066/google3/runfiles/google3/third_party/tensorflow/python/framework/test_util.py", line 1397, in decorated
return f(self, *args, **kwargs)
File "/build/work/12b5ec9ab1fdb4841ff23eda896242132066/google3/runfiles/google3/third_party/tensorflow/python/compiler/tensorrt/test/tf_trt_integration_test_base.py", line 1107, in _Test
self.RunTest(run_params)
File "/build/work/12b5ec9ab1fdb4841ff23eda896242132066/google3/runfiles/google3/third_party/tensorflow/python/compiler/tensorrt/test/tf_trt_integration_test_base.py", line 1030, in RunTest
GraphState.INFERENCE)
File "/build/work/12b5ec9ab1fdb4841ff23eda896242132066/google3/runfiles/google3/third_party/tensorflow/python/compiler/tensorrt/test/tf_trt_integration_test_base.py", line 910, in _VerifyGraphDef
graph_state)
File "/build/work/12b5ec9ab1fdb4841ff23eda896242132066/google3/runfiles/google3/third_party/tensorflow/python/compiler/tensorrt/test/tf_trt_integration_test_base.py", line 848, in _VerifyGraphDefV1
self._VerifyConnections(expected_engines, original_gdef, gdef_to_verify)
File "/build/work/12b5ec9ab1fdb4841ff23eda896242132066/google3/runfiles/google3/third_party/tensorflow/python/compiler/tensorrt/test/tf_trt_integration_test_base.py", line 670, in _VerifyConnections
(sorted(expected_input_map.items()), sorted(actual_input_map.items())))
AssertionError: {'TRTEngineOp_0': {'pre_nms_scores', 'pre_nms_boxes'}, 'input_0': set(), 'input_1': set(), 'output_0': {'TRTEngineOp_0'}, 'output_1': {'TRTEngineOp_0'}, 'output_2': {'TRTEngineOp_0'}, 'output_3': {'TRTEngineOp_0'}, 'pre_nms_boxes': {'input_0'}, 'pre_nms_scores': {'input_1'}} != {'TRTEngineOp_0': {'input_1', 'input_0'}, 'input_0': set(), 'input_1': set(), 'output_0': {'TRTEngineOp_0'}, 'output_1': {'TRTEngineOp_0'}, 'output_2': {'TRTEngineOp_0'}, 'output_3': {'TRTEngineOp_0'}} (
expected:
[('TRTEngineOp_0', {'pre_nms_scores', 'pre_nms_boxes'}), ('input_0', set()), ('input_1', set()), ('output_0', {'TRTEngineOp_0'}), ('output_1', {'TRTEngineOp_0'}), ('output_2', {'TRTEngineOp_0'}), ('output_3', {'TRTEngineOp_0'}), ('pre_nms_boxes', {'input_0'}), ('pre_nms_scores', {'input_1'})]
vs actual:
[('TRTEngineOp_0', {'input_1', 'input_0'}), ('input_0', set()), ('input_1', set()), ('output_0', {'TRTEngineOp_0'}), ('output_1', {'TRTEngineOp_0'}), ('output_2', {'TRTEngineOp_0'}), ('output_3', {'TRTEngineOp_0'})])
repr() of differing entries:
'TRTEngineOp_0': {'pre_nms_scores', 'pre_nms_boxes'} != {'input_1', 'input_0'}

Missing entries:
'pre_nms_boxes': {'input_0'}
'pre_nms_scores': {'input_1'}

@gbaned

gbaned commented Nov 10, 2020

Copy link
Copy Markdown
Contributor

@DEKHTIARJonathan Can you please check @bixia1's comments and keep us posted ? Thanks!

@gbaned gbaned added stat:awaiting response Status - Awaiting response from author and removed ready to pull PR ready for merge process labels Nov 10, 2020
@DEKHTIARJonathan

Copy link
Copy Markdown
Contributor Author

@bixia1 the C++ unittest wasn't properly deactivated with TRT < 7.1.3.

Fixed has been applied and commits squashed: https://github.com/tensorflow/tensorflow/pull/40062/files#diff-
b9ae60f058d9ae72ddc0625fa93ff1b8441e57db5695e8444d18becdb3abea2dL2976-R3002

Please run the CI again ;) And we can merge if good

@google-ml-butler google-ml-butler Bot added kokoro:force-run Tests on submitted change ready to pull PR ready for merge process labels Nov 16, 2020
@kokoro-team kokoro-team removed the kokoro:force-run Tests on submitted change label Nov 16, 2020
@gbaned gbaned removed the stat:awaiting response Status - Awaiting response from author label Nov 17, 2020
@bixia1

bixia1 commented Nov 17, 2020

Copy link
Copy Markdown
Contributor

It seems to me that this failure is still reproducible
#40062 (comment)

@gbaned

gbaned commented Nov 24, 2020

Copy link
Copy Markdown
Contributor

@DEKHTIARJonathan Can you please check @bixia1's comments and keep us posted ? Thanks!

@gbaned gbaned added stat:awaiting response Status - Awaiting response from author and removed ready to pull PR ready for merge process labels Nov 24, 2020
@DEKHTIARJonathan

Copy link
Copy Markdown
Contributor Author

Reassigning this issue to @tfeher

@tensorflowbutler tensorflowbutler removed the stat:awaiting response Status - Awaiting response from author label Nov 26, 2020
@gbaned gbaned added stat:awaiting response Status - Awaiting response from author and removed stat:awaiting response Status - Awaiting response from author labels Nov 27, 2020
@DEKHTIARJonathan

Copy link
Copy Markdown
Contributor Author

@tfeher could we finalized the last few bits of that one ?

@tensorflowbutler tensorflowbutler removed the stat:awaiting response Status - Awaiting response from author label Dec 16, 2020
@gbaned gbaned added the stat:awaiting response Status - Awaiting response from author label Dec 23, 2020
@tensorflowbutler tensorflowbutler added the stale This label marks the issue/pr stale - to be closed automatically if no activity label Jan 9, 2021
@tensorflowbutler

Copy link
Copy Markdown
Member

It has been 15 days with no activity and the awaiting response label was assigned. Is this PR still valid? Assigning the stalled label. Please comment to reassure me that this is still being worked on.

- We have to set top_k so that keep_top_k <= top_k, otherwise the plugin does
  not work with TRT 7.0
- Enabled explicit batch mode for the converter, added test for it. Dynamic
  shapes are not supported by the current plugin.
- Added test to check the clib_boxes attribute usage
- Added test with nonzero score threshold
- Added test where the boxes are defined as y_max, x_max, y_min, x_min. This
  test will fail with TRT 7.1.2 or earlier and highlights that the CombinedNMS
  plugin is not compatible with the TF definition of the operator in these
  versions of TRT.
@tfeher

tfeher commented Jan 12, 2021

Copy link
Copy Markdown
Contributor

I have updated the PR. I could not reproduce the failing test yet. According to the log it is caused by the V1 graph def verification (_VerifyGraphDefV1) which is known to be finicky. The nodes in the converted graphs has to match the lists given by ExpectedEnginesToBuild. I have removed the extra identity nodes added by the new test, in principle this should fix the error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla: yes comp:gpu:tensorrt Issues specific to TensorRT ready to pull PR ready for merge process size:XS CL Change Size: Extra Small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants