Skip to content

Fix absent weights in native sparse permutation operators - #6341

Open
eric-gecheng wants to merge 1 commit into
pytorch:mainfrom
eric-gecheng:bugfix/preserve-none-permute-weights
Open

eric-gecheng wants to merge 1 commit into
pytorch:mainfrom
eric-gecheng:bugfix/preserve-none-permute-weights

Conversation

@eric-gecheng

Copy link
Copy Markdown

Sparse permutation operators can return an undefined Tensor instead of None for absent weights. When a native TorchScript graph passes that result directly to another permutation, the second operator treats the weights as present and fails. On CUDA, this reproduces as:

RuntimeError: Expected a proper Tensor but got None (or an undefined Tensor in C++) for argument #0 'self'

This affects both nonempty inputs and inputs whose jagged lengths are all zero, including empty-request model warmup. It is not specific to quantized embeddings; chained TorchRec KJT permutations are one way to expose it.

Cause and fix

The affected implementations declare Tensor permuted_weights, assign it only when input weights are present, and return it as part of a tuple whose third element is std::optional<Tensor>. Without weights, this constructs an engaged optional containing an undefined tensor rather than std::nullopt.

Use std::optional<Tensor> for the local output, matching the existing CPU 2D implementation:

  • Fix CUDA 1D and 2D permutations, including both vector and flat-kernel returns and the shared preallocated-output implementation.
  • Fix the same return-value bug in legacy permute_sparse_features on CPU/CUDA and in CPU 1D permutation.
  • Preserve actual weight tensors, including defined empty tensors. Operator schemas and weighted computations stay unchanged.

Regression coverage

The new test loads native operator libraries in fresh subprocesses without importing FBGEMM's Python registrations. Python autograd wrappers can normalize undefined tensors to None, masking the bug in ordinary Python tests.

It checks optional-weight presence inside TorchScript and feeds each output directly into a second permutation. Coverage includes six public entry points, int32/int64 inputs, nonempty/mixed/all-zero lengths, absent/present weights, preallocated outputs, and both forced CUDA kernel paths. Defined empty weights must remain tensors.

Validation

  • Rebuilt the three affected C++/CUDA translation units before and after the change against PyTorch 2.12.1+cu130 and CUDA 13.0 (SM 89), linking the existing FBGEMM helper libraries. This was a focused native build, not a full wheel rebuild.
  • Before the fix, the regression fails on CPU 1D and on CUDA 2D with both flat-kernel settings. The CUDA failures reproduce the error above.
  • After the fix, all 216 native TorchScript cases pass: 72 on CPU and 72 for each CUDA kernel setting.
  • All 12 selected existing permutation tests pass, including repeated indices, noncontiguous inputs, vector kernels, 2D weights, large segments, preallocated outputs, and legacy sparse features.
  • ufmt diff, Ruff E/F checks, copyright-header checks, and git diff --check pass.

The full repository test suite and ROCm execution were not run locally.

Related downstream workaround: meta-pytorch/torchrec#4761.

Keep absent output weights as an empty optional instead of wrapping an undefined Tensor. Apply the same semantics to CUDA 1D/2D and legacy sparse permutations, and to the affected CPU implementations.

Add native TorchScript regression coverage without Python autograd registrations, including chained permutations, vector/flat CUDA paths, empty inputs, and defined weights.
@meta-cla meta-cla Bot added the cla signed label Sep 20, 2026
@meta-codesync

meta-codesync Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

@q10 has imported this pull request. If you are a Meta employee, you can view this in D120923861.

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.

1 participant