Распознавание речи

Распознавание речи с Python

Сравнение 9 наиболее известных альтернатив.

Технологии распознавания речи стремительно развиваются в течение последних двух лет и переходят из области науки в область инженерии. С ростом популярности голосовых помощников, таких как Alexa, Siri и Google Assistant, некоторые приложения (например, YouTube, Gana, Paytm Travel, My Jio) начинают иметь функции, управляемые голосом. В Slang Labs мы создаем платформу, позволяющую программистам легко дополнять существующие приложения голосовыми функциями.

Автоматическое распознавание речи (ASR) - необходимый первый шаг в обработке голоса. В ASR аудиофайл или речь, произносимая в микрофон, обрабатывается и преобразуется в текст, поэтому она также известна как преобразование речи в текст (STT). Затем этот текст передается в модуль обработки / понимания естественного языка (NLP / NLU) для понимания и извлечения ключевой информации (например, намерений, настроений), после чего предпринимаются соответствующие действия. Существуют также автономные приложения ASR, например расшифровка диктовки или создание субтитров для видео в реальном времени.

Нас интересуют ASR и NLU в целом и их эффективность в цикле преобразования голоса в действие в приложениях, в частности. Наши Android и веб-SDK предоставляют простые API-интерфейсы, подходящие с точки зрения программистов приложений, в то время как платформа Slang берет на себя бремя сложности объединения ASR, NLU и преобразования текста в речь (TTS). Но, естественно, нам интересно узнать о состоянии дел в ASR, NLU и TTS, хотя мы не представляем эти части нашего технологического стека как отдельные предложения SaaS. Это исследование существующих решений ASR - результат этого любопытства.

Сервис против программного обеспечения

Есть две возможности: позвонить в SaaS для преобразования речи в текст в облаке или разместить один из программных пакетов ASR в своем приложении.

Служба - самый простой способ начать. Вы должны подписаться на SaaS и получить ключ / учетные данные. Затем вы готовы использовать его в своем коде либо через конечные точки HTTP, либо через библиотеки на языках программирования по вашему выбору. Однако при достаточно большом использовании он обычно стоит больше денег.

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

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

Пакетная или потоковая передача

Вам необходимо определить, требуется ли вашему приложению пакетная ASR или потоковая ASR.

Пакетный. Если у вас есть аудиозаписи, которые необходимо расшифровать в автономном режиме, пакетная обработка будет более экономичной. В пакетном API аудиофайл передается в качестве параметра, а преобразование речи в текст выполняется за один раз.

Потоковая передача: если вам нужно обрабатывать речь в режиме реального времени (например, в приложениях с голосовым управлением, субтитрах к видео), вам понадобится API потоковой передачи. В случае потокового API он многократно вызывается с доступными фрагментами аудиобуфера. Он может отправлять промежуточные результаты, но окончательный результат доступен в конце.

Все сервисы и программные пакеты имеют пакетные API-интерфейсы, но в некоторых из них на данный момент отсутствуют потоковые API-интерфейсы. Так что, если у вас есть потоковое приложение, это избавляет от некоторых вариантов.

Выбор Python

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

Я выбираю Python для этой статьи, потому что большинство речевых облачных сервисов и программных пакетов ASR имеют библиотеки Python. Кроме того, вы можете запускать фрагменты кода статьи с помощью сопутствующего ему Colab notebook в браузере, не требуя установки чего-либо на ваш компьютер.

Один из распространенных вариантов использования - это сбор звука с микрофона и передача буфера (пакетного или потокового) в API распознавания речи. Неизменно в таких транскриберах доступ к микрофону осуществляется через PyAudio, который реализован поверх PortAudio. Но поскольку микрофон недоступен в Colab, мы его упрощаем. Мы будем использовать полный аудиофайл для изучения пакетного API. А для потокового API мы разбиваем аудиофайл на куски и имитируем поток.

Как лучше всего использовать остальную часть статьи

Покрываются следующие услуги и пакеты программного обеспечения.

Услуги:

  1. Преобразование речи в текст Google
  2. Речь Microsoft Azure
  3. IBM Watson Speech to Test
  4. Amazon Transcribe
  5. Нюанс

