Files
2026-07-13 13:18:33 +08:00

77 lines
3.0 KiB
Python

# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0
# DeepSpeed Team
import torch
try:
from torch._subclasses import FakeTensorMode
from torch._subclasses.fake_tensor import unset_fake_temporarily
from torch._dynamo.variables.builder import wrap_to_fake_tensor_and_record
except ImportError:
# Unsupported torch version
pass
def wrap_if_ds_param(t):
if hasattr(t, 'ds_id'):
data = torch.rand(t.ds_shape,
dtype=t.dtype,
layout=t.layout,
device=t.device,
pin_memory=t.is_pinned(),
requires_grad=t.requires_grad)
if isinstance(t, torch.nn.Parameter):
t = torch.nn.Parameter(data, requires_grad=t.requires_grad)
else:
t = data
return t
def _get_guard_sizes_strides(t):
if hasattr(t, "ds_id"):
# ZeRO-3 may temporarily all-gather a parameter during tracing, but the
# stable module state used by TorchDynamo guards is the released
# partitioned form, where DeepSpeed resets param.data to empty(0).
released = torch.empty(0, dtype=t.dtype, device=t.device)
return released.size(), released.stride()
return t.size(), t.stride()
def patch_fake_tensor():
# dynamo tracer uses wrap_to_fake_tensor_and_record
# Wrapping FakeTensorMode.from_tensor is not sufficient as dynamo generates SymbolicContext before calling from_tensor
original_wrap_to_fake_tensor_and_record = wrap_to_fake_tensor_and_record
def wrap_to_fake_tensor_and_record_wrapper(t, *args, **kwargs):
dummy_tensor = wrap_if_ds_param(t)
ret = original_wrap_to_fake_tensor_and_record(dummy_tensor, *args, **kwargs)
tx = kwargs.get("tx") if "tx" in kwargs else args[0]
source = kwargs.get("source")
if tracing_context := torch._guards.TracingContext.try_get():
tracing_context.tensor_to_context[t] = tracing_context.tensor_to_context.pop(dummy_tensor)
if source is not None:
# Keep the full ds_shape symbolic context from the dummy tensor, but
# use the stable released ZeRO-3 parameter representation for
# TorchDynamo's tensor-match guards. PyTorch 2.9 started enforcing
# those guards for parameters during build_guards().
size, stride = _get_guard_sizes_strides(t)
tx.output.input_source_to_sizes_strides[source] = {
"size": size,
"stride": stride,
}
return ret
torch._dynamo.variables.builder.wrap_to_fake_tensor_and_record = wrap_to_fake_tensor_and_record_wrapper
# aot_module_simplified uses fake_mode.from_tensor to process inputs
original_from_tensor = FakeTensorMode.from_tensor
def from_tensor_wrapper(self, t, *args, **kwargs):
with unset_fake_temporarily():
return original_from_tensor(self, wrap_if_ds_param(t), *args, **kwargs)
FakeTensorMode.from_tensor = from_tensor_wrapper