Skip to content

Traingen parity

Shared training parity helpers for generator packages.

BatchStreamReport dataclass

Comparison report for two dataloader streams.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
51
52
53
54
55
56
57
@dataclass(frozen=True)
class BatchStreamReport:
    """Comparison report for two dataloader streams."""

    passed: bool
    checked_steps: int
    first_mismatch: str | None = None

OptimizerStepReport dataclass

Comparison report for parameters after an optimizer step.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
42
43
44
45
46
47
48
@dataclass(frozen=True)
class OptimizerStepReport:
    """Comparison report for parameters after an optimizer step."""

    passed: bool
    comparisons: tuple[TensorComparison, ...]
    missing: tuple[str, ...]

StepReport dataclass

Comparison report for two training-step traces.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
33
34
35
36
37
38
39
@dataclass(frozen=True)
class StepReport:
    """Comparison report for two training-step traces."""

    passed: bool
    comparisons: tuple[TensorComparison, ...]
    missing: tuple[str, ...]

TensorComparison dataclass

Result for one tensor comparison.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
22
23
24
25
26
27
28
29
30
@dataclass(frozen=True)
class TensorComparison:
    """Result for one tensor comparison."""

    name: str
    passed: bool
    max_abs_diff: float
    max_rel_diff: float
    message: str

TensorTolerance dataclass

Absolute and relative tolerances for tensor comparison.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
14
15
16
17
18
19
@dataclass(frozen=True)
class TensorTolerance:
    """Absolute and relative tolerances for tensor comparison."""

    atol: float = 0.0
    rtol: float = 0.0

DeterminismConfig dataclass

Determinism options used by parity harnesses.

Parameters:

Name Type Description Default
seed int

Seed used when strict deterministic mode is enabled.

42975
deterministic_algorithms bool

Whether to require deterministic torch kernels.

True
cudnn_benchmark bool

Value for torch.backends.cudnn.benchmark.

False
allow_tf32 bool

Whether TF32 matmul and cuDNN kernels are allowed.

False
cublas_workspace_config str | None

Optional CUBLAS workspace config. This must be present before CUDA kernels start for strict bitwise checks.

':4096:8'

Returns:

Type Description

Configuration dataclass.

Raises:

Type Description
RuntimeError

If deterministic algorithms are unavailable.

Examples:

>>> cfg = DeterminismConfig(seed=1)
>>> cfg.seed
1
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@dataclass(frozen=True)
class DeterminismConfig:
    """Determinism options used by parity harnesses.

    Args:
        seed: Seed used when strict deterministic mode is enabled.
        deterministic_algorithms: Whether to require deterministic torch kernels.
        cudnn_benchmark: Value for ``torch.backends.cudnn.benchmark``.
        allow_tf32: Whether TF32 matmul and cuDNN kernels are allowed.
        cublas_workspace_config: Optional CUBLAS workspace config. This must be
            present before CUDA kernels start for strict bitwise checks.

    Returns:
        Configuration dataclass.

    Raises:
        RuntimeError: If deterministic algorithms are unavailable.

    Examples:
        >>> cfg = DeterminismConfig(seed=1)
        >>> cfg.seed
        1
    """

    seed: int = 42975
    deterministic_algorithms: bool = True
    cudnn_benchmark: bool = False
    allow_tf32: bool = False
    cublas_workspace_config: str | None = ":4096:8"

RNGState dataclass

Captured Python, NumPy, torch CPU, and torch CUDA RNG state.

Source code in lib/traingen-parity/src/traingen_parity/determinism.py
48
49
50
51
52
53
54
55
@dataclass(frozen=True)
class RNGState:
    """Captured Python, NumPy, torch CPU, and torch CUDA RNG state."""

    python: PythonRandomState
    numpy: tuple[str, UInt32[np.ndarray, "state"], int, int, float]
    torch_cpu: Shaped[torch.Tensor, "..."]
    torch_cuda: tuple[Shaped[torch.Tensor, "..."], ...]

StepTrace dataclass

Named tensor trace from a training step.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
39
40
41
42
43
44
45
46
@dataclass(frozen=True)
class StepTrace:
    """Named tensor trace from a training step."""

    name: str
    tensors: dict[str, Shaped[torch.Tensor, "..."]]
    summaries: dict[str, TensorSummary]
    metadata: TraceMetadata

TensorSummary dataclass

Compact deterministic summary of a tensor.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
26
27
28
29
30
31
32
33
34
35
36
@dataclass(frozen=True)
class TensorSummary:
    """Compact deterministic summary of a tensor."""

    shape: tuple[int, ...]
    dtype: str
    device: str
    sha256: str
    min: float | None
    max: float | None
    mean: float | None

TrainingStepModule

Bases: Protocol

Protocol for objects that expose a Lightning-like training step.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
17
18
19
20
21
22
23
class TrainingStepModule(Protocol):
    """Protocol for objects that expose a Lightning-like training step."""

    def training_step(
        self, batch: dict[str, Shaped[torch.Tensor, "..."]], batch_idx: int
    ) -> Shaped[torch.Tensor, "..."]:
        """Run one training step."""

training_step

training_step(
    batch: dict[str, Shaped[Tensor, "..."]], batch_idx: int
) -> Shaped[torch.Tensor, "..."]

Run one training step.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
20
21
22
23
def training_step(
    self, batch: dict[str, Shaped[torch.Tensor, "..."]], batch_idx: int
) -> Shaped[torch.Tensor, "..."]:
    """Run one training step."""

compare_batch_stream

compare_batch_stream(
    reference_loader: Iterable[
        Mapping[str, Shaped[Tensor, "..."]]
    ],
    target_loader: Iterable[
        Mapping[str, Shaped[Tensor, "..."]]
    ],
    *,
    steps: int,
) -> BatchStreamReport

