Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
3d04ab9
[graph_trainer] Replace trace_module/run_traced_module with aot_funct…
tugsbayasgalan Mar 30, 2026
da526a8
Update on "[graph_trainer] Replace trace_module/run_traced_module wit…
tugsbayasgalan Mar 30, 2026
3394aaf
Update on "[graph_trainer] Replace trace_module/run_traced_module wit…
tugsbayasgalan Mar 31, 2026
8f276ba
Update on "[graph_trainer] Replace trace_module/run_traced_module wit…
tugsbayasgalan Mar 31, 2026
4f56847
Update on "[graph_trainer] Replace trace_module/run_traced_module wit…
tugsbayasgalan Mar 31, 2026
155d120
Update on "[graph_trainer] Replace trace_module/run_traced_module wit…
tugsbayasgalan Mar 31, 2026
49bd670
[graph_trainer] Add remat pass and torch.no_grad() execution to minim…
tugsbayasgalan Mar 31, 2026
d7e80e0
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Mar 31, 2026
2ebcc94
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Mar 31, 2026
92f7588
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Mar 31, 2026
6960a36
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Mar 31, 2026
bfb303b
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Mar 31, 2026
0b66ad1
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Mar 31, 2026
4dfbaf8
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Mar 31, 2026
cc97983
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Mar 31, 2026
10de659
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Mar 31, 2026
0783db3
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Mar 31, 2026
4b4ec15
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Mar 31, 2026
4b48a21
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 1, 2026
03b648f
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 1, 2026
84c908a
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 1, 2026
4e9d810
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 1, 2026
d538249
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 1, 2026
b3daa48
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 1, 2026
201ed86
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 1, 2026
055e0ce
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 1, 2026
fd4bd77
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 2, 2026
f0eb787
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 2, 2026
803cc90
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 2, 2026
24a1be0
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 2, 2026
6559ba6
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 3, 2026
4c1d0d2
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 3, 2026
3036bae
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 4, 2026
467d42e
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 4, 2026
386810a
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 4, 2026
e3867cb
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 4, 2026
933726a
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 6, 2026
ef5babd
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 6, 2026
6580931
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 6, 2026
bc213b6
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 6, 2026
8bd77b7
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 6, 2026
0ca9c95
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 6, 2026
9693ffe
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 6, 2026
f17af31
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 6, 2026
eba5038
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 6, 2026
ae36cae
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 6, 2026
f1ae755
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 6, 2026
04f2ac4
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 6, 2026
3bcc838
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 6, 2026
83dcd2b
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 6, 2026
9b92650
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 7, 2026
dfca436
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 7, 2026
01d002a
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 8, 2026
3726f86
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 8, 2026
85526b2
Update base for Update on "[graph_trainer] Add remat pass and torch.n…
tugsbayasgalan Apr 8, 2026
a9b01f9
Update on "[graph_trainer] Add remat pass and torch.no_grad() executi…
tugsbayasgalan Apr 8, 2026
fa35998
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 8, 2026
0e44929
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 8, 2026
0ea91a0
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 9, 2026
19afae3
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 9, 2026
9e42167
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 10, 2026
a2f3343
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 10, 2026
13cf04c
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 12, 2026
246b992
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 12, 2026
32942cd
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 12, 2026
775dfe7
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 12, 2026
a838dc2
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 13, 2026
1618ddd
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 13, 2026
7bb5d54
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 13, 2026
fdaa93c
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 13, 2026
3a64ffd
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 13, 2026
339194e
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 13, 2026
404b1a3
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 14, 2026
202f0cb
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 14, 2026
5a02e95
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 14, 2026
a8b13f8
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 14, 2026
b28baa4
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 14, 2026
4c620f5
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 14, 2026
e7e251c
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 14, 2026
1267aae
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 14, 2026
64bf2c7
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 15, 2026
87b7abc
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 15, 2026
d28765b
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 15, 2026
1147da4
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 15, 2026
7f57f92
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 15, 2026
24d5218
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 15, 2026
723e0e4
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 15, 2026
d989706
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 15, 2026
4bdc488
Update base for Update on "[graph_trainer] Add torch.no_grad() and gr…
tugsbayasgalan Apr 16, 2026
c60367c
Update on "[graph_trainer] Add torch.no_grad() and graph-based SAC to…
tugsbayasgalan Apr 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ jobs:
# Run precompile unit tests
pytest torchtitan/experiments/graph_trainer/tests/test_precompile.py -v

