- BrainTools - https://www.braintools.ru -
Имея на руках всего три оставшихся слота для отправки, наша команда вошла в последние часы дататона [1].
Всю предыдущую неделю мы наращивали ансамбль, который встал на отметке 0.6605. Каждая новая модель приносила от силы одну-две тысячных прироста и требовала лишних полутора часов инференса. Восьмая архитектура не имела смысла.
Поэтому мы прекратили возиться с моделями и переключились на то, как из уже посчитанных векторов строится индекс соседей. Рассчитывали попасть куда-то в диапазон 0.67–0.69. Получили 0.7042 и десятое место среди 93 участников.
Это рассказ о неделе работы с голосовыми эмбеддингами: что за задача перед нами стояла, почему она оказалась неожиданно трудной, где мы потеряли два дня и почему прорыв в итоге пришёл совсем не с той стороны, откуда его ждали.
Дано: 134 697 аудиофайлов в формате FLAC, полностью лишённых меток, имён дикторов и любых сопутствующих данных. Просто неструктурированная груда записей.
Цель: для каждой отдельной записи отыскать десять других фрагментов, принадлежащих тому же человеку.
Обратите внимание [2] на то, чего здесь намеренно нет. Нет заранее заданного списка дикторов, из которого следует выбирать. Нет эталонных образцов голоса. Содержание речи не имеет значения и не анализируется. И это не задача «установления личности»: система уклоняется от вопроса «кто это» и вместо него решает «какие ещё дорожки в этом массиве принадлежат тому же голосу».
В литературе такая постановка называется speaker retrieval и отличается от двух более привычных. Верификация спрашивает: «эти два фрагмента произнёс один и тот же человек?» – бинарный вопрос, управляемый порогом. Идентификация спрашивает: «кто из N известных дикторов это сказал?» – задача с закрытым множеством. Наша же задача поиск по открытому корпусу, где и запросы, и ответы находятся внутри одного анонимного массива.

Метрика оценки – Precision@10. Для каждого запроса мы смотрим первую десятку результатов и считаем, сколько из них действительно принадлежит искомому диктору. Семь совпадений дают 0.7 для этого конкретного запроса, а итоговая оценка усредняется по всему набору.
На этом различии стоит остановиться, потому что масштаб принципиально меняет характер задачи, а вовсе не только время счёта.
В верификации вы оцениваете пару фрагментов и применяете порог. Ошибки [3] происходят на конкретных парах, а качество описывается кривой ошибок, где отражено соотношение ложных допусков и ложных отказов.
При поиске по всему корпусу каждый запрос конкурирует со всеми оставшимися 134 696 записями. Достаточно, чтобы у десяти случайных людей голоса при определённых условиях записи оказались акустически похожими и настоящее совпадение окажется вытеснено, а запрос испорчен. С ростом корпуса вероятность встретить таких случайных соседей только увеличивается.
Отсюда следует контринтуитивный вывод: P@10 на уровне 0.70 при таком масштабе не означает, что модель ошибается в трети случаев по причине собственной слабости. Скорее это отражает жёсткую конкуренцию внутри огромного множества претендентов. Для сравнения: базовое решение организаторов набирало всего 0.0799.
Общая архитектура одинакова у всех участников и по большому счёту не меняется уже лет десять.
Энкодер отображает аудио переменной длины в вектор фиксированной размерности – эмбеддинг диктора. Векторы приводятся к единичной длине. После этого близость считается скалярным произведением, а поиск ближайших соседей берёт на себя FAISS.
Вся настоящая сложность спрятана внутри f_theta.
Исторически господствующим подходом были i-векторы – факторный анализ поверх гауссовых смесей, эпоха, предшествовавшая глубокому обучению [4]. Им на смену пришли x-векторы (Snyder et al., 2018): свёрточные сети с временным контекстом и статистическим пулингом, обученные различать дикторов на больших размеченных корпусах, а на инференсе отдающие активации скрытого слоя.
С тех пор архитектуры заметно усложнились. ECAPA-TDNN [5] (2020) добавила внимание по каналам, многомасштабную агрегацию признаков и attentive statistics pooling, закрепившись в роли рабочей лошадки отрасли. Параллельно развивались варианты на основе ResNet, породившие модели вроде WeSpeaker ResNet293. Из недавнего ReDimNet [6] от IDRnD (2024), которая перераспределяет временное и частотное измерения между блоками сети.
Стоит также сказать, почему косинусная близость вообще оказывается работоспособной. Современные энкодеры обучаются с угловым отступом (AAM-softmax, он же ArcFace, изначально получивший известность в распознавании лиц). Такая функция потерь явным образом разносит классы по гиперсфере: каждый диктор занимает узкий конус, а между конусами остаются отчётливые угловые зазоры. В результате скалярное произведение нормированных векторов служит естественной мерой сходства, а тяжёлые вероятностные бэкенды вроде PLDA для таких моделей становятся практически излишними.
Обучаются подобные системы, как правило, на VoxCeleb – это несколько тысяч публичных лиц и порядка миллиона аудиофрагментов, нарезанных из интервью на YouTube.
Фундаментальный изъян голосовых эмбеддингов в том, что они добросовестно кодируют не только голосовой тракт говорящего.
В вектор просачивается информация о языке, о конкретных произнесённых словах, о длительности высказывания, о микрофоне, о кодеке, об окружающем шуме, о реверберации помещения и, что раздражает сильнее всего, о полосе частот канала.

