Перейти к содержанию

Fine-tune bge-m3-hse-v2 + 3-way бенчмарк

30 апреля — день между pilot run миграции (28-29 апр) и основной миграцией Lyumi (2-3 мая). Сделан полный sprint fine-tune embedding модели на казахстанских HSE-кодексах + честный 3-way бенчмарк (e5-large baseline vs bge-m3 vanilla vs наш fine-tune).

Затраты: $5-6 на vast.ai за 8+ часов R&D. Кредит $0.22 сохранён.

Кратко — что сделано

  1. v1 fine-tune утром на RTX 6000 Ada (1ч 13мин, ~$2-3) — 34К synthetic triplets из 4518 структурированных чанков 8 кодексов РК (ТК/УК/КоАП/ЭК/ЗК/ВК/КЗ/КН).
  2. v2 fine-tune днём на RTX PRO 5000 Blackwell (88мин, $0.87) — 45К triplets с hard negatives (cross-code same number + adjacent articles) + natural language anchors из exam_qa и penalties.
  3. ONNX export — модель в HF под двумя репо (PyTorch + ONNX FP32, identical accuracy cos=1.0).
  4. Re-embed 164,496 чанков на v2 — chroma_v2 готова к деплою на AX41.
  5. Honest 3-way benchmark на полной 164K базе с тем же скриптом и теми же тестами. Результат — обнаружен trade-off, см. ниже.
  6. 398К triplets для будущего v3 (через 1-2 месяца) — hard negatives mining через cross-collection nearest neighbours.

Артефакты

HuggingFace (private under LyumiHSE)

  • LyumiHSE/bge-m3-hse-v2 — PyTorch FP32, 2.27 GB safetensors. Для GPU/cloud inference.
  • LyumiHSE/bge-m3-hse-v2-onnx — ONNX FP32, идентичная точность. Для CPU production на AX41.

На AX41 (готовое к субботе)

  • /opt/lyumi/chroma_v2.tar.gz (1.6 GB) — embeddings от bge-m3-hse-v2 на 164,496 чанках.
  • /opt/lyumi/chroma_20260430.tar.gz (3.6 GB) — backup старой e5-large базы для rollback.

На маке в Карточки Core New/hse_copilot/research/2026-04-30/

  • 3 eval лога: eval_e5_full.log, eval_vanilla_full.log, eval_v2_full.log
  • triplets_v3_full.jsonl (398К triplets, 1.5 GB) — для будущего v3 fine-tune
  • triplets_v3_seed.jsonl (43К triplets) — sample seed
  • duplicates_top200.json + outliers_top300.json + cluster_map.json (UMAP 25K чанков, 62 кластера)
  • eval_baseline_full.py, reembed_vanilla.py — рабочие скрипты
  • eval.log, duplicates.log, outliers.log, cluster.log, triplets.log, hard_neg_full.log — логи всех экспериментов

⭐ Финальная eval таблица (полная 164K база, единый скрипт keyword-matching)

Сет e5-large baseline bge-m3 vanilla bge-m3-hse-v2 (наш)
Golden v1 (14, короткие "ст. N кодекс") 36% 43% 79%
Exam holdout (41, длинные natural language) 66% 63% 39%
Penalty holdout (72, описания нарушений) 86% 82% 38%
Total weighted (127) 74% 72% 43%

Что увидели: - Наш fine-tune доминирует на коротких структурированных запросах: Hit@5 +43pp над baseline (36% → 79%). - Но проигрывает baseline на длинных natural language: -27pp на exam, -48pp на penalty. - Это catastrophic forgetting от full fine-tune через TripletLoss на синтетических anchors. - Vanilla bge-m3 ≈ e5-large на длинных запросах (72% vs 74% weighted average).

⚠️ Главный вывод — НЕ просто замена, а HYBRID retriever

Если в субботу просто заменить e5-large на bge-m3-hse-v2, пользователи с длинными запросами получат деградацию (с 74% до 43%). Это плохо.

Правильный подход — гибрид по типу запроса:

import re
SHORT_STRUCTURED = re.compile(
    r'\bст\.?\s*\d+|\bстатья\s+\d+|приказ\s+№?\s*\d+|пункт\s+\d+',
    re.IGNORECASE
)

def select_model(query):
    if SHORT_STRUCTURED.search(query):
        return 'bge-m3-hse-v2'   # наш fine-tune, 79% golden
    return 'bge-m3-vanilla'      # или e5-large, ~70-75% на длинных

Vanilla или e5-large для длинных: - Они почти равны (72% vs 74%), разница в пределах шума. - Vanilla имеет ту же архитектуру (XLM-RoBERTa, 1024-dim) что и наш fine-tune → проще production. - Vanilla лучше на golden (43% vs 36%); e5 чуть лучше на penalty (86% vs 82%). - Рекомендация: vanilla для consistency (один base весов в проде), e5 как backup если vanilla окажется медленнее на CPU.

TODO для миграции в субботу 2-3 мая

1. Pull модель и chroma на AX41

pip install huggingface_hub
hf auth login   # токен LyumiHSE/lyumi-vast-upload
hf download LyumiHSE/bge-m3-hse-v2-onnx --local-dir /opt/lyumi/models/bge-m3-hse-v2-onnx
tar -xzf /opt/lyumi/chroma_v2.tar.gz -C /opt/lyumi/

