Add torch.normal and Tensor.normal_ to the PyTorch converter - #2878
Open
GodfredArhinful wants to merge 1 commit into
Open
GodfredArhinful wants to merge 1 commit into
GodfredArhinful wants to merge 1 commit into
Conversation
Converts every overload of torch.normal (Tensor_float, float_Tensor, Tensor_Tensor, float_float) and the in-place Tensor.normal_, which torch.export lowers to normal_functional. Scalar mean and std known at conversion time map onto mb.random_normal directly. Tensor or runtime parameters shift and scale a standard normal sample over the broadcast shape of mean and std. Fixes apple#1528
TobyRoseman
reviewed
Oct 1, 2026
|
|
||
| @register_torch_op( | ||
| torch_alias=[ | ||
| "normal_functional", |
Collaborator
There was a problem hiding this comment.
Are your unit tests testing each of these five alias, as well as normal?
Author
There was a problem hiding this comment.
Yes. Every test is parametrized over both the TorchScript and torch.export frontends, and together they reach every registered name:
normal(TorchScript, all out-of-place overloads):test_normal_overloads(all four),test_normal_broadcast_shape,test_normal_constant_tensor_parameters,test_normal_dynamic_shapenormal_(TorchScript in-place, resolved tonormal) andnormal_functional(torch.export in-place):test_normal_inplace,test_normal_dynamic_shape[inplace]normal.tensor_float:test_normal_overloads[Tensor_float]normal.float_tensor:test_normal_overloads[float_Tensor]normal.tensor_tensor:test_normal_overloads[Tensor_Tensor],test_normal_broadcast_shape,test_normal_constant_tensor_parameters,test_normal_dynamic_shape[Tensor_Tensor]normal.float_float:test_normal_overloads[float_float],test_normal_dynamic_shape[float_float]
This was confirmed by wrapping the registered converter and logging node.kind while running TestNormal on both frontends.
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.
Fixes #1528
Adds a converter for
torch.normaland the in-placeTensor.normal_. It follows the suggestion in #1528 to build onmb.random_normalthe same waytorch.randbuilds onmb.random_uniform.Why
normal_is how StyleGAN2-style generators inject per-pixel noise. This isNoiseInjectionfrom rosinality/stylegan2-pytorch, which GFPGAN uses unchanged (mentioned in #1528):On
main, converting a conv block with this module fails withPyTorch convert function for op 'normal_' not implemented. With this change it converts, and the injected noise has mean -0.008 and std 1.003. #1528 also reports the same error for a GPT model.What's covered
Tensor.normal_(mean=0, std=1)normal_normal_functionalselfnormal.Tensor_float(mean, std=1)normal(3 inputs)normal.tensor_floatnormal.float_Tensor(mean, std)normal(3 inputs)normal.float_tensornormal.Tensor_Tensor(mean, std)normal(3 inputs)normal.tensor_tensornormal.float_float(mean, std, size)normal(8 inputs)normal.float_floatsize, honoringdtypeWhen mean and std are scalars known at conversion time, they go straight into
random_normal'smeanandstddev. Otherwise the converter scales and shifts a standard normal sample. A dynamicsize, which TorchScript passes as a list of scalars, is concatenated into a shape tensor. A 0-d result is sampled as one value and squeezed. As withrandandrandn, thegeneratorargument is ignored.Tests
All 48 new tests fail on
mainwithnot implementederrors and pass with this change.TestNormalcan't compare random values directly. Each model instead returns 1.0 when the mean and standard deviation of a 16,384-value sample land within 0.1 standard deviations of their expected values. That margin is more than 12 standard errors wide, so the check stays strict even though the fp16 backend loosensatol. The tests cover:normal_with default and explicit mean and stdThe ExecuTorch cases are marked
xfail. PyTorch's edge verifier rejects these ops because they are not in the Core ATen opset, the same situation as the existingrandn_liketest.Ran locally on macOS 26.6.1 (arm64) with torch 2.8.0. All
TestNormalcases pass on TorchScript and torch.export, for both the mlprogram and neuralnetwork backends. I also ran the rest of the torch frontend tests on this branch and onmain. The results are identical: a fewTestPad::test_pad_constantandTestConvcases fail or crash on this machine with or without this change.