docs(research): уточнены batch-контракты embedding-моделей
- Зачем: - вопрос тикета требует проверить формы официальных release-графов, а исходная записка опиралась только на экспортные контракты. - Что: - зафиксированы реальные формы и CPU smoke-test batch size 2 для WeSpeaker, CAMPPlus и TitaNet. - уточнены поддержка equal-length batch у CAMPPlus и fallback между S8S8, U8U8 и U8S8. - Проверка: - git diff --check.
This commit is contained in:
1 parent
6420eb07ea
commit
82dbfcb332
1 file changed
+25
-14
@@ -6,9 +6,10 @@
|
|||||||
менялись.
|
менялись.
|
||||||
|
|
||||||
**Метод:** проверены `sherpa-onnx==1.13.5`, `onnxruntime==1.28.0`, официальные
|
**Метод:** проверены `sherpa-onnx==1.13.5`, `onnxruntime==1.28.0`, официальные
|
||||||
скрипты экспорта и исходники владельцев моделей. ONNX-модели не скачивались.
|
скрипты экспорта и исходники владельцев моделей. Три официальных release asset
|
||||||
Формы ниже подтверждены экспортными контрактами, проверками метаданных и кодом
|
прочитаны потоком без сохранения на диск: WeSpeaker ResNet34 LM, CAMPPlus en и
|
||||||
загрузчика. Файлы из выпуска повторно не разбирались.
|
TitaNet small. Их входы, выходы и метаданные разобраны через ORT 1.28.0; для
|
||||||
|
каждого выполнен CPU smoke-test с batch size 2.
|
||||||
|
|
||||||
## Вопрос и краткий ответ
|
## Вопрос и краткий ответ
|
||||||
|
|
||||||
@@ -64,9 +65,18 @@ ORT по умолчанию исполняет граф последовател
|
|||||||
|
|
||||||
| Модель | Вход и выход официального экспорта | Следствие для batch |
|
| Модель | Вход и выход официального экспорта | Следствие для batch |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| WeSpeaker ResNet34 LM | Один `float32`-вход `[B, T, 80]`, один выход `[B, D]`. Скрипт, которым sherpa-onnx добавляет метаданные, проверяет символические `B`, `T`, размерность 80 и единственный выход. Метаданные включают `framework=wespeaker`, `sample_rate`, `output_dim`, `normalize_samples=0` ([проверка sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/scripts/wespeaker/add_meta_data.py), [экспорт WeSpeaker](https://github.com/wenet-e2e/wespeaker/blob/master/wespeaker/bin/export_onnx.py)). | Равные `T` можно сложить по `B`. Длины или маску граф не принимает; дополнение участвует в pooling и меняет эмбеддинг. |
|
| WeSpeaker ResNet34 LM | Release asset имеет один `float32`-вход `[B, T, 80]` и выход `[B, 256]` ([asset](https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/wespeaker_en_voxceleb_resnet34_LM.onnx)). Скрипт, которым sherpa-onnx добавляет метаданные, проверяет символические `B`, `T`, размерность 80 и единственный выход. Метаданные включают `framework=wespeaker`, `sample_rate`, `output_dim`, `normalize_samples=0` ([проверка sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/scripts/wespeaker/add_meta_data.py), [экспорт WeSpeaker](https://github.com/wenet-e2e/wespeaker/blob/master/wespeaker/bin/export_onnx.py)). | Равные `T` можно сложить по `B`. Длины или маску граф не принимает; дополнение участвует в pooling и меняет эмбеддинг. |
|
||||||
| CAMPPlus zh/en | Экспорт создает `float32`-вход `[N, T, 80]`, метаданные `framework=3d-speaker`, `output_dim`, `normalize_samples=1`, `feature_normalize_type=global-mean` ([скрипт sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/scripts/3dspeaker/export-onnx.py)). | В скрипте есть ошибка: выход называется `embedding`, а dynamic axis задан для `embeddings`. Поэтому динамичность оси выхода файла из выпуска по исходнику не доказана. Upstream подтверждает лишь, что batch равной длины *должен* работать; для разных длин нужна маска ([ответ разработчика](https://github.com/k2-fsa/sherpa-onnx/issues/780)). |
|
| CAMPPlus en | Release asset имеет `float32`-вход `[N, T, 80]` и выход с динамической первой осью `[*, 512]` ([asset](https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/3dspeaker_speech_campplus_sv_en_voxceleb_16k.onnx)). Метаданные: `framework=3d-speaker`, `output_dim=512`, `normalize_samples=1`, `feature_normalize_type=global-mean` ([экспорт sherpa-onnx](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/scripts/3dspeaker/export-onnx.py)). | Несмотря на опечатку экспортного скрипта (`embedding`/`embeddings`), release asset принимает batch равной длины и возвращает все строки. Для разных длин граф по-прежнему не принимает маску или длины. |
|
||||||
| NeMo TitaNet small | Два входа: `float32 [N, C, T]` и `int64 [N]` с длинами; embedding имеет форму `[N, D]` ([контракт C++-обертки](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/sherpa-onnx/csrc/speaker-embedding-extractor-nemo-model.h)). Метаданные содержат `framework=nemo`, `output_dim`, `feat_dim`, sample rate, параметры окна и нормализации ([экспорт](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/scripts/nemo/speaker-verification/export-onnx.py)). | Граф имеет нужный контракт для batch переменной длины с дополнением. Но sherpa-onnx создает обе входные формы с `N=1` и возвращает только первую строку ([реализация](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/sherpa-onnx/csrc/speaker-embedding-extractor-nemo-impl.h)). |
|
| NeMo TitaNet small | Release asset имеет входы `float32 [N, 80, T]` и `int64 [N]`; выходы — logits `[N, 16681]` и embedding `[N, 192]` ([asset](https://github.com/k2-fsa/sherpa-onnx/releases/download/speaker-recongition-models/nemo_en_titanet_small.onnx), [контракт C++-обертки](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/sherpa-onnx/csrc/speaker-embedding-extractor-nemo-model.h)). Метаданные содержат `framework=nemo`, `output_dim`, `feat_dim`, sample rate, параметры окна и нормализации ([экспорт](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/scripts/nemo/speaker-verification/export-onnx.py)). | Граф принимает batch и вектор длин. Но sherpa-onnx создает обе входные формы с `N=1` и возвращает только первую строку ([реализация](https://github.com/k2-fsa/sherpa-onnx/blob/v1.13.5/sherpa-onnx/csrc/speaker-embedding-extractor-nemo-impl.h)). |
|
||||||
|
|
||||||
|
Smoke-test с синтетическими `float32`-признаками и одним intra-op thread дал
|
||||||
|
для WeSpeaker `(2, 256)`, для CAMPPlus `(2, 512)` и для TitaNet `(2, 192)`.
|
||||||
|
У WeSpeaker и CAMPPlus результат batch size 2 совпал с конкатенацией двух
|
||||||
|
последовательных `Run` (`max_abs_diff=0`). У TitaNet элемент длиной 100 кадров
|
||||||
|
также совпал, но элемент длиной 80, дополненный до 100 кадров, отличался от
|
||||||
|
отдельного непаддированного вызова (`max_abs_diff=0,0269`). Это не тест качества
|
||||||
|
на голосе, а подтверждение, что допустимый порог для variable-length batch нужно
|
||||||
|
определить в прототипе, а не считать эквивалентность гарантированной контрактом.
|
||||||
|
|
||||||
WeSpeaker ResNet34 состоит из Conv2d-блоков и statistics pooling
|
WeSpeaker ResNet34 состоит из Conv2d-блоков и statistics pooling
|
||||||
([исходник WeSpeaker](https://github.com/wenet-e2e/wespeaker/blob/master/wespeaker/models/resnet.py));
|
([исходник WeSpeaker](https://github.com/wenet-e2e/wespeaker/blob/master/wespeaker/models/resnet.py));
|
||||||
@@ -87,9 +97,9 @@ assets нет. Статический INT8 здесь означает собс
|
|||||||
|
|
||||||
| Способ | Техническая доступность | Вердикт |
|
| Способ | Техническая доступность | Вердикт |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Настоящий batch | Граф WeSpeaker поддерживает равные длины; CAMPPlus требует прямой проверки файла из выпуска; TitaNet поддерживает разные длины через второй вход. Sherpa-onnx для всех трех жестко формирует `N=1` и не имеет batch API. | Прототипировать только TitaNet и только условно для режима с известным числом говорящих. Для WeSpeaker/CAMPPlus без маски возможны лишь группы с одинаковым `T`; ожидаемая наполняемость неизвестна. |
|
| Настоящий batch | Release-графы WeSpeaker и CAMPPlus поддерживают batch равной длины; TitaNet принимает batch и второй вход с длинами. Sherpa-onnx для всех трех жестко формирует `N=1` и не имеет batch API. | Прототипировать только TitaNet и только условно для режима с известным числом говорящих. Для WeSpeaker/CAMPPlus без маски возможны лишь группы с одинаковым `T`; ожидаемая наполняемость неизвестна. |
|
||||||
| Несколько stream, одна session | Stream независимы, `Compute` использует локальные тензоры, а ORT разрешает нескольким потокам одновременно вызывать `Run` одной session ([архитектура ORT](https://onnxruntime.ai/docs/reference/high-level-design.html), [контракт 1.28.0](https://github.com/microsoft/onnxruntime/blob/v1.28.0/onnxruntime/core/session/inference_session.h)). Текущий цикл sherpa-onnx этого не делает. | Достойно узкого прототипа на WeSpeaker. У одной session общий intra-op pool; нужно сравнить внутренний и внешний параллелизм. Полный pool для каждого worker не нужен. |
|
| Несколько stream, одна session | Stream независимы, `Compute` использует локальные тензоры, а ORT разрешает нескольким потокам одновременно вызывать `Run` одной session ([архитектура ORT](https://onnxruntime.ai/docs/reference/high-level-design.html), [контракт 1.28.0](https://github.com/microsoft/onnxruntime/blob/v1.28.0/onnxruntime/core/session/inference_session.h)). Текущий цикл sherpa-onnx этого не делает. | Достойно узкого прототипа на WeSpeaker. У одной session общий intra-op pool; нужно сравнить внутренний и внешний параллелизм. Полный pool для каждого worker не нужен. |
|
||||||
| Несколько session | Можно создать несколько extractor, но каждая session получает собственные пулы потоков и арены памяти. ORT прямо отмечает эти накладные расходы для двух session ([ответ сопровождающего](https://github.com/microsoft/onnxruntime/issues/11628)). | Не брать как самостоятельный кандидат. Допустима одна контрольная ячейка против shared-session, чтобы подтвердить отказ по реальному времени и RSS. |
|
| Несколько session | Можно создать несколько extractor, но по умолчанию каждая session получает собственный intra-op pool и CPU arena. ORT отдельно предлагает общий pool против конкуренции session pools и общий allocator против роста памяти ([thread management](https://onnxruntime.ai/docs/performance/tune-performance/threading.html), [C API guide](https://onnxruntime.ai/docs/get-started/with-c.html#share-allocator-s-between-sessions)). | Не брать как самостоятельный кандидат. Допустима одна контрольная ячейка против shared-session, чтобы подтвердить отказ по реальному времени и RSS. |
|
||||||
| Статический INT8 | ORT предоставляет `quantize_static`, использует calibration data и рекомендует static quantization для CNN. Для CPU первым выбором служит S8S8 QDQ; квантизация может ухудшить точность и даже скорость ([официальное руководство](https://onnxruntime.ai/docs/performance/model-optimizations/quantization.html)). | Главный кандидат для действующего WeSpeaker. CAMPPlus и TitaNet квантизовать только после продуктового решения использовать соответствующую модель. |
|
| Статический INT8 | ORT предоставляет `quantize_static`, использует calibration data и рекомендует static quantization для CNN. Для CPU первым выбором служит S8S8 QDQ; квантизация может ухудшить точность и даже скорость ([официальное руководство](https://onnxruntime.ai/docs/performance/model-optimizations/quantization.html)). | Главный кандидат для действующего WeSpeaker. CAMPPlus и TitaNet квантизовать только после продуктового решения использовать соответствующую модель. |
|
||||||
|
|
||||||
Batch сокращает число `Session::Run` и может лучше загрузить SIMD, но число
|
Batch сокращает число `Session::Run` и может лучше загрузить SIMD, но число
|
||||||
@@ -111,8 +121,11 @@ AVX512-VNNI kernels
|
|||||||
|
|
||||||
Официальное руководство ORT предупреждает:
|
Официальное руководство ORT предупреждает:
|
||||||
|
|
||||||
- на AVX2 и AVX-512 без VNNI путь U8S8 использует `VPMADDUBSW` и может дать
|
- S8S8 QDQ остается первым выбором CPU. Если он дает значимую потерю
|
||||||
saturation; при потере точности предусмотрены `reduce_range` или U8U8;
|
точности, ORT советует проверить U8U8;
|
||||||
|
- отдельный путь U8S8 на AVX2 и AVX-512 без VNNI использует `VPMADDUBSW` и
|
||||||
|
может дать saturation; если до него дойдет матрица, этот риск снижают
|
||||||
|
`reduce_range` или переход на U8U8;
|
||||||
- на x86 с VNNI этой проблемы нет, а INT8 обычно выигрывает больше;
|
- на x86 с VNNI этой проблемы нет, а INT8 обычно выигрывает больше;
|
||||||
- на старом CPU без подходящих инструкций quantize/dequantize overhead способен
|
- на старом CPU без подходящих инструкций quantize/dequantize overhead способен
|
||||||
сделать модель медленнее
|
сделать модель медленнее
|
||||||
@@ -143,8 +156,6 @@ WeSpeaker на старом Intel использовал в среднем 6,84
|
|||||||
не загрузит.
|
не загрузит.
|
||||||
- Точность статического INT8 после калибровки и необходимость исключить отдельные
|
- Точность статического INT8 после калибровки и необходимость исключить отдельные
|
||||||
узлы через quantization debugging.
|
узлы через quantization debugging.
|
||||||
- Фактическая batch-форма выхода CAMPPlus release asset из-за ошибки в экспортном
|
|
||||||
скрипте.
|
|
||||||
- Распределение `T` у пар "окно, локальный говорящий". Без него нельзя оценить
|
- Распределение `T` у пар "окно, локальный говорящий". Без него нельзя оценить
|
||||||
полезность exact-length buckets для WeSpeaker/CAMPPlus.
|
полезность exact-length buckets для WeSpeaker/CAMPPlus.
|
||||||
- Выигрыш shared-session concurrency после ограничения общего числа потоков,
|
- Выигрыш shared-session concurrency после ограничения общего числа потоков,
|
||||||
@@ -165,8 +176,8 @@ WeSpeaker на старом Intel использовал в среднем 6,84
|
|||||||
- только после технического выигрыша повторить действующие проверки числа
|
- только после технического выигрыша повторить действующие проверки числа
|
||||||
голосовых кластеров, purity и слов без говорящего.
|
голосовых кластеров, purity и слов без говорящего.
|
||||||
|
|
||||||
U8U8 или `reduce_range` добавлять лишь при подтвержденной потере точности на
|
При значительной потере точности S8S8 проверить U8U8. Отдельный U8S8 с
|
||||||
AVX2. В первую матрицу эти варианты не входят.
|
`reduce_range` в первую матрицу не входит.
|
||||||
|
|
||||||
### 2. Shared-session streams - второй кандидат
|
### 2. Shared-session streams - второй кандидат
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user