[Relax][ONNX] Add roi_pool op and MaxRoiPool frontend support#18952
[Relax][ONNX] Add roi_pool op and MaxRoiPool frontend support#18952tlopex merged 2 commits intoapache:mainfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements the roi_pool operator in Relax, providing the necessary attributes, ONNX frontend support, and TOPI implementation for NCHW layout. It also includes structural info inference, legalization rules, and comprehensive tests. Additionally, the PR updates the handling of __slots__ in TVMDerivedObject within the runtime and meta-schedule utilities. Feedback was provided to optimize the TOPI implementation of roi_pool by avoiding redundant bin boundary calculations through the use of the -inf sentinel value to identify empty bins.
| return te.compute( | ||
| (num_roi, channel, pooled_size_h, pooled_size_w), | ||
| lambda i, c, ph, pw: tvm.tirx.if_then_else( | ||
| _is_empty(i, ph, pw), zero, pooled[i, c, ph, pw] | ||
| ), | ||
| ) |
There was a problem hiding this comment.
The current implementation computes bin boundaries twice: once in _sample (within the pooled compute) and again in _is_empty (in the final compute). This is inefficient.
This can be optimized by checking if the result of the max-pooling is -inf, which indicates an empty bin, as -inf is used as a sentinel value in _sample. This avoids recomputing the bounds.
With this change, the _is_empty function (lines 70-72) is no longer needed and can be removed.
Note: This change in logic assumes that the input data does not contain -inf. If a non-empty bin contains only values less than or equal to -inf, the original code would return -inf, while this suggested change would return 0. Given that roi_pool is typically used on feature maps from CNNs, this assumption is likely safe.
| return te.compute( | |
| (num_roi, channel, pooled_size_h, pooled_size_w), | |
| lambda i, c, ph, pw: tvm.tirx.if_then_else( | |
| _is_empty(i, ph, pw), zero, pooled[i, c, ph, pw] | |
| ), | |
| ) | |
| return te.compute( | |
| (num_roi, channel, pooled_size_h, pooled_size_w), | |
| lambda i, c, ph, pw: tvm.tirx.if_then_else( | |
| pooled[i, c, ph, pw] == neg_inf, zero, pooled[i, c, ph, pw] | |
| ), | |
| ) |
There was a problem hiding this comment.
I kept the explicit empty-bin check here because using -inf as the final sentinel could mis-handle valid non-empty bins whose max value is actually -inf. This is a bit more work, but it preserves the intended semantics without assuming anything about the input values.
|
hi @tlopex. i also made a small compatibility fix in Without this change,
This is not specific to |
| "Unique": Unique, | ||
| "NonZero": NonZero, | ||
| # "MaxRoiPool": MaxRoiPool, | ||
| "If": If, |
There was a problem hiding this comment.
remove this line
The If operator is handled via directly_handled_ops, not through the converter map
There was a problem hiding this comment.
Sorry, you’re right. That line was added by mistake during rebase conflict resolution. I’ve removed it in the latest update.
|
Thanks your review |
Summary
Add Relax
roi_poolsupport and wire it through the ONNX frontend forMaxRoiPool.Changes
relax.vision.roi_pool, including attrs, Python wrapper, struct info inference, and legalizationroi_poolcompute for NCHW layoutMaxRoiPoolin the Relax ONNX frontend0instead of propagating invalid reductionsValidation
pytest tests/python/relax/test_op_vision.py -k roi_poolpytest tests/python/relax/test_frontend_onnx.py -k 'max_roi_pool'This PR completes the
MaxRoiPoolportion of the Relax ONNX frontend operator work tracked in #18945.