NextStatNextStat

Надёжный харнесс для HEP‑бенчмарков HistFactory (pyhf и ROOT)

Сначала проверяем численную согласованность (|ΔNLL|), затем измеряем время: детерминизм, явные настройки модели, воспроизводимые входы и проверяемые JSON‑артефакты.

HistFactorypyhfROOTБенчмаркиКорректность

2026-02-08 · 10 мин. чтения


Бенчмарки легко сделать неправильно даже без злого умысла. В ФВЭ (HEP) самый опасный режим отказа устроен просто:

Можно «выиграть», если бенчмаркать не тот статистический вывод.

Если две реализации расходятся в модели правдоподобия (коды интерполяции, ограничения, маскирование, параметризация), сравнение времени становится бессмысленным, потому что вы измеряете разные вычисления.

Этот пост объясняет, как мы строим HEP-бенчмарк-харнесс, который трактует производительность как научное утверждение: сначала гейты корректности, затем явные протоколы, закрепленные окружения и артефакты, которые другие команды могут перезапустить.


Аннотация. Мы бенчмаркаем end-to-end задачи вывода HistFactory (NLL, градиенты, фиты, сканы, тои) с использованием pyhf как основной эталонной реализации и, выборочно, ROOT/RooFit/RooStats там, где рабочий процесс можно автоматизировать воспроизводимо. Числа скорости публикуются только после прохождения гейтов корректности, а каждый прогон производит проверяемые артефакты.

1.Модель угроз: как HEP-бенчмарки вводят в заблуждение

Цель харнесса не в том, чтобы произвести впечатляющие числа. Его задача предотвратить типовые режимы отказа.

1.1 Несовпадение модели (не то же правдоподобие)

Две реализации могут расходиться «тихо», если не закрепить соглашения модели:

  • коды интерполяции (code4 vs альтернативы)
  • ограничения и приоры
  • соглашения о маскировании при nᵢ = 0 или νᵢ → 0
  • имена/порядок параметров (особенно побиновые модификаторы)
  • односторонние vs двусторонние соглашения для тестовых статистик

Если модель не идентична, сравнения времени не значат ничего.

1.2 Несовпадение оптимизатора («быстрее», потому что остановился раньше)

Для фитов и сканов можно казаться быстрее, если использовать более слабые допуски, упираться в границы и объявлять сходимость или возвращать субоптимальную точку, которая «выглядит нормально» в таблице. Поэтому харнесс рассматривает метаданные сходимости и кросс-оценку как первоклассные выходы, а не как логи.

1.3 Несовпадение warm-start (особенно для профильных сканов)

Бенчмарк профильного скана это во многом бенчмарк политики теплого старта: холодный старт каждой μ-точки от фиксированной инициализации против warm-start от соседней точки (стандартный рабочий процесс аналитика). Если политика не опубликована, это не бенчмарк.

1.4 Дрейф окружения («у меня на машине быстро»)

Бенчмарки меняются при изменении версии компилятора/тулчейна, BLAS/GPU стека, Python-зависимостей, модели CPU/GPU и поведения троттлинга. Поэтому каждый публикуемый прогон захватывает манифест окружения и хеши наборов данных.

1.5 Смещение в отчетности (театр одной цифры)

Одна цифра скрывает дисперсию и выбор измерений. Заслуживающий доверия прогон публикует сырые тайминги по повторам, явную политику агрегации и конкретные входы и настройки.


2.Что мы бенчмаркаем (workflow-first)

Мы бенчмаркаем сквозные (end-to-end) HEP-рабочие процессы, которые доминируют по wall-time:

  • оценку NLL в фиксированной точке параметров (базовый строительный блок)
  • градиенты (необходимо для оптимизаторов и методов типа HMC/NUTS)
  • MLE-фиты (свободные и условные)
  • сканы профильного правдоподобия (политика warm-start должна быть явной)
  • ансамбли тоев (toys/sec, масштабирование с числом параметров)

3.Гейты корректности: fail fast до измерения времени

Каждый запуск набора (suite run) должен включать проверку корректности до вывода таймингов. Например, текущий харнесс pyhf vs NextStat (в репозитории):

  • загружает pyhf workspace
  • строит модель pyhf с явными настройками интерполяции (code4, code4p)
  • маппит параметры по имени, а не по индексу
  • считает NLL в обеих реализациях
  • падает сразу, если NLL расходятся сильнее допуска

Только после этого выводятся показатели производительности.

Seed‑контракт для HEP suite зафиксирован в benchmarks/nextstat-public-benchmarks/suites/hep/run.py: пороги NLL_SANITY_ATOL = 1e-8 и NLL_SANITY_RTOL = 1e-12, а кейс считается корректным, еслиabs_diff ≤ atol или rel_diff ≤ rtol(то есть падение — только когда оба порога нарушены одновременно).

Конкретный гейт (сегодня): для каждого кейса требуем abs(NLL_nextstat − NLL_pyhf) ≤ 1e-8 или rel_diff ≤ 1e-12 до записи таймингов.

Почему это важно:

  • это предотвращает регрессии «быстро, потому что неверно»
  • это превращает расхождение в багрепорт с контекстом, а не в спор

4.Маппинг параметров и закрепленные соглашения модели

4.1 Маппинг параметров по имени

Разные реализации могут упорядочивать параметры по-разному (особенно побиновые модификаторы вроде ShapeSys gammas). Поэтому харнесс маппит вектора параметров по имени параметра, а не по индексу, прежде чем сравнивать NLL или измерять время фитов.

4.2 Явные коды интерполяции

У HistFactory несколько соглашений по интерполяции. Бенчмарки обязаны закреплять коды интерполяции NormSys и HistoSys, иначе вы бенчмаркаете не одну и ту же статистическую модель.


