docker / build (push) Successful in 43s
Метки пересобраны новыми парсерами (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]>
133 lines
10 KiB
Markdown
133 lines
10 KiB
Markdown
# 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 вариантов: «многоголосое» и т.п.)
|
||
частично закрывает этот пробел.
|