Files
grabber-ai/docs/dataset-coverage.md
T
Denozordec 0f359837c5
docker / build (push) Successful in 1m20s
Датасет: полное покрытие data/raw (71 339 строк из 30 401 релиза), правки парсеров и аудит
Переразбор всех страниц data/raw: legacy-страницы импорта, форматы префиксов ([*]Перевод (1):, Озвучка:, №2, диапазоны), дорожки только в строках «Аудио» (в т.ч. «(Русский, X)», «| Rus | Звук: …»), «Язык озвучки», несколько студий в одной строке, студия без типа. Кодек-строки: «Аудио #N Русский:», «Аудио pic RUS:», «Звук N:», «Аудиодорожка 01:», кириллические АVO/МVO. «Авторский» без числа голосов -> авт. одноголосый, «двугоголосый». Чистка студий: языки, кодеки, «по заказу», «в составе контейнера», отказы от озвучки.

Итог: страниц с метками 30 260 (85.5 %), страниц с дорожкой без меток 1 259 -> 223; data/pages 30 444; после prepare_data 60 944 строки (train 54 686 / test 6 258).

Новый tools/coverage_audit.py + reports/coverage_audit.md, docs/dataset-coverage.md. Переобучен models/best (base): на общем тесте type acc 0.976 против 0.949 у прежней, span 0.674 против 0.643; e2e kinozal 0.805/0.867, rt 0.771/0.740, nnm 0.752/0.693.
2026-11-09 13:29:53 +07:00

154 lines
12 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.
# Покрытие страниц `data/raw` датасетом: аудит сборщика
Отчёт о том, как сборщик (`tools/collect.py` → `tools/harvest/harvest_core.py` →
`src/prepare_data.py`) превращает сохранённые страницы в обучающий датасет, какие
форматы строк он терял и что исправлено. Цифры получены на всех страницах
`data/raw` (35 385 шт.), а не на выборке.
Инструмент замера — `tools/coverage_audit.py` (пишет `reports/coverage_audit.md`,
`data/raw/_coverage_pages.csv`, `data/raw/_coverage_lines.csv`). Строка считается
«дорожкой» независимым от парсеров детектором (префикс «Перевод/Озвучка/Аудио…»,
слово типа озвучки или блок `|студия|`), а «покрытой» — если для неё есть строка
`labels.csv` этого релиза (`raw` / `audio_raw` / `role_raw`).
## Как устроен сборщик и где терялись данные
Пять стадий, у каждой свой кэш:
| стадия | вход → выход | кэш / версия |
|---|---|---|
| `collect` | браузер → `data/raw/<трекер>/<id>.json` + `.html` | `_state.json` |
| `build` | `data/raw` → `data/pages/<release_id>.txt` + строки `data/labels.csv` | `_built.json`, `PARSE_VERSION` |
| `meta` | страницы → `data/meta.csv` | `_meta_cache.json`, `META_VERSION` |
| `prepare_data` | `labels.csv` → `data/processed/dataset.json` | — |
| `train` | `dataset.json` → `models/best`, `reports/` | — |
До этого аудита датасет собирался из 28 155 релизов (56 131 строка), хотя страниц
в `data/raw` было 35 385: **7 371 страница не дала ни одной строки**. Часть из них
законно не содержит озвучки (русский оригинал, «Перевод: не требуется», немое
кино, музыка/сканы), но не менее **1 259 страниц с настоящими дорожками** в
датасет не попадали. Причины — в порядке убывания потерь:
1. **legacy-страницы не переразбирались.** Импорт старого harvest дал 2 633
страницы только с текстом поста (`.legacy.json`); `build` брал лишь пары
`json+html`, поэтому их метки остались от старых регулярок и больше не
обновлялись.
2. **Форматы строк, которых не понимали префиксы.** `[*]Перевод (1):`,
`►Перевод:`, `Перевод №2:`, `Перевод 01-02:`, `Аудио RUS 1-3:`, `Озвучка:`,
`Озвучивание:` (nnm/rutracker) не совпадали с `RT_RE_FIELD` / `NNM_RE_PEREVOD`,
потому что те ждали ровно «Перевод:» или «Перевод 2:».
3. **Дорожки, названные только строкой «Аудио»** (nnm/rutracker, аниме-раздачи):
`Аудио 4: AC3 … (внешние) (Русский, Anilibria)`, `| Rus | Звук: Zendos &
Eladiel`, `Аудио RUS: … Озвучка: двухголосая (… )`. Студия была в скобках после
языка или в хвосте «Звук:/Озвучка:», а разметка такие строки не читала: у nnm
требовался «(MVO, Студия)», а язык — только «Русский/Английский/Украинский».
4. **Студия без типа озвучки** («Перевод: Dreamers Team», «Перевод: CrunchyRoll»,
«Озвучка: Persona99») выбрасывалась: `translation_type` давал «неизвестно», и
строка отбрасывалась вместе с автором. Для головы автора это потеря: на
странице автора назвали.
5. **Несколько студий в одной строке** («Профессиональный (многоголосый) — Jaskier,
TVShows, HDrezka Studio, LostFilm», «| ОРТ, KidsCo»): в метки шла одна студия
или склеенное «Jaskier, TVShows».
6. **Строка «Язык озвучки: Русский (Berofu, Takera, Euji [AniMaunt])»** (nnm, аниме)
вообще не считалась дорожкой.
7. **kinozal читал только одну вкладку.** Если в «Релизе» была строка «Перевод:»,
«Техданные» игнорировались (и наоборот) — терялись типы или студии второй
вкладки.
8. **Кодек-строки мимо правил сервиса** (`segmenter.RE_AUDIO_TRACK`,
`release.RE_CODEC_TRACK`): «Аудио pic RUS:», «Аудио #1 Русский:», «Аудио N Rus:»,
«Звук N:», «Аудиодорожка 01:», «Audio #3:», кириллические «АVO/МVO». Это дыра не
только в метках сегментатора, но и в запасном пути инференса.
## Что исправлено
`tools/harvest/harvest_core.py` (`PARSE_VERSION` 4 → 6), `src/html_extract.py`,
`src/release.py`, `src/segmenter.py`, `src/trackinfo.py`, `tools/collect.py`,
`src/prepare_data.py`, `src/studio_norm.py`:
* общий разбор префикса дорожки: декоративные `[*] ► •`, номер `(1)`, `№2`,
диапазоны `01-02`, «Озвучка/Озвучивание/Дубляж» — для rutracker, nnm и kinozal;
* `build` переразбирает legacy-страницы (метки обновляются, страница не
перезаписывается);
* nnm: студии из `(Русский, Anilibria)`, `| Rus | Звук: …`, язык `RUS/Rus/RU`;
строка «Язык озвучки»; несколько студий в «Перевод:» → по строке на студию;
студия без типа сохраняется с типом «неизвестно»;
* rutracker: разбор `(Русский, Студия)` и `[студия]`, хвостов «Озвучка:»/«Звук:»,
списков студий; те же правила для «Перевод/Озвучка/Озвучивание»;
* kinozal: обе вкладки, несколько студий в строке, «Отсутствует/Без перевода» не
считаются автором;
* кодек-строки: префиксы «Аудио #N Русский:», «Аудио pic RUS:», «Звук N:»,
«Аудиодорожка 01:», «Audio #3:», «Track #2:», «Title :»; тип-слова с
кириллическими двойниками (АVO/МVO/DVO); если у релиза нет ни одной строки,
из кодек-строки берётся дорожка без имени (тип без студии);
* чистка имён: «Русский, - AlexFilm» → AlexFilm, «X по заказу Y» → X,
«озвучил - N» → N; мусор (коды/каналы/языки/«по умолчанию»/«в составе
контейнера»/«Отсутствует»/эпизоды) отбрасывается; в `prepare_data` строки-отказы
от озвучки удаляются отдельным счётчиком.
## Результат
| | было | стало |
|---|---|---|
| страниц в `data/raw` | 35 385 | 35 385 |
| релизов в `labels.csv` | 28 155 | 30 401 |
| строк в `labels.csv` | 56 131 | 71 339 |
| страниц с метками | 28 014 | 30 260 (85.5 %) |
| страниц без меток, но с дорожкой (по детектору) | 1 259 | 223 |
| `data/pages` (страниц для сегментатора) | 28 198 | 30 444 |
| строк после `prepare_data` | 46 894 | 60 944 (train 54 686 / test 6 258) |
| строк со студией (спан найден) | 38 583 (82.3 %) | 50 477 (82.8 %) |
| уникальных текстов | 25 614 | 30 761 |
| дорожек 18+ | 1 006 | 1 156 |
По трекерам (строки `labels.csv` → строки после подготовки, включая аугментацию):
* kinozal: 21 773 → 23 969 (15 188 после подготовки);
* nnm: 18 384 → 27 092 (24 453);
* rutracker: 15 974 → 20 278 (21 303).
Остаток 223 страниц — почти весь музыка/OST-раздачи, где «дорожкой» оказался
трек-лист, плюс единичные нестандартные строки («Аудио 6: двухголосая закадровая
Flowers Media» без кодек-параметров, «Аудио ShinkaDan: …», «Аудио #1: Russian …
| Original | Censor»). Они перечислены в `data/raw/_coverage_lines.csv` и годятся
для следующей итерации правил.
Непокрытые строки на страницах **с** метками (12 908 из 56 921) — в основном не
потерянные дорожки, а дубли: строка «Аудио N:» той же дорожки, что уже размечена
из «Перевод:», дорожки оригинала/другого языка и техданные. Их доля видна в
`reports/coverage_audit.md`.
## Как воспроизвести
```powershell
# замер покрытия (кэш текстов ускоряет повтор)
.venv\Scripts\python tools\coverage_audit.py --cache data\raw\_coverage.pkl
# переиндексация: страницы + метки + meta (после правки парсеров поднять PARSE_VERSION)
.venv\Scripts\python tools\collect.py build --rewrite --relabel
# подготовка датасета и аудит
.venv\Scripts\python -m src.prepare_data
```
Переиндексация всех 35 тыс. страниц одним процессом занимает ~30 мин (основное
время — запись новых страниц и `meta.csv`); на нескольких процессах — в разы
быстрее (`Runner(workers)`), но в песочнице DSH процессы с именованными каналами
недоступны.
## Что это дало модели
Переобучение на расширенном датасете (held-out test 6 258 строк, обе модели
оценены на одном тесте):
| модель | type acc | type macro-F1 | span exact | joint exact |
|---|---|---|---|---|
| прежняя `models/best` (02.11) | 0.949 | 0.880 | 0.643 | 0.615 |
| новая `models/best` (09.11) | 0.976 | 0.906 | 0.674 | 0.658 |
E2E по релизам (пары тип + студия, precision / recall; те же 400 страниц на
трекер): прежняя модель — kinozal 0.752 / 0.830, rutracker 0.729 / 0.700,
nnm 0.669 / 0.604; новая — 0.805 / 0.867, 0.771 / 0.740, 0.752 / 0.693.
Абсолютный `span exact` на новом тесте ниже прежних 0.922 из-за того, что в тест
попали форматы, которых раньше в датасете не было; сравнение «на одном тесте»
показывает рост по всем головам.