Repository navigation
Releases: slavabars/decision-cascade
Releases · slavabars/decision-cascade
Release list
v0.7.0
Added
- Калибровка
P(ошибка)в замерах (Шаг 1): ECE и Brier score считаются на вероятности ошибки1 − scoreпротив факта1 − correct— вrisk_report/calibration_report(eval/risk/features.py) и вranker_report(eval/risk/core.py, значит и вmetrics.json/risk.json). Метрики выводятся в отчётахprint_report,print_loo_calibrationиprint_shots_reportи попадают во все агрегатыfeatures.json(per_seed,loo,shots) как mean ± std по seed'ам. - Калибровка в hard gate — только там, где она разрешима: ECE/Brier входят в гейт пула (
GATE_AB_METRICS,GATE_RANKER_METRICS) со своими допусками (GATE_TOL_ECE = 0.02,GATE_TOL_BRIER = 0.01≈1σ измеренного seed-разброса; AURC-допуск остался жёстким 0.0005). В по-вопросный гейт (GATE_LOO_METRICS, новыйGATE_SHOTS_METRICS) калибровка не входит: измеренный шум разницы на одном вопросе (σ 0.019–0.026) сравним с эффектом, и постоянный допуск отвергал бы на шуме — вернём через bootstrap-CI в Шаге 3. Метрика гейта — теперьGateMetric(ключ, меньше_лучше, допуск);tolвgate_risk_vs_confidenceпо умолчанию берётся по метрике и может быть переопределён числом. - Кривая few-shot по нескольким порядкам примеров (Шаг 2): флаг
--shot-seeds;shots_reportотдаёт точки по каждому порядку, аaverage_shot_seedsусредняет их перед гейтом и агрегацией (удачный порядок не должен выглядеть улучшением). Разброс по порядкам хранится рядом (<метрика>_shot_std), печатаетсяprint_shots_stabilityи попадает вfeatures.jsonвместе сshot_seeds,shots_per_questionиshots_per_shot_seed. - Оценка разброса: bootstrap-CI и стабильность по seeds (Шаг 3). Точечные числа не отвечают на вопрос «реальна ли разница», поэтому добавлены:
bootstrap_mean_ci(перцентильный CI среднего),bootstrap_ranker_ci(перевыборка тестовых строк с повторнымranker_report; интервалы уезжают вranking_ciиgate.ciсертификатаrisk.json),paired_differences(разницаcandidate − baselineпо парам «seed × вопрос», знак нормирован так, что «+» всюду = «кандидат хуже») иstability_report(CI, доля замеров с худшим результатом, признак значимости). Worst-case по вопросам даётworst_case_by_question, печать —print_stability, всё складывается вfeatures.json → stability(in_dist,loo,loo_worst_auc,shots,shots_worst_auc). - Синтетические сценарии S1–S6 (
eval/risk/simulate.py, Шаг 4): управляемые данные, где причины разделены по построению — латентная сложностьz, сдвиг и наклон вопроса, зашумлённые признаки, аn_classes— атрибут вопроса. Сценарии: S1 коллизия классов, S2 разныеn_classes, S3 дрейф связи (noul_logitперевёрнут на новом вопросе), S4 кривая few-shot при коллизии, S5 отчёт по калибровке, S6 худший случай (вопрос вне диапазона обучения). Метрики те же, что в замерной части (_fit_logistic,risk_report), вывод — в консоль иsummary.json. - Hard gate «принимать только лучшее решение» (
eval/risk/core.py,gate_risk_vs_confidence): вариант принимается, только если он не хуже baselineconfidenceпо AURC, eAURC, coverage@5% risk и acc@0.7 (допуск 0.0005 поедает только шум). Считается вeval/risk/run.pyи вeval/risk/features.py— по in-dist, по LOO (новый вопрос) и по кривой few-shot (точка против baseline при том же числе примеров); вердикты печатаются в отчёт и пишутся вfeatures.json/metrics.json→gate. - Сертификат гейта в
risk.json(ErrorRiskModel.gate) и продакшен-фолбэк: приaccepted: falseRiskAwareCascadeBackendбезусловно переходит на порог уверенности (DECISION_CASCADE_THRESHOLD), причина эскалации вusageстановитсяrisk_gate, в лог пишется предупреждение,/info → engine.risk_gateпоказываетrejected. Без сертификата режим работает как прежде. - Замеры гейта (доля проходов
productionпротивconfidence): in-dist — 2/3 (RouterBench/hash, 3 seeds), 1/1 (RouterBench/gpt2), 1/1 (AG News/gpt2); LOO 0-shot — 5/9, 0/3 и 3/3 соответственно. Кривая few-shot: на gpt2escalateпроходит сn ≥ 5,routeиbenefitне проходят ни при какомn(включая «все»); на hash — 4–5 из 9 при любомn; на AG News — 3/3 приn = 0и 2/3 дальше (добавление своих примеров переобучаетbusiness). - Вариант
confidenceв кривой--shots: однопризнаковая baseline-модель в той же точке кривой — с ней и сравнивается гейт. - Флаг
--stateвeval/risk/features.pyи вариантыstate[C]/prod+state[C]: замер, несёт ли замороженное состояние энкодера (пулированный вектор промпта) сигнал об ошибке сверх шести признаковDecisionResult. Сила L2 у вариантов с состоянием своя (--state-C), потому что 768 измерений на 400 строках валидации переобучаются. - Базовая линия
randomвeval/risk/features.py— случайный балл («без навыка»), его AURC ≈ базовая частота ошибок; отделяет «модель не работает» от «модель хуже случайной». - Флаг
--shotsвeval/risk/features.py: кривая дообучения на новом вопросе — модель обучается на валидации остальных вопросов плюсnслучайных строк валидации отложенного вопроса, тест — его тест. Точки вложены (n=0= LOO,shots=None= in-dist). Позволяет оценить, сколько размеченных примеров нового вопроса нужно, чтобы снять потерю переноса. - Флаги
--qmean/--qmean-Cи--ablateвeval/risk/features.py(Шаг 5):--qmeanдобавляет варианты со средним пулированным вектором вопроса (qmean[C],prod+qmean[C]),--ablate— drop-one вариантыproduction(no_n_classes/no_log_odds_gap/no_noul_logit). Вfeatures.jsonпишутся ключиqmean_csиablated. - Флаг
--C-gridвeval/risk/features.py(Шаг 5а): вариантыproduction[C]делят сproductionту же матрицу признаков, отличаясь только силой L2. Сетка поC— один прогон вместо прогона на значение (кодирование и обучение голов общие). Ключc_gridвfeatures.json. - Правила перехода risk-aware в stable (Шаг 6):
src.risk.gate_verdictиErrorRiskModel.gate_verdictпересчитывают вердикт гейта с допускомdeltaпо-метричным превышениямgate.excess(пишетсяeval.risk.run, считаетeval.risk.core.gate_excess); конфигDECISION_RISK_GATE_DELTA(> 0ослабляет гейт,< 0ужесточает) иDECISION_RISK_FEW_SHOT_N. - Few-shot переобучение риск-модели под новый вопрос (Шаг 6): numpy-решатель
src.risk.fit_logistic(Ньютон/IRLS с L2, без sklearn — соглашение оCкак уLogisticRegression) иErrorRiskModel.retrained_with(схема {общие строки + своиn}). ВRiskAwareCascadeBackendпорогfew_shot_nиadd_examples: набравDECISION_RISK_FEW_SHOT_N(дефолтRISK_FEW_SHOT_MIN_N = 10) размеченных примеров вопроса, каскад переобучает модель и применяет её только к этому вопросу. КонстантаRISK_FEW_SHOT_MIN_N;/infoотдаётrisk_few_shot_n/risk_few_shot/risk_gate_delta. - Раздел «Правила перехода в stable» в
docs/risk-aware-cascade.md— формализует условия beta→stable (включение, hard gate и его допуск, zero-shot, few-shot, возврат). Транспорт размеченных примеров в сервисе пока не подключён: это программный шов, не продуктовый API.
Changed
- Дефолт силы L2 риск-модели —
C=0.2вместо1.0(Шаг 5а). Причина — перерегуляризация: приC=1.0productionпереобучает межвопросные константы и на hash значимо проигрываетconfidenceна новом вопросе (+0.0079 * по LOO). СеткаC(замерный харнессeval.risk.features, новый флаг--C-grid) монотонно улучшает LOO доC≈0.2(−0.0072 * [−0.0155,−0.0011]) при неизменном in-dist, и разрыв сconfidenceисчезает (+0.0007 ns); подтверждено на RouterBench/gpt2 (−0.0062 * по LOO, in-dist ns), нейтрально на AG News, разброс по seeds не растёт. Единый источник —RISK_C_DEFAULTвsrc/risk.py, его используют и продукт (training.recipe.risk), и замер (eval.risk.features). Разбор — вdocs/risk-aware-cascade.md(«Находка: провал hash — это перерегуляризация, а не признак»). - По-вопросная калибровка не стала критерием гейта (отрицательный результат): в первом замере (один seed) на
escalate/benefitвиделись провалы ECE (0.326 против 0.277 и 0.141 против 0.095), но на нескольких seeds и порядках примеров они не воспроизводятся (escalateдаёт +0.007 ± 0.030). Поэтому вердикты LOO/кривой считаются по SLO-метрикам (AURC/eAURC/coverage/acc), а калибровка — по пулу. Bootstrap-CI Шага 3 подтвердил это и уточнил: по ECE на новом вопросе интервал накрывает ноль на всех трёх наборах, а в пуле знак ECE зависит от энкодера (hash −0.031 значимо лучше, gpt2 +0.015 и +0.006 значимо хуже), тогда как Brier значимо лучше везде. Замер-обоснование — вdocs/risk-aware-cascade.md. - Кривая
--shotsсчитает и baselineconfidenceв каждой точке, поэтомуSHOT_COLUMNS/агрегат группируются по(variant, shots)— иначе точки разных вариантов смешивались бы в одну строку. eval/risk/features.pyсчитаетproductionи варианты с состоянием при одном и том жеC(--C), а для вариантов с состоянием берёт--state-C; это убирает сравнение, в котором выигрыш давала не новая информация, а более сильная регуляризация.
Fixed
- RLCD-обучение не училось (вырожденный градиент): награда считалась по вероятности политики (
−|p − o|), а не по взятому действию-сэмплу, поэтомуE_s[∇ log π(s)] = 0— ожидаемый градиент был строго нулевым, и «обучение» шло только конечновыборочным шумом (улучшение примерно на половине seeds; на одном seed это выглядело как успех, а на CI с другой версией torch тест падал). Теперь награда — за сэмпл (−|s − o|) с GRPO-нормализацией (group_advantages, ранее не использовалась). Замер на 20 seeds: MAE0.50 → 0.04, улучшение20/20(было6/20); регрессионный тест проверяет сходимость сразу на нескольких seeds. Продуктовый путь (calibrate_noul_heads) и раньше был защищён гейтом «не навреди».
Измерено и не подключено
- Сигнал из замороженного состояния энкодера: на новый в...
v0.6.0
Added
- Голова выбора option-scoring (
DECISION_CHOICE_HEAD=option_scoring): вариант оценивается общим билинейным скорером по текстовому эмбеддингу, поэтому число параметров не зависит от числа вариантов, а набор вариантов можно подменить на инференсе без переобучения. Замер переноса —eval/option_transfer/run.py, честные числа —docs/option-scoring.md(перенос работает на близких вариантах, но не на произвольных новых словах). Режим по умолчанию —linear; старые чекпоинты читаются без изменений. - Флаги
--choice-head(eval/report/run.py,training/recipe/train_heads.py) и--loo(eval/risk/features.py). - LOO-замер переноса риск-модели: leave-one-question-out проверка показала, что выигрыш шести признаков — подстройка под известные вопросы, а не новый сигнал о конкретном решении; разбор и оговорка —
docs/risk-aware-cascade.md.
Changed
- Оценщик риска
P(ошибка)(src/risk.py) получил три признака к прежним трём:log_odds_gap(ln(p1/p2)двух лучших исходов),n_classes(число исходов) иnoul_logit(знаковый логитnoul). На RouterBench при--train-steps 500это даёт AURC 0.2633 против 0.3116 у прежней модели на gpt2 (+5.8 п.п. принятой точности при 50% эскалации) и 0.2547 против 0.2625 на hash; на AG News 0.0357 против 0.0509. Метрика считается по всем вопросам сразу, а проверка--looпоказала, что выигрыш — межвопросное упорядочивание: внутри вопроса и на новом вопросеconfidenceне хуже. Модели, обученные на трёх прежних признаках, загружаются и работают в прежней семантике. ErrorRiskModel.from_dictопределяет имена признаков по числу весов, если в файле нетfeature_names: трёхвесовыйrisk.jsonбез списка признаков больше не падает при загрузке, а читается как модель прежнего формата.- Замер состава признаков вынесен в
eval/risk/features.py; вариантproductionв нём побитово совпадает сrisk_modelизeval.risk.run.
Полный список — в CHANGELOG.md.
0.4.0
0.4.0 — 2026-10-14
Added
- Self-hosted «живой» конкурент (
eval/competitors/serve.py): локальная causal-LM подPOST /v1/systemone, отвечает по правдоподобию вариантов (sequence log-likelihood); реальные числа — вdocs/competitor-benchmark.md. - CI-регрессия конвейера бенчмарка (
tests/test_competitors_regression.py) и офлайн-тесты сервиса на крошечной локальной модели.
Changed
- Vision-энкодер
ClipVisionEncoderгрузит бэкбон черезAutoModel/AutoImageProcessor— поддерживает SigLIP (google/siglip-*), не только CLIP. - Бренд унифицирован на decision-cascade;
SystemOneостаётся названием внешнего протокола совместимости.
Полный список изменений — в CHANGELOG.md.
v0.3.0
Кодовый релиз: публичный бенчмарк RouterBench и гигиена релиза.
Что нового
RouterBench (публичный decision-датасет)
- Адаптер
eval/datasets/routerbench.py— пин ревизии Hugging Face, вопросы
escalate/route/benefit. - Интеграция в отчёт untrained-vs-trained (
eval/report) и в сравнение с
конкурентами (eval/competitors); свип--sweep«качество/доля эскалаций». - Честные числа в
docs/routerbench.md: замороженный gpt2 даёт overall
0.356 → 0.593, ноescalate≈ базовая частота класса — узкое место в
замороженных признаках, а не в головах.
Гигиена релиза
- Лицензия Apache-2.0 (
LICENSE,NOTICE). - Упаковка:
pyproject.toml, дистрибутивdecision-cascade, единый источник
версииsrc.__version__ = 0.3.0. - CI (
.github/workflows/ci.yml): ruff + shellcheck + pytest + валидация упаковки. CHANGELOG.md,SECURITY.md.- README: позиционирование уточнено до честной beta.
Установка
# из ассетов ниже
uv pip install decision_cascade-0.3.0-py3-none-any.whl
# или из исходников
uv pip install -e .Прогон сервера и примеры — см. README.md и examples/README.md.
Веса голов по-прежнему публикуются отдельным релизом v0.2.0-weights.tar.gz.
Полный список изменений: CHANGELOG.md ([0.3.0]).
v0.2.0 weights
Trained decision-head packs (v0.2.0). Распакуйте архив и укажите DECISION_CHECKPOINT_DIR на нужный пак.
v0.1.0 weights
Trained decision-head packs (v0.1.0). Распакуйте архив и укажите DECISION_CHECKPOINT_DIR на нужный пак.