Compare two dataloader streams for exact tensor equality.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def compare_batch_stream(
    reference_loader: Iterable[Mapping[str, Shaped[torch.Tensor, "..."]]],
    target_loader: Iterable[Mapping[str, Shaped[torch.Tensor, "..."]]],
    *,
    steps: int,
) -> BatchStreamReport:
    """Compare two dataloader streams for exact tensor equality."""
    for step, (reference_batch, target_batch) in enumerate(
        zip(reference_loader, target_loader, strict=False)
    ):
        if step >= steps:
            break
        for key, reference_value in reference_batch.items():
            target_value = target_batch.get(key)
            if isinstance(reference_value, torch.Tensor) and isinstance(
                target_value, torch.Tensor
            ):
                if not torch.equal(reference_value, target_value):
                    return BatchStreamReport(False, step + 1, f"{step}:{key}")
    return BatchStreamReport(True, steps)

compare_optimizer_step

compare_optimizer_step(
    reference_state: Mapping[str, Shaped[Tensor, "..."]],
    target_state: Mapping[str, Shaped[Tensor, "..."]],
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> OptimizerStepReport

Compare two state dictionaries after an optimizer step.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
def compare_optimizer_step(
    reference_state: Mapping[str, Shaped[torch.Tensor, "..."]],
    target_state: Mapping[str, Shaped[torch.Tensor, "..."]],
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> OptimizerStepReport:
    """Compare two state dictionaries after an optimizer step."""
    tol_map = tolerances or {}
    missing = tuple(name for name in reference_state if name not in target_state)
    comparisons = tuple(
        compare_tensors(
            name, target_state[name], reference_state[name], tol_map.get(name)
        )
        for name in reference_state
        if name not in missing
    )
    return OptimizerStepReport(
        passed=not missing and all(item.passed for item in comparisons),
        comparisons=comparisons,
        missing=missing,
    )

compare_step_trace

compare_step_trace(
    reference: StepTrace,
    target: StepTrace,
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> StepReport

Compare two named step traces.

Parameters:

Name Type Description Default
reference StepTrace

Reference trace.

required
target StepTrace

Converted implementation trace.

required
tolerances Mapping[str, TensorTolerance] | None

Per-tensor tolerance map.

None

Returns:

Type Description
StepReport

Step comparison report.

Raises:

Type Description
RuntimeError

If tensor comparisons fail unexpectedly.

Examples:

>>> from traingen_parity.trace import build_step_trace
>>> a = build_step_trace("a", {"x": torch.ones(1)})
>>> compare_step_trace(a, a).passed
True
Source code in lib/traingen-parity/src/traingen_parity/compare.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def compare_step_trace(
    reference: StepTrace,
    target: StepTrace,
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> StepReport:
    """Compare two named step traces.

    Args:
        reference: Reference trace.
        target: Converted implementation trace.
        tolerances: Per-tensor tolerance map.

    Returns:
        Step comparison report.

    Raises:
        RuntimeError: If tensor comparisons fail unexpectedly.

    Examples:
        >>> from traingen_parity.trace import build_step_trace
        >>> a = build_step_trace("a", {"x": torch.ones(1)})
        >>> compare_step_trace(a, a).passed
        True
    """
    tol_map = tolerances or {}
    names = tuple(reference.tensors.keys())
    missing = tuple(name for name in names if name not in target.tensors)
    comparisons = tuple(
        compare_tensors(
            name,
            target.tensors[name],
            reference.tensors[name],
            tol_map.get(name),
        )
        for name in names
        if name not in missing
    )
    return StepReport(
        passed=not missing and all(item.passed for item in comparisons),
        comparisons=comparisons,
        missing=missing,
    )

compare_tensors

compare_tensors(
    name: str,
    actual: Shaped[Tensor, "..."],
    expected: Shaped[Tensor, "..."],
    tolerance: TensorTolerance | None = None,
) -> TensorComparison

Compare two tensors and return max-difference diagnostics.

Parameters:

Name Type Description Default
name str

Tensor name.

required
actual Shaped[Tensor, '...']

Actual tensor.

required
expected Shaped[Tensor, '...']

Expected tensor.

required
tolerance TensorTolerance | None

Absolute and relative tolerance. Defaults to exact equality.

None

Returns:

Type Description
TensorComparison

Tensor comparison report.

Raises:

Type Description
RuntimeError

If tensors cannot be broadcast for comparison.

Examples:

>>> compare_tensors("x", torch.ones(1), torch.ones(1)).passed
True
Source code in lib/traingen-parity/src/traingen_parity/compare.py
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def compare_tensors(
    name: str,
    actual: Shaped[torch.Tensor, "..."],
    expected: Shaped[torch.Tensor, "..."],
    tolerance: TensorTolerance | None = None,
) -> TensorComparison:
    """Compare two tensors and return max-difference diagnostics.

    Args:
        name: Tensor name.
        actual: Actual tensor.
        expected: Expected tensor.
        tolerance: Absolute and relative tolerance. Defaults to exact equality.

    Returns:
        Tensor comparison report.

    Raises:
        RuntimeError: If tensors cannot be broadcast for comparison.

    Examples:
        >>> compare_tensors("x", torch.ones(1), torch.ones(1)).passed
        True
    """
    tol = tolerance or TensorTolerance()
    if actual.shape != expected.shape:
        return TensorComparison(
            name, False, float("inf"), float("inf"), "shape mismatch"
        )
    actual_detached = actual.detach()
    expected_detached = expected.detach()
    diff = (actual_detached.float() - expected_detached.float()).abs()
    max_abs = float(diff.max().item()) if diff.numel() else 0.0
    denom = expected_detached.float().abs().clamp_min(torch.finfo(diff.dtype).eps)
    rel = diff / denom
    max_rel = float(rel.max().item()) if rel.numel() else 0.0
    if actual_detached.is_floating_point() or expected_detached.is_floating_point():
        passed = torch.allclose(actual, expected, atol=tol.atol, rtol=tol.rtol)
    else:
        passed = torch.equal(actual, expected)
    message = "ok" if passed else f"max_abs={max_abs:.6g}, max_rel={max_rel:.6g}"
    return TensorComparison(name, passed, max_abs, max_rel, message)

apply_determinism

apply_determinism(config: DeterminismConfig) -> None

Apply deterministic runtime settings.

Parameters:

Name Type Description Default
config DeterminismConfig

Determinism configuration.

required

Returns:

Type Description
None

None.

Raises:

Type Description
RuntimeError

If torch cannot enable deterministic algorithms.

Examples:

>>> apply_determinism(DeterminismConfig(deterministic_algorithms=False))
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def apply_determinism(config: DeterminismConfig) -> None:
    """Apply deterministic runtime settings.

    Args:
        config: Determinism configuration.

    Returns:
        None.

    Raises:
        RuntimeError: If torch cannot enable deterministic algorithms.

    Examples:
        >>> apply_determinism(DeterminismConfig(deterministic_algorithms=False))
    """
    if config.cublas_workspace_config is not None:
        os.environ.setdefault("CUBLAS_WORKSPACE_CONFIG", config.cublas_workspace_config)
    random.seed(config.seed)
    np.random.seed(config.seed)
    torch.manual_seed(config.seed)
    if torch.cuda.is_available():
        torch.cuda.manual_seed_all(config.seed)
    torch.backends.cuda.matmul.allow_tf32 = config.allow_tf32
    torch.backends.cudnn.allow_tf32 = config.allow_tf32
    torch.backends.cudnn.benchmark = config.cudnn_benchmark
    torch.use_deterministic_algorithms(config.deterministic_algorithms)

capture_rng_state

capture_rng_state() -> RNGState

Capture all RNG states needed for step-level parity.

Returns:

Type Description
RNGState

RNG state dataclass.

Raises:

Type Description
RuntimeError

If torch cannot read CUDA RNG state.

Examples:

>>> state = capture_rng_state()
>>> isinstance(state.torch_cpu, torch.Tensor)
True
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
def capture_rng_state() -> RNGState:
    """Capture all RNG states needed for step-level parity.

    Args:
        None.

    Returns:
        RNG state dataclass.

    Raises:
        RuntimeError: If torch cannot read CUDA RNG state.

    Examples:
        >>> state = capture_rng_state()
        >>> isinstance(state.torch_cpu, torch.Tensor)
        True
    """
    cuda_state = (
        tuple(torch.cuda.get_rng_state_all()) if torch.cuda.is_available() else ()
    )
    return RNGState(
        python=cast(PythonRandomState, random.getstate()),
        numpy=cast(
            tuple[str, UInt32[np.ndarray, "state"], int, int, float],
            np.random.get_state(),
        ),
        torch_cpu=torch.random.get_rng_state(),
        torch_cuda=cuda_state,
    )

restore_rng_state

restore_rng_state(state: RNGState) -> None

Restore a state captured with :func:capture_rng_state.

Parameters:

Name Type Description Default
state RNGState

Previously captured RNG state.

required

Returns:

Type Description
None

None.

Raises:

Type Description
RuntimeError

If CUDA state restoration fails.

Examples:

>>> state = capture_rng_state()
>>> restore_rng_state(state)
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def restore_rng_state(state: RNGState) -> None:
    """Restore a state captured with :func:`capture_rng_state`.

    Args:
        state: Previously captured RNG state.

    Returns:
        None.

    Raises:
        RuntimeError: If CUDA state restoration fails.

    Examples:
        >>> state = capture_rng_state()
        >>> restore_rng_state(state)
    """
    random.setstate(state.python)
    np.random.set_state(state.numpy)
    torch.random.set_rng_state(state.torch_cpu)
    if torch.cuda.is_available() and state.torch_cuda:
        torch.cuda.set_rng_state_all(list(state.torch_cuda))

build_step_trace

build_step_trace(
    name: str,
    tensors: dict[str, Shaped[Tensor, "..."]],
    *,
    metadata: TraceMetadata | None = None,
) -> StepTrace

Build a trace from named tensors.

Parameters:

Name Type Description Default
name str

Trace name.

required
tensors dict[str, Shaped[Tensor, '...']]

Named tensor values.

required
metadata TraceMetadata | None

Optional non-tensor metadata.

None

Returns:

Type Description
StepTrace

Step trace with summaries.

Raises:

Type Description
RuntimeError

If tensor summaries cannot be computed.

Examples:

>>> trace = build_step_trace("step", {"loss": torch.tensor(1.0)})
>>> "loss" in trace.summaries
True
Source code in lib/traingen-parity/src/traingen_parity/trace.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def build_step_trace(
    name: str,
    tensors: dict[str, Shaped[torch.Tensor, "..."]],
    *,
    metadata: TraceMetadata | None = None,
) -> StepTrace:
    """Build a trace from named tensors.

    Args:
        name: Trace name.
        tensors: Named tensor values.
        metadata: Optional non-tensor metadata.

    Returns:
        Step trace with summaries.

    Raises:
        RuntimeError: If tensor summaries cannot be computed.

    Examples:
        >>> trace = build_step_trace("step", {"loss": torch.tensor(1.0)})
        >>> "loss" in trace.summaries
        True
    """
    return StepTrace(
        name=name,
        tensors=tensors,
        summaries={key: summarize_tensor(value) for key, value in tensors.items()},
        metadata=metadata or {},
    )

scalar_trace_value

scalar_trace_value(value: Float[Tensor, '']) -> float

Return a Python scalar from a scalar tensor.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
182
183
184
def scalar_trace_value(value: Float[torch.Tensor, ""]) -> float:
    """Return a Python scalar from a scalar tensor."""
    return float(value.detach().cpu().item())

summarize_tensor

summarize_tensor(
    tensor: Shaped[Tensor, "..."],
) -> TensorSummary

Build a deterministic tensor summary.

Parameters:

Name Type Description Default
tensor Shaped[Tensor, '...']

Tensor to summarize.

required

Returns:

Type Description
TensorSummary

Tensor summary dataclass.

Raises:

Type Description
RuntimeError

If tensor statistics cannot be computed.

Examples:

>>> summarize_tensor(torch.ones(2)).mean
1.0
Source code in lib/traingen-parity/src/traingen_parity/trace.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def summarize_tensor(tensor: Shaped[torch.Tensor, "..."]) -> TensorSummary:
    """Build a deterministic tensor summary.

    Args:
        tensor: Tensor to summarize.

    Returns:
        Tensor summary dataclass.

    Raises:
        RuntimeError: If tensor statistics cannot be computed.

    Examples:
        >>> summarize_tensor(torch.ones(2)).mean
        1.0
    """
    detached = tensor.detach()
    stats = detached.float()
    if detached.numel() == 0:
        min_value = max_value = mean_value = None
    else:
        min_value = float(stats.min().item())
        max_value = float(stats.max().item())
        mean_value = float(stats.mean().item())
    return TensorSummary(
        shape=tuple(detached.shape),
        dtype=str(detached.dtype),
        device=str(detached.device),
        sha256=tensor_sha256(detached),
        min=min_value,
        max=max_value,
        mean=mean_value,
    )

tensor_sha256

tensor_sha256(tensor: Shaped[Tensor, '...']) -> str

Return a SHA-256 digest for tensor bytes on CPU.

Parameters:

Name Type Description Default
tensor Shaped[Tensor, '...']

Tensor to hash.

required

Returns:

Type Description
str

Hex digest of the contiguous CPU tensor bytes.

Raises:

Type Description
RuntimeError

If the tensor cannot be copied to CPU.

Examples:

>>> tensor_sha256(torch.tensor([1, 2])).startswith("0")
False
Source code in lib/traingen-parity/src/traingen_parity/trace.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def tensor_sha256(tensor: Shaped[torch.Tensor, "..."]) -> str:
    """Return a SHA-256 digest for tensor bytes on CPU.

    Args:
        tensor: Tensor to hash.

    Returns:
        Hex digest of the contiguous CPU tensor bytes.

    Raises:
        RuntimeError: If the tensor cannot be copied to CPU.

    Examples:
        >>> tensor_sha256(torch.tensor([1, 2])).startswith("0")
        False
    """
    array = tensor.detach().contiguous().cpu().numpy()
    return hashlib.sha256(array.tobytes()).hexdigest()

trace_training_step

trace_training_step(
    module: TrainingStepModule,
    batch: dict[str, Shaped[Tensor, "..."]],
    rng_state: RNGState | None,
    trace_points: tuple[str, ...],
) -> StepTrace

Run module.training_step and collect requested trace points.

Parameters:

Name Type Description Default
module TrainingStepModule

Object exposing training_step and optionally latest_step_trace.

required
batch dict[str, Shaped[Tensor, '...']]

Training batch.

required
rng_state RNGState | None

Optional RNG state restored before the step.

required
trace_points tuple[str, ...]

Requested tensor names.

required

Returns:

Type Description
StepTrace

Step trace for requested tensor names.

Raises:

Type Description
AttributeError

If the module does not expose training_step.

Examples:

>>> class M:
...     def training_step(self, batch, batch_idx):
...         self.latest_step_trace = {"loss": torch.tensor(1.0)}
...         return torch.tensor(1.0)
>>> trace_training_step(M(), {}, None, ("loss",)).tensors["loss"].item()
1.0
Source code in lib/traingen-parity/src/traingen_parity/trace.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def trace_training_step(
    module: TrainingStepModule,
    batch: dict[str, Shaped[torch.Tensor, "..."]],
    rng_state: RNGState | None,
    trace_points: tuple[str, ...],
) -> StepTrace:
    """Run ``module.training_step`` and collect requested trace points.

    Args:
        module: Object exposing ``training_step`` and optionally
            ``latest_step_trace``.
        batch: Training batch.
        rng_state: Optional RNG state restored before the step.
        trace_points: Requested tensor names.

    Returns:
        Step trace for requested tensor names.

    Raises:
        AttributeError: If the module does not expose ``training_step``.

    Examples:
        >>> class M:
        ...     def training_step(self, batch, batch_idx):
        ...         self.latest_step_trace = {"loss": torch.tensor(1.0)}
        ...         return torch.tensor(1.0)
        >>> trace_training_step(M(), {}, None, ("loss",)).tensors["loss"].item()
        1.0
    """
    if rng_state is not None:
        restore_rng_state(rng_state)
    loss = module.training_step(batch, 0)
    raw = dict(getattr(module, "latest_step_trace", {}))
    raw.setdefault("train_loss", loss)
    tensors = {
        key: value
        for key, value in raw.items()
        if key in trace_points and isinstance(value, torch.Tensor)
    }
    return build_step_trace(
        getattr(module, "__class__", type(module)).__name__,
        tensors,
        metadata={"trace_points": trace_points},
    )

compare

Comparison reports for training parity traces.

TensorTolerance dataclass

Absolute and relative tolerances for tensor comparison.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
14
15
16
17
18
19
@dataclass(frozen=True)
class TensorTolerance:
    """Absolute and relative tolerances for tensor comparison."""

    atol: float = 0.0
    rtol: float = 0.0

TensorComparison dataclass

Result for one tensor comparison.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
22
23
24
25
26
27
28
29
30
@dataclass(frozen=True)
class TensorComparison:
    """Result for one tensor comparison."""

    name: str
    passed: bool
    max_abs_diff: float
    max_rel_diff: float
    message: str

StepReport dataclass

Comparison report for two training-step traces.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
33
34
35
36
37
38
39
@dataclass(frozen=True)
class StepReport:
    """Comparison report for two training-step traces."""

    passed: bool
    comparisons: tuple[TensorComparison, ...]
    missing: tuple[str, ...]

OptimizerStepReport dataclass

Comparison report for parameters after an optimizer step.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
42
43
44
45
46
47
48
@dataclass(frozen=True)
class OptimizerStepReport:
    """Comparison report for parameters after an optimizer step."""

    passed: bool
    comparisons: tuple[TensorComparison, ...]
    missing: tuple[str, ...]

BatchStreamReport dataclass

Comparison report for two dataloader streams.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
51
52
53
54
55
56
57
@dataclass(frozen=True)
class BatchStreamReport:
    """Comparison report for two dataloader streams."""

    passed: bool
    checked_steps: int
    first_mismatch: str | None = None

compare_tensors

compare_tensors(
    name: str,
    actual: Shaped[Tensor, "..."],
    expected: Shaped[Tensor, "..."],
    tolerance: TensorTolerance | None = None,
) -> TensorComparison

Compare two tensors and return max-difference diagnostics.

Parameters:

Name Type Description Default
name str

Tensor name.

required
actual Shaped[Tensor, '...']

Actual tensor.

required
expected Shaped[Tensor, '...']

Expected tensor.

required
tolerance TensorTolerance | None

Absolute and relative tolerance. Defaults to exact equality.

None

Returns:

Type Description
TensorComparison

Tensor comparison report.

Raises:

Type Description
RuntimeError

If tensors cannot be broadcast for comparison.

Examples:

>>> compare_tensors("x", torch.ones(1), torch.ones(1)).passed
True
Source code in lib/traingen-parity/src/traingen_parity/compare.py
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def compare_tensors(
    name: str,
    actual: Shaped[torch.Tensor, "..."],
    expected: Shaped[torch.Tensor, "..."],
    tolerance: TensorTolerance | None = None,
) -> TensorComparison:
    """Compare two tensors and return max-difference diagnostics.

    Args:
        name: Tensor name.
        actual: Actual tensor.
        expected: Expected tensor.
        tolerance: Absolute and relative tolerance. Defaults to exact equality.

    Returns:
        Tensor comparison report.

    Raises:
        RuntimeError: If tensors cannot be broadcast for comparison.

    Examples:
        >>> compare_tensors("x", torch.ones(1), torch.ones(1)).passed
        True
    """
    tol = tolerance or TensorTolerance()
    if actual.shape != expected.shape:
        return TensorComparison(
            name, False, float("inf"), float("inf"), "shape mismatch"
        )
    actual_detached = actual.detach()
    expected_detached = expected.detach()
    diff = (actual_detached.float() - expected_detached.float()).abs()
    max_abs = float(diff.max().item()) if diff.numel() else 0.0
    denom = expected_detached.float().abs().clamp_min(torch.finfo(diff.dtype).eps)
    rel = diff / denom
    max_rel = float(rel.max().item()) if rel.numel() else 0.0
    if actual_detached.is_floating_point() or expected_detached.is_floating_point():
        passed = torch.allclose(actual, expected, atol=tol.atol, rtol=tol.rtol)
    else:
        passed = torch.equal(actual, expected)
    message = "ok" if passed else f"max_abs={max_abs:.6g}, max_rel={max_rel:.6g}"
    return TensorComparison(name, passed, max_abs, max_rel, message)

compare_step_trace

compare_step_trace(
    reference: StepTrace,
    target: StepTrace,
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> StepReport

Compare two named step traces.

Parameters:

Name Type Description Default
reference StepTrace

Reference trace.

required
target StepTrace

Converted implementation trace.

required
tolerances Mapping[str, TensorTolerance] | None

Per-tensor tolerance map.

None

Returns:

Type Description
StepReport

Step comparison report.

Raises:

Type Description
RuntimeError

If tensor comparisons fail unexpectedly.

Examples:

>>> from traingen_parity.trace import build_step_trace
>>> a = build_step_trace("a", {"x": torch.ones(1)})
>>> compare_step_trace(a, a).passed
True
Source code in lib/traingen-parity/src/traingen_parity/compare.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
def compare_step_trace(
    reference: StepTrace,
    target: StepTrace,
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> StepReport:
    """Compare two named step traces.

    Args:
        reference: Reference trace.
        target: Converted implementation trace.
        tolerances: Per-tensor tolerance map.

    Returns:
        Step comparison report.

    Raises:
        RuntimeError: If tensor comparisons fail unexpectedly.

    Examples:
        >>> from traingen_parity.trace import build_step_trace
        >>> a = build_step_trace("a", {"x": torch.ones(1)})
        >>> compare_step_trace(a, a).passed
        True
    """
    tol_map = tolerances or {}
    names = tuple(reference.tensors.keys())
    missing = tuple(name for name in names if name not in target.tensors)
    comparisons = tuple(
        compare_tensors(
            name,
            target.tensors[name],
            reference.tensors[name],
            tol_map.get(name),
        )
        for name in names
        if name not in missing
    )
    return StepReport(
        passed=not missing and all(item.passed for item in comparisons),
        comparisons=comparisons,
        missing=missing,
    )

compare_optimizer_step

compare_optimizer_step(
    reference_state: Mapping[str, Shaped[Tensor, "..."]],
    target_state: Mapping[str, Shaped[Tensor, "..."]],
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> OptimizerStepReport

Compare two state dictionaries after an optimizer step.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
def compare_optimizer_step(
    reference_state: Mapping[str, Shaped[torch.Tensor, "..."]],
    target_state: Mapping[str, Shaped[torch.Tensor, "..."]],
    tolerances: Mapping[str, TensorTolerance] | None = None,
) -> OptimizerStepReport:
    """Compare two state dictionaries after an optimizer step."""
    tol_map = tolerances or {}
    missing = tuple(name for name in reference_state if name not in target_state)
    comparisons = tuple(
        compare_tensors(
            name, target_state[name], reference_state[name], tol_map.get(name)
        )
        for name in reference_state
        if name not in missing
    )
    return OptimizerStepReport(
        passed=not missing and all(item.passed for item in comparisons),
        comparisons=comparisons,
        missing=missing,
    )

compare_batch_stream

compare_batch_stream(
    reference_loader: Iterable[
        Mapping[str, Shaped[Tensor, "..."]]
    ],
    target_loader: Iterable[
        Mapping[str, Shaped[Tensor, "..."]]
    ],
    *,
    steps: int,
) -> BatchStreamReport

Compare two dataloader streams for exact tensor equality.

Source code in lib/traingen-parity/src/traingen_parity/compare.py
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
def compare_batch_stream(
    reference_loader: Iterable[Mapping[str, Shaped[torch.Tensor, "..."]]],
    target_loader: Iterable[Mapping[str, Shaped[torch.Tensor, "..."]]],
    *,
    steps: int,
) -> BatchStreamReport:
    """Compare two dataloader streams for exact tensor equality."""
    for step, (reference_batch, target_batch) in enumerate(
        zip(reference_loader, target_loader, strict=False)
    ):
        if step >= steps:
            break
        for key, reference_value in reference_batch.items():
            target_value = target_batch.get(key)
            if isinstance(reference_value, torch.Tensor) and isinstance(
                target_value, torch.Tensor
            ):
                if not torch.equal(reference_value, target_value):
                    return BatchStreamReport(False, step + 1, f"{step}:{key}")
    return BatchStreamReport(True, steps)

determinism

Determinism controls and RNG snapshots for training parity.

DeterminismConfig dataclass

Determinism options used by parity harnesses.

Parameters:

Name Type Description Default
seed int

Seed used when strict deterministic mode is enabled.

42975
deterministic_algorithms bool

Whether to require deterministic torch kernels.

True
cudnn_benchmark bool

Value for torch.backends.cudnn.benchmark.

False
allow_tf32 bool

Whether TF32 matmul and cuDNN kernels are allowed.

False
cublas_workspace_config str | None

Optional CUBLAS workspace config. This must be present before CUDA kernels start for strict bitwise checks.

':4096:8'

Returns:

Type Description

Configuration dataclass.

Raises:

Type Description
RuntimeError

If deterministic algorithms are unavailable.

Examples:

>>> cfg = DeterminismConfig(seed=1)
>>> cfg.seed
1
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@dataclass(frozen=True)
class DeterminismConfig:
    """Determinism options used by parity harnesses.

    Args:
        seed: Seed used when strict deterministic mode is enabled.
        deterministic_algorithms: Whether to require deterministic torch kernels.
        cudnn_benchmark: Value for ``torch.backends.cudnn.benchmark``.
        allow_tf32: Whether TF32 matmul and cuDNN kernels are allowed.
        cublas_workspace_config: Optional CUBLAS workspace config. This must be
            present before CUDA kernels start for strict bitwise checks.

    Returns:
        Configuration dataclass.

    Raises:
        RuntimeError: If deterministic algorithms are unavailable.

    Examples:
        >>> cfg = DeterminismConfig(seed=1)
        >>> cfg.seed
        1
    """

    seed: int = 42975
    deterministic_algorithms: bool = True
    cudnn_benchmark: bool = False
    allow_tf32: bool = False
    cublas_workspace_config: str | None = ":4096:8"

RNGState dataclass

Captured Python, NumPy, torch CPU, and torch CUDA RNG state.

Source code in lib/traingen-parity/src/traingen_parity/determinism.py
48
49
50
51
52
53
54
55
@dataclass(frozen=True)
class RNGState:
    """Captured Python, NumPy, torch CPU, and torch CUDA RNG state."""

    python: PythonRandomState
    numpy: tuple[str, UInt32[np.ndarray, "state"], int, int, float]
    torch_cpu: Shaped[torch.Tensor, "..."]
    torch_cuda: tuple[Shaped[torch.Tensor, "..."], ...]

apply_determinism

apply_determinism(config: DeterminismConfig) -> None

Apply deterministic runtime settings.

Parameters:

Name Type Description Default
config DeterminismConfig

Determinism configuration.

required

Returns:

Type Description
None

None.

Raises:

Type Description
RuntimeError

If torch cannot enable deterministic algorithms.

Examples:

>>> apply_determinism(DeterminismConfig(deterministic_algorithms=False))
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
def apply_determinism(config: DeterminismConfig) -> None:
    """Apply deterministic runtime settings.

    Args:
        config: Determinism configuration.

    Returns:
        None.

    Raises:
        RuntimeError: If torch cannot enable deterministic algorithms.

    Examples:
        >>> apply_determinism(DeterminismConfig(deterministic_algorithms=False))
    """
    if config.cublas_workspace_config is not None:
        os.environ.setdefault("CUBLAS_WORKSPACE_CONFIG", config.cublas_workspace_config)
    random.seed(config.seed)
    np.random.seed(config.seed)
    torch.manual_seed(config.seed)
    if torch.cuda.is_available():
        torch.cuda.manual_seed_all(config.seed)
    torch.backends.cuda.matmul.allow_tf32 = config.allow_tf32
    torch.backends.cudnn.allow_tf32 = config.allow_tf32
    torch.backends.cudnn.benchmark = config.cudnn_benchmark
    torch.use_deterministic_algorithms(config.deterministic_algorithms)

capture_rng_state

capture_rng_state() -> RNGState

Capture all RNG states needed for step-level parity.

Returns:

Type Description
RNGState

RNG state dataclass.

Raises:

Type Description
RuntimeError

If torch cannot read CUDA RNG state.

Examples:

>>> state = capture_rng_state()
>>> isinstance(state.torch_cpu, torch.Tensor)
True
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
def capture_rng_state() -> RNGState:
    """Capture all RNG states needed for step-level parity.

    Args:
        None.

    Returns:
        RNG state dataclass.

    Raises:
        RuntimeError: If torch cannot read CUDA RNG state.

    Examples:
        >>> state = capture_rng_state()
        >>> isinstance(state.torch_cpu, torch.Tensor)
        True
    """
    cuda_state = (
        tuple(torch.cuda.get_rng_state_all()) if torch.cuda.is_available() else ()
    )
    return RNGState(
        python=cast(PythonRandomState, random.getstate()),
        numpy=cast(
            tuple[str, UInt32[np.ndarray, "state"], int, int, float],
            np.random.get_state(),
        ),
        torch_cpu=torch.random.get_rng_state(),
        torch_cuda=cuda_state,
    )

restore_rng_state

restore_rng_state(state: RNGState) -> None

Restore a state captured with :func:capture_rng_state.

Parameters:

Name Type Description Default
state RNGState

Previously captured RNG state.

required

Returns:

Type Description
None

None.

Raises:

Type Description
RuntimeError

If CUDA state restoration fails.

Examples:

>>> state = capture_rng_state()
>>> restore_rng_state(state)
Source code in lib/traingen-parity/src/traingen_parity/determinism.py
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
def restore_rng_state(state: RNGState) -> None:
    """Restore a state captured with :func:`capture_rng_state`.

    Args:
        state: Previously captured RNG state.

    Returns:
        None.

    Raises:
        RuntimeError: If CUDA state restoration fails.

    Examples:
        >>> state = capture_rng_state()
        >>> restore_rng_state(state)
    """
    random.setstate(state.python)
    np.random.set_state(state.numpy)
    torch.random.set_rng_state(state.torch_cpu)
    if torch.cuda.is_available() and state.torch_cuda:
        torch.cuda.set_rng_state_all(list(state.torch_cuda))

trace

Tensor summaries and step traces for training parity.

TrainingStepModule

Bases: Protocol

Protocol for objects that expose a Lightning-like training step.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
17
18
19
20
21
22
23
class TrainingStepModule(Protocol):
    """Protocol for objects that expose a Lightning-like training step."""

    def training_step(
        self, batch: dict[str, Shaped[torch.Tensor, "..."]], batch_idx: int
    ) -> Shaped[torch.Tensor, "..."]:
        """Run one training step."""

training_step

training_step(
    batch: dict[str, Shaped[Tensor, "..."]], batch_idx: int
) -> Shaped[torch.Tensor, "..."]

Run one training step.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
20
21
22
23
def training_step(
    self, batch: dict[str, Shaped[torch.Tensor, "..."]], batch_idx: int
) -> Shaped[torch.Tensor, "..."]:
    """Run one training step."""

TensorSummary dataclass

Compact deterministic summary of a tensor.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
26
27
28
29
30
31
32
33
34
35
36
@dataclass(frozen=True)
class TensorSummary:
    """Compact deterministic summary of a tensor."""

    shape: tuple[int, ...]
    dtype: str
    device: str
    sha256: str
    min: float | None
    max: float | None
    mean: float | None

StepTrace dataclass

Named tensor trace from a training step.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
39
40
41
42
43
44
45
46
@dataclass(frozen=True)
class StepTrace:
    """Named tensor trace from a training step."""

    name: str
    tensors: dict[str, Shaped[torch.Tensor, "..."]]
    summaries: dict[str, TensorSummary]
    metadata: TraceMetadata

tensor_sha256

tensor_sha256(tensor: Shaped[Tensor, '...']) -> str

Return a SHA-256 digest for tensor bytes on CPU.

Parameters:

Name Type Description Default
tensor Shaped[Tensor, '...']

Tensor to hash.

required

Returns:

Type Description
str

Hex digest of the contiguous CPU tensor bytes.

Raises:

Type Description
RuntimeError

If the tensor cannot be copied to CPU.

Examples:

>>> tensor_sha256(torch.tensor([1, 2])).startswith("0")
False
Source code in lib/traingen-parity/src/traingen_parity/trace.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
def tensor_sha256(tensor: Shaped[torch.Tensor, "..."]) -> str:
    """Return a SHA-256 digest for tensor bytes on CPU.

    Args:
        tensor: Tensor to hash.

    Returns:
        Hex digest of the contiguous CPU tensor bytes.

    Raises:
        RuntimeError: If the tensor cannot be copied to CPU.

    Examples:
        >>> tensor_sha256(torch.tensor([1, 2])).startswith("0")
        False
    """
    array = tensor.detach().contiguous().cpu().numpy()
    return hashlib.sha256(array.tobytes()).hexdigest()

summarize_tensor

summarize_tensor(
    tensor: Shaped[Tensor, "..."],
) -> TensorSummary

Build a deterministic tensor summary.

Parameters:

Name Type Description Default
tensor Shaped[Tensor, '...']

Tensor to summarize.

required

Returns:

Type Description
TensorSummary

Tensor summary dataclass.

Raises:

Type Description
RuntimeError

If tensor statistics cannot be computed.

Examples:

>>> summarize_tensor(torch.ones(2)).mean
1.0
Source code in lib/traingen-parity/src/traingen_parity/trace.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def summarize_tensor(tensor: Shaped[torch.Tensor, "..."]) -> TensorSummary:
    """Build a deterministic tensor summary.

    Args:
        tensor: Tensor to summarize.

    Returns:
        Tensor summary dataclass.

    Raises:
        RuntimeError: If tensor statistics cannot be computed.

    Examples:
        >>> summarize_tensor(torch.ones(2)).mean
        1.0
    """
    detached = tensor.detach()
    stats = detached.float()
    if detached.numel() == 0:
        min_value = max_value = mean_value = None
    else:
        min_value = float(stats.min().item())
        max_value = float(stats.max().item())
        mean_value = float(stats.mean().item())
    return TensorSummary(
        shape=tuple(detached.shape),
        dtype=str(detached.dtype),
        device=str(detached.device),
        sha256=tensor_sha256(detached),
        min=min_value,
        max=max_value,
        mean=mean_value,
    )

build_step_trace

build_step_trace(
    name: str,
    tensors: dict[str, Shaped[Tensor, "..."]],
    *,
    metadata: TraceMetadata | None = None,
) -> StepTrace

Build a trace from named tensors.

Parameters:

Name Type Description Default
name str

Trace name.

required
tensors dict[str, Shaped[Tensor, '...']]

Named tensor values.

required
metadata TraceMetadata | None

Optional non-tensor metadata.

None

Returns:

Type Description
StepTrace

Step trace with summaries.

Raises:

Type Description
RuntimeError

If tensor summaries cannot be computed.

Examples:

>>> trace = build_step_trace("step", {"loss": torch.tensor(1.0)})
>>> "loss" in trace.summaries
True
Source code in lib/traingen-parity/src/traingen_parity/trace.py
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
def build_step_trace(
    name: str,
    tensors: dict[str, Shaped[torch.Tensor, "..."]],
    *,
    metadata: TraceMetadata | None = None,
) -> StepTrace:
    """Build a trace from named tensors.

    Args:
        name: Trace name.
        tensors: Named tensor values.
        metadata: Optional non-tensor metadata.

    Returns:
        Step trace with summaries.

    Raises:
        RuntimeError: If tensor summaries cannot be computed.

    Examples:
        >>> trace = build_step_trace("step", {"loss": torch.tensor(1.0)})
        >>> "loss" in trace.summaries
        True
    """
    return StepTrace(
        name=name,
        tensors=tensors,
        summaries={key: summarize_tensor(value) for key, value in tensors.items()},
        metadata=metadata or {},
    )

trace_training_step

trace_training_step(
    module: TrainingStepModule,
    batch: dict[str, Shaped[Tensor, "..."]],
    rng_state: RNGState | None,
    trace_points: tuple[str, ...],
) -> StepTrace

Run module.training_step and collect requested trace points.

Parameters:

Name Type Description Default
module TrainingStepModule

Object exposing training_step and optionally latest_step_trace.

required
batch dict[str, Shaped[Tensor, '...']]

Training batch.

required
rng_state RNGState | None

Optional RNG state restored before the step.

required
trace_points tuple[str, ...]

Requested tensor names.

required

Returns:

Type Description
StepTrace

Step trace for requested tensor names.

Raises:

Type Description
AttributeError

If the module does not expose training_step.

Examples:

>>> class M:
...     def training_step(self, batch, batch_idx):
...         self.latest_step_trace = {"loss": torch.tensor(1.0)}
...         return torch.tensor(1.0)
>>> trace_training_step(M(), {}, None, ("loss",)).tensors["loss"].item()
1.0
Source code in lib/traingen-parity/src/traingen_parity/trace.py
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def trace_training_step(
    module: TrainingStepModule,
    batch: dict[str, Shaped[torch.Tensor, "..."]],
    rng_state: RNGState | None,
    trace_points: tuple[str, ...],
) -> StepTrace:
    """Run ``module.training_step`` and collect requested trace points.

    Args:
        module: Object exposing ``training_step`` and optionally
            ``latest_step_trace``.
        batch: Training batch.
        rng_state: Optional RNG state restored before the step.
        trace_points: Requested tensor names.

    Returns:
        Step trace for requested tensor names.

    Raises:
        AttributeError: If the module does not expose ``training_step``.

    Examples:
        >>> class M:
        ...     def training_step(self, batch, batch_idx):
        ...         self.latest_step_trace = {"loss": torch.tensor(1.0)}
        ...         return torch.tensor(1.0)
        >>> trace_training_step(M(), {}, None, ("loss",)).tensors["loss"].item()
        1.0
    """
    if rng_state is not None:
        restore_rng_state(rng_state)
    loss = module.training_step(batch, 0)
    raw = dict(getattr(module, "latest_step_trace", {}))
    raw.setdefault("train_loss", loss)
    tensors = {
        key: value
        for key, value in raw.items()
        if key in trace_points and isinstance(value, torch.Tensor)
    }
    return build_step_trace(
        getattr(module, "__class__", type(module)).__name__,
        tensors,
        metadata={"trace_points": trace_points},
    )

scalar_trace_value

scalar_trace_value(value: Float[Tensor, '']) -> float

Return a Python scalar from a scalar tensor.

Source code in lib/traingen-parity/src/traingen_parity/trace.py
182
183
184
def scalar_trace_value(value: Float[torch.Tensor, ""]) -> float:
    """Return a Python scalar from a scalar tensor."""
    return float(value.detach().cpu().item())