5.Профильные сканы: cold-start vs warm-start это и есть бенчмарк

Профильные сканы это классическое место, где наивные бенчмарки врут. Две реализации могут быть корректными, но измерять разные воркфлоу, если одна делает cold-start каждой точки, а другая warm-start от соседней. Поэтому харнесс должен публиковать POI-grid, политику warm-start, границы и допуски, а также соглашения о клиппинге (односторонние qμ/q₀).


6.Сравнения ROOT/RooFit: что мы будем (и не будем) утверждать

ROOT важен как независимая точка сравнения, но в публичных seed‑бенчмарках мы разделяем две вещи:валидацию корректности (может требовать тяжёлого окружения) ипубликуемые утверждения о скорости (должны быть воспроизводимыми для внешних команд).

Поэтому для ROOT‑сравнений мы публично утверждаем только то, что можно воспроизвести и диагностировать:

  • Публиковать режимы отказов и частоты fit-status, а не только средние
  • Публиковать кросс-проверки (вычислять NLL реализации A при параметрах из B)
  • Сохранять «сошлось ли?» как первоклассную метрику

Строгая валидация профсканов ROOT/HistFactory vs NextStat живёт в основном репозитории:tests/validate_root_profile_scan.py. Она:

  • экспортирует pyhf‑workspace в HistFactory XML + ROOT‑гистограммы (через pyhf.writexml)
  • строит RooWorkspace через hist2workspace
  • делает free‑fit и фиксированный POI‑скан в ROOT и тот же POI‑скан в NextStat
  • сравнивает q(μ), μ̂ и значения NLL, чтобы поймать расхождения модели/оптимизации

В seed‑репозитории публичных бенчмарков ROOT‑часть сейчас оформлена как шаблон (benchmarks/nextstat-public-benchmarks/suites/hep/baselines/root/run.py) и пока не является источником «скоростных» цифр: она проверяет доступность PyROOT/версии, чтобы внешние команды могли честно зафиксировать, что ROOT‑окружение присутствует.

У нас также есть отдельный строгий разбор численной согласованности: «Численная корректность». Бенчмарки и численная корректность это две стороны одной задачи доверия.


7.От прогона харнесса к публичному снимку

Результаты производительности должны включать:

  • сырые измерения по повторам (чтобы была видна дисперсия)
  • политику агрегации (median, min-of-N и т.д.)
  • манифест окружения (тулчейны, зависимости, железо)
  • отчеты корректности, которые использовались как гейты

Это разница между скриншотом и артефактом. См. также: «Бенчмарк-снимки как продукты».

7.1 Артефакты и схемы (что именно пишет HEP suite)

В минимальном seed-харнессе (standalone публичные бенчмарки) мы фиксируем результат как машиночитаемые JSON-артефакты с версиями схем. Это важно, потому что без формата сравнение превращается в «прочитай лог и поверь».

  • Пер-кейс артефакт: nextstat.benchmark_result.v1(NLL паритет + тайминги + сырые повторы; опционально — fit-метаданные).
  • Suite индекс: nextstat.benchmark_suite_result.v1(список кейсов с путями+SHA‑256 и суммарный worst-case по |ΔNLL|).

Каноничные JSON Schema для этих артефактов — часть seed‑контракта:benchmarks/nextstat-public-benchmarks/manifests/schema/benchmark_result_v1.schema.json и benchmarks/nextstat-public-benchmarks/manifests/schema/benchmark_suite_result_v1.schema.json. HEP suite пишет per‑case JSON в out_dir/cases/*.json и индексout_dir/hep_suite.json.

Когда результаты публикуются как snapshot, к ним добавляются базовые документы публикационного слоя:baseline_manifest.json (схема nextstat.baseline_manifest.v1) и snapshot_index.json (схема nextstat.snapshot_index.v1).


8.Как перезапустить (сегодня)

Сквозная sanity‑проверка и тайминг для pyhf vs NextStat (включает гейт корректности) в основном репозитории NextStat:

bash
PYTHONPATH=bindings/ns-py/python ./.venv/bin/python \
  tests/benchmark_pyhf_vs_nextstat.py --fit

Минимальный воспроизводимый seed‑харнесс (single case, пишет один JSON‑артефактnextstat.benchmark_result.v1):

bash
python3 benchmarks/nextstat-public-benchmarks/suites/hep/run.py \
  --case simple_workspace_nll \
  --workspace benchmarks/nextstat-public-benchmarks/suites/hep/datasets/simple_workspace.json \
  --measurement-name GaussExample \
  --deterministic \
  --fit \
  --out tmp/hep_simple_case.json

Полный suite прогон (пишет hep_suite.json + per-case JSONs):

bash
python3 benchmarks/nextstat-public-benchmarks/suites/hep/suite.py \
  --out-dir tmp/hep \
  --deterministic \
  --fit

Короткая сводка по suite (таблица worst-case + speedups):

bash
python3 benchmarks/nextstat-public-benchmarks/suites/hep/report.py \
  --suite tmp/hep/hep_suite.json \
  --format markdown

Валидация ROOT профильного скана (нужны ROOT и hist2workspace):

bash
PYTHONPATH=bindings/ns-py/python ./.venv/bin/python tests/validate_root_profile_scan.py \
  --pyhf-json tests/fixtures/simple_workspace.json \
  --measurement GaussExample \
  --start 0.0 --stop 5.0 --points 51

9.Закрытие: «перезапусти меня», а не «поверь мне»

Наш эндстейт это не «у нас хорошие числа». Наш эндстейт это:

  • вы можете перезапустить харнесс на своей машине
  • увидеть те же гейты корректности
  • и сравнить результаты с полным контекстом

Так производительность становится свидетельством.


Связанное чтение