Skip to content

Add the CUDA implementation to the Rotated Box Iou Calculation - #9404

Merged
NicolasHug merged 14 commits into
pytorch:mainfrom
zy1git:rotated-cuda
Mar 10, 2026
Merged

NicolasHug merged 14 commits into
pytorch:mainfrom
zy1git:rotated-cuda

Conversation

@zy1git

@zy1git zy1git commented Feb 25, 2026

Copy link
Copy Markdown
Contributor

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)

@pytorch-bot

pytorch-bot Bot commented Feb 25, 2026

Copy link
Copy Markdown

🔗 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 Failures

As of commit 66db05b with merge base 1cc5693 (image):

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.

@meta-cla meta-cla Bot added the cla signed label Feb 25, 2026
Comment thread test/test_ops.py Outdated
"""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")

@NicolasHug NicolasHug Feb 25, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

use xfail, here and everywhere else where relevant

@zy1git zy1git Feb 26, 2026

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.

Actually, I implemented this:https://github.com/pytorch/vision/pull/9404/changes#r2857140067

Then we don't need this pytest.skip/xfail thing.

Comment thread test/test_ops.py Outdated
ious, torch.tensor([[expected_iou]], dtype=torch.float32, device=device), atol=1e-4, rtol=1e-4
)

# ==================== CUDA-specific Tests ====================

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for adding the test below, it's a good test. Just remove this comment please

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.

Removed in the new commit.

@NicolasHug NicolasHug left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @zy1git , made a quick first pass

const at::Tensor& boxes1,
const at::Tensor& boxes2) {
using scalar_t = float;
AT_ASSERTM(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should use TORCH_CHECK instead of AT_ASSERTM for consistency with the rest

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.

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;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

@zy1git zy1git Feb 26, 2026

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.

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.

Comment on lines +42 to +43
__shared__ float block_boxes1[BLOCK_DIM_X * 5];
__shared__ float block_boxes2[BLOCK_DIM_Y * 5];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems wrong, shouldn't it be T?

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.

Yeah, I agree. The previous implementation from Detectron2 used float. T is better.

Fixed in the new commit.

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) ||

@zy1git zy1git Feb 27, 2026

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.

This 1e-4 is different from the cpp implementation PR: #9379 to address the test failures caused by numerical precision issues.

Comment thread torchvision/csrc/ops/box_iou_rotated_utils.h
template <typename T>
struct Point {
T x, y;
HOST_DEVICE Point(const T& px = 0, const T& py = 0) : x(px), y(py) {}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These, and others, are HOST_DEVICE_INLINE in the detectron2 implem. Is there a particular reason we're using HOST_DEVICE here instead?

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.

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];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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?

@zy1git zy1git Mar 3, 2026

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.

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?

@NicolasHug
NicolasHug merged commit cf080e9 into pytorch:main Mar 10, 2026
65 of 73 checks passed
@github-actions

Copy link
Copy Markdown

Hey @NicolasHug!

You merged this PR, but no labels were added.
The list of valid labels is available at https://github.com/pytorch/vision/blob/main/.github/process_commit.py

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants