Files
grabber-ai/README.md
T
DenozordecandClaude Opus 5.5 e8035e1e9d
docker / build (push) Successful in 43s
Переобучение на нескольких авторах в строке: метки PARSE_VERSION 9, новая models/best (base)
Метки пересобраны новыми парсерами (collect.py build --relabel): 69 511 строк из 30 451 релиза;
после prepare_data 52 658 строк, 3 529 с несколькими авторами, 5 ручных решений применены.

Новая models/best (ruBert-base) на общем тесте 4 984 строк: joint exact 0.903 против 0.800 у
прежней, span exact 0.919 против 0.813, type macro-F1 0.976 против 0.909; строки с 2+ авторами —
span 0.815 против 0.011. Прежняя модель — models/best_backup_20261109_164800. ONNX пересобран,
паритет 100 %.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-09 16:56:12 +07:00

133 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# grabber-ai — нейро-модель «тип озвучки + автор + 18+»
По тексту дорожки озвучки (или HTML-странице релиза с трекеров rutracker /
kinozal / nnm-club) модель определяет:
* **тип озвучки** (`translation_type`, 15 классов: проф. дубляж, проф. многоголосый,
авт. одноголосый, …) — классификация;
* **автора** (`studio`: студия или переводчик) — извлечение имени прямо из текста
(работает и для авторов, которых не было в обучении) + нормализация по словарю
алиасов («HDRezka Studio» → `HDrezka`, «Ю. Сербин» → «Юрий Сербин»);
* **18+** дорожка или нет — бинарная голова.
Обучено на датасете из 52 658 строк (69 511 размеченных строк из 30 451 релиза
`data/raw` + морфологическая аугментация; у строки может быть несколько авторов —
«Многоголосый (HDRezka Studio, LostFilm)» даёт обоих). Как страницы превращаются в строки и
что было исправлено в сборщике — [docs/dataset-coverage.md](docs/dataset-coverage.md).
Multi-task RuBERT: сравниваются `rubert-tiny2` и `ruBert-base`,
лучшая кладётся в `models/best`.
## Квикстарт (5 минут)
```bash
# 1. окружение (Windows, Python 3.13; GPU требует колёс cu128 — см. docs/training-windows.md)
python -m venv .venv
.venv\Scripts\python -m pip install torch --index-url https://download.pytorch.org/whl/cu128
.venv\Scripts\python -m pip install -r requirements.txt
# 2. данные -> подготовка (data/labels.csv уже в репозитории)
.venv\Scripts\python -m src.prepare_data
# 3. обучение (обе модели, 5-fold CV; ~15-20 мин на RTX 5070 Ti)
.venv\Scripts\python -m src.train
# результат: models/best, reports/summary.md, reports/*.png
# 4. инференс
.venv\Scripts\python -m src.predict --text "Перевод: Профессиональный (многоголосый закадровый) | HDRezka Studio 18+"
.venv\Scripts\python -m src.predict --html data/samples/rt-topic.html
.venv\Scripts\python -m src.predict --file data/pages/6907007.txt --out result.json
```
Python API:
```python
from src.predict import DubPredictor
model = DubPredictor() # models/best по умолчанию
model.predict_text("Авторский (одноголосый закадровый) - Ю. Сербин")
# {'translation_type': 'авт. одноголосый', 'studio': 'Юрий Сербин', 'is_18plus': False, ...}
model.predict_html(open("data/samples/rt-topic.html", encoding="utf-8").read())
# [ {...дорожка 1...}, {...дорожка 2...}, ... ]
```
HTTP-сервис и интеграция из Rust/TypeScript (ONNX без Python) — см.
**[docs/integration.md](docs/integration.md)**.
## Структура
```
data/ датасет (labels.csv — снимок) и HTML-дампы страниц
data/processed/ подготовленные данные (dataset.json, label_maps.json)
src/ код: подготовка, модель, обучение, инференс, сервис, ONNX-экспорт
models/ чекпоинты (best — итоговая модель)
reports/ метрики, аудит датасета, confusion matrix, ONNX-parity
tests/ юнит-тесты (tests/run_tests.py)
examples/ клиенты: rust (HTTP, ONNX), typescript (HTTP, ONNX)
docs/ документация
```
## Документация
* [docs/architecture.md](docs/architecture.md) — устройство модели и пайплайна
* [docs/dataset.md](docs/dataset.md) — схема датасета, семантика классов, аудит
* [docs/dataset-coverage.md](docs/dataset-coverage.md) — покрытие всех страниц
`data/raw`, найденные дыры сборщика и что исправлено
* [docs/training-windows.md](docs/training-windows.md) — обучение на Windows+GPU, troubleshooting
* [docs/api-reference.md](docs/api-reference.md) — **все значения ответа сервиса (15 классов `translation_type` и др.) и принцип работы; `labels.csv` для этого открывать не нужно**
* [docs/inference.md](docs/inference.md) — CLI/API, JSON-контракт
* [docs/integration.md](docs/integration.md) — Rust/TypeScript: HTTP-сервис и ONNX
## Качество
Held-out test (4 984 строки, группировка по релизам и текстам; метки пересобраны
парсерами `PARSE_VERSION` 9, строки со списком студий склеены в одну с несколькими
авторами). Все модели оценены на **одном и том же** тесте:
| модель | type acc | type macro-F1 | span exact | 18+ acc | lang acc | joint exact [95 %] | строки с 2+ авторами (438), span |
|---|---|---|---|---|---|---|---|
| прежняя `models/best` (09.11, один автор на строку) | 0.981 | 0.909 | 0.813 | 1.000 | 0.998 | 0.800 [0.788–0.810] | 0.011 |
| rubert-tiny2, несколько авторов | 0.978 | 0.904 | 0.869 | 0.999 | 0.999 | 0.854 [0.843–0.863] | 0.637 |
| **ruBert-base, несколько авторов (`models/best`)** | **0.979** | **0.976** | **0.919** | **1.000** | **0.999** | **0.903** [0.895–0.911] | **0.815** |
* joint exact — строка распознана полностью (тип + все авторы + 18+); span exact
сравнивает набор авторов строки целиком.
* Новая `models/best` против прежней на тех же строках: исправлено 647, сломано 131
(знаковый критерий p ≈ 1e-83). Прежняя модель часть тестовых строк видела при
обучении, так что сравнение в её пользу.
* Противоречивых строк (один текст — разные метки) в датасете 1.2 % вместо 20 %:
исправлены парсеры студий (пол голоса, техпараметры, «т/к», «N-й канал»), а
списки студий размечаются целиком. Оставшиеся расхождения между релизами
разбираются вручную: `tools/collect.py` → «Разбор противоречий»
(`data/text_fixes.csv`).
* E2E по релизам (замер для модели от 09.11 с одним автором на строку) (`tests/e2e_segmenter.py`, по 400 тестовых страниц на трекер, пары
тип + студия, precision / recall) — новая модель на тех же страницах:
kinozal 0.805 / 0.867, rutracker 0.771 / 0.740, nnm 0.752 / 0.693; прежняя
модель там же: 0.752 / 0.830, 0.729 / 0.700, 0.669 / 0.604. Справочно, правила:
0.792 / 0.859, 0.697 / 0.721, 0.670 / 0.646.
* Сегментатор (`models/segmenter`) переобучен на расширенном наборе страниц
(`models/segmenter_v2`, line precision 0.933 / recall 0.977), но e2e новых весов
хуже по nnm (0.610 / 0.560) — в `models/segmenter` оставлены прежние веса.
* `models/best-onnx` пересобран под новую модель: паритет с PyTorch 100 % по типу,
авторам и 18+ — [reports/onnx_parity.md](reports/onnx_parity.md).
## Ограничения
* Метки датасета сгенерированы регулярками (пайплайн deepseek-harness) — метрики
измеряют согласование с этой разметкой; ценность модели — обобщение на новые
формулировки без сопровождения регулярок.
* Датасет: 69 511 строк из 30 451 релиза (kinozal 23 749 / nnm 26 478 /
rutracker 19 284); после подготовки 52 658 строк (3 529 — с несколькими авторами). Покрытие страниц `data/raw`
— 85.5 % (30 260 из 35 385); оставшиеся — почти все без озвучки (русский
оригинал, «не требуется», музыка/сканы), см. [docs/dataset-coverage.md](docs/dataset-coverage.md).
* Извлечение автора уверенно работает на форматах записи, представленных в
датасете (имя после типа через разделитель, в скобках у AVO/MVO/DVO-дорожек,
после тире); на непривычных форматах («Одноголосый закадровый (Фамилия)»)
модель может не выделить имя — span остаётся пустым, тип при этом верный.
* kinozal-страницы: авторы озвучки лежат во вкладках, которые сайт подгружает
JavaScript-ом. По `url` сервис скачивает их сам (`fetch_html`, `showtab`); в
присланном `html`/`text` без этих вкладок студий может не быть.
* Классы с 1–8 примерами почти не выучиваются (видно в macro-F1 и confusion
matrix); морфологическая аугментация (458 вариантов: «многоголосое» и т.п.)
частично закрывает этот пробел.