docker / build (push) Successful in 1m20s
Переразбор всех страниц 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.
154 lines
12 KiB
Markdown
154 lines
12 KiB
Markdown
# Покрытие страниц `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 из-за того, что в тест
|
||
попали форматы, которых раньше в датасете не было; сравнение «на одном тесте»
|
||
показывает рост по всем головам.
|