feat: add inference_speed benchmark with throughput score#148
Conversation
9420481 to
4ec5c8d
Compare
Adds a new `inference_speed` benchmark (leaving `scaling` untouched) that measures MD throughput and how it scales with system size, and turns it into a score. - Reuses the `scaling` dataset via a new `dataset_name` hook on the base Benchmark, so no duplicate data is shipped. - Produces a Hill-function speed score 1 / (1 + (t / t0)^k) on the per-atom step time, averaged over systems; faster models score higher. The score is wall-clock based and only comparable across models run on the same GPU. It contributes to the overall model score. - New GUI page: throughput (ns/day) with log-log axes, power-law fit lines, per-episode variance error bars, and a per-model summary table. - Records per-episode times and the MD timestep on the result. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> # Conflicts: # CHANGELOG.md # docs/source/api_reference/index.rst # docs/source/benchmarks/general/index.rst # src/mlipaudit/benchmark.py
inference_speed now reports two complementary speeds per system: - Model throughput (atoms/s): the raw forward pass, engine-independent. For mlip models this times the pure network forward on a pre-built graph (mirroring mlip-jax scripts/time_inference.py); for external ASE calculators it forces a recompute on the pre-built atoms (includes their neighbour-list build). Uses warm-up, block-until-ready/numpy-read sync, and slowest-20% outlier trimming. - MD throughput (ns/day): the existing end-to-end short MD run. The speed score now uses the per-atom model forward time (engine-independent) rather than the MD step time. The GUI gains a metric selector across both families and a graph-cutoff column in the summary table. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
b0ace79 to
fe38174
Compare
|
Claude finished @lwalew's task in 3m 59s —— View job Review:
|
The rebase onto develop dropped this PR's benchmark.py change (develop had independently added dataset reuse as `data_name` + the `data_dir` property), so inference_speed still referenced the now-undefined `self._dataset_name`, raising AttributeError in run_model/analyze. - Use the base-class mechanism: `data_name = "scaling"` and `self.data_dir`. - Also pass `structures` on the empty-run early return (Pydantic requires it). - Restore the CHANGELOG entry lost in the rebase. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
…peed Each structure now records model forward throughput plus MD throughput on every backend the model can natively run: mlip models on both JAX-MD and ASE (the latter via MLIPForceFieldASECalculator), external models on ASE only. ASE is the shared backend, giving an apples-to-apples MD comparison across JAX and external models, while the JAX-MD-vs-ASE gap isolates backend overhead. - Result schema: per-structure `md: dict[backend, MDBackendResult]` replacing the single MD field; model output carries per-structure `md_episode_times` keyed by backend. Score still uses the engine-independent model forward time. - GUI metric selector gains ASE and JAX-MD variants; summary keeps the graph-cutoff column. Decided against torch->JAX conversion (e.g. tojax) for external models: it targets correctness/portability over native performance and breaks on the dynamic shapes / views that MLIP message passing needs, so timings would not reflect real speed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
The MD timing assumed a JAX-MD-style episode structure (mean episode time divided by num_steps//num_episodes). That is wrong for the ASE engine, which has no episodes: it calls loggers every log_interval steps and its first logged chunk includes compilation. So ASE step times (and thus the ns/day of every external model, and the ASE backend for mlip models) were miscalculated. Time instead against the cumulative `state.step` reported at each logger call: each chunk's step time is its wall-time delta over its step-count delta, and the compilation chunk is dropped (opening interval when the first sample is at step 0 for ASE; JAX-MD's first call already lands after the compile episode). Correct for both backends without assuming a chunk size; results store per-chunk step-time samples directly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude finished @lwalew's task in 1m 39s —— View job Re-review:
|
Adds a new
inference_speedbenchmark. The existingscalingbenchmark is left completely untouched (verified: no diff vsdevelop).What it does
Measures MD throughput and how it scales with system size, and turns it into a score.
scalingdataset via a newdataset_namehook on the baseBenchmark— no duplicate data shipped.1 / (1 + (t/t₀)ᵏ)on the per-atom step time (size-normalised), averaged over systems → faster models score higher. Contributes to the overall model score (scalingstill does not).Caveats
t₀(SCORE_PER_ATOM_STEP_TIME_MIDPOINTininference_speed.py) is a documented placeholder calibrated for H100 — needs tuning against a real run so scores spread sensibly.Tests added for the new benchmark +
compute_speed_score; full suite (132) + ruff + mypy green.🤖 Generated with Claude Code