Repository navigation
Conversation
Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com>
prepare_for_saving and restore_from_saved run for every tensor every TE module saves, so the DistributedWeight check sits on a hot path for all users, not just GTP. Test None and torch.Tensor first, read the marker with an inline getattr (DistributedWeight implementers must be Tensor subclasses), and only query torch.compiler.is_compiling() for a flagged weight. On restore, test the common None/Tensor case first. On a CPU microbenchmark this brings the non-distributed cost back to roughly main's, e.g. 4.5 -> 5.2 us (was 10.0 us) per prepare_for_saving for a 32-expert bf16 GroupedLinear. Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the Linear and GroupedLinear saved-tensor hook tests from NVIDIA#3545 to the prepare_for_saving fix, and extend them: - Run each module case both under identity saved_tensors_hooks and under te.checkpoint(use_reentrant=False), whose pack hook discards saved tensors and returns recomputed ones in backward. - Cover LayerNormLinear, which also gates its backward on the saved weight being a DistributedWeight. - Add CPU-only checks that prepare_for_saving keeps a DistributedWeight by reference and that backward gets the same object back with no hooks, identity hooks, and torch.utils.checkpoint. Co-authored-by: Xiaowei Ren <xren@nvidia.com> Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[Medium impact] The PR appears safe to merge; no actionable issues remain. SummaryKeeps the original
Diagram%%{init: {'theme': 'neutral'}}%%
flowchart LR
W[DistributedWeight] --> P[prepare_for_saving]
P --> S[Tensor saved through autograd]
P --> R[Original object kept by reference]
S --> U[Unpack saved tensors]
U --> B[restore_from_saved]
R --> B
B --> M[Provider gathers weight for backward]
Reviews (3) · Last reviewed commit: "Merge branch 'main' into fix_dweights_fo..." · Reviewed by Greptile |
Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com>
|
/te-ci pytorch L0 |
| reference and restored in place of the saved tensor: saved-tensor hooks | ||
| (e.g. activation offloading) unpack saved tensors as plain tensors, which | ||
| drops the subclass and its distributed-weight hooks.""" |
There was a problem hiding this comment.
Can you explain in more detail? You're saying that something (in CPU offloading or Mcore or PyTorch?) replaces the contents of ctx.saved_tensors with a copy of the original tensors, so that they are not identical objects?
There was a problem hiding this comment.
Yes pytorch autograd is the culprit. With a hook installed, autograd wraps the return object from the hook into a fresh torch.Tensor, so any attributes set on it are lost. This method works around autograd by saving a reference outside and using that instead. @xrennvidia's #3545 implemented a similar change (now removed) at the module level (linear and groupedlinear).
| # Skipped under torch.compile so traced graphs are unchanged. | ||
| if ( | ||
| getattr(tensor, "is_distributed_weight", False) | ||
| and not torch.compiler.is_compiling() |
There was a problem hiding this comment.
Does this work? If the old logic was invalid for eager exectuion, I'm skeptical that it's valid under torch.compile. It might be better to error out if GTP and torch.compile are used together.
There was a problem hiding this comment.
I'm not sure I follow your comment about the invalid logic? The modules force eager execution for torch compile with is_distributed_weight anyway. Although I agree that GTP + torch.compile is untested, so I've opted to error out here.
| metadata: Dict[str, Any] | ||
|
|
||
|
|
||
| class _SavedDistributedWeight(NamedTuple): |
There was a problem hiding this comment.
If I understand correctly (maybe false), the root problem is that we need the restored tensor to be identical to the saved tensor (not just identical data, but restored is saved) because the saved tensor might have weird monkeypatched attrs (like GTP callbacks). If that's the case, this fix is more general than DistributedWeight and it could apply to any class that requires identical tensor objects in the forward and backward.
There was a problem hiding this comment.
This is the correct assessment
There was a problem hiding this comment.
Maybe prematurely generalizing, but it may be clearer to rename this to something like _SavedTensorRef.
Signed-off-by: Kirthi Shankar Sivamani <ksivamani@nvidia.com>
timmoon10
left a comment
There was a problem hiding this comment.
Overall LGTM, with minor suggestions.
| pytest.skip("requires CUDA") | ||
|
|
||
|
|
||
| def test_saved_tensor_hooks_unpack_subclass_as_plain_tensor(): |
There was a problem hiding this comment.
Do we need to test this? This is more of a PyTorch contract. Even if they break it, it shouldn't affect us since we unconditionally restore the original tensor object for any tensor with is_distributed_weight=True.
Description
An alternate approach to fixing the bug outlined in #3545 that tackles all modules at once. Cherry-picked parts of tests from @xrennvidia . The main advantages of this approach are tackling CPU overhead and having a central solution that covers all modules that use our
restore_from*functions.Type of change
Changes
QuantizedTensorChecklist: