CONCEPTS

Tracing

Tracing

Tutorial: TracingSee also: API: language

Motivation

Writing config files as explicit L.call trees is safe and composable, but it means maintaining two parallel representations: the training code and the config. Tracing lets you write the training code directly and derive the config from it automatically.

@L.configurable

Mark a function or class as traceable:

@L.configurable
def build_model(in_features: int, out_features: int) -> nn.Module:
    return nn.Linear(in_features, out_features)

Outside a trace, build_model(784, 10) behaves normally: it builds and returns an nn.Module.

Inside a trace, the call is recorded rather than executed. The function body does not run; instead a L.call(build_model)(in_features=784, out_features=10) node is produced.

L.trace

cfg = L.trace(lambda: build_model(in_features=784, out_features=10))
# cfg is a DictConfig, not an nn.Module

L.trace(thunk) activates the _TRACING ContextVar for the duration of the thunk, then deactivates it via try/finally (so exceptions don't leave tracing active). The return value is the root DictConfig of the recorded call graph.

Argument Tiers

Arguments passed to a @L.configurable function inside a trace are classified:

TierTypeBehavior
1DictConfigSpliced in as a sub-node
2Primitive (int, float, str, bool, None)Kept as-is
3OtherTypeError: non-serializable argument inside trace

Positional → Named Binding

Positional arguments are converted to named arguments using inspect.Signature:

@L.configurable
def build(in_features: int, out_features: int) -> nn.Module: ...

cfg = L.trace(lambda: build(784, 10))
# equivalent to: L.call(build)(in_features=784, out_features=10)

*args (VAR_POSITIONAL) raises TypeError inside a trace: variadic positionals cannot be represented in a keyed config node.

Strict Mode

cfg = L.trace(thunk, strict=True)

strict=True (default) raises TypeError if the root of the trace does not produce a DictConfig. Use strict=False to fall back to the executed value when the thunk's root call is not @L.configurable.

Purity Requirement

The thunk body should be pure (no side effects): it will run only once and its side effects will be skipped inside the trace. In particular, avoid logging, file I/O, or random number generation inside a thunk.

When to Use Tracing vs Explicit L.call

SituationRecommendation
Config file with fixed targetsL.call, explicit, zero overhead
Code-first workflow; config derived from existing functionsL.trace
Need typed groups or L.DefaultsL.call + L.Group
Wrapping a third-party function you can't decorateL.call with the function as target