Из-за этого записи одного человека не образуют аккуратный обособленный кластер, а размазываются по нескольким областям, продиктованным условиями записи. И наоборот: записи разных людей, сделанные в одинаковой обстановке, сближаются между собой. Это явление обычно формулируют так: система выучивает канал, а не диктора.
Борьба именно с этой проблемой съела у нас всю неделю.
Мы загрузили SpeechBrain ECAPA-TDNN, предобученную на VoxCeleb, прогнали инференс и получили примерно 0.35.
Результат не выглядел откровенно испорченным, и именно этим он был коварен. Сабмиты проходили проверку. Векторы считались корректно. На слух [7] ближайшие соседи звучали правдоподобно похоже – тембр, темп, манера. Типичная реакция [8] в такой ситуации списать VoxCeleb-модель как неподходящую для целевого домена и перейти на другую архитектуру.
Вместо этого мы решили проверить собственный пайплайн. Взяли один файл, посчитали для него вектор своим скриптом и официальной реализацией SpeechBrain, а затем сравнили.
Косинусная близость составила 0.514.
Веса были идентичны. Расхождение крылось в препроцессинге. В нашей реализации отсутствовали два принципиальных шага:
вычитание среднего по времени из log-mel-признаков каждой записи;
нормализация выходных векторов по сохранённым статистикам модели.
Первая операция это стандартная mean normalization, придуманная ровно для того, чтобы убирать артефакты канала. Вычитая постоянное спектральное смещение, вносимое конкретным микрофоном и помещением, мы устраняем влияние среды. Именно этот шаг заставляет модель сосредоточиться на дикторе, а не на записывающей аппаратуре.
После исправления сходство с эталонной реализацией подскочило до 0.9964, а P@10 — до 0.5062. Ни архитектуру, ни веса мы не меняли. Половина итогового прироста пришла целиком из двух строчек препроцессинга.
Доверься мы первому впечатлению [9] и уйди перебирать модели весь дататон был бы потрачен на отладку собственных ошибок вместо доработки энкодеров.
Следующий шаг выглядит неочевидным для новичков, хотя в распознавании дикторов представляет собой давнюю традицию.
Сырая косинусная близость 0.7 не несёт абсолютного смысла. Для одной записи это может быть сосед первого ранга, оторвавшийся от остальных с огромным отрывом. Для другой совершенно рядовое значение, потому что образец окружён плотным облаком из полусотни файлов с такими же оценками. Сравнивать эти два числа напрямую некорректно, а метрика тем не менее требует единого ранжированного списка.
Чтобы с этим справиться, отрасль опирается на целое семейство методов нормализации оценок, восходящих к оценкам NIST конца 1990-х и 2000-х: Z-norm, T-norm, S-norm и их потомки. Основной принцип у всех один – скорректировать оценку с учётом того, насколько сильно она выделяется на фоне заведомо чужих записей.
Мы применили AS-Norm, адаптивную симметричную нормализацию, которая нормирует оценку с обеих сторон пары:
Взяв 10 000 тестовых векторов в качестве опорной выборки C, мы считали статистику по первой тысяче совпадений. Это подняло результат с 0.5062 до 0.5367.