Программное обеспечение:

  1. КМУ Сфинкс
  2. Mozilla DeepSpeech
  3. Kaldi
  4. Facebook wav2letter

Примеры кода для wav2letter Amazon Transcribe, Nuance, Kaldi и Facebook не предоставляются из-за некоторых особенностей или ограничений (перечисленных в соответствующих разделах). Вместо этого даются ссылки на образцы кода и ресурсы.

В следующем разделе представлены общие служебные функции и тестовые примеры. В последнем разделе рассматривается пакет Python SpeechRecognition, который обеспечивает абстракцию над пакетным API нескольких сервисов и программных пакетов.

Если вы хотите получить обзор всех услуг и пакетов программного обеспечения, откройте Colab и выполните код, читая этот пост. Если вас интересует только конкретная услуга или пакет, сразу переходите к этому разделу. Но в любом случае поиграйте с кодом в Colab, чтобы лучше изучить его.

Давайте погрузимся в код.

Общая настройка

Загрузите аудиофайлы, которые мы будем использовать для тестирования сервисов и программных пакетов распознавания речи:

$ curl -LO https://github.com/mozilla/DeepSpeech/releases/download/v0.6.0/audio-0.6.0.tar.gz

$ tar -xvzf audio-0.6.0.tar.gz

$ ls -l ./audio/

В нем три аудиофайла. Определите тестовые примеры с необходимыми метаданными:

TESTCASES = [
  {
    'filename': 'audio/2830-3980-0043.wav',
    'text': 'experience proves this',
    'encoding': 'LINEAR16',
    'lang': 'en-US'
  },
  {
    'filename': 'audio/4507-16021-0012.wav',
    'text': 'why should one halt on the way',
    'encoding': 'LINEAR16',
    'lang': 'en-US'
  },
  {
    'filename': 'audio/8455-210777-0068.wav',
    'text': 'your power is sufficient i said',
    'encoding': 'LINEAR16',
    'lang': 'en-US'
  }
]

Также напишите несколько служебных функций. read_wav_file() принимает путь к аудиофайлу и возвращает байты буфера и частоту дискретизации:

def read_wav_file(filename) -> Tuple[bytes, int]:
    with wave.open(filename, 'rb') as w:
        rate = w.getframerate()
        frames = w.getnframes()
        buffer = w.readframes(frames)

    return buffer, rate

simulate_stream() полезен для имитации Steam, чтобы попробовать потоковые API. Обычно используется источник звука, например микрофон. Через определенные промежутки времени микрофон будет генерировать речевой фрагмент, который необходимо передать в потоковый API. Функция simulate_stream() помогает избежать всей этой сложности и сосредоточиться на API. Требуется аудиобуфер и размер пакета, и генерирует фрагменты этого размера. Обратите внимание на оператор yield buf в следующем:

def simulate_stream(buffer: bytes, batch_size: int = 4096):
    buffer_len = len(buffer)
    offset = 0
    while offset < buffer_len:
        end_offset = offset + batch_size
        buf = buffer[offset:end_offset]
        yield buf
        offset = end_offset

Преобразование речи в текст Google

В Google есть функция преобразования речи в текст как одна из облачных служб Google. Имеет библиотеки на C #, Go, Java, JavaScript, PHP, Python и Ruby. Он поддерживает как пакетный, так и потоковый режимы.

Настраивать

Вам понадобятся ваши Учетные данные Google Cloud. Вам нужно будет настроить переменную среды GOOGLE_APPLICATION_CREDENTIALS, указывающую на файл cred:

$ export GOOGLE_APPLICATION_CREDENTIALS='/path/to/google/cloud/cred/file/gc-creds.json'
$ ls -l $GOOGLE_APPLICATION_CREDENTIALS

Пакетный API

Использовать пакетный API преобразования речи в текст очень просто. Вам нужно создать SpeechClient, создать config со звуковыми метаданными и вызвать recognize() метод речевого клиента.

from google.cloud import speech_v1
from google.cloud.speech_v1 import enums