# Run bitwise deterministic guardrail test
# Run bitwise deterministic and SAC peak-memory guardrail tests
pytest torchtitan/experiments/graph_trainer/tests/test_bitwise_deterministic.py -v
pytest torchtitan/experiments/graph_trainer/tests/test_sac_peak_memory.py -v

rm -rf $RUNNER_TEMP/artifacts-to-be-uploaded/*/checkpoint
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ jobs:
# Run the MoE numerics tests
NCCL_NVLS_ENABLE=0 pytest torchtitan/experiments/graph_trainer/tests/test_numerics.py::TestGraphTrainerNumerics -v -k "moe"

# Run bitwise deterministic guardrail test (includes H100-only hardcoded-hash tests)
# Run bitwise deterministic and SAC peak-memory guardrail tests
pytest torchtitan/experiments/graph_trainer/tests/test_bitwise_deterministic.py -v
pytest torchtitan/experiments/graph_trainer/tests/test_sac_peak_memory.py -v

rm -rf $RUNNER_TEMP/artifacts-to-be-uploaded/*/checkpoint
1 change: 0 additions & 1 deletion tests/integration_tests/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ def run_single_test(

def run_tests(args, test_list: list[OverrideDefinitions], module=None, config=None):
"""Run all integration tests to test the core features of TorchTitan"""

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: why delete this line?

exclude_set = set()
if hasattr(args, "exclude") and args.exclude:
exclude_set = {name.strip() for name in args.exclude.split(",")}
Expand Down
69 changes: 14 additions & 55 deletions torchtitan/experiments/graph_trainer/make_fx_tracer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@
import torch
import torch.nn as nn
import torch.utils._pytree as pytree
from torch._functorch._aot_autograd.logging_utils import (
setup_stacktrace_preservation_hooks,
)
from torch._guards import tracing, TracingContext
from torch._subclasses import FakeTensorMode
from torch.fx.experimental.proxy_tensor import make_fx
Expand Down Expand Up @@ -200,52 +197,6 @@ def _remove_cpu_shadow_chains(gm: torch.fx.GraphModule) -> None:
gm.recompile()


@contextmanager
def _patch_engine_run_backward() -> Generator[None, None, None]:
"""Patch _engine_run_backward to install stacktrace preservation hooks.

Why this is needed:
When make_fx traces a function that calls loss.backward(), the backward
pass is decomposed into primitive ATen ops. Normally (in eager autograd),
``setup_stacktrace_preservation_hooks`` is called by the autograd engine
to propagate ``seq_nr`` from forward ops to their corresponding backward
ops. Under make_fx tracing, this hook setup doesn't happen automatically
because the engine path differs, so backward FX nodes end up without
``seq_nr`` metadata. Without ``seq_nr``, we can't correlate backward
nodes back to their forward counterparts (needed by
``_copy_fwd_metadata_to_bw_nodes``).

This context manager patches ``_engine_run_backward`` to call
``setup_stacktrace_preservation_hooks`` before the autograd engine runs,
restoring ``seq_nr`` propagation during tracing.

We must patch the name in both modules since ``torch.autograd.__init__``
imports it via ``from .graph import``.
"""
import torch.autograd
import torch.autograd.graph

_orig_fn = torch.autograd.graph._engine_run_backward

def _patched(t_outputs, *args, **kwargs): # type: ignore[no-untyped-def]
roots = [
t.grad_fn
for t in t_outputs
if isinstance(t, torch.Tensor) and t.grad_fn is not None
]
if roots:
setup_stacktrace_preservation_hooks(roots)
return _orig_fn(t_outputs, *args, **kwargs)

torch.autograd.graph._engine_run_backward = _patched # type: ignore[assignment]
torch.autograd._engine_run_backward = _patched # type: ignore[assignment]
try:
yield
finally:
torch.autograd.graph._engine_run_backward = _orig_fn # type: ignore[assignment]
torch.autograd._engine_run_backward = _orig_fn # type: ignore[assignment]


def _copy_fwd_metadata_to_bw_nodes(fx_g: torch.fx.GraphModule) -> None:
"""Copy forward node metadata (custom) to later nodes sharing the same seq_nr.

Expand Down Expand Up @@ -402,33 +353,36 @@ def fn_with_subclass_handling(*plain_args: Any) -> list:

state_for_fn = dict(zip(state_fqns, state_wrapped, strict=True))
user_list = pytree.tree_unflatten(list(user_flat), user_args_spec)

with _patch_engine_run_backward():
with torch.compiler._patch_autograd_grad():
result = fn(state_for_fn, *user_list)

flat_outs, output_spec = pytree.tree_flatten(result)
num_flat_outputs = len(flat_outs)
unwrapped_outs, output_layouts = _unwrap_subclasses(flat_outs)
return unwrapped_outs

ctx = TracingContext(fake_mode)
# preserve_node_meta propagates fx.traceback.annotate metadata to traced nodes

# Disable autograd multithreading so that backward tracing
# runs on the calling thread. Without this, the C++ autograd
# runs on the calling thread. Without this, the C++ autograd
# engine dispatches backward to a worker thread that has a
# fresh contextvars.Context, making the compile_on_one_rank
# ContextVar invisible and causing _sym_get_coordinate to
# bake rank 0's concrete coordinates into the backward graph.
# TODO: Move set_multithreading_enabled(False) to global init.
# Forcing backward onto the main CPU thread is a good default
# for both tracing and runtime, not just the tracing path.
# _skip_nested_compile lets the current make_fx trace inline through
# torch.compile'd FlexAttention kernels instead of erroring.
# _non_strict_tracing_context is required by _patch_autograd_grad() and

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not a fan of needing _non_strict_tracing_context coupling with _patch_autograd_grad.
What breaks if we don't have this context?
Is there other ways to fix this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only want to enable patching autograd in the cases we know it is carefully coupled with rest of the stack. So we added check in patch_autograd that it should only succeed if this specific context is on. The context is _non_strict_tracing_context. For example, we don't want to do this non-strict export.

# marks this make_fx pass as the non-strict tracing flow, distinct from
# other make_fx-based entry points such as non-strict export.
with (
fake_mode,
tracing(ctx),
preserve_node_meta(),
_skip_nested_compile(),
torch.autograd.set_multithreading_enabled(False),
torch.compiler._non_strict_tracing_context(),
Comment thread
tugsbayasgalan marked this conversation as resolved.
):
traced = make_fx(
fn_with_subclass_handling,
Expand Down Expand Up @@ -470,6 +424,10 @@ def run_traced(
This is a reference implementation of traced-graph execution. It keeps the
state handling, subclass unwrapping, and output reconstruction logic
explicit instead of baking those semantics into ``TracedResult`` itself.
Runs under ``torch.no_grad()`` because the graph already contains explicit
Comment thread
tugsbayasgalan marked this conversation as resolved.
backward ops (from ``torch.autograd.grad`` traced by make_fx). Without
this, PyTorch would build a redundant autograd graph on top, keeping all
forward intermediates alive via ``grad_fn`` references.
"""
state_flat = list(state.values())
user_args_flat, _ = pytree.tree_flatten(list(args))
Expand All @@ -481,7 +439,8 @@ def run_traced(
all_args = list(state_flat) + list(user_args_flat)
flat_inputs, _ = _unwrap_subclasses(all_args)

flat_outputs = traced_result.gm(*flat_inputs)
with torch.no_grad():
flat_outputs = traced_result.gm(*flat_inputs)
wrapped = _wrap_subclasses(
flat_outputs,
traced_result.num_flat_outputs,
Expand Down
34 changes: 32 additions & 2 deletions torchtitan/experiments/graph_trainer/passes.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@
from torchtitan.tools.logging import logger


def _is_backward_node(node: torch.fx.Node) -> bool:
return node.meta.get("autograd_backward", False)


def compile_time_passes(
traced_result: "TracedResult",
) -> list[Callable]:
Expand All @@ -69,6 +73,7 @@ def compile_time_passes(
remove_detach_pass,
remove_identity_view_pass,
remove_identity_slice_pass,
selective_activation_remat_pass,
# FlexAttention HOPs must be compiled (via regional_inductor) to
# produce bitwise identical results to the eager Trainer path.
# When left uncompiled, flex_attention still runs correctly but
Expand Down Expand Up @@ -452,6 +457,11 @@ def apply_sac_pass(
if node.op != "call_function":
continue

# Skip backward nodes — they must not carry recompute tags,
# otherwise the remat pass would try to duplicate backward ops.
if _is_backward_node(node):
continue

if node.target in (
operator.getitem,
torch.ops._c10d_functional.wait_tensor.default,
Expand All @@ -469,7 +479,6 @@ def apply_sac_pass(
node.meta["recompute"] = parent.meta["recompute"]
node.meta["ac_graph_id"] = parent.meta.get("ac_graph_id", 0)
continue

custom_meta = node.meta.get("custom", {})
ac_region_id = custom_meta.get(_AC_REGION_ID, 0)
node.meta["ac_graph_id"] = ac_region_id
Expand Down Expand Up @@ -504,6 +513,27 @@ def apply_sac_pass(
return gm


def selective_activation_remat_pass(
gm: torch.fx.GraphModule, example_inputs: tuple | None = None
) -> torch.fx.GraphModule:
"""Apply graph-based SAC to a traced fwd+loss+bwd graph.

Tags forward nodes with recompute policy via apply_sac_pass (backward
nodes are skipped automatically via ``node.meta["autograd_backward"]``), then
applies remat_using_tags_for_fwd_loss_bwd_graph to duplicate
PREFER_RECOMPUTE forward ops before backward and DCE originals.

The model must have been annotated with annotate_ac_regions before
tracing so that nodes have custom["ac_region_id"] metadata.
"""
from torch._functorch._activation_checkpointing.remat_using_tags_for_fwd_loss_bwd_graph_pass import (

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

follow up in future diff, I also think it' better to have remat_using_tags_for_fwd_loss_bwd_graph_pass in titan, since no one it's using it in core, and it's applicable senario is niche.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do use it in torch.compile(fullgraph=True) today.

remat_using_tags_for_fwd_loss_bwd_graph,
)

apply_sac_pass(gm)
return remat_using_tags_for_fwd_loss_bwd_graph(gm)


# Apply activation checkpointing on joint graph before partitioner
def fsdp_reshard_after_fwd_pass(
gm: torch.fx.GraphModule,
Expand Down Expand Up @@ -604,7 +634,7 @@ def inductor_decomposition_pass(
f"Placeholder count mismatch: {len(orig_placeholders)} vs {len(decomp_placeholders)}"
)

for orig, decomp in zip(orig_placeholders, decomp_placeholders):
for orig, decomp in zip(orig_placeholders, decomp_placeholders, strict=True):
# Copy all metadata from original to decomposed
for key, value in orig.meta.items():
if key not in decomp.meta:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.

from types import SimpleNamespace

import torch
import torch.nn as nn

from torchtitan.components.loss import cross_entropy_loss
from torchtitan.config import ActivationCheckpointConfig
from torchtitan.distributed.utils import get_train_context
from torchtitan.experiments.graph_trainer.trainer import GraphTrainer
from torchtitan.trainer import Trainer


def build_minimal_trainer(
model: nn.Module,
model_config,
trainer_cls: type[Trainer],
*,
activation_checkpoint_mode: str = "none",
compile_enable_passes: bool = True,
compile_passes: list[str] | None = None,
compile_joint_passes: list[str] | None = None,
tokenizer=None,
) -> Trainer:
"""Build the minimal Trainer/GraphTrainer needed for single-GPU test steps."""
trainer = object.__new__(trainer_cls)
trainer.model_parts = [model]
trainer.loss_fn = cross_entropy_loss
trainer.parallel_dims = SimpleNamespace(pp_enabled=False, cp_enabled=False)
trainer.train_context = get_train_context(False)
trainer.model_config = model_config
trainer.device = torch.device("cuda")
trainer.tokenizer = tokenizer

if trainer_cls is GraphTrainer:
trainer.config = SimpleNamespace(
compile=SimpleNamespace(
mode="aot_fx_trace",
enable_passes=compile_enable_passes,
passes=[] if compile_passes is None else list(compile_passes),
joint_passes=[]
if compile_joint_passes is None
else list(compile_joint_passes),
precompile_artifact_dir="",
),
activation_checkpoint=ActivationCheckpointConfig(
mode=activation_checkpoint_mode
),
)
trainer._fwd_bwd_step_module = None
trainer._traced_step = None
else:
trainer.config = SimpleNamespace()

return trainer
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import tempfile
import unittest
from collections.abc import Callable
from types import SimpleNamespace

import torch
import torch.nn as nn
Expand All @@ -26,7 +25,6 @@

from torchtitan.components.loss import cross_entropy_loss
from torchtitan.components.tokenizer import HuggingFaceTokenizer
from torchtitan.distributed.utils import get_train_context
from torchtitan.experiments.graph_trainer.deepseek_v3 import (
model_registry as dsv3_model_registry,
)
Expand All @@ -37,6 +35,9 @@
model_registry as llama3_model_registry,
)
from torchtitan.experiments.graph_trainer.llama3.parallelize import annotate_llama
from torchtitan.experiments.graph_trainer.tests._trainer_test_utils import (
build_minimal_trainer,
)
from torchtitan.experiments.graph_trainer.trainer import GraphTrainer
from torchtitan.tools.utils import has_cuda_capability
from torchtitan.trainer import Trainer
Expand All @@ -58,43 +59,6 @@ def _set_deterministic(seed: int = SEED) -> None:
_TOKENIZER_PATH = "./tests/assets/tokenizer"


def _build_trainer(
model: nn.Module,
model_config,
trainer_cls: type,
*,
enable_passes: bool = True,
) -> Trainer:
"""Build a minimal Trainer/GraphTrainer for single-GPU non-distributed testing.

Uses object.__new__ to bypass __init__ because the full Trainer constructor
requires a distributed environment, job config, and checkpoint manager that
are unnecessary for single-GPU numerical verification. The attributes set
below are the minimal set required by forward_backward_step().
"""
trainer = object.__new__(trainer_cls)
trainer.model_parts = [model]
trainer.loss_fn = cross_entropy_loss
trainer.parallel_dims = SimpleNamespace(pp_enabled=False, cp_enabled=False)
trainer.train_context = get_train_context(False)
trainer.model_config = model_config
trainer.device = torch.device("cuda")
trainer.tokenizer = HuggingFaceTokenizer(tokenizer_path=_TOKENIZER_PATH)

if trainer_cls is GraphTrainer:
trainer.config = SimpleNamespace(
compile=SimpleNamespace(
mode="aot_fx_trace",
enable_passes=enable_passes,
precompile_artifact_dir="",
)
)
trainer._fwd_bwd_step_module = None
trainer._traced_step = None

return trainer


@unittest.skipIf(not torch.cuda.is_available(), "CUDA not available")
class BitwiseDeterministicBase(unittest.TestCase):
"""Base class for bitwise determinism tests.
Expand Down Expand Up @@ -133,8 +97,12 @@ def _run_steps(
# Annotate after deepcopy: annotate_fn wrappers capture bound methods
# that don't rebind correctly through copy.deepcopy.
self.annotate_model(model)
trainer = _build_trainer(
model, self.model_config, trainer_cls, enable_passes=enable_passes
trainer = build_minimal_trainer(
model,
self.model_config,
trainer_cls,
compile_enable_passes=enable_passes,
tokenizer=HuggingFaceTokenizer(tokenizer_path=_TOKENIZER_PATH),
)
global_valid_tokens = torch.tensor(
BATCH_SIZE * SEQ_LEN, dtype=torch.float, device="cuda"
Expand Down Expand Up @@ -436,11 +404,6 @@ def test_eager_self_deterministic(self):
"""8bb6e647c3edaa229cc65872086ccc5c4e1b7f1647bb01da4506ab777a64a0db""",
)

# TODO: OOMs during flex_attention compilation on A100 GPUs.
# Revisit when GraphTrainer addresses peak memory during compilation.
@unittest.skipUnless(
has_cuda_capability(9, 0), "OOMs during flex_attention compilation on A100"
)
def test_aot_fx_trace_vs_eager(self):
"""aot_fx_trace with passes and eager produce bitwise identical results."""
run_eager = self._run_steps(copy.deepcopy(self.model), Trainer)
Expand Down
Loading
Loading