Урезанный непрерывный ASR в Tensorflow

Этот блог поможет вам написать базовую сквозную систему ASR с использованием Tensorflow. Я рассмотрю каждый компонент минимальной нейронной сети и декодер поиска префиксного луча, необходимый для генерации читаемой транскрипции из аудио. Я сталкиваюсь с множеством ресурсов по созданию базовых систем машинного обучения для задач компьютерного зрения и обработки естественного языка, но очень мало ресурсов по распознаванию речи. Это попытка восполнить этот пробел и сделать эту область менее сложной для новичков.

Предпосылки

Знакомство с:

  • Компоненты нейронной сети
  • Обучение нейронной сети
  • Использование языковой модели для получения вероятности последовательности слов

Обзор

  • Предварительная обработка звука: преобразование необработанного звука в числовые функции, которые могут использоваться в качестве входных данных для нейронной сети.
  • Нейронная сеть: простая архитектура для преобразования звуковых функций в вероятностные распределения возможных символов в расшифровке.
  • CTC loss: вычисление потерь без аннотирования каждого временного шага звука соответствующим символом.
  • Декодирование: создание стенограммы из распределений вероятностей для каждого временного шага с использованием префиксного поиска луча и языковой модели.

Я сосредоточусь на нейронной сети, потере CTC и декодировании.

Предварительная обработка аудио

Вам необходимо преобразовать звук в матрицу функций, чтобы передать его в нейронную сеть. Один простой способ - создать спектрограммы.

Эта функция вычисляет кратковременное преобразование Фурье вашего аудиосигнала, а затем вычисляет спектр мощности. На выходе получается матрица, называемая спектрограммой. Вы можете напрямую использовать это как свой ввод. Другими альтернативами этому являются банки фильтров и MFCC. Предварительная обработка звука - это отдельная тема. Подробнее об этом можно прочитать здесь.

Нейронная сеть

Вот простая архитектура.

Вход спектрограммы можно рассматривать как вектор на каждой временной метке. Сверточный слой 1D извлекает признаки из каждого из этих векторов, чтобы получить последовательность векторов признаков для обработки слоем LSTM. Выходные данные уровня (Bi) LSTM передаются на полностью подключенный уровень для каждого временного шага, который дает распределение вероятностей символа на этом временном шаге с использованием активации softmax. Эта сеть будет обучена с помощью функции потерь CTC (Connectionist Temporal Classification). Не стесняйтесь экспериментировать с более сложными моделями после понимания всего конвейера.

Почему CTC? Эта сеть пытается предсказать символ на каждом временном шаге. Однако наши ярлыки - это не символы на каждом временном шаге, а просто транскрипция аудио. Имейте в виду, что каждый символ в транскрипции может занимать несколько временных интервалов. Слово C-A-T будет восприниматься как C-C-C-A-A-T-T, если вы каким-то образом обозначите каждый временной шаг в аудио. Аннотирование набора аудиоданных каждые 10 мс невозможно. CTC решает эту проблему, поскольку не требует от нас маркировки каждого временного шага. Он принимает в качестве входных данных всю матрицу выходных вероятностей указанной выше нейронной сети и соответствующий текст, игнорируя положение и фактические смещения каждого символа в расшифровке.

Расчет убытков CTC

Предположим, что метка истинности - CAT. В пределах этих четырех временных шагов последовательности, такие как C-C-A-T, C-A-A-T, C-A-T-T, _-C-A-T, C-A-T-_, все соответствуют нашей основной истине. Мы рассчитаем вероятность нашей основной истины, суммируя вероятности для всех этих последовательностей. Вероятность единственной последовательности вычисляется путем умножения вероятностей ее символов в соответствии с выходной матрицей вероятностей. Для приведенных выше последовательностей общая вероятность составляет 0,0288 + 0,0144 + 0,0036 + 0,0576 + 0,0012 = 0,1056. Убыток - это отрицательный логарифм этой вероятности. Функция потерь уже реализована в TensorFlow. Вы можете прочитать документацию здесь.

Расшифровка