def google_batch_stt(filename: str, lang: str, encoding: str) -> str:
    buffer, rate = read_wav_file(filename)
    client = speech_v1.SpeechClient()

    config = {
        'language_code': lang,
        'sample_rate_hertz': rate,
        'encoding': enums.RecognitionConfig.AudioEncoding[encoding]
    }

    audio = {
        'content': buffer
    }

    response = client.recognize(config, audio)
    # For bigger audio file, replace previous line with following:
    # operation = client.long_running_recognize(config, audio)
    # response = operation.result()

    for result in response.results:
        # First alternative is the most probable result
        alternative = result.alternatives[0]
        return alternative.transcript

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('google-cloud-batch-stt: "{}"'.format(
        google_batch_stt(t['filename'], t['lang'], t['encoding'])
    ))

Когда вы запустите это, вы увидите текст каждого из файлов аудио-теста на выходе:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
google-cloud-batch-stt: "experience proves this"

audio file="audio/4507-16021-0012.wav"    expected text="why should one halt on the way"
google-cloud-batch-stt: "why should one halt on the way"

audio file="audio/8455-210777-0068.wav"    expected text="your power is sufficient i said"
google-cloud-batch-stt: "your power is sufficient I said"

Потоковый API

API потоковой передачи Google также довольно прост. Для обработки аудиопотока вы можете многократно вызывать потоковый API с доступным фрагментом звука, и он вернет вам промежуточные результаты:

from google.cloud import speech
from google.cloud.speech import enums
from google.cloud.speech import types

def response_stream_processor(responses):
    print('interim results: ')

    transcript = ''
    num_chars_printed = 0
    for response in responses:
        if not response.results:
            continue

        result = response.results[0]
        if not result.alternatives:
            continue

        transcript = result.alternatives[0].transcript
        print('{0}final: {1}'.format(
            '' if result.is_final else 'not ',
            transcript
        ))

    return transcript

def google_streaming_stt(filename: str, lang: str, encoding: str) -> str:
    buffer, rate = read_wav_file(filename)

    client = speech.SpeechClient()

    config = types.RecognitionConfig(
        encoding=enums.RecognitionConfig.AudioEncoding[encoding],
        sample_rate_hertz=rate,
        language_code=lang
    )

    streaming_config = types.StreamingRecognitionConfig(
        config=config,
        interim_results=True
    )

    audio_generator = simulate_stream(buffer)  # chunk generator
    requests = (
        types.StreamingRecognizeRequest(audio_content=chunk)
        for chunk in audio_generator
    )
    responses = client.streaming_recognize(
        streaming_config, requests
    )
    # Now, put the transcription responses to use.
    return response_stream_processor(responses)

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('google-cloud-streaming-stt: "{}"'.format(
        google_streaming_stt(
            t['filename'], t['lang'], t['encoding']
        )
    ))

На выходе вы можете видеть, что результат улучшается по мере поступления большего количества звука:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
interim results: 
not final: next
not final: iSpy
not final: Aspira
not final: Xperia
not final: Experian
not final: experience
not final: experience proved
not final: experience proves
not final: experience proves the
not final: experience proves that
not final: experience
final: experience proves this
google-cloud-streaming-stt: "experience proves this"

Речь Microsoft Azure

Когнитивные службы Microsoft Azure - это семейство служб ИИ и когнитивных API. Речевые услуги включают услуги Преобразование речи в текст, Преобразование текста в речь, услуги перевода речи.

Настраивать

Установите пакет речи Azure:

$ pip3 install azure-cognitiveservices-speech

Вы можете включить службу речи и найти учетные данные для своей учетной записи на портале Microsoft Azure. Вы можете бесплатно открыть счет здесь. Учетные данные службы:

AZURE_SPEECH_KEY = 'YOUR AZURE SPEECH KEY'
AZURE_SERVICE_REGION = 'YOUR AZURE SERVICE REGION'

Пакетный API

Пакетный API Azure тоже прост. Он принимает конфигурацию и аудиовход и возвращает текст:

import azure.cognitiveservices.speech as speechsdk

def azure_batch_stt(filename: str, lang: str, encoding: str) -> str:
    speech_config = speechsdk.SpeechConfig(
        subscription=AZURE_SPEECH_KEY,
        region=AZURE_SERVICE_REGION
    )
    audio_input = speechsdk.AudioConfig(filename=filename)
    speech_recognizer = speechsdk.SpeechRecognizer(
        speech_config=speech_config,
        audio_config=audio_input
    )
    result = speech_recognizer.recognize_once()

    return result.text if result.reason == speechsdk.ResultReason.RecognizedSpeech else None

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('azure-batch-stt: "{}"'.format(
        azure_batch_stt(t['filename'], t['lang'], t['encoding'])
    ))