Следом мы поэкспериментировали с multi-crop: нарезали запись на пять фрагментов, извлекали эмбеддинг для каждого и усредняли. В первой итерации усреднение выполнялось до L2-нормализации, из-за чего фрагменты с аномально большой нормой непропорционально перекашивали результат. Смена порядка на L2 → average → L2 это исправила.
Любопытно, что сам по себе multi-crop отработал хуже обычного одинарного прогона: 0.4792 против 0.5062. Однако смесь 0.25 × single + 0.75 × multi-crop вместе с AS-Norm дала 0.5617. Компонент, проигрывающий в одиночку, оказался полезен внутри ансамбля — за неделю эта закономерность повторилась ещё дважды.
Организаторы предоставили обучающую часть из 673 277 файлов и 11 053 дикторов. Игнорировать такой ресурс казалось неразумным, и мы взялись за дообучение.
Здесь нас поджидала ловушка, характерная именно для этой области, и разобрать её стоит подробно, не как признание в провале, а потому что на ней регулярно спотыкаются те, кто приходит в распознавание дикторов из общего машинного обучения.
В стандартных задачах классификации случайное разбиение по объектам уместно. В распознавании дикторов оно строго противопоказано. Разбиение обязано быть speaker-disjoint: люди, присутствующие в обучающей выборке, должны полностью отсутствовать в валидационной и тестовой частях. Все стандартные протоколы это предписывают; тестовые списки VoxCeleb специально сконструированы как speaker-disjoint, и это не избыточная осторожность, а часть определения задачи. Система обязана обобщаться на голоса, которых не слышала. Если диктор пересекается между выборками, вы измеряете запоминание [10], а не обобщение.
Мы изначально разбили данные по файлам. В результате фрагменты одного и того же человека попали и в обучение, и в валидацию.
Локальная метрика отрапортовала внушительные 0.9446. На публичном лидерборде тот же самый чекпоинт набрал 0.4504.
Это резкое падение ровно та цена, которая платится за неверное разбиение, и распознали мы его в тот момент, когда сопоставили локальную оценку с результатом отправки. Правильным исправлением было бы пересобрать сплит по дикторам и продолжить обучение. Но времени не оставалось: до дедлайна было около двух суток, а один цикл «обучить – прогнать инференс на 134 тысячах файлов – отправить» занимал часы.
Мы предприняли ещё два захода с LMFT. Первый дал локальные 0.9225 и примерно 0.58 на лидерборде. Существенное улучшение, но всё ещё хуже нашего текущего ансамбля. Второй завершился странно: локальные 0.9367 при 0.0298 на лидерборде. Разбираться основательно было некогда, но в логах загрузки чекпоинта обнаружился отсутствующий ключ fin_wght1d.w, а полученные векторы практически не коррелировали с исходными эмбеддингами ReDimNet. Модель попросту не инициализировалась как следует.
Дообучение в распознавании дикторов — стандартная и работающая практика, но она требует строгого протокола и заметного времени на итерации. Не имея ни того ни другого, мы выбрали другой путь.
Когда одной модели не хватает, логичным шагом становится объединение нескольких архитектур.

Подключение WeSpeaker ResNet293 подняло результат до 0.6143, ReDimNet-B6 довела его до 0.6345. Добавление SpeechBrain ResNet и возвращение ECAPA вывели метрику на 0.6574.
Работает это по той же причине, по которой ансамбли работают везде в машинном обучении: разные модели ошибаются по-разному. Проверка на случайной выборке из 500 файлов показала, что ближайший сосед совпадал у разных энкодеров лишь в 12–21% случаев. Свой вклад в это разнообразие внесли различия в структуре сетей, обучающих наборах, предпочтениях по длительности и акустических каналах.
Скажу прямо: формально независимость этих ошибок мы не доказали. Без эталонной разметки для тестовой части проверить, кто именно из моделей прав, было невозможно. Тем не менее наблюдаемый стабильный прирост от конкатенации оправдывал продолжение.
К вечеру 18 апреля мы находились на 20-м месте с результатом 0.6574, и в запасе оставались сутки.
Взяв по 5000 файлов из обучающей и тестовой частей, мы посчитали спектральный rolloff – пороговую частоту, ниже которой сосредоточено 85% энергии сигнала. Медианные значения составили 3044 Hz для обучающей выборки и 1881 Hz для тестовой. Записи с rolloff ниже 4 кГц составили 77.1% обучающего аудио против 89.1% тестового.
У тестовой части заметно более узкая полоса. Такая сигнатура указывает на телефонные каналы и сильное сжатие, где полоса обычно обрезается в районе 3.4-4 кГц, лишая сигнал верхних областей спектра, важных для различения голосов.
Между тем наши энкодеры обучались на VoxCeleb, состоящем из широкополосных интервью с YouTube. Это расхождение обнажило явное несовпадение доменов.
Прогон Whisper-small по случайным выборкам дал представление о языковом составе: русский определялся реже, чем английский, испанский и португальский. При отсутствии ручной разметки это осталось качественным наблюдением, а не твёрдым фактом, но гипотезу о том, что набор далеко выходит за пределы русской речи, оно поддержало.
Из этого наблюдения о полосе родилась седьмая ветка ансамбля. Мы взяли ReDimNet и искусственно портили ей вход преобразованием 16 kHz → 8 kHz → 16 kHz. Прогоняя аудио через узкое телефонное горлышко перед извлечением эмбеддингов, мы заставляли сеть опираться на признаки, которые переживают реальные условия телефонной связи.
Этот 384-мерный блок поднял результат с 0.6591 до 0.6605.

