Ниже единый план: твой разбор репозитория + roadmap коллеги. Главное изменение приоритетов: human-CV больше не гейт. Коллега проверил тремя сабмитами: LB ≈ LLM-прокси − 0.19, а human 0.74 не ранжирует кандидатов. Поэтому fold 4 / hard-soup / категорийные веса на human-OOF уходят вниз.
Цифры коллеги, от которых пляшем: LB 0.43059 (E5) → 0.43169 (soup+V2+категории). Их бленд твоего E5 с их CatBoost — 0.43456.
Правило отбора экспериментов
Каждый кандидат меряется так, в этом порядке:
- LLM-прокси (фиксированный сэмпл, не в обучении) — основное.
- Human disjoint folds — вторично, «не уехала ли модель с ручных меток».
- Сабмит на LB — только если прокси вырос и архив/время влезают.
Не принимать решение по human-OOF, если прокси не вырос. Коллега: прирост на прокси переносится в LB с коэффициентом ~0.4; калибровка LB ≈ прокси − 0.19.
Не делать (уже проверено у них): bi-encoder косинусы, AutoGluon, hard-mine по human-OOF, категорийные веса по human-CV, масштабирование таблички 2M→8M LLM.
Фаза 0. Заморозить якоря
Пока это не сделано — не двигать файлы и не переобучать.
-
Зафиксировать текущий боевой набор:
- E5 чекпоинт (
model.safetensors) - compact
*.joblib+ версия sklearn ensemble-candidate.json- SHA zip (
21767a7d…в README) — сверитьGet-FileHash
- E5 чекпоинт (
-
Снять два референса, не один:
# A. Human (регрессия runtime, не оценка качества)
python -u run_ensemble_candidate.py \
--items_path data/items_human.parquet \
--matches_path data/matches.parquet \
--output_path submit-reference.csv \
--model-path <E5_DIR> \
--tabular-path <COMPACT.joblib> \
--config-path ensemble-candidate.json
python -u verify_candidate_output.py \
--matches-path data/matches.parquet \
--prediction-path submit-reference.csv \
--items-path data/items_human.parquet
- Зафиксировать LLM-прокси (действие №1 коллеги). У тебя уже есть зачатки:
prepare_proxy_data.py,new_ideas/X_proxy.npy,new_ideas/proxy_meta.parquet. Канон:
- один неизменяемый сэмпл (~300k LLM-пар),
random_state=42 - бинаризация
target >= 0.5 - macro PR-AUC по категориям
- эти пары исключены из любого дальнейшего обучения
- скрипт оценки: взять/адаптировать их
scripts/eval_llm_proxy.py
Записать в таблицу три точки коллеги как sanity калибровки:
| Модель | Прокси | LB | Прокси − LB |
|---|---|---|---|
| (их слабая) | 0.502 | 0.3097 | 0.192 |
| твой E5 | 0.613 | 0.4306 | 0.182 |
| E5 + их CatBoost | 0.624 | 0.4346 | 0.189 |
Готово, когда: есть submit-reference.csv и одно число прокси для текущего zip. Дальше любой эксперимент пишет строку в эту таблицу.
Фаза 1. Один runtime (закрывает дыру у обоих разборов)
Коллега, §5: в боевом run.py сейчас чистый CE, ансамбль только в run_ensemble_candidate.py.
1.1. run.py = ансамбль
- Логику
run_ensemble_candidate.pyперенести вrun.py. - Алиасы на 3 строки:
from run import main. - Падать, если в конфиге нет
neural_weight(иначе снова уедет чистый CE).
Проверка: run.py даёт byte-identical submit-reference.csv.
1.2. Один ensemble.json
- Содержимое
ensemble-candidate.json→ensemble.json. - Старый файл удалить после смены ссылок.
1.3. Один упаковщик
- Канон:
make_ensemble_submission.py. make_submission.pyубрать или вexperiments/с пометкой DEAD (пакуетmodel.joblib+ GPUrun.py).make_gpu_submission.py— только E5-only fallback.
python make_ensemble_submission.py \
--model-dir <E5_DIR> \
--tabular-model <COMPACT.joblib> \
--config-path ensemble.json \
--run-path run.py \
--output-path submission.zip
1.4. README
Один блок Current submission. Human-CV и refit 0.785 — в Historical / sanity, не как оценка LB. Добавить строку «gate = LLM-прокси».
Готово, когда: по README собирается тот же zip, что на LB 0.43169.
Фаза 2. Перемерить всё, что уже лежит на диске (H100, без нового обучения)
Это пункт 1 недели коллеги: «до +0.01–0.02, если пик не в конце файнтюна». Делать до fold 4 и до нового претрейна.
На том же прокси прогнать:
- Чекпоинт этапа 1:
models/multilingual-e5-llm(до human-finetune). - Финальный human-finetune.
- Hard-soup 0.10 (текущий LB).
- Промежуточные
checkpoint-*этапа 2, если сохранились. - Супы этап1 × этап2:
tuned_weight ∈ {0.3, 0.5, 0.7, 1.0}через уже существующийmerge_transformer_weights.py.
python merge_transformer_weights.py \
--base-model models/multilingual-e5-llm \
--tuned-model <HUMAN_OR_SOUP> \
--tuned-weight 0.5 \
--output-dir models/soup-stage1-2-w05
Потом тот же eval_llm_proxy на каждый чекпоинт.
Решение:
- если этап 1 или ранний этап 2 выше на прокси, чем текущий soup — это новый runtime без обучения;
- human-метрика при этом может упасть — это ожидаемо (у них CatBoost: прокси 0.513 → 0.484 после human-finetune);
- в архив класть победителя по прокси, если влезает в 780 с.
Готово, когда: таблица чекпоинт → прокси. Выбран новый baseline. Human-fold 4 не блокирует этот выбор.
Фаза 3. Освободить бюджет инференса (разблокирует e5-base)
Коллега: из 469 с полного прогона 281 с — однопоточный V2, ~190 с — CE. Лимит ~780 с.
3.1. Распараллелить V2
В build_features_v2 (и при необходимости base build_features): чанки пар, multiprocessing, ~20 CPU. Ожидание: 281 с → 25–40 с, запас ~4 минуты.
Не менять численные значения фич (битовая идентичность на 1k пар).
3.2. Двойная буферизация CE
В predict_cross_encoder: токенизировать батч N+1, пока GPU считает N. Ожидание +20–30% к CE-стадии, без смены скоров.
3.3. Symmetric TTA — только после 3.1
Скоринг (A,B) и (B,A), усреднение. Для small это ещё ~190 с. Влезает только если V2 уже быстрый. Мерить на прокси, не на human.
3.4. max_length
Доля пар, обрезанных при 160. Если заметная — 192/224 на small (бюджет уже есть). На прокси.
Готово, когда: полный прогон в образе, V2 < 50 с, CE не медленнее, CSV совпадает с якорем (кроме TTA/max_len — те отдельные ветки).
Фаза 4. Баги фич, которые коллега и разбор оба указали
Делать вместе с 3.1, пока трогаешь features_v2.py. Меняет схему → ретрейн таблички.
batteryвMEASUREMENT_KINDS— сейчас mah/мач парсятся и выкидываются из per-kind match/conflict.- Числовой допуск ±5% (их
num_val_close):990 гvs1 кгу тебя conflict. Добавить в V2, не ломая нормализацию единиц. - Пустые атрибуты: оба пустые → similarity 1.0, как Jaccard (твой разбор).
- Категория пары только по
id1: на прокси померить альтернативу (id1, или id1 если равны иначеunknown). Менять runtime только если прокси вырос. - TF-IDF: один check fit-on-train vs transductive на прокси. В
run.pyоставить transductive.
Их 32 фичи (src/features.py) + твои слоты/измерения — отдельный дешёвый стек, не в этом же коммите.
После изменения схемы: новый кэш, новый joblib, новый прокси-скор. Старый compact несовместим — это ок.
Фаза 5. Переобучение под тестовое распределение (H100, ночи)
Только после Фазы 2 (знаешь, какой чекпоинт вообще лучший) и Фазы 3 (есть бюджет на base).
Все варианты мерять на прокси. Human — в лог, не в решение.
5.1. Мягкий этап 2, не 4 эпохи human
Подозрение коллеги: 4 эпохи, lr 1e-5, batch 1024 утащили E5 с LLM-теста.
Порядок:
- Если Фаза 2 уже нашла лучший ранний чекпоинт — стартовать от него.
- Смешанный этап 2: human + 0.5–1M LLM-пар (не из прокси-сэмпла), human с большим весом, 1–2 эпохи, не 4.
- Не делать hard-mine по human-OOF (у них перенос в LB ≈ 0).
5.2. Больше претрейна этапа 1
Сейчас 1 эпоха на 11.2M. На H100 эпоха ~1.5–2 ч (batch 2048, seq 160).
2–3 эпохи, cosine → 0. На мягких метках E5-small скорее недообучен.
5.3. e5-base / USER-base
После ускорения V2:
intfloat/multilingual-e5-basedeepvk/USER-base(русский, попробовать оба)
Тот же пайплайн: претрейн LLM → мягкий этап 2.
Инференс base ~3× small → ~570 с CE + 40 с V2 ≈ 650 с < 780 с.
Претрейн base: 4–6 ч/эпоха, ночь.
Large не трогать, пока не режешь max_len или не дистиллируешь.
Ожидание коллеги: +0.02–0.04 LB на base + быстрые фичи.
Фаза 6. Ансамбль на LLM-распределении
Текущая V2-таблица учится только на human и тянет бленд к human. Их факт: CatBoost на 2M LLM (CE по soft labels) + human вес 5 → прокси 0.51 vs 0.41 human-only. Твой E5 + их CatBoost, ранг-бленд 0.8/0.2 → +0.004 LB.
6.1. Переобучить табличку на LLM-миксе
Варианты, дешевле → дороже:
- Забрать их
artifacts/catboost_v5_llm8m.cbm+src/features.pyи смешать с твоим E5 (быстрый потолок 0.43456). - Обучить свой HGB/CatBoost на LLM-миксе (
scripts/train_gbdt_llm.pyу них) на твоих V2 (+ допуск ±5%, battery). - Стек: их 32 фичи ∪ твои слоты/измерения.
Не гнать 2M→8M: у них +0.003 прокси / +0.001 LB, насыщение.
6.2. Категорийные веса — только на прокси
Твой tune_category_blend.py оставить, данные сменить на прокси. Human cross-fit не использовать как accept-gate.
6.3. Второй CE
Когда будет base или USER-base: бленд small+base (+ LLM-табличка третьим). Веса по прокси, tune_three_blend.py уже есть. Два разных CE обычно дают больше, чем ещё одна табличка.
Готово, когда: прокси ансамбля > прокси лучшего одиночного CE, полный прогон < 780 с, zip < 4.7 GB.
Фаза 7. Инженерный долг (не блокирует H100)
Делать в паузах между ночными трейнами.
7.1. Дубли
macro_average_precisionтолько вvalidation.pyproduct_textтолько вsolution/transformer.py(+ тест vs DuckDB)- set-helpers в одном модуле
category_ranksтолько вtune_blend.py- канон проверки CSV:
verify_candidate_output.py
7.2. Тесты без GPU и без data/
- фолды: overlap == 0
- фичи: swap-invariance, длина схемы, battery, finite
- verify: NaN / чужой порядок падают
- zip: namelist + есть
neural_weight
Убрать хак experiments_next из test_features_v2.py.
7.3. Гигиена train_cross_encoder.py
worker_init_fnдля swap (коллега и разбор: глобальный numpy RNG коррелирует воркеры)drop_last=Falseна коротком human/микс этапе; на 11M pretrain можно оставить True- раз в N шагов — прокси на 2–4k пар, не ждать конца
- в
train_gpu_pipeline.shдефолт.venv-autogluon→.venv-gpu
7.4. Раскладка репо — последней
Только когда 1.x и тесты зелёные:
solution/ runtime, training/, eval/, packaging/, experiments/ (AutoGluon, Qwen-as-runtime, proxy leftovers).
Фаза 8. Тяжёлое, если 5.x выдохлись
Qwen как runtime не возвращать (0.53 на human-fold, медленный). H100 между экспериментами:
- Переразметить серую зону 11.2M (метка 0.3–0.7 или сильный разъезд E5 vs табличка) через Qwen3-8B/32B-Instruct (Apache 2.0). Код почти готов:
build_teacher_distillation_data.py. - Дистилляция: teacher-ансамбль (E5-base + CatBoost + …) → 11M мягких меток → студент small/base. В zip одна быстрая модель.
Ожидание неизвестно, 2–3 дня H100. Не начинать, пока не закрыты Фазы 2 и 5.1–5.2.
Human fold 4: посчитать как вторичную метрику, когда будет простой. Не ждать его, чтобы выбрать чекпоинт или веса бленда.
Честные baselines в README: leaky 0.59 не ставить рядом с disjoint 0.73 и не ставить их рядом с LB 0.43 без подписи protocol.
Календарь на неделю (сшивка двух планов)
| Слот | Что | GPU | Зачем |
|---|---|---|---|
| День 1 утро | Фаза 0 + 1 (якоря, run.py, zip, README) |
нет | не отправить не тот архив |
| День 1 день | Фаза 2: прокси на этапе 1 / этапе 2 / супах 0.3–1.0 | мало | самый дешёвый LB |
| День 1–2 | Фаза 3.1–3.2 + Фаза 4 (V2 parallel, battery, ±5%) | нет | бюджет на base |
| Ночь 1–2 | Фаза 5.2: претрейн 2–3 эпохи small | H100 | недообучен на LLM |
| День 2 | Фаза 5.1: мягкий этап 2 (микс), выбор по прокси | H100 | не уехать с теста |
| День 2–3 | Фаза 6.1–6.2: LLM-табличка + веса на прокси | CPU | их +0.004 уже доказан |
| Ночь 3 | Фаза 5.3: e5-base и/или USER-base | H100 | крупный прирост |
| День 4 | Фаза 6.3: бленд small+base+табличка по прокси | мало | |
| Паузы | Фаза 7 тесты/дубли | нет | |
| Если плато | Фаза 8 переразметка | H100 |
Не параллелить перенос папок (7.4) с Фазой 1–2.
Не менять фичи и entry point в одном коммите.
Не запускать 4 эпохи human и hard-mine по human-OOF — это уже опровергнутый путь.
Definition of Done
python run.pyлокально = содержимоеsubmission.zip.- Один
ensemble.jsonс весами, один упаковщик. - Есть неизменяемый LLM-прокси; все решения в одной таблице прокси / (опц.) LB.
- Выбран чекпоинт по прокси, не по концу 4-й human-эпохи.
- V2 в контейнере < 50 с; полный прогон < 780 с; zip < 4.7 GB.
- Battery + ±5% в схеме; табличка, если есть, обучена на LLM-миксе.
- Категорийные веса, если есть, подобраны на прокси.
- Human-CV в README помечен как вторичный; leaky 0.59 не сравнивается с LB.
pytest -qзелёный без данных соревнования.- В бэклоге нет bi-encoder / AutoGluon / human hard-mine / Qwen-runtime.
Если переключишься в Agent mode, логичный старт — Фаза 0+1 (не ломает обучение), сразу за ней скрипт прокси-оценки существующих чекпоинтов: это единственный пункт, который коллега оценивает как возможный +0.01–0.02 без новой ночи H100.