Результат будет следующим:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
azure-batch-stt: "Experience proves this."

audio file="audio/4507-16021-0012.wav"    expected text="why should one halt on the way"
azure-batch-stt: "Whi should one halt on the way."

audio file="audio/8455-210777-0068.wav"    expected text="your power is sufficient i said"
azure-batch-stt: "Your power is sufficient I said."

Потоковый API

В Azure есть несколько видов потокового API. Создавая различные типы источников звука, можно либо отправить фрагменты звука, либо передать обратный вызов в Azure для получения фрагмента звука. Он запускает несколько типов событий распознавания речи для обратных вызовов. Вот как можно связать push-аудиопоток с генератором аудиопотока:

import time
import azure.cognitiveservices.speech as speechsdk

def azure_streaming_stt(filename: str, lang: str, encoding: str) -> str:
    speech_config = speechsdk.SpeechConfig(
        subscription=AZURE_SPEECH_KEY,
        region=AZURE_SERVICE_REGION
    )
    stream = speechsdk.audio.PushAudioInputStream()
    audio_config = speechsdk.audio.AudioConfig(stream=stream)
    speech_recognizer = speechsdk.SpeechRecognizer(
        speech_config=speech_config,
        audio_config=audio_config
    )

    # Connect callbacks to the events fired by the speech recognizer
    speech_recognizer.recognizing.connect(
        lambda evt: print('interim text: "{}"'.format(
            evt.result.text
        ))
    )
    speech_recognizer.recognized.connect(
        lambda evt:  print('azure-streaming-stt: "{}"'.format(
            evt.result.text
        ))
    )

    # start continuous speech recognition
    speech_recognizer.start_continuous_recognition()

    # push buffer chunks to stream
    buffer, rate = read_wav_file(filename)
    audio_generator = simulate_stream(buffer)
    for chunk in audio_generator:
      stream.write(chunk)
      time.sleep(0.1)  # to give callback a chance against fast loop

    # stop continuous speech recognition
    stream.close()
    time.sleep(0.5)  # give chance to VAD to kick in
    speech_recognizer.stop_continuous_recognition()
    time.sleep(0.5)  # Let all callback run

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    azure_streaming_stt(t['filename'], t['lang'], t['encoding'])

Результат для первого тестового примера выглядит так:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
interim text: "experience"
interim text: "experienced"
interim text: "experience"
interim text: "experience proves"
interim text: "experience proves this"
azure-streaming-stt: "Experience proves this."

Речь в текст IBM Watson

IBM Watson Speech to Text - это служба ASR с библиотеками .NET, Go, JavaScript, Python, Ruby, Swift и Unity API, а также конечными точками HTTP. Имеет богатую документацию.

Настраивать

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

Пакетный API

Пакетный API предсказуемо прост:

import os

from ibm_watson import SpeechToTextV1
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

def watson_batch_stt(filename: str, lang: str, encoding: str) -> str:
    authenticator = IAMAuthenticator(WATSON_API_KEY)
    speech_to_text = SpeechToTextV1(authenticator=authenticator)
    speech_to_text.set_service_url(WATSON_STT_URL)

    with open(filename, 'rb') as audio_file:
        response = speech_to_text.recognize(
            audio=audio_file,
            content_type='audio/{}'.format(
                os.path.splitext(filename)[1][1:]
            ),
            model=lang + '_BroadbandModel',
            max_alternatives=3,
        ).get_result()

    return response['results'][0]['alternatives'][0]['transcript']

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('watson-batch-stt: "{}"'.format(
        watson_batch_stt(t['filename'], t['lang'], t['encoding'])
    ))

Вот результат:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
watson-batch-stt: "experience proves this "

audio file="audio/4507-16021-0012.wav"    expected text="why should one halt on the way"
watson-batch-stt: "why should one hold on the way "

audio file="audio/8455-210777-0068.wav"    expected text="your power is sufficient i said"
watson-batch-stt: "your power is sufficient I set "

Потоковый API

API потоковой передачи Watson работает через WebSocket и требует небольшой работы, чтобы все это настроить. Он состоит из следующих этапов:

  • Создайте RecognizeCallback объект для получения уведомлений и результатов распознавания речи.
  • Создайте буферную очередь. Аудио фрагменты, созданные микрофоном (или имитатором потока), должны быть записаны в эту очередь, и Watson считывает и потребляет фрагменты.
  • Запустить поток, в котором выполняется распознавание речи (вместе с обменом данными через WebSocket).
  • Запустите микрофон или симулятор речи, чтобы начать воспроизведение звуковых фрагментов.
  • По завершении присоединитесь к потоку распознавания речи (т.е. дождитесь его завершения).
import json
import logging
import os
from queue import Queue
from threading import Thread
import time

from ibm_watson import SpeechToTextV1
from ibm_watson.websocket import RecognizeCallback, AudioSource
from ibm_cloud_sdk_core.authenticators import IAMAuthenticator

# Watson websocket prints justs too many debug logs, so disable it
logging.disable(logging.CRITICAL)

# Chunk and buffer size
CHUNK_SIZE = 4096
BUFFER_MAX_ELEMENT = 10

# A callback class to process various streaming STT events
class MyRecognizeCallback(RecognizeCallback):
    def __init__(self):
        RecognizeCallback.__init__(self)
        self.transcript = None

    def on_transcription(self, transcript):
        # print('transcript: {}'.format(transcript))
        pass

    def on_connected(self):
        # print('Connection was successful')
        pass

    def on_error(self, error):
        # print('Error received: {}'.format(error))
        pass

    def on_inactivity_timeout(self, error):
        # print('Inactivity timeout: {}'.format(error))
        pass

    def on_listening(self):
        # print('Service is listening')
        pass

    def on_hypothesis(self, hypothesis):
        # print('hypothesis: {}'.format(hypothesis))
        pass

    def on_data(self, data):
        self.transcript = data['results'][0]['alternatives'][0]['transcript']
        print('{0}final: {1}'.format(
            '' if data['results'][0]['final'] else 'not ',
            self.transcript
        ))

    def on_close(self):
        # print("Connection closed")
        pass

def watson_streaming_stt(filename: str, lang: str, encoding: str) -> str:
    authenticator = IAMAuthenticator(WATSON_API_KEY)
    speech_to_text = SpeechToTextV1(authenticator=authenticator)
    speech_to_text.set_service_url(WATSON_STT_URL)

    # Make watson audio source fed by a buffer queue
    buffer_queue = Queue(maxsize=BUFFER_MAX_ELEMENT)
    audio_source = AudioSource(buffer_queue, True, True)

    # Callback object
    mycallback = MyRecognizeCallback()

    # Read the file
    buffer, rate = read_wav_file(filename)

    # Start Speech-to-Text recognition thread
    stt_stream_thread = Thread(
        target=speech_to_text.recognize_using_websocket,
        kwargs={
            'audio': audio_source,
            'content_type': 'audio/l16; rate={}'.format(rate),
            'recognize_callback': mycallback,
            'interim_results': True
        }
    )
    stt_stream_thread.start()

    # Simulation audio stream by breaking file into chunks and filling buffer queue
    audio_generator = simulate_stream(buffer, CHUNK_SIZE)
    for chunk in audio_generator:
        buffer_queue.put(chunk)
        time.sleep(0.5)  # give a chance to callback

    # Close the audio feed and wait for STTT thread to complete
    audio_source.completed_recording()
    stt_stream_thread.join()

    # send final result
    return mycallback.transcript

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('watson-cloud-streaming-stt: "{}"'.format(
        watson_streaming_stt(t['filename'], t['lang'], t['encoding'])
    ))

Произведено продукции:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
not final: X. 
not final: experts 
not final: experience 
not final: experienced 
not final: experience prove 
not final: experience proves 
not final: experience proves that 
not final: experience proves this 
final: experience proves this 
watson-cloud-streaming-stt: "experience proves this "

Amazon Transcribe

Amazon Transcribe - это облачный сервис AWS для преобразования речи в текст с библиотеками на C #, Go, Java, JavaScript, PHP, Python и Ruby. Он имеет пакетный API преобразования речи в текст (также доступный как командная строка), но требует, чтобы аудиофайл находился либо в сегменте S3, либо был доступен через HTTP. Также есть потоковый API на WebSocket и HTTP / 2. Вот пример с AWS Java SDK, но без привязок Python (конечно, можно использовать библиотеку сокетов Python, но для этого потребуется попасть в низкоуровневое кодирование потока событий).

API-интерфейсы Amazon Transcribe Python в настоящее время не поддерживают сценарии использования, описанные в этой статье, поэтому примеры кода здесь не включены.

Нюанс

Nuance, скорее всего, является старейшим коммерческим продуктом для распознавания речи, даже настроенным для различных областей и отраслей. У них есть привязки Python для службы распознавания речи. Вот образец кода в их репозитории на GitHub.

Я не мог придумать способ создать учетную запись разработчика. Я надеюсь, что есть способ получить ограниченный период бесплатных пробных кредитов, как и на другие продукты, и получить учетные данные, необходимые для доступа к услугам.

КМУ Сфинкс

CMUSphinx существует уже довольно давно и адаптируется к достижениям в технологиях ASR. PocketSphinx - пакет Python для преобразования речи в текст.

Настраивать

Сначала установите swig. В macOS вы можете установить, используя brew:

$ brew install swig
$ swig -version

В Linux вы можете использовать apt-get:

$ apt-get install -y swig libpulse-dev
$ swig -version

А затем установите pocketsphinx с помощью pip:

$ pip3 install pocketsphinx
$ pip3 list | grep pocketsphinx

Создать объект декодера

Независимо от того, используете ли вы пакетный или потоковый API, вам потребуется объект декодера:

import pocketsphinx
import os

MODELDIR = os.path.join(os.path.dirname(pocketsphinx.__file__), 'model')

config = pocketsphinx.Decoder.default_config()
config.set_string('-hmm', os.path.join(MODELDIR, 'en-us'))
config.set_string('-lm', os.path.join(MODELDIR, 'en-us.lm.bin'))
config.set_string('-dict', os.path.join(MODELDIR, 'cmudict-en-us.dict'))

decoder = pocketsphinx.Decoder(config)

Пакетный API

Пакетный API ожидаемо прост, всего пара строк кода:

def sphinx_batch_stt(filename: str, lang: str, encoding: str) -> str:
    buffer, rate = read_wav_file(filename)
    decoder.start_utt()
    decoder.process_raw(buffer, False, False)
    decoder.end_utt()
    hypothesis = decoder.hyp()
    return hypothesis.hypstr

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text'])
    )
    print('sphinx-batch-stt: "{}"'.format(
        sphinx_batch_stt(t['filename'], t['lang'], t['encoding'])
    ))

И вы увидите уже знакомый результат:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
sphinx-batch-stt: "experience proves this"

audio file="audio/4507-16021-0012.wav"    expected text="why should one halt on the way"
sphinx-batch-stt: "why should one hold on the way"

audio file="audio/8455-210777-0068.wav"    expected text="your power is sufficient i said"
sphinx-batch-stt: "your paris sufficient i said"

Обратите внимание на ошибки в транскрипции. Чем больше обучающих данных, тем лучше.

Потоковый API

API-интерфейсы потоковой передачи также довольно просты, но для получения промежуточных результатов нет никакого крючка:

def sphinx_streaming_stt(filename: str, lang: str, encoding: str) -> str:
    buffer, rate = read_wav_file(filename)
    audio_generator = simulate_stream(buffer)

    decoder.start_utt()
    for chunk in audio_generator:
        decoder.process_raw(chunk, False, False)
    decoder.end_utt()

    hypothesis = decoder.hyp()
    return hypothesis.hypstr

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('sphinx-streaming-stt: "{}"'.format(
        sphinx_streaming_stt(t['filename'], t['lang'], t['encoding'])
    ))

Mozilla DeepSpeech

Mozilla выпустила программный пакет DeepSpeech 0.6 в декабре 2019 года с API-интерфейсами на языках C, Java, .NET, Python и JavaScript, включая поддержку моделей TensorFlow Lite для использования на периферийных устройствах.

Настраивать

Вы можете установить DeepSpeech с помощью pip (сделайте это deepspeech-gpu==0.6.0, если вы хотите использовать графический процессор в среде выполнения Colab или на своем компьютере):

$ pip install deepspeech==0.6.0

Загрузите и разархивируйте модели (это займет некоторое время):

$ curl -LO https://github.com/mozilla/DeepSpeech/releases/download/v0.6.0/deepspeech-0.6.0-models.tar.gz
$ tar -xvzf deepspeech-0.6.0-models.tar.gz
$ ls -l ./deepspeech-0.6.0-models/

Убедитесь, что все работает. Изучите вывод последних трех команд, и вы увидите результаты «меньше опыта», «почему нужно останавливаться на пути» и «ваш мощности достаточно, я сказал » соответственно. У вас все настроено.

$ deepspeech --model deepspeech-0.6.0-models/output_graph.pb --lm deepspeech-0.6.0-models/lm.binary --trie ./deepspeech-0.6.0-models/trie --audio ./audio/2830-3980-0043.wav

$ deepspeech --model deepspeech-0.6.0-models/output_graph.pb --lm deepspeech-0.6.0-models/lm.binary --trie ./deepspeech-0.6.0-models/trie --audio ./audio/4507-16021-0012.wav

$ deepspeech --model deepspeech-0.6.0-models/output_graph.pb --lm deepspeech-0.6.0-models/lm.binary --trie ./deepspeech-0.6.0-models/trie --audio ./audio/8455-210777-0068.wav

Создать объект модели

Первый шаг - прочитать файлы модели и создать объект модели DeepSpeech.

import deepspeech

model_file_path = 'deepspeech-0.6.0-models/output_graph.pbmm'
beam_width = 500
model = deepspeech.Model(model_file_path, beam_width)

# Add language model for better accuracy
lm_file_path = 'deepspeech-0.6.0-models/lm.binary'
trie_file_path = 'deepspeech-0.6.0-models/trie'
lm_alpha = 0.75
lm_beta = 1.85
model.enableDecoderWithLM(lm_file_path, trie_file_path, lm_alpha, lm_beta)

Пакетный API

Для пакетного преобразования речи в текст требуется всего пара строк кода:

import numpy as np

def deepspeech_batch_stt(filename: str, lang: str, encoding: str) -> str:
    buffer, rate = read_wav_file(filename)
    data16 = np.frombuffer(buffer, dtype=np.int16)
    return model.stt(data16)

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('deepspeech-batch-stt: "{}"'.format(
        deepspeech_batch_stt(t['filename'], t['lang'], t['encoding'])
    ))

Вывод:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
deepspeech-batch-stt: "experience proof less"

audio file="audio/4507-16021-0012.wav"    expected text="why should one halt on the way"
deepspeech-batch-stt: "why should one halt on the way"

audio file="audio/8455-210777-0068.wav"    expected text="your power is sufficient i said"
deepspeech-batch-stt: "your power is sufficient i said"

Потоковый API

API потоковой передачи DeepSpeech требует создания контекста потока и многократного его использования для подачи фрагментов звука:

def deepspeech_streaming_stt(filename: str, lang: str, encoding: str) -> str:
    buffer, rate = read_wav_file(filename)
    audio_generator = simulate_stream(buffer)

    # Create stream
    context = model.createStream()

    text = ''
    for chunk in audio_generator:
        data16 = np.frombuffer(chunk, dtype=np.int16)
        # feed stream of chunks
        model.feedAudioContent(context, data16)
        interim_text = model.intermediateDecode(context)
        if interim_text != text:
            text = interim_text
            print('inetrim text: {}'.format(text))

    # get final resut and close stream
    text = model.finishStream(context)
    return text

# Run tests
for t in TESTCASES:
    print('\naudio file="{0}"    expected text="{1}"'.format(
        t['filename'], t['text']
    ))
    print('deepspeech-streaming-stt: "{}"'.format(
        deepspeech_streaming_stt(t['filename'], t['lang'], t['encoding'])
    ))