Финальный вектор признаков конкатенировал семь различных компонентов:
|
Сигнал |
Размерность |
|---|---|
|
WeSpeaker ResNet293-LM |
256 |
|
IDRnD ReDimNet-B6 |
192 |
|
SpeechBrain ECAPA-TDNN |
192 |
|
SpeechBrain ResNet |
256 |
|
Whisper-small, mean+std pooling |
1536 |
|
ReDimNet multi-crop |
192 |
|
ReDimNet 16/8 kHz combo |
384 |
|
После конкатенации |
3008 |
Каждая часть проходила независимую нормализацию, умножалась на свой вес, объединялась с остальными и нормализовалась ещё раз.

Whisper попал сюда по остаточному принципу. Он нацелен на распознавание речи, а не на верификацию диктора, однако его усреднённые скрытые состояния улавливают характеристики канала и языка. Он вводился одновременно с multi-crop ReDim, и вместе они сдвинули результат с 0.6574 до 0.6591, так что изолированный вклад Whisper остался неизмеренным. В продакшн-пайплайне я бы проверил его первым: полторы тысячи измерений из трёх тысяч составляют половину вектора без подтверждённой пользы.
Ансамбль показывал 0.6605, у нас оставались три попытки отправки и два метода-кандидата.
Alpha-QE применяет расширение запроса через усреднение с ближайшими соседями – простая и предсказуемая техника. K-reciprocal re-ranking сложнее и потенциально мощнее. Ни то ни другое нельзя было проверить локально из-за отсутствия валидационной выборки, а каждая проба съедала одну из оставшихся отправок.

Обычный поиск ближайших соседей асимметричен. Файл j может попасть в первую десятку соседей i, тогда как i отсутствует в десятке j из-за более плотного окружения вокруг j.
K-reciprocal re-ranking, заимствованный из исследований по re-identification людей [11], требует взаимного согласия:
Мы извлекали top-K1 соседей для каждого аудиофайла, строили множества взаимных соседей, расширяли их за счёт пересекающихся локальных окрестностей и смешивали пересчитанную оценку с исходной:
K1 = 20
K2 = 6
lambda = 0.3
Инженерная деталь для тех, кто станет это воспроизводить: полная матрица сходств для 134 697 объектов во float32 требует порядка 72 GB памяти [12]. Держать её целиком негде, поэтому мы обрабатывали батчи по 4096 запросов, сохраняя лишь top-K1 индексы и значения. На RTX 3090 полный пересчёт занимал полторы минуты – дешевле, чем один проход инференса через любой из семи энкодеров.
Применение AS-Norm поверх уточнённых результатов подняло качество ещё выше.
P@10 = 0.7042, перемещение с 20-го места на 10-е.

Скачок в 0.0437, полученный чистым пересчётом соседей, превзошёл суммарный прирост от всех моделей, добавленных за предыдущие сутки.
Строгого доказательства такому росту у нас нет, но правдоподобное объяснение лежит в геометрии многомерных пространств: в векторных пространствах возникают «хабы» – точки, оказывающиеся ближайшими соседями необычно большого числа других точек просто в силу пространственных свойств, а не смысловой близости. Такие хабы засоряют выдачу без разбора. Требование взаимности их отфильтровывает, поскольку сам хаб не держит эти записи в собственной десятке.
Короткий перечень неудач избавит вас от лишних экспериментов.
GigaAM-v3 возвращала NaN в fp16. Переход на bf16 снял падения, но изолированный P@10 рухнул до 0.0021. Её внутренние представления, вероятно, не подходят для различения дикторов, хотя глубоко мы это не исследовали.
CN-Celeb ResNet34 выдала 0.2748. По одному замеру невозможно вычленить причину – языковое несовпадение, сдвиг домена или ограничения архитектуры.
Простое взвешенное усреднение векторов вместо конкатенации отставало примерно на 0.003. Подмешивание дообученных и SSL-веток стабильно ухудшало позицию на публичном лидерборде.
Alpha-QE мы реализовали и прогнали, но результаты не сохранили. Потеря возможности напрямую сравнить две стратегии re-ranking – самое досадное упущение проекта.

