Motivation
We want lower wall-clock time per epoch at unchanged mAP. compile=True exists as an opt-in (config.py:502) and is documented as being "for faster throughput" (config.py:467), but there is no benchmark in the repo establishing what it actually buys, on which hardware, or for which configs. That number is unknown, and it should not be.
This issue is scoped to measuring and understanding, not to landing a fix. Any change to defaults or the compile path should follow from numbers produced here.
Hard constraint throughout: no accuracy regression. Any candidate change gets validated on mAP, not just ms/step. A throughput win that moves the metric is not a win.
What we don't know
Open questions, in no particular order. Answering any one of them is useful on its own.
Baseline
- What is the steady-state ms/step for eager vs
compile=True, per model size, on common GPUs (A100, L4, 4090, T4)? With warm-up excluded and validation excluded?
- Does compilation succeed at all under each config we ship?
torch._dynamo.explain(model)(samples) gives graph_count / graph_break_count / break_reasons without needing a full run.
- How much wall time does the first-step compile cost, and at what epoch count does it pay back?
Where the time actually goes
- What fraction of a training step is the model forward/backward, versus the criterion + matcher, the dataloader, GPU-side augmentation, and logging? A
torch.profiler trace with schedule(wait=20, warmup=5, active=10) answers this directly.
- How often is the GPU idle waiting on input?
num_workers defaults to 2 (config.py:1094) — is that the binding constraint on typical hardware before anything else matters?
- Where are the host syncs, and how much do they cost? Candidates to look at in a trace:
matcher.py:726, _assignment.py:83.
Compile configuration
- How do
dynamic=True (current, module_model.py:440), dynamic=None, and dynamic=False compare on identical workloads?
- What do
mode="reduce-overhead" and mode="max-autotune-no-cudagraphs" do here? Does reduce-overhead work at all under Lightning, or does it need cudagraph_mark_step_begin() per step?
- What are the
torch._dynamo.config settings at module_model.py:436-437 doing in practice? suppress_errors=True in particular means a failed compile is indistinguishable from a working one at the log level — worth checking what happens with it off.
- Results likely differ across torch versions;
pyproject.toml allows >=2.2.0, and dynamic-shape handling and inductor coverage moved a lot over that range. Which versions were tested?
Shapes and the gate
- Under which configs do input shapes actually vary per batch? The gate at
module_model.py:416 keys on multi_scale, while the scale selection also depends on do_random_resize_via_padding (coco.py:1189) — worth tracing what shapes reach the model under each combination, empirically, rather than reasoning about it.
- If shapes do vary, how many distinct ones per epoch, and how many recompiles does that trigger? (
TORCH_LOGS="recompiles", and torch._dynamo.config.cache_size_limit defaults to 8.)
- What is the pos-embed interpolation path (
dinov2_with_windowed_attn.py:369-401) doing per step under each config, and does it interact with compilation?
Beyond compile — same motivation, different levers, all open:
- What does
augmentation_backend="gpu" cost or save, and on which hardware profile?
- Would compiling the dense loss math separately from the matcher help, or not be worth the complexity?
- Multi-GPU: how does
DDPOptimizer's graph splitting change any of the above?
- Anything else a profile turns up. If the trace says the bottleneck is somewhere nobody here guessed, that's the most useful outcome.
How to contribute
Pick any question. Partial answers are welcome — a single profiler trace on one GPU and one model is a real contribution.
When posting results, please include:
- torch version, GPU, driver
- model size,
batch_size, num_workers, precision, DDP or single-GPU
- the exact config flags that differ from defaults
- how steps were timed (warm-up excluded? validation excluded? how many steps?)
- for any candidate speedup: mAP on the same eval set, before and after
Raw traces and explain() output are more useful than summaries — post them if you can.
Out of scope here
Landing changes to defaults or to the compile path. Those follow once we know what the numbers say; if this investigation surfaces something concrete, it gets its own PR with the measurement attached.
Motivation
We want lower wall-clock time per epoch at unchanged mAP.
compile=Trueexists as an opt-in (config.py:502) and is documented as being "for faster throughput" (config.py:467), but there is no benchmark in the repo establishing what it actually buys, on which hardware, or for which configs. That number is unknown, and it should not be.This issue is scoped to measuring and understanding, not to landing a fix. Any change to defaults or the compile path should follow from numbers produced here.
Hard constraint throughout: no accuracy regression. Any candidate change gets validated on mAP, not just ms/step. A throughput win that moves the metric is not a win.
What we don't know
Open questions, in no particular order. Answering any one of them is useful on its own.
Baseline
compile=True, per model size, on common GPUs (A100, L4, 4090, T4)? With warm-up excluded and validation excluded?torch._dynamo.explain(model)(samples)givesgraph_count/graph_break_count/break_reasonswithout needing a full run.Where the time actually goes
torch.profilertrace withschedule(wait=20, warmup=5, active=10)answers this directly.num_workersdefaults to2(config.py:1094) — is that the binding constraint on typical hardware before anything else matters?matcher.py:726,_assignment.py:83.Compile configuration
dynamic=True(current,module_model.py:440),dynamic=None, anddynamic=Falsecompare on identical workloads?mode="reduce-overhead"andmode="max-autotune-no-cudagraphs"do here? Doesreduce-overheadwork at all under Lightning, or does it needcudagraph_mark_step_begin()per step?torch._dynamo.configsettings atmodule_model.py:436-437doing in practice?suppress_errors=Truein particular means a failed compile is indistinguishable from a working one at the log level — worth checking what happens with it off.pyproject.tomlallows>=2.2.0, and dynamic-shape handling and inductor coverage moved a lot over that range. Which versions were tested?Shapes and the gate
module_model.py:416keys onmulti_scale, while the scale selection also depends ondo_random_resize_via_padding(coco.py:1189) — worth tracing what shapes reach the model under each combination, empirically, rather than reasoning about it.TORCH_LOGS="recompiles", andtorch._dynamo.config.cache_size_limitdefaults to 8.)dinov2_with_windowed_attn.py:369-401) doing per step under each config, and does it interact with compilation?Beyond compile — same motivation, different levers, all open:
augmentation_backend="gpu"cost or save, and on which hardware profile?DDPOptimizer's graph splitting change any of the above?How to contribute
Pick any question. Partial answers are welcome — a single profiler trace on one GPU and one model is a real contribution.
When posting results, please include:
batch_size,num_workers, precision, DDP or single-GPURaw traces and
explain()output are more useful than summaries — post them if you can.Out of scope here
Landing changes to defaults or to the compile path. Those follow once we know what the numbers say; if this investigation surfaces something concrete, it gets its own PR with the measurement attached.