docs(diarization): спроектирована end-to-end карта
- Зачем: - локальные оптимизации каскада не достигли 30%-го порога ускорения; - старые закрытые хранилища и капсулы не должны стать будущей зависимостью. - Что: - собран единый реестр результатов задач #41 и #42; - опубликовано разложение Ryzen baseline и выбрана архитектурная гипотеза; - подготовлены самодостаточная спецификация и ready-for-agent задача #46. - Проверка: - пройдены self-review и две независимые линии ревью; - проверены 44 строки реестра, 42 арифметических инварианта и ссылки; - выполнены ai-text-lint, privacy scan и post-lint guard. Refs: #45
This commit is contained in:
1 parent
312153f4bc
commit
89475b9b97
3 files changed
+927
-11
No files matched your search
@@ -0,0 +1,472 @@
|
||||
# Эксперимент Streaming Sortformer v2 Q8_0 на Ryzen CPU
|
||||
|
||||
**Дата:** 2026-09-01
|
||||
|
||||
**Статус:** готовый контракт следующего эксперимента, исполняемый в
|
||||
[задаче #46](https://git.dementev.space/ddmitry/local-transcriber/issues/46).
|
||||
Запуск модели и аудио начинается после подготовки свежей закрытой основы.
|
||||
|
||||
## Цель и исходы
|
||||
|
||||
Эксперимент отвечает на один вопрос: сокращает ли Streaming Sortformer v2
|
||||
Q8_0 через NeMo-Speech.cpp время построения разметки говорящих на целевом Ryzen
|
||||
минимум на 30% относительно свежего последовательного W0 при приемлемом
|
||||
качестве и памяти.
|
||||
|
||||
Допустимы три исхода:
|
||||
|
||||
- `go`: медиана пяти финальных парных ускорений не ниже 30%, автоматические и
|
||||
слуховые gates пройдены;
|
||||
- `stop`: нарушен обязательный gate, первичное ускорение ниже 10%, финальная
|
||||
медиана ниже 30% или слуховая проверка подтвердила регрессию;
|
||||
- `needs-user`: отсутствует подтверждение свежей опоры или требуемое решение
|
||||
по прослушиванию. Это состояние ожидания, его нельзя публиковать как результат
|
||||
кандидата.
|
||||
|
||||
`go` разрешает подготовку отдельного production-решения. Экспериментальный
|
||||
runtime остается изолированным, а production-профиль, CLI, config и модель по
|
||||
умолчанию сохраняются.
|
||||
|
||||
## Сначала прочитать
|
||||
|
||||
1. Прочитать [карту архитектур](../research/2026-09-01-end-to-end-cpu-diarization-map.md),
|
||||
особенно разделы "Граница выводов", A1 и формулу полной замены.
|
||||
Критерий завершения: агент может объяснить, почему старые значения
|
||||
`3 / 2 / 2`, unmatched words и purity не являются порогами нового опыта.
|
||||
2. Прочитать [ADR-007](../adr/007-word-level-speaker-diarization.md) и
|
||||
[старую спецификацию](2026-08-30-cpu-diarization-experiment.md). Критерий
|
||||
завершения: сохранены каноническое сведение слов, правила 5%/10%/30% и
|
||||
memory gate.
|
||||
3. Прочитать `src/local_transcriber/benchmark_experiment.py` и
|
||||
`tests/test_benchmark_experiment.py` перед реализацией. Критерий завершения:
|
||||
новый стенд использует отдельный модуль и schema, не принимает старый
|
||||
manifest или закрытые хранилища задач #41/#42.
|
||||
|
||||
## Границы
|
||||
|
||||
В scope входят свежая закрытая основа, точный W0/Sortformer A/B на Ryzen,
|
||||
проверка трех полных записей после прохождения 30%-го порога на фрагментах и
|
||||
слуховая приемка.
|
||||
|
||||
За пределами scope остаются:
|
||||
|
||||
- replay W/M/Q/E/C и восстановление старых patch/wheel;
|
||||
- C1; ее повторное открытие требует отдельной свежей W0/C1 пары и нового
|
||||
слухового материала;
|
||||
- Intel и другие CPU;
|
||||
- production integration, dependency lock, упаковка runtime и изменение ADR;
|
||||
- параллельное планирование ASR/диаризации - это
|
||||
[задача #22](https://git.dementev.space/ddmitry/local-transcriber/issues/22);
|
||||
- автоматическое включение - это
|
||||
[задача #23](https://git.dementev.space/ddmitry/local-transcriber/issues/23);
|
||||
- joint ASR+diarization и shared-ASR-encoder. ASR создает только quality
|
||||
sidecar до измерений.
|
||||
|
||||
## Закрепленные реализации
|
||||
|
||||
### W0
|
||||
|
||||
W0 использует действующий последовательный путь на восьми физических ядрах:
|
||||
|
||||
- `sherpa-onnx/core 1.13.6`;
|
||||
- Pyannote Segmentation 3.0 FP32, SHA-256
|
||||
`220ad67ca923bef2fa91f2390c786097bf305bceb5e261d4af67b38e938e1079`;
|
||||
- WeSpeaker ResNet34 LM FP32, SHA-256
|
||||
`e9848563da86f263117134dfd7ad63c92355b37de492b55e325400c9d9c39012`;
|
||||
- `window_shift_ratio=0.1`;
|
||||
- `FastClustering(auto, 0.89)`;
|
||||
- `provider=cpu` для segmentation и embeddings;
|
||||
- `debug=True` для обеих model configs: stage times читаются из штатного
|
||||
debug-журнала и входят в измерительный рецепт;
|
||||
- `min_duration_on=0.3`, `min_duration_off=0.5`;
|
||||
- один worker, одна session, `intra_op_threads=8`, `inter_op_threads=1`, batch 1;
|
||||
- штатный непатченный `diarizer.process(samples)`.
|
||||
|
||||
Старые experimental patch/wheel не загружаются и не восстанавливаются. До
|
||||
первого запуска стенд проверяет версии, хеши и все effective values рецепта.
|
||||
Критерий завершения: `--validate-only` показывает рецепт `W0-FRESH` и
|
||||
останавливается при любом несовпадении.
|
||||
|
||||
### Sortformer
|
||||
|
||||
Runtime:
|
||||
|
||||
- репозиторий [NVIDIA/NeMo-Speech.cpp](https://github.com/NVIDIA/NeMo-Speech.cpp);
|
||||
- commit `4f9676226f667d14608487df744f375db87127f8`;
|
||||
- license Apache-2.0;
|
||||
- source build штатным CPU-only preset:
|
||||
`git submodule update --init ggml`, затем `scripts/configure.sh cpu-diar` и
|
||||
`cmake --build --preset cpu-diar`
|
||||
([инструкция build](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/docs/build.md),
|
||||
[точный preset](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/CMakePresets.json));
|
||||
- preset использует Release/Ninja, включает только diarization и отключает
|
||||
patched GGML; runtime запускается с `gpu=-1`, одним процессом и одним stream;
|
||||
- CPU graph использует закрепленные в этом commit четыре внутренних потока;
|
||||
runtime knob для их изменения отсутствует
|
||||
([вызов scheduler](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/src/runtime/ggml/session.cpp#L903));
|
||||
- submodule commits, compiler, CMake options и SHA-256 готового executable и
|
||||
shared library сохраняются в новом manifest.
|
||||
|
||||
Модель:
|
||||
|
||||
- repo `nvidia/diar_streaming_sortformer_4spk-v2`;
|
||||
- revision `5240a64075176943f677d30fa2171c780229f341`;
|
||||
- файл `diar_streaming_sortformer_4spk-v2.q8_0.gguf`;
|
||||
- размер `147075776` байт;
|
||||
- SHA-256 `0679cfeb1ce356d0dea9470b31274f4bfc7eb927497d82005483770666da998a`;
|
||||
- license CC BY 4.0.
|
||||
|
||||
Эти revision, размер и хеш также закреплены в
|
||||
[официальном model index выбранного runtime](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/models/index.json#L75-L88).
|
||||
После подготовки байтов стенд работает без сети.
|
||||
|
||||
Кандидат вызывается через
|
||||
[standalone C ABI](https://github.com/NVIDIA/NeMo-Speech.cpp/blob/4f9676226f667d14608487df744f375db87127f8/include/nemo_speech/diar.h),
|
||||
чтобы сохранить effective config и покадровую диагностику. Stateful streaming
|
||||
получает точную геометрию NVIDIA в 80-мс кадрах:
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---:|
|
||||
| `chunk_frames` | `340` |
|
||||
| `right_context_frames` | `40` |
|
||||
| `left_context_frames` | `0` |
|
||||
| `fifo_frames` | `40` |
|
||||
| `spkcache_frames` | `188` |
|
||||
| `update_period_frames` | `300` |
|
||||
|
||||
Сумма chunk и right context дает input buffer latency 30,4 с. Опубликованный
|
||||
RTF этой конфигурации измерен на RTX 6000 Ada и в CPU-гипотезу не переносится
|
||||
([model card](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2#setting-up-streaming-configuration)).
|
||||
Full-attention `--offline` не используется.
|
||||
|
||||
Post-processing передается явно при каждом запросе:
|
||||
|
||||
| Поле | Значение |
|
||||
|---|---:|
|
||||
| `onset` | `0.641` |
|
||||
| `offset` | `0.561` |
|
||||
| `pad_onset_sec` | `0.229` |
|
||||
| `pad_offset_sec` | `0.079` |
|
||||
| `min_duration_sec` | `0.511` |
|
||||
| `min_gap_sec` | `0.296` |
|
||||
|
||||
Это callhome-tuned конфигурация закрепленного runtime. Она остается quality
|
||||
риском для русских рабочих встреч и не настраивается по трем контрольным
|
||||
фрагментам. Любое изменение геометрии, post-processing, quantization или
|
||||
runtime commit создает другую гипотезу и требует новой спецификации.
|
||||
|
||||
Критерий завершения подготовки кандидата: сборка выполняет синтетический
|
||||
ABI-тест без аудио, `nemo_speech_diar_num_speakers()` возвращает 4,
|
||||
`nemo_speech_diar_seconds_per_frame()` возвращает 0,08, а manifest содержит все
|
||||
закрепленные значения и хеши. Синтетический тест не заменяет smoke-проверку с
|
||||
аудио.
|
||||
|
||||
## Свежая закрытая основа
|
||||
|
||||
### Шаг 1. Выбрать источники и фрагменты
|
||||
|
||||
Владелец выбирает три сохраненные исходные записи и по одной 300-секундной
|
||||
области в каждой. Набор должен включать русскую рабочую речь, смену говорящего,
|
||||
короткий ответ и перекрытие хотя бы где-то в совокупности. В каждой области и
|
||||
каждой полной записи должно быть от двух до четырех слышимых голосов. Запись с
|
||||
пятью голосами закрывает кандидат до измерения: модель выдает не более четырех
|
||||
выходных голосовых кластеров
|
||||
([technical limitations](https://huggingface.co/nvidia/diar_streaming_sortformer_4spk-v2#technical-limitations)).
|
||||
|
||||
В закрытом manifest сохраняются source hash, точные границы и recipe
|
||||
mono/16 kHz float32. Публичные документы получают только число фрагментов,
|
||||
длительность и агрегаты.
|
||||
|
||||
Критерий завершения: три source hash уникальны, три WAV имеют ровно 300 секунд
|
||||
после единственного закрепленного преобразования, а ни один путь, ID или
|
||||
интервал не попадает в stdout режима `--validate-only`.
|
||||
|
||||
### Шаг 2. Создать ASR-sidecar и опорную разметку
|
||||
|
||||
Действующий ASR выполняется один раз для каждой полной записи до измерений.
|
||||
Sidecar хранит канонические слова с временной привязкой и нормализованный текст;
|
||||
fragment-sidecar получается детерминированным срезом той же версии. Затем
|
||||
человек прослушивает каждый фрагмент целиком, фиксирует ожидаемое число
|
||||
голосовых кластеров для фрагментов и полных записей и создает опорную разметку,
|
||||
достаточную для mapped purity и выбора мест прослушивания. Опорная разметка
|
||||
остается приближенной и не объявляется истиной границ.
|
||||
|
||||
Критерий завершения: для каждого фрагмента и каждой полной записи есть
|
||||
подтвержденное человеком `expected_cluster_count` в диапазоне `2..4`, один
|
||||
неизменяемый sidecar и SHA-256; для фрагментов также есть опорная разметка.
|
||||
Числа старых контролей не копируются.
|
||||
|
||||
### Шаг 3. Пройти пользовательский gate
|
||||
|
||||
До первого модельного запуска владелец подтверждает:
|
||||
|
||||
- право использовать выбранные записи в закрытом локальном опыте;
|
||||
- пригодность трех областей и полных записей, а также
|
||||
`expected_cluster_count` каждого фрагмента и каждой полной записи;
|
||||
- доступность исходных полных записей для этапа после 30%-го порога на
|
||||
фрагментах;
|
||||
- готовность выполнить безусловный финальный слуховой gate, если медиана
|
||||
достигнет 30%. Diagnostics только добавляют обязательные места прослушивания.
|
||||
|
||||
Критерий завершения: в закрытом manifest есть timestamped decision `approved`.
|
||||
Без него исход `needs-user`; стенд не загружает модели.
|
||||
|
||||
## Измеряемая величина и A/B
|
||||
|
||||
Время W0 - wall вокруг одного `diarizer.process(samples)`. Время кандидата -
|
||||
wall вокруг `stream_open -> push all prepared samples -> finish -> segment
|
||||
post-processing`. Для обеих ветвей модель уже загружена, WAV уже декодирован в
|
||||
один и тот же mono/16 kHz float32 buffer. ASR, скачивание, build, model load,
|
||||
декодирование, чтение sidecar, запись artifacts и расчет метрик находятся вне
|
||||
таймера.
|
||||
|
||||
Полная замена оценивается только измерением:
|
||||
|
||||
```text
|
||||
B = measured W0 wall
|
||||
A = measured Sortformer wall
|
||||
speedup_percent = 100 * (B - A) / B
|
||||
```
|
||||
|
||||
Восьмиклеточное историческое Ryzen-разложение не подставляется вместо свежего
|
||||
`B`. CPU prediction для `A` отсутствует.
|
||||
|
||||
Каждая ячейка запускается новым дочерним процессом на одной машине, от сети, в
|
||||
стабильном power mode. Process affinity разрешает те же восемь физических ядер
|
||||
обеим ветвям. W0 получает `intra_op_threads=8`; закрепленный candidate runtime
|
||||
исполняет CPU graph четырьмя внутренними потоками. Это часть сравниваемого
|
||||
runtime recipe. Изменение hardcoded числа потоков образует новую гипотезу.
|
||||
Фиксируются logical/physical cores, CPUID/ISA, RAM, ОС, compiler/runtime
|
||||
versions, affinity, effective threads, power mode, governor, turbo, throttling
|
||||
и swap. Прогон со сменой режима или throttling не учитывается и повторяется
|
||||
один раз после стабилизации.
|
||||
|
||||
### Шаг 4. Принять свежий W0
|
||||
|
||||
Один `W0-FRESH` обрабатывает три фрагмента последовательно. Для каждого
|
||||
сохраняются raw wall/CPU/RSS и stage times; публично выводится сумма. W0 должен
|
||||
дать ровно подтвержденные `expected_cluster_count`, сохранить sidecar-текст и
|
||||
пройти memory gate.
|
||||
|
||||
Критерий завершения: W0 прошел все обязательные gates и его закрытый result
|
||||
имеет SHA-256. При провале итог `stop`: база сравнения непригодна.
|
||||
|
||||
### Шаг 5. Выполнить первичный A/B
|
||||
|
||||
Сразу после принятого W0 запускается одна ячейка кандидата на тех же buffers и в
|
||||
том же порядке фрагментов. Primary order закреплен как `W0 -> candidate`; пять
|
||||
дорогих циклов ниже устраняют постоянный порядок чередованием. Один primary
|
||||
cycle равен сумме трех wall times каждой ветви.
|
||||
|
||||
Критерий завершения: обе ячейки имеют raw result, одинаковый список input
|
||||
hashes и один pair ID; рассчитаны ускорение, CPU и RSS delta.
|
||||
|
||||
Решение после primary:
|
||||
|
||||
- `abs(speedup) <= 5%` - результат фиксируется как равенство по скорости;
|
||||
- `speedup < 10%` - `stop`: причина `equal-speed` для равенства по скорости,
|
||||
иначе `below-continuation`;
|
||||
- `speedup >= 10%` при всех gates - перейти к пяти финальным циклам;
|
||||
- любой обязательный quality/memory/Sortformer gate - немедленный `stop`.
|
||||
|
||||
### Шаг 6. Выполнить пять финальных циклов
|
||||
|
||||
Каждый цикл содержит свежую ячейку W0 и свежую ячейку кандидата на всех трех
|
||||
фрагментах. Primary pair в пять финальных циклов не входит. Порядок закреплен
|
||||
заранее и чередуется так:
|
||||
|
||||
1. final 1: `candidate -> W0`;
|
||||
2. final 2: `W0 -> candidate`;
|
||||
3. final 3: `candidate -> W0`;
|
||||
4. final 4: `W0 -> candidate`;
|
||||
5. final 5: `candidate -> W0`.
|
||||
|
||||
Вместе с primary `W0 -> candidate` это исключает выбор порядка по уже видимому
|
||||
результату. Дополнительные варианты, модели и настройки не добавляются.
|
||||
|
||||
Критерий завершения: получены пять парных ускорений, их медиана и MAD; все
|
||||
десять ячеек прошли gates. Медиана не ниже 30% открывает проверку полных записей.
|
||||
Медиана ниже 30% дает `stop`. Дополнительные повторы не назначаются.
|
||||
|
||||
### Шаг 7. Проверить полные записи и пройти слуховой gate
|
||||
|
||||
После медианы не ниже 30% W0 и candidate однократно обрабатывают три полные
|
||||
исходные записи. Скорость полных прогонов остается диагностикой и не заменяет
|
||||
пятипарную медиану.
|
||||
|
||||
Владелец получает blinded A/B материал по пяти категориям:
|
||||
|
||||
- короткие ответы и перебивки;
|
||||
- смены говорящего;
|
||||
- перекрывающаяся речь;
|
||||
- устойчивость соответствия голоса кластеру;
|
||||
- слова без говорящего и малые остаточные кластеры.
|
||||
|
||||
Материал включает все места, отмеченные сравнительными diagnostics, и
|
||||
фиксированную случайную выборку совпадающих мест. Порядок A/B и имя кандидата
|
||||
раскрываются после вердикта. По каждой категории владелец записывает `pass` или
|
||||
`fail` и короткую причину в закрытом хранилище; публично остается только
|
||||
вердикт.
|
||||
|
||||
Критерий завершения: три пары на полных записях прошли автоматические gates,
|
||||
все пять слуховых категорий имеют решение. Любой подтвержденный `fail` дает
|
||||
`stop`; полный `pass` завершает эксперимент как `go`.
|
||||
|
||||
## Gates и диагностика
|
||||
|
||||
### Обязательное качество и корректность
|
||||
|
||||
Каждая ячейка W0 и кандидата обязана выполнить все условия:
|
||||
|
||||
- число голосовых кластеров каждого обрабатываемого контрольного объекта -
|
||||
фрагмента или полной записи - точно равно свежему, подтвержденному человеком
|
||||
`expected_cluster_count`;
|
||||
- нормализованный текст и порядок слов побайтно совпадают с одним sidecar;
|
||||
- нет потерянных, продублированных или переставленных слов;
|
||||
- интервалы конечны, имеют положительную длительность, лежат в пределах audio
|
||||
duration с учетом явно заданного padding и отсортированы по началу;
|
||||
- каноническая нумерация меток детерминирована на повторном расчете метрик;
|
||||
- все inputs, параметры и output artifacts имеют SHA-256.
|
||||
|
||||
Purity и число слов без говорящего сравниваются с новым `W0-FRESH`. Ухудшение
|
||||
не дает автоматического `fail`, но обязательно добавляет все затронутые места в
|
||||
слуховой gate. Старые абсолютные значения не участвуют.
|
||||
|
||||
Открытый диагностикой слуховой gate не прерывает шаги 5-6. Стенд накапливает
|
||||
затронутые места и добавляет их в материал шага 7. Состояние `needs-user` из-за
|
||||
прослушивания возможно только после достижения 30%-го порога и подготовки
|
||||
полного blinded-материала.
|
||||
|
||||
### Sortformer-specific gate
|
||||
|
||||
Для каждой ячейки кандидата сохраняются и проверяются:
|
||||
|
||||
- `num_speakers=4`, `seconds_per_frame=0.08` и точная geometry/post-processing
|
||||
из этой спецификации;
|
||||
- `frame_count`, `frame_probs_start` и размер доступной матрицы `T x 4`;
|
||||
- каждое сохраненное probability конечно и принадлежит `[0, 1]`;
|
||||
- каждая итоговая speaker label принадлежит `1..4`;
|
||||
- число и суммарная длительность интервалов по каждому каналу;
|
||||
- число коротких интервалов, overlap ratio, unmatched words, малые/остаточные
|
||||
кластеры и mapped purity относительно свежей опорной разметки;
|
||||
- wall отдельно для model inference и segment post-processing.
|
||||
|
||||
Любой неверный shape/value/label или эффективная конфигурация, отличная от
|
||||
закрепленной, дает `stop`. Появление лишнего/пропажа ожидаемого кластера дает
|
||||
`stop`. Изменение channel stability, short-turn, overlap, unmatched-word или
|
||||
purity diagnostics открывает слуховую проверку; числовой порог для этих proxy
|
||||
не вводится.
|
||||
|
||||
Жесткий предел четырех выходных голосовых кластеров, риск записей с пятью и
|
||||
более слышимыми голосами и риск non-English/out-of-domain сохраняются в
|
||||
публичном решении даже после `go`; опыт не доказывает применимость к другим
|
||||
встречам.
|
||||
|
||||
### Память
|
||||
|
||||
Peak RSS измеряется process-wide для каждой ячейки. Также сохраняются swap до и
|
||||
после, page faults и RSS после каждого фрагмента.
|
||||
|
||||
Memory gate дает `stop` при OOM, активной подкачке во время ячейки, RSS без плато
|
||||
между повторами или линейном росте RSS с числом обработанных фрагментов. Peak
|
||||
RSS выше 2 ГиБ на машине с 16 ГиБ требует отдельного разбора владельца и
|
||||
состояния `needs-user`; одно превышение не является автоматическим `fail`.
|
||||
|
||||
## Артефакты и приватность
|
||||
|
||||
Checkout и дерево сборки NeMo-Speech.cpp, скачанные веса и новое закрытое
|
||||
хранилище размещаются вне рабочей копии local-transcriber. Обычная `.scratch`
|
||||
внутри репозитория не подходит: `.gitignore` покрывает там только
|
||||
`.scratch/handoffs/`. Ни один runtime/model/build artifact или закрытый вход не
|
||||
попадает в Git.
|
||||
|
||||
Новое закрытое хранилище содержит:
|
||||
|
||||
- versioned manifest со schema, clean local-transcriber source commit,
|
||||
source/model/runtime/build hashes и расписанием;
|
||||
- исходные ссылки, подготовленные WAV и recipe преобразования;
|
||||
- ASR-sidecar и опорную разметку;
|
||||
- raw per-fragment results, intervals, word assignments и probability
|
||||
diagnostics;
|
||||
- machine/power/runtime guards и stderr/stdout logs;
|
||||
- материал и решения слуховой проверки;
|
||||
- байты runtime/model либо проверяемый download recipe с revision, size и hash.
|
||||
|
||||
Хранилище не ссылается на закрытые хранилища задач #41/#42 и остается
|
||||
достаточным для разбора собственного результата. Удаление старых хранилищ не
|
||||
блокирует ни один шаг.
|
||||
|
||||
Публичный отчет содержит `clean local-transcriber source commit`, точные
|
||||
рецепты, хеши, агрегаты, вердикты gates и итоговое решение. В Git, комментарии
|
||||
Gitea, задания на ревью и вывод `--validate-only` не попадают пути,
|
||||
`source/recording IDs`, текст, временные интервалы, сырые строки, содержимое
|
||||
manifest, логи, имена участников или аудио.
|
||||
|
||||
При нарушении приватности стенд останавливается до публикации. Уже
|
||||
сформированный публичный артефакт удаляется из рабочей ветки и создается заново
|
||||
из безопасных агрегатов.
|
||||
|
||||
## Реализация стенда и тесты
|
||||
|
||||
Новый стенд реализуется отдельным модулем
|
||||
`src/local_transcriber/streaming_sortformer_experiment.py`; существующий
|
||||
`benchmark_experiment.py` остается источником общих проверенных механизмов.
|
||||
Стенд получает отдельную schema и только две recipe: `W0-FRESH` и
|
||||
`SORTFORMER-V2-Q8`. Manifest validation выполняется до загрузки моделей.
|
||||
`--validate-only` проверяет:
|
||||
|
||||
- три уникальных source hashes, 300-секундные фрагменты и fresh-basis marker;
|
||||
- human approval и `expected_cluster_count` каждого фрагмента и каждой полной
|
||||
записи в диапазоне `2..4`;
|
||||
- W0 model/runtime hashes и effective values: CPU provider, `debug=True`,
|
||||
`min_duration_on=0.3`, `min_duration_off=0.5`, threads и clustering;
|
||||
- clean local-transcriber worktree и source commit из manifest;
|
||||
- Sortformer revision, size, SHA-256, runtime commit, submodules, build hashes,
|
||||
CPU backend, geometry и post-processing;
|
||||
- одинаковые input/sidecar hashes обеих ветвей;
|
||||
- заранее созданные primary/final schedules;
|
||||
- отсутствие корней старых хранилищ и legacy ID ячеек.
|
||||
|
||||
Минимальные детерминированные тесты выполняются без модели и аудио:
|
||||
|
||||
```bash
|
||||
uv run pytest -q \
|
||||
tests/test_streaming_sortformer_experiment.py \
|
||||
tests/test_benchmark_experiment.py \
|
||||
tests/test_speaker_diarizer.py \
|
||||
tests/test_diarization.py
|
||||
```
|
||||
|
||||
Новый модуль тестов покрывает отклонение `schema`, несовпадение пинов и хешей,
|
||||
требование свежей опоры, обезличенный вывод `--validate-only`, правило
|
||||
`expected_cluster_count`, точное расписание A/B, границы 5%/10%/30%, gates
|
||||
качества, памяти и Sortformer, переход к прослушиванию, безопасную сериализацию
|
||||
и остановку при первом отказе. Стенд C ABI имеет отдельный синтетический тест
|
||||
размеров структур, выбора CPU и эффективной конфигурации; модель в модульных
|
||||
тестах не загружается.
|
||||
|
||||
Критерий завершения реализации стенда: все детерминированные тесты проходят,
|
||||
`--validate-only` проходит на закрытом manifest и публичный вывод проходит
|
||||
privacy scan. Реализация стенда фиксируется чистым коммитом исходников,
|
||||
совпадающим с manifest. Только после этого разрешен первый запуск модели W0.
|
||||
|
||||
## Критерии завершения эксперимента
|
||||
|
||||
- [ ] Свежая опора подтверждена владельцем и не наследует старые контрольные
|
||||
значения.
|
||||
- [ ] Runtime, модель, сборка и оба рецепта закреплены и проверены до моделей.
|
||||
- [ ] Clean local-transcriber source commit сохранен в закрытом хранилище и
|
||||
публичном отчете, а `--validate-only` проверяет его до моделей.
|
||||
- [ ] Свежий W0 принят либо итог `stop` объясняет провал базы сравнения.
|
||||
- [ ] Первичный A/B завершен; решение 10% применено без дополнительных ветвей.
|
||||
- [ ] При продолжении завершены ровно пять финальных циклов, медиана и MAD.
|
||||
- [ ] Каждая выполненная ячейка имеет вердикты качества, текста, памяти и
|
||||
Sortformer.
|
||||
- [ ] При медиане 30% выполнены три пары на полных записях и пять слуховых
|
||||
решений.
|
||||
- [ ] Все остановленные шаги имеют первую точную причину и хеш результата.
|
||||
- [ ] Закрытое хранилище самодостаточно; публичный отчет содержит только безопасные
|
||||
агрегаты и SHA-256.
|
||||
- [ ] Итог равен `go` или `stop`; `needs-user` остается открытым до решения.
|
||||
- [ ] Ни один результат автоматически не меняет production-зависимости,
|
||||
профиль, CLI, config или модель по умолчанию.
|
||||
Reference in new issue
Block a user