Skip to content

fix: Canonicalize LoRA compute dtype - #3638

Open
benthecarman wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
benthecarman:fix/lora-compute-dtype
Open

fix: Canonicalize LoRA compute dtype#3638
benthecarman wants to merge 1 commit into
NVIDIA-NeMo:mainfrom
benthecarman:fix/lora-compute-dtype

Conversation

@benthecarman

@benthecarman benthecarman commented Aug 24, 2026

Copy link
Copy Markdown

What does this PR do ?

Fixes LoRA forward failures when adapter, activation, and base-weight dtypes disagree, by canonicalizing the compute dtype on both the Triton and eager paths.

Changelog

  • Triton path (TritonLinearLoRA.forward): anchor the kernel's single dtype on the base output dtype (res.dtype); cast the activation and adapter weights to it before apply_memory_efficient_lora / the kernel call, so the fused residual add stays dtype-clean.
  • Eager path (LinearLoRA.forward): compute the LoRA branch in the adapter dtype (F.linear requires matching dtypes) and cast the addend back to the base output dtype.
  • The casts stay outside the autograd Function, so gradients flow back in the original dtypes (fp32 adapter grads, bf16 activation grads).

Before your PR is "Ready for review"

Pre checks:

  • Make sure you read and followed Contributor guidelines
  • Did you write any new necessary tests?
  • Did you add or update any necessary documentation?

Additional Information

  • Two failure modes fixed, both reproduced by the new tests without this change:
    • eager, bf16 base + fp32 adapters (lora_dtype=torch.float32): RuntimeError: expected m1 and m2 to have the same dtype, but got: c10::BFloat16 != float.
    • Triton, bf16 base with an autocast-promoted fp32 activation (e.g. torch.square under bf16 autocast, as used by relu虏 activations): kernel dtype mismatch / fp32 output leaking past a bf16 module.
  • Tests: test_eager_lora_fp32_adapters_over_bf16_base (CPU, always runs) and TestTritonLoRAMixedDtype (CUDA-gated): plain bf16 input and autocast-promoted fp32 input, checking output dtype, fp32 adapter grads, and bf16 input grads.
  • Rebased onto current main: the memory-efficient LoRA path (apply_memory_efficient_lora) is now the default route on both forwards, so the canonicalization feeds it directly. All existing memory-efficiency, DTensor, and compile tests pass unchanged (the casts are no-ops when dtypes already agree); full file: 33 passed, 4 TE-gated skips.
  • No docs change: internal dtype handling, no API or config change.
  • Related to # (issue): none.

馃 Generated with Claude Code

@benthecarman
benthecarman requested a review from a team as a code owner August 24, 2026 02:00
@copy-pr-bot

copy-pr-bot Bot commented Aug 24, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

The Triton LoRA path required the activation, both
adapters, and the kernel output to already share one
dtype, and the eager path required the adapter dtype to
match the activation dtype. Three setups break that:

- fp32 master adapters over a bf16 base (wanted for
  small-lr optimizer precision) fail the Triton dtype
  assert or F.linear's dtype check;
- activations promoted under autocast (torch.square, and
  ReLUSquaredActivation feeds exactly that) make the
  Triton kernel compile fp32 operands, which needs 2x
  shared memory and exceeds the sm_120 limit;
- an fp32 LoRA addend then also leaks into `res +
  lora_res`, promoting the base output.

Canonicalize at the boundary: the Triton path computes in
the base output dtype, the eager path computes in the
adapter dtype and casts the addend back to the base output
dtype. The casts sit outside the autograd Function, so
gradients flow back through them to the original dtypes
(fp32 adapters keep fp32 gradients).

Verified on an RTX 5090: bf16 input, autocast-promoted
fp32 input, and the eager path all return bf16 outputs
with fp32 adapter gradients and bf16 activation
gradients; the promoted case previously raised
OutOfResources at 9B scale.

Signed-off-by: benthecarman <benthecarman@live.com>
@benthecarman
benthecarman force-pushed the fix/lora-compute-dtype branch from 6c5ad4f to 29d32bd Compare August 24, 2026 02:27
@HuiyingLi

Copy link
Copy Markdown
Contributor

/claude review

@claude

claude Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

LGTM

@svcnvidia-nemo-ci svcnvidia-nemo-ci added the waiting-on-maintainers Waiting on maintainers to respond label Aug 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community-request waiting-on-maintainers Waiting on maintainers to respond

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants