Repository navigation
Conversation
Port of miles@ba28991834 miles/utils/flops_utils.py (vendored as oracle). Vendored miles flops_utils.py as the ground-truth oracle plus an 8-config verifier (dense/GQA/MoE/MLA/GDN/KDA/DSA-indexer/mamba2/compressed-attention) that fails on relative error >= 1e-6. Auto-skips until the vime implementation lands in F10-1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port of miles@ba28991834 miles/utils/flops_utils.py. Adds vime/utils/flops_model.py: the miles analytical FLOPs model (dense/GQA/MLA/MoE/GDN/KDA/DSA+QSA indexers/compressed attention/mamba2) plus a model_flops_from_args adapter that loads the HF config from args.hf_checkpoint and degrades to None on failure. Passes the V5 oracle verifier (72 checks, 8 configs, rel err < 1e-6). MTP layers stay excluded, matching miles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port of miles@ba28991834 miles/utils/device_flops.py and the MFU block of miles/backends/training_utils/metrics/perf.py. Adds vime/utils/device_flops.py (peak BF16 TFLOPS table incl. AMD MI300X/MI325X/MI355X with source URLs, detection via vime.utils.accelerator), logs perf/actor_train_mfu + perf/mfu_peak_tflops + perf/actor_train_tflops_hf in log_perf_data from the new HF-config FLOPs model, and adds the --mfu-peak-tflops override flag. The slime-origin perf/actor_train_tflops path is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port of miles@ba28991834 tests/ci/metric_history/storage/{store,sqlite_store}.py.
Adds the MetricHistoryStore contract (runs + metric_values, trusted run flag,
baseline query on (test_path, backend, suite, metric_key, step)) and its
SQLite backend under tests/ci/metric_history/, with CI-neutral provenance
columns (ci_run_id/ci_run_attempt/pipeline replacing github_*/event_name).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port of miles@ba28991834 tests/ci/metric_history/{selection,constraints,gate}.py.
selection.py and constraints.py are verbatim; gate.py drops the miles
CIRegistry dependency -- gate identity (test_path/backend) is passed
explicitly and register_ci_gate spec parsing is a lazy import (lands in
F10-5). Gate semantics unchanged: cold start INACTIVE, band constraints
against the mean of up to 20 trusted baselines, TRACKED for constraint-less
specs, ERROR on unselectable metrics.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port of miles@ba28991834 tests/ci/metric_history/register.py. AST-parsed register_ci_gate marker with literal-only keyword validation, GATE_DEFAULTS for the 8 whitelisted metrics (kept verbatim, incl. the two tito keys reserved for the C1 port), and byte-stable canonical JSON provenance keys. zip(strict=True) relaxed to plain zip for 3.9 compat (vacuous: AST dict keys/values are always equal length). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port of miles@ba28991834 miles/utils/tracking_utils/ci_history.py and the gate-hook semantics of miles tests/ci/ci_utils.py. Adds vime/observability/ci_metric_history.py (whitelist JSONL capture hooked into logging_utils.log, gated on VIME_CI_GATE_RECORD_DIR), the run_gate.py CLI (merge, evaluate, MIN_ENFORCED_BASELINES=10 enforcement, --write-baseline, --mark-untrusted-sha, Buildkite env provenance), the --metric-history-path flag with VIME_METRIC_HISTORY_PATH fallback, and verify_gate_e2e.py (V1): 12 seeded baselines, 2nd-run history read, steady PASS, tampered value FAIL, tampered threshold FAIL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the V5 FLOPs oracle verifier, the metric_history pytest suite, and the V1 gate e2e verifier to the plugin-contracts CPU step of .buildkite/pipeline.yml; updates .buildkite/README.md command count; documents the GPU opt-in path (record dir + artifact-uploaded SQLite store, no hostPath assumption). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request ports the MFU metric and metric-history regression gate tooling from the miles repository to vime, including the analytical FLOPs model, SQLite-backed metric-history store, and Buildkite CI integration. Feedback on these changes highlights three key improvements: moving the transformers import inside the exception handler in train_metric_utils.py to prevent training crashes, coercing step counters to standard Python integers in ci_metric_history.py to support numpy and PyTorch types, and automatically creating the parent directory for the SQLite database in sqlite_store.py to avoid operational errors.
| def _mfu_model_flops(hf_checkpoint: str): | ||
| """HF-config FLOPs model for MFU accounting, cached per checkpoint; None when unsizable.""" | ||
| from transformers import AutoConfig | ||
|
|
||
| try: | ||
| hf_config = AutoConfig.from_pretrained(hf_checkpoint, trust_remote_code=True) |
There was a problem hiding this comment.
The from transformers import AutoConfig import is placed outside the try...except block. If transformers is not installed in the environment, this will raise an ImportError and crash the training process, violating the goal of the exception handler (accounting must never break training). Additionally, if hf_checkpoint is empty or not set, calling AutoConfig.from_pretrained will fail and log a noisy warning. Checking for an empty hf_checkpoint and moving the import inside the try block resolves both issues.
def _mfu_model_flops(hf_checkpoint: str):
\"\"\"HF-config FLOPs model for MFU accounting, cached per checkpoint; None when unsizable.\"\"\"
if not hf_checkpoint:
return None
try:
from transformers import AutoConfig
hf_config = AutoConfig.from_pretrained(hf_checkpoint, trust_remote_code=True)| step = metrics.get(step_key) | ||
| recorder.log(metrics, step if isinstance(step, int) and not isinstance(step, bool) else None) |
There was a problem hiding this comment.
The check isinstance(step, int) will evaluate to False if step is a numpy integer (e.g., numpy.int64) or a PyTorch 0-dimensional tensor, which are very common types for step counters in training loops. This causes the step to be recorded as None (and serialized as null in JSONL), which subsequently triggers a SelectionError in the CI gate when evaluating steps: \"all\". Coercing the step to a standard Python integer using int() with a fallback to None ensures robust step capture.
| step = metrics.get(step_key) | |
| recorder.log(metrics, step if isinstance(step, int) and not isinstance(step, bool) else None) | |
| step = metrics.get(step_key) | |
| if step is not None and not isinstance(step, bool): | |
| try: | |
| step = int(step) | |
| except (TypeError, ValueError, RuntimeError): | |
| step = None | |
| else: | |
| step = None | |
| recorder.log(metrics, step) |
| def __init__(self, database: str = ":memory:"): | ||
| # check_same_thread is left at its default; the store is meant for the | ||
| # single-threaded CI gate process and the test suite. | ||
| self._conn = sqlite3.connect(database) |
There was a problem hiding this comment.
If the parent directory of the SQLite database file does not exist, sqlite3.connect will raise a sqlite3.OperationalError: unable to open database file and crash the CI gate. Automatically creating the parent directory if it does not exist makes the store initialization much more robust when custom paths are configured.
def __init__(self, database: str = \":memory:\"):
# check_same_thread is left at its default; the store is meant for the
# single-threaded CI gate process and the test suite.
if database != \":memory:\":
import os
parent = os.path.dirname(database)
if parent:
os.makedirs(parent, exist_ok=True)
self._conn = sqlite3.connect(database)
Ports miles' FLOPs model / MFU metric and the metric-history CI gate (SQLite store + declarative
register_ci_gate).Source:
radixark/miles@ba28991834. Port is additive (new modules + newadd_*_arguments()groups); slime-origin files are not restructured so future[Sync] Mirror SlimePRs stay clean. One commit per sub-PR; review each commit separately.Commits:
Verification:
tests/ci/flops_oracle/(V5) checks the FLOPs model against a hand-computed oracle;tests/ci/metric_history/(V1) runs the gate end to end on a synthetic history. GPU suite baseline persistence still needs one real Buildkite run.Merge order of the miles-port series: F10 → F02 → F06 → F11a → F11b → F05 → F09 → F04 → F03 → F07 → F08 → F01.
train.py/vime/utils/arguments.pyare touched by several branches; later ones are rebased after each merge.🤖 Generated with Claude Code