2. Реализовать hybrid retriever в retriever.py

Regex selector + двухпуть retrieval: - Короткие structured queries → bge-m3-hse-v2 + chroma_v2 - Длинные natural language → bge-m3 vanilla (или e5-large как сейчас) + старая chroma_db - Объединение через RRF (reciprocal rank fusion) - Cohere reranker поверх объединённого top-20

3. Speed bench локально на AX41 CPU (бесплатно)

Измерить latency single query: - PyTorch bge-m3-hse-v2 - ONNX bge-m3-hse-v2 - Vanilla bge-m3 Цель: short_structured query <100ms на CPU AX41 (12 threads, Ryzen 5 3600).

4. INT8 quantization ONNX (опционально, +30 минут)

optimum-cli onnxruntime quantize --avx512_vnni \
  --onnx_model /opt/lyumi/models/bge-m3-hse-v2-onnx \
  -o /opt/lyumi/models/bge-m3-hse-v2-onnx-int8

Ускорит CPU inference в 3-5x. ~600 MB вместо 2.2 GB. Точность теряет ~1-2pp — приемлемо.

5. Cohere Reranker test (важно)

У тебя в /opt/lyumi/.env уже есть COHERE_API_KEY. Прогнать тот же eval_baseline_full.py, но top-20 кандидатов от каждой модели отдавать в Cohere Rerank 4 Fast перед оценкой.

Гипотеза: reranker компенсирует weakness'ы embedding-модели на длинных запросах. Может оказаться что bge-m3-hse-v2 + reranker = 70%+ даже на penalty/exam — тогда гибрид не нужен, одна модель + reranker делает всю работу.

Если подтвердится — упрощает архитектуру в production.

Зоны роста — v3 fine-tune через 1-2 месяца

  1. Mixed dataset — synthetic anchors (текущий подход) + natural language anchors (exam + penalties + 1000+ из query_logs проды). Решит catastrophic forgetting на длинных queries.
  2. LoRA вместо full fine-tune — меньше catastrophic forgetting, не теряем generalization. Память тоже меньше требует.
  3. Подзаконные акты в chroma — Приказ 1019 (обучение по БиОТ), ППБ 55 (пожарка), ЗРК 188-V (гражданская защита), СТ РК. Сейчас они не покрыты структурированными чанками. Цель: ~30K дополнительных чанков с metadata code_type/code_articles.
  4. Hard negatives с context — сейчас просто "одинаковый номер в другом кодексе", добавить семантические негативы (close embeddings но другая тема).
  5. Trigger для v3: когда накопится 100+ 👎 в feedback на новой v2, или 1000+ запросов в логах с low retrieval score (через 4-6 недель работы в проде).

Зачем 7B модель НЕ нужна сейчас

Есть мысль перейти на e5-mistral-7B-instruct, gte-Qwen2-7B, NV-Embed-v2 (топ MTEB).

Проблема: 7B даёт +3-7% на benchmarks, но требует: - $300-500/мес за GPU server для production (AX41 только CPU, 7B на нём не работает). - LoRA минимум для training (full fine-tune не влезет в 48GB VRAM RTX 6000 Ada). - В 5-10x дороже за весь sprint vs текущие $5.

ROI отрицательный при 48 пользователях. Имеет смысл при 5000+ платящих и 100K+ запросов/месяц. Сейчас bottleneck — дистрибуция и feedback, не качество модели.

Реалистичный путь: bge-m3 + smart fine-tune + reranker → 6-12 месяцев → если станет узко по качеству, тогда LoRA на 7B с classifier-based routing (только сложные запросы → 7B).

Honest assessment

Что получили: - В 2x точнее baseline на короткой задаче ("ст.156 УК" → 79% vs 36%). - Готовая инфраструктура continuous learning ($1-2 за итерацию через 1-2 месяца). - Чистый 3-way benchmark — знаем где модель сильна, где слаба, без розовых очков. - Hybrid strategy — production план, не "ура замена".

Что НЕ получилось: - Fine-tuned модель проиграла baseline на длинных запросах (catastrophic forgetting обнаружен). - Holdout 25-39% на v2 на natural language — синтетика не покрывает реальные запросы. - В одиночку наш fine-tune не подходит для production — нужен гибрид.

Взрослая инженерная позиция: знаем trade-off → планируем гибрид → не заменяем e5 в проде наобум. Если бы поверили утренним 86% Hit@5 на узкой подвыборке — пользователи получили бы regression на длинных запросах после миграции.

Цифры измерили честно. Это и есть ценность сегодняшнего дня — не просто 79% Hit@5, а карта сильных и слабых сторон для production.

Связанные страницы

  • [[lyumi/migration_ax41]] — основной план миграции CPX62 → AX41. Раздел "Fine-tune bge-m3" обновлён ссылкой сюда.
  • [[lyumi/lookup_tool_design]] — детерминистичный lookup для exact-match запросов (дополнение к hybrid retriever).
  • [[lyumi/strategy_2026]] — общая стратегия Lyumi на год.
  • [[lyumi/fact_check_apr29]] — fact-check кодексов РК, источник expected_keywords для golden_retrieval_v1.