Add the CUDA implementation to the Rotated Box Iou Calculation - #9404
Conversation
🔗 Helpful Links🧪 See artifacts and rendered test results at hud.pytorch.org/pr/pytorch/vision/9404
Note: Links to docs will display an error until the docs builds have been completed. ❌ 2 New Failures, 2 Unrelated FailuresAs of commit 66db05b with merge base 1cc5693 ( NEW FAILURES - The following jobs have failed:
BROKEN TRUNK - The following jobs failed but were present on the merge base:👉 Rebase onto the `viable/strict` branch to avoid these failures
This comment was automatically generated by Dr. CI and updates every 15 minutes. |
| """Core test: IoU computation with different formats, dtypes, and rotations.""" | ||
| # CUDA kernel only supports float32, skip float64 on CUDA | ||
| if device == "cuda" and dtype == torch.float64: | ||
| pytest.skip("CUDA kernel only supports float32") |
There was a problem hiding this comment.
use xfail, here and everywhere else where relevant
There was a problem hiding this comment.
Actually, I implemented this:https://github.com/pytorch/vision/pull/9404/changes#r2857140067
Then we don't need this pytest.skip/xfail thing.
| ious, torch.tensor([[expected_iou]], dtype=torch.float32, device=device), atol=1e-4, rtol=1e-4 | ||
| ) | ||
|
|
||
| # ==================== CUDA-specific Tests ==================== |
There was a problem hiding this comment.
Thanks for adding the test below, it's a good test. Just remove this comment please
There was a problem hiding this comment.
Removed in the new commit.
NicolasHug
left a comment
There was a problem hiding this comment.
Thanks @zy1git , made a quick first pass
| const at::Tensor& boxes1, | ||
| const at::Tensor& boxes2) { | ||
| using scalar_t = float; | ||
| AT_ASSERTM( |
There was a problem hiding this comment.
I think we should use TORCH_CHECK instead of AT_ASSERTM for consistency with the rest
There was a problem hiding this comment.
Thanks for pointing this out. I have updated it in the new commit.
| // input must be contiguous | ||
| const at::Tensor& boxes1, | ||
| const at::Tensor& boxes2) { | ||
| using scalar_t = float; |
There was a problem hiding this comment.
Hm, is there any reason double isn't support on CUDA? I'm hoping we can make it work through AT_DISPATCH_FLOATING_TYPES like what was done for the CPU part. Can you try that and see if the tests are complaining?
There was a problem hiding this comment.
Great point!
In the new commit, I can have the Input to be float64 for CUDA, but the output is still float32 to match the CPU behavior. And I removed the pytest.skip/xfail parts in the test file.
| __shared__ float block_boxes1[BLOCK_DIM_X * 5]; | ||
| __shared__ float block_boxes2[BLOCK_DIM_Y * 5]; |
There was a problem hiding this comment.
This seems wrong, shouldn't it be T?
There was a problem hiding this comment.
Yeah, I agree. The previous implementation from Detectron2 used float. T is better.
Fixed in the new commit.
…ance for xyxyxyxy format on CUDA
| for (int i = 1; i < num_in - 1; i++) { | ||
| for (int j = i + 1; j < num_in; j++) { | ||
| T crossProduct = cross_2d<T>(q[i], q[j]); | ||
| if ((crossProduct < -1e-4) || |
There was a problem hiding this comment.
This 1e-4 is different from the cpp implementation PR: #9379 to address the test failures caused by numerical precision issues.
| template <typename T> | ||
| struct Point { | ||
| T x, y; | ||
| HOST_DEVICE Point(const T& px = 0, const T& py = 0) : x(px), y(py) {} |
There was a problem hiding this comment.
These, and others, are HOST_DEVICE_INLINE in the detectron2 implem. Is there a particular reason we're using HOST_DEVICE here instead?
There was a problem hiding this comment.
Fixed in the new commit. Good catch! HOST_DEVICE_INLINE is better here because it eliminates function call overhead for these small, frequently-called helper functions.
| // Sort point 1 ~ num_in according to their relative cross-product values | ||
| // (essentially sorting according to angles) | ||
| // If the angles are the same, sort according to their distance to origin | ||
| T dist[24]; |
There was a problem hiding this comment.
detectron2 has a different path for CUDA and for CPU here: https://github.com/facebookresearch/detectron2/blob/fd27788985af0f4ca800bca563acdb700bb890e2/detectron2/layers/csrc/box_iou_rotated/box_iou_rotated_utils.h#L202
Any specific reason we're not doing something similar?
There was a problem hiding this comment.
The CUDA and CPU paths are almost identical, except the CPU path recalculates the distance after sorting, which is redundant since we swap both q[] and dist[] together during sorting. I think Detectron2 kept this step because they originally intended to use std::sort (now commented out) for CPU, which wouldn't swap dist[] alongside q[].
In the new commit, I separated the CUDA and CPU paths to match Detectron2 exactly, and reverted the tolerance from 1e-4 to 1e-6. The test failures returned in my local run (not CI yet), confirming that the two-path structure is not the cause.
I think we can still combine the two paths into one, given the analysis above. Would you prefer I do that, or keep them separated to match Detectron2?
|
Hey @NicolasHug! You merged this PR, but no labels were added. |
Implementation Details (Adapted from Detectron2)
Uses shared memory optimization with 32×16 thread blocks (512 threads per block)
Handles transpose for large box counts (>65535 in Y dimension)
CUDA kernel only supports float32 (consistent with Detectron2)
Shared header allows both CPU and CUDA kernels to use the same math utilities
Testing
All existing tests now run on both CPU and CUDA
Added test_cuda_cpu_consistency to verify CUDA and CPU produce the same results
float64 tests are skipped on CUDA (kernel only supports float32)