Repository navigation
feat(conversion): convert small antialiased bilinear downscales by default - #5024
Open
shoumikhin wants to merge 2 commits into
Open
shoumikhin wants to merge 2 commits into
shoumikhin wants to merge 2 commits into
Conversation
…DA kernel The antialiased resize converter computed its filter weights in float64. PyTorch's CUDA kernel computes them in float32, and its compiler fuses some multiply and add steps. So for float32 inputs the two results differed by up to about 4e-3 on pixel values from 0 to 255. That is normally harmless, but images are often resized and then rounded to uint8. Many exact resize results end in .5, so a small difference moves a pixel by one level. At a 288x512 to 234x416 downscale, 0.2% to 0.7% of the pixels changed. In Praxis-1, whose encoder rounds its resized camera frames like this, the resize alone moved the encoded output by up to 2.2% of its largest value against eager PyTorch. For float32 inputs, compute the weights the way the kernel does: float32 at every step, the same fused multiply-adds, and the weights summed in order. The fused multiply-adds use a float64 product on every NumPy version. float64 inputs keep float64 weights, as in PyTorch. A window with no input pixels, which explicit scales can cause, keeps zero weights like the kernel instead of dividing 0 by 0. Also mask the pixels past a window's end before the multiply instead of after it, so TensorRT can fuse the multiply and the sum like the kernel. The new weights equal PyTorch's CUDA weights exactly, which a new test reads out by resizing an identity matrix. On A100 and H100 GPUs with TensorRT 11.4, the TensorRT output was bit for bit the same as PyTorch's for bilinear downscales by up to about 3 (at most 6 input pixels per output pixel per axis) and for some bicubic sizes. Other cases, such as bilinear upscales and larger downscales, stayed within a few float32 roundings.
…fault Antialiased resize (F.interpolate with antialias=True) only ran in TensorRT with convert_antialiased_resize=True. Otherwise it stayed in PyTorch and split the graph, often right at the start of an image model. convert_antialiased_resize is now Optional[bool], and None is the new default: - None converts float32 bilinear downscales with at most 6 input pixels per output pixel along each axis, up to about 3x. In our measurements on A100, H100 and Jetson Orin GPUs with TensorRT 11.4 and a PyTorch 2.16 build for CUDA 13.2, TensorRT summed the taps in the same order as PyTorch's CUDA kernel there, and the output was bit for bit the same. Elsewhere it can differ by a few float32 roundings. Upscales, half-precision inputs, larger downscales and bicubic resize stay in PyTorch. - True converts every antialiased bilinear and bicubic resize, as before. The output can then differ from PyTorch by a few roundings. - False keeps them all in PyTorch, as before. A falsy value such as 0 means False, and settings pickled before this setting existed load as False, so refit partitions them as before. The limit and the per-axis check live in impl/upsample.py as DEFAULT_MAX_ANTIALIAS_TAPS and antialias_converts_by_default. A validator called without settings now uses the defaults, and the documented opt-out names the operator overload that torch_executed_ops matches.
shoumikhin
force-pushed
the
antialias-bilinear-default
branch
from
November 14, 2026 17:20
6af773c to
35f05f9
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This sits on top of #5023, so the first commit here is #5023. Only the last commit is new.
What is wrong today
Antialiased resize (
F.interpolatewithantialias=True) runs in TensorRT only withconvert_antialiased_resize=True. Otherwise it splits the graph. This is common at the start of image models, which resize camera frames. Exporting frameworks often cannot pass extra settings.What this change does
convert_antialiased_resizebecomesOptional[bool], withNoneas the new default:Noneconverts float32 bilinear downscales with at most 6 input pixels per output pixel along each axis (up to about 3x). On A100, H100 and Jetson Orin GPUs with TensorRT 11.4 and a PyTorch 2.16 build for CUDA 13.2, its output matched PyTorch's bit for bit, also at 6 nonzero taps. Elsewhere it can differ by a few float32 roundings; setFalsefor PyTorch's exact output.Trueconverts every antialiased resize, as before.Falsekeeps them all in PyTorch, as before. A falsy value such as0meansFalse. Settings pickled before this setting existed load asFalse.The limit and the per-axis check are
DEFAULT_MAX_ANTIALIAS_TAPSandantialias_converts_by_defaultinimpl/upsample.py. Without settings, the validator uses the defaults. The docs name the overload thattorch_executed_opsmatches,torch.ops.aten._upsample_bilinear2d_aa.default.Upscales, larger downscales, half-precision inputs and bicubic resize stay in PyTorch. They were not always bit for bit: a 4x downscale was within 5e-5 on 0 to 255, a 1.25x upscale one float32 rounding off.
Speed, for a resize followed by a 3x3 convolution: 0.18 ms in one engine against 0.35 ms split for 2x3x288x512 to 234x416, and 0.80 ms against 1.31 ms for 8x3x1080x1920 to 360x640. A resize alone is slower in TensorRT; the gain is the avoided split. Memory: for the second case the engine needs about 21 MiB of activation memory, about what PyTorch allocates for the resize with
False.Tests
test_antialias2d_matches_pytorchruns the default at 3 and 6 nonzero taps (within 1e-4).test_antialias2d_validator_default: by default 6 taps convert, also withalign_cornersor a 0.5 scale; 7 taps (either axis,align_cornersor a scale), an upscale, float16 and float64 do not.Trueconverts 7 taps,0nothing.test_antialias2d_setting_is_bool,test_antialias2d_old_pickle_keeps_resize_in_pytorch: the twoFalsecases above.test_antialias2d_default_float64_log: no wrongtruncate_doublehint.test_antialias2d_engines: by default 1 engine, withFalsethe split; bicubic stays in PyTorch.test_upsample_aten.pypasses on A100 and H100.