Решение воспроизводится через Docker: prepare_models.sh скачивает веса, run_inference.sh выполняет пайплайн. Полный прогон занимает около 2.5 часов на RTX 3090. Работа без доступа к сети проверялась от начала до конца на 1500 аудиофайлах.
Тем не менее метрика требует правильного контекста:
она отражает публичный лидерборд одного соревнования;
язык и спектральный rolloff оценивались автоматически и по выборкам;
Precision@10 считает все ошибки равнозначными, тогда как в реальности их стоимость различается;
разбивка по полу, возрасту, акценту и условиям записи не проводилась;
speaker retrieval ранжирует акустическое сходство, а не выполняет криминалистическое установление личности.
Последнее различие принципиально. Система, которая достаёт похожие голоса из архива, и система, которая юридически утверждает личность человека, принципиально разные вещи с принципиально разной ценой ошибки.
Главный вывод недели: большую часть времени мы оптимизировали векторы, а прорыв пришёл от того, как из этих эмбеддингов строятся списки соседей.
Для задач крупномасштабного поиска это, похоже, общее правило. Энкодеры задают потолок качества, но преодоление разрыва между текущим результатом и этим потолком редко требует более тяжёлой модели – оно требует работы с геометрией поиска через нормализацию оценок, симметризацию соседства и расширение запроса. Все эти операции выполняются за минуты и не требуют ни одной эпохи обучения.
Осознание этого в последний вечер с тремя оставшимися попытками стало для нас уроком. Если вы столкнулись с похожей задачей,то начинайте отсюда.
P.S. Репозиторий решения: GG1KENOBI/Dataton_Tembrrrr [13]. Короткие заметки про прикладной AI публикуем в @aify_studio [14].
X-vectors: Robust DNN Embeddings for Speaker Recognition [16]
ECAPA-TDNN [5]
SpeechBrain [17]
Analysis of Score Normalization in Multilingual Speaker Recognition [18]
ReDimNet [6]
Re-ranking Person Re-identification with k-reciprocal Encoding [11]
Hubs in Space: Popular Nearest Neighbors in High-Dimensional Data [20]
FAISS [21]
Автор: GG1KENOBI
Источник [22]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/34600
URLs in this post:
[1] дататона: https://dataton-kryptonite.ru/
[2] внимание: http://www.braintools.ru/article/7595
[3] Ошибки: http://www.braintools.ru/article/4192
[4] обучению: http://www.braintools.ru/article/5125
[5] ECAPA-TDNN: https://arxiv.org/abs/2005.07143
[6] ReDimNet: https://arxiv.org/abs/2407.18223
[7] слух: http://www.braintools.ru/article/6251
[8] реакция: http://www.braintools.ru/article/1549
[9] впечатлению: http://www.braintools.ru/article/2012
[10] запоминание: http://www.braintools.ru/article/722
[11] исследований по re-identification людей: https://arxiv.org/abs/1701.08398
[12] памяти: http://www.braintools.ru/article/4140
[13] GG1KENOBI/Dataton_Tembrrrr: https://github.com/GG1KENOBI/Dataton_Tembrrrr
[14] @aify_studio: https://t.me/aify_studio
[15] NIST Speaker Recognition Evaluation: https://www.nist.gov/itl/iad/mig/speaker-recognition
[16] X-vectors: Robust DNN Embeddings for Speaker Recognition: https://danielpovey.com/files/2018_icassp_xvectors.pdf
[17] SpeechBrain: https://arxiv.org/abs/2106.04624
[18] Analysis of Score Normalization in Multilingual Speaker Recognition: https://www.isca-archive.org/interspeech_2017/matejka17_interspeech.html
[19] VoxCeleb: large-scale speaker verification in the wild: https://www.sciencedirect.com/science/article/pii/S0885230819302712
[20] Hubs in Space: Popular Nearest Neighbors in High-Dimensional Data: https://www.jmlr.org/papers/v11/radovanovic10a.html
[21] FAISS: https://github.com/facebookresearch/faiss
[22] Источник: https://habr.com/ru/articles/1043378/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1043378
Нажмите здесь для печати.