DeepSpeech возвращает промежуточные результаты:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
inetrim text: i
inetrim text: e
inetrim text: experi en
inetrim text: experience pro
inetrim text: experience proof les
deepspeech-streaming-stt: "experience proof less"

Kaldi

Kaldi - очень популярный программный инструментарий для распознавания речи среди исследовательского сообщества. Он предназначен для экспериментов с различными исследовательскими идеями и возможностями. Он имеет богатую коллекцию различных возможных техник и альтернатив. Кривая обучения более крутая по сравнению с другими альтернативами, обсуждаемыми в лаборатории кода.

PyKaldi предоставляет привязки Python. Пожалуйста, взгляните на README их репозитория на GitHub.

Готового к использованию пакета PyPI для предварительной сборки не существует, и вы должны собрать его либо из исходного кода, либо из Conda. Ни один из вариантов не подходит для среды Colab.

Facebook wav2letter

Facebook выпустил wav2letter @where в январе 2020 года. Он может похвастаться полностью сверточной (CNN) акустической моделью вместо рекуррентной нейронной сети (RNN), которая используется в других решениях. Очень многообещающий, в том числе для использования в периферийных устройствах. Он имеет привязки Python для своей структуры вывода.

Как и Kaldi, он также не предоставляет пакет PyPI, и его необходимо собирать и устанавливать из исходников.

Пакет Python SpeechRecognition

Пакет SpeechRecognition предоставляет красивую абстракцию над несколькими решениями. Мы уже исследовали использование сервиса Google и CMU Sphinxpackage. Теперь мы будем использовать их через API пакета SpeechRecognition. Его можно установить с помощью pip:

Пакетный API

SpeechRecognition имеет только пакетный API. Первый шаг для создания аудиозаписи из файла или с микрофона, а второй шаг - вызов функции recognize_<speech engine name>. В настоящее время у него есть API для CMU Sphinx, Google, Microsoft, IBM, Houndify и Wit. Давайте оформим заказ, используя один облачный сервис (Google) и один программный пакет (Sphinx) через абстракцию SpeechRecognition.

import speech_recognition as sr
from enum import Enum, unique

@unique
class ASREngine(Enum):
    sphinx = 0
    google = 1

def speech_to_text(filename: str, engine: ASREngine, language: str, show_all: bool = False) -> str:
    r = sr.Recognizer()

    with sr.AudioFile(filename) as source:
        audio = r.record(source)

    asr_functions = {
        ASREngine.sphinx: r.recognize_sphinx,
        ASREngine.google: r.recognize_google,
    }

    response = asr_functions[engine](audio, language=language, show_all=show_all)
    return response

# Run tests
for t in TESTCASES:
    filename = t['filename']
    text = t['text']
    lang = t['lang']

    print('\naudio file="{0}"    expected text="{1}"'.format(
        filename, text
    ))
    for asr_engine in ASREngine:
        try:
            response = speech_to_text(filename, asr_engine, language=lang)
            print('{0}: "{1}"'.format(asr_engine.name, response))
        except sr.UnknownValueError:
            print('{0} could not understand audio'.format(
                asr_engine.name
            ))
        except sr.RequestError as e:
            print('{0} error: {0}'.format(asr_engine.name, e))

Вывод:

audio file="audio/2830-3980-0043.wav"    expected text="experience proves this"
sphinx: "experience proves that"
google: "experience proves this"

audio file="audio/4507-16021-0012.wav"    expected text="why should one halt on the way"
sphinx: "why should one hold on the way"
google: "why should one halt on the way"

audio file="audio/8455-210777-0068.wav"    expected text="your power is sufficient i said"
sphinx: "your paris official said"
google: "your power is sufficient I said"

API для других провайдеров

Для других провайдеров распознавания речи вам нужно будет создать учетные данные API, которые вы должны передать функции recognize_<speech engine name>, вы можете проверить этот пример.

Он также имеет красивую абстракцию для микрофона, реализованную через PyAudio / PortAudio. Ознакомьтесь с примерами захвата входного сигнала с микрофона пакетно и непрерывно в фоновом режиме.

Хотите написать расшифровщик Python, который преобразует ввод с микрофона в текст? Проверь это:



Если вам это понравилось, пожалуйста:

Изначально опубликовано в Блоге Slang Labs.