Результат, который вы получаете от вышеупомянутой нейронной сети, - это матрица CTC. Матрица CTC дает вероятность каждого символа в своем наборе на каждом временном шаге. Мы используем префиксный поиск луча, чтобы сделать значимый текст из этой матрицы.

Набор символов в матрице CTC имеет два специальных маркера, кроме символа алфавита и пробела. Это пустой токен и токен конца строки.

Назначение пустого токена. Временной шаг в матрице CTC обычно невелик. (~ 10 мс) Таким образом, каждый символ произносимого предложения растягивается на несколько временных шагов. Например, C-A-T становится C-C-C-A-A-T-T. Поэтому мы сворачиваем все повторения в возможных строках-кандидатах, которые выделяются в матрице CTC. А как насчет таких слов, как FUNNY, где N должен повторяться? Пустой токен между двумя N предотвращает их сворачивание в один без добавления чего-либо в текст. Итак, F-F-U-N- [blank] -N-N - Y сворачивается в ВЕСЕЛО.

Назначение маркера конца: Конец строки обозначает конец произнесенного предложения. Декодирование на временных шагах после маркера конца строки ничего не добавляет к строке-кандидату.

Процедура:

Инициализация:

  • Изначально у нас есть список кандидатов. Он состоит из одной пустой строки. Список также содержит вероятность того, что этот кандидат оканчивается пустым токеном и оканчивается непустым токеном на каждом временном шаге. Вероятность того, что пустая строка закончится пустым токеном в момент времени 0, равна 1. Вероятность того, что она закончится непустым токеном, равна 0.

Итерации:

  • Мы берем эту строку и добавляем к ней каждый символ по очереди. Мы берем каждую сформированную расширенную строку и вычисляем ее вероятность того, что она закончится пустым и непустым токеном в момент времени = 1. Затем мы сохраняем эти расширенные строки вместе с их вероятностями в нашем списке. Мы вносим этих новых кандидатов в наш список и повторяем процесс для следующего временного шага.
  • Случай A: если добавленный символ - пустой токен, мы не вносим изменений в кандидата.
  • Случай B: если добавленный символ - это пробел, мы умножаем вероятность на число, пропорциональное вероятности кандидата согласно языковой модели. Это препятствует тому, чтобы неправильное написание могло стать лучшим кандидатом. Таким образом, COOL не будет обозначаться как KUL в окончательном выводе.
  • Случай C: если добавленный символ совпадает с последним символом кандидата. (кандидат = FUN. character = N) Мы создаем двух новых кандидатов, FUNN и FUN. Вероятность FUN рассчитывается из вероятности завершения FUN пустым токеном. Вероятность FUNN рассчитывается с использованием вероятности завершения FUN непустым токеном. Итак, если FUN не заканчивается пустым токеном, мы отбрасываем дополнительные N вместо того, чтобы добавлять их.

Вывод:
Лучшим кандидатом после всех временных шагов является вывод.

Мы делаем две модификации, чтобы ускорить этот процесс.

  1. После каждого временного шага мы отбрасываем всех, кроме лучших K кандидатов. Кандидаты сортируются по сумме их вероятностей оказаться в пустом и непустом токене.
  2. Мы не рассматриваем символы, вероятность которых в матрице ниже определенного порога (~ 0,001).

Просмотрите приведенный ниже код для получения подробной информации о реализации.

Это завершает простую систему распознавания речи. Вы можете ввести множество сложностей, чтобы получить лучший результат. Большие сети и уловки предварительной обработки звука очень помогают. Вот полный код.

Примечания:
1. В приведенном выше коде используется TensorFlow 2.0, а образец аудиофайла был взят из набора данных LibriSpeech.
2. Вам нужно будет написать свои собственные генераторы пакетов для обучения набору аудиоданных. Эти детали реализации не включены в код.
3. Вам нужно будет написать собственную функцию языковой модели для части декодирования. Одна из самых простых реализаций - создать словарь биграмм и их вероятностей на основе некоторого текстового корпуса.

Источники:
[1] А.Ю. Hannun et al., Prefix Search Decoding (2014), препринт arXiv arXiv: 1408.2873, 2014
[2] A. Graves et al., CTC Loss (2006), ICML 2006
[ 3] Л. Боргхолт, Prefix Beam Search (2018), Medium