В статье предлагается рассмотреть работу младших моделей преобразования речи в текст на edge устройстве — raspberry pi 4b. Фраза будет непростая, хоть и короткая — в ней будут элементы и русской, и английской речи. В соревновательный состав войдут представители семейства whisper: whisper, whisper-cpp, whisper-jax и vosk. Будет проведена оценка скорости и точности работы. Также, в качестве бонуса, будет предпринята попытка перевести фразу с таджикского языка на русский с помощью vosk.


Введение.


Сразу необходимо сослаться на статью — Сравнение Vosk и Whisper, чтобы сэкономить время тех, кто уже знает, что такое vosk и whisper.
Однако в упомянутой статье проводилось сравнение только одного пакета (возможно, уже даже framework) — whisper с другим — vosk. Здесь же интересно посмотреть, как vosk и whisper поведут себя в ограниченном пространстве — на одноплатнике raspberry pi4b Raspbian Bullseye aarch64. А также посмотреть на результаты других представителей семейства whisper.
В качестве wav файла для тестов будет использоваться синтезированная речь другим пакетом — piper.
Аудиофрагмент короткий и содержит следующую фразу: «Добро пожаловать в синтез речи. Welcome to our speech synthesis.»
Чтобы уровнять условия данный аудиофрагмент был «стандартизирован» командой:
ffmpeg -i welcome.wav -ar 16000 -ac 1 -c:a pcm_s16le welcome.wav

Все whisperы и vosk устанавливаются без проблем на raspberry pi.

Whisper.



import whisper
from time import time

##Добро пожаловать в синтез речи. Welcome to our speech synthesis.
model = whisper.load_model("tiny")
ts=time()
result = model.transcribe("welcome_.wav")
print(result["text"])
print(time() -ts)

ts=time()
result = model.transcribe("welcome_.wav")
print(result["text"])
print(time() -ts)


*В коде двойной запуск одного и того же фрагмента. Зачем это нужно, будет продемонстрировано позднее.

На выходе:
"Добро пожаловать с синтизеречи. Веркомтодовый улдов спич синтез".
С результатом: 20,5 сек.

Whisper неплохо справился с русской частью фразы и даже перевел в стиле одного политика английскую речь.

Интересно, можно ли передать в whisper аудио как объект pickle?
Данный объект был сериализован из датасета huggingface.co/datasets/hf-internal-testing/librispeech_asr_dummy командой:
from datasets import load_dataset; import pickle
ds = load_dataset("hf-internal-testing/librispeech_asr_dummy", "clean", split="validation")
sample = ds[4]["audio"]
with open('audio_dump.obj', 'wb') as fp:
    pickle.dump(sample, fp)

*на raspberry с 8гб ram это сделать не удалось, т.к. датасет в память не поместился. Поэтому сериализация экземпляра была проведена на более мощной системе.

Фраза из аудио приведена в коде ниже, она полностью на английском и достаточно длинная.
Код, в котором попытаемся скормить whisper audio как объект pickle:
import whisper
from time import time
import pickle
import numpy as np

"""
LINNELL'S PICTURES ARE A SORT OF UP GUARDS AND AT EM PAINTINGS AND \
MASON'S EXQUISITE IDYLLS ARE AS NATIONAL AS A JINGO POEM MISTER BIRKET \
FOSTER'S LANDSCAPES SMILE AT ONE MUCH IN THE SAME WAY THAT MISTER CARKER \
USED TO FLASH HIS TEETH AND MISTER JOHN COLLIER GIVES HIS SITTER A CHEERFUL \
SLAP ON THE BACK BEFORE HE SAYS LIKE A SHAMPOOER IN A TURKISH BATH NEXT MAN
"""

with open('audio_dump.obj', 'rb') as fp:
    sample = pickle.load(fp)

model = whisper.load_model("tiny")
ts=time()
result = model.transcribe(sample)
print(result["text"])
print(time() -ts)

ts=time()
result = model.transcribe(sample)
print(result["text"])
print(time() -ts)

К сожалению, данный вариант не работает с whisper. Но он пригодится в дальнейшем.

Whisper-cpp



Также устанавливается на raspberry pi без проблем и обрабатывает audio wav:
cd whisper-cpp
./main -m models/ggml-tiny.en.bin -f samples/welcome.wav


На выходе:
«The group has always seen this region. Welcome to the world of speech synthesis.»
Whisper-cpp не справился с русской часть фразы и допустил небольшие неточности в английской.
Время: 11 сек.

whisper-cpp позволяет немного ускорить время за счет квантования. Не будем рассматривать другие возможности, такие как open-vino и т.п. Только то, что доступно «на месте».
Итак, квантуем и запускаем:
./quantize models/ggml-tiny.en.bin models/ggml-tiny.en-q4_0.bin q4_0
./main -m models/ggml-tiny.en-q4_0.bin -f samples/welcome.wav 

К сожалению, нельзя «ужать» модель до q2 или q1, минимум — q4.

Результат тот же: «The purpose of the scene is raging. Welcome to the world of speech synthesis.»
А вот время сократилось: 6,3 сек.

Русских моделей малого размера у whisper-cpp нет (пока нет ?). base модель также некорректно отображает русскую речь. А вот medium и large варианты хорошо справляются. Но эти модели не для raspberry, даже если их квантовать.

Jax-whisper



Данный пакет построен на достаточно свежей идее jax. Который также, называют «numpy на стероидах». За более подробной информацией можно обратиться к книге «Deep Learning with JAX» Grigory Sapunov.

Наш код для raspberry следующий:
from whisper_jax import FlaxWhisperPipline
from time import time

#Добро пожаловать в синтез речи. Welcome to our speech synthesis.

# instantiate pipeline
pipeline = FlaxWhisperPipline("openai/whisper-tiny")

ts=time()
# JIT compile the forward call - slow, but we only do once
text = pipeline("welcome_.wav")
print(text)
print(time() -ts)

ts=time()
# used cached function thereafter - super fast!!
text = pipeline("welcome_.wav")
print(text)
print(time() -ts)


Результат: «Добро пожаловать с синтизеречи. Веркомтодовый улток с печь синтез.»
По времени исполнения — интересные вещи.
Первый «прогон» — 25 сек, последующий — 8,8 сек.
Объясняется, как уже упомянуто в коде, jit компиляцией, которая на старте дает такую задержку.

На этом тестирование jax-whisper не заканчивается.
Посмотрим следующий код:

from whisper_jax import FlaxWhisperPipline
from time import time
import time

"""
LINNELL'S PICTURES ARE A SORT OF UP GUARDS AND AT EM PAINTINGS AND \
MASON'S EXQUISITE IDYLLS ARE AS NATIONAL AS A JINGO POEM MISTER BIRKET \
FOSTER'S LANDSCAPES SMILE AT ONE MUCH IN THE SAME WAY THAT MISTER CARKER \
USED TO FLASH HIS TEETH AND MISTER JOHN COLLIER GIVES HIS SITTER A CHEERFUL \
SLAP ON THE BACK BEFORE HE SAYS LIKE A SHAMPOOER IN A TURKISH BATH NEXT MAN
"""

# instantiate pipeline
pipeline = FlaxWhisperPipline("openai/whisper-tiny")

ts=time()
# JIT compile the forward call - slow, but we only do once
text = pipeline("welcome_.wav")
print(text)
print(time() -ts)

ts=time()
# used cached function thereafter - super fast!!
text = pipeline("welcome_.wav")
print(text)
print(time() -ts)

В этом примере, мы взяли ранее сериализованный аудиофрагмент и поместили его в jax-whisper.
Результат и время следующие (напомним, что это другой аудиофрагмент, взятый из датасета с англ. речью):
{'text': <b>"Lennils, pictures are a sort of upguards and atom paintings, and Mason's exquisite Idols are as national as a jingo poem. Mr. Birkut Foster's landscapes smile at one much in the same way that Mr. Karker used to flash his teeth. And Mr. John Colier gives his sitter a cheerful slap on the back before he says like a shampoo or a Turkish bath. Next man."</b>}
56.28657627105713
{'text': <b>"Lennils, pictures are a sort of upguards and atom paintings, and Mason's exquisite Idols are as national as a jingo poem. Mr. Birkut Foster's landscapes smile at one much in the same way that Mr. Karker used to flash his teeth. And Mr. John Colier gives his sitter a cheerful slap on the back before he says like a shampoo or a Turkish bath. Next man."</b>}
25.147851943969727

Если учесть, что сам аудиофрагмент длительностью 29 сек, результат неплохой, в том числе и по содержанию текста.

Воск



Запустим из cli:
vosk-transcriber --model-name vosk-model-small-ru-0.22 -i welcome.wav

Результат:
«добро пожаловать синтеза речи тогда вы отдых с печь синтаксис»
Время: 4.369 sec

Как видно, с содержанием — каша, однако время исполнения поражает.
К сожалению, следующая в семействе vosk (https://alphacephei.com/vosk/models) модель — 1,8 Гб, по сравнению с текущей — 45Мб, разница существенна.

Английская младшая модель (vosk-model-small-en-us-0.15) справляется, как и следовало ожидать, с иностранной речью, но с русской — нет:
«that up i shall have it seems is it hm welcome to the world of speech synthesis».

В завершение, небольшой эксперимент с vosk и таджикским языком. Попытка перевести пословицы, которые были найдены на просторах сети с готовым переводом:
vosk-transcriber --model-name vosk-model-tg-0.22 -i tadjik.wav

Результат на видео:

то же на rutube

Таким образом, подводя итог, можно заключить:
— Vosk опережает всех остальных при переводе коротких аудио в текст по времени исполнения.
Ему в затылок дышит whisper-cpp, подкрученный при помощи квантизации, далее jax-whisper и в хвосте плетется — whisper.
— в части качества распознавания русской речи, пальму первенства несут (по скромному мнению автора) whisper и vosk. При этом whisper немного опережает соперника.

p.s.
Результаты по 43 сек аудио-фрагменту отрывок из "Демон" Лермонтова М.Ю. :
whisper

печальный демон. Дух изгнания. Летал над грешной землей и лучших дней в воспоминании приеднемтесь нельзя толпой. 
Тех дней, когда в жили еще света блесталом, чистый хирувим. Когда бегущая комета, улыбкой ласковой привета, любила поменяться с ним.
Когда сквозь вечная туманы, познания жадный, он следил качующая караваны в пространстве брошенных светил. 
Когда он верил, и любил, счастливый первенец творения. Не знал ни злубы, ни сомнения, и не грозил моего веков бесплодных ряд он и лэм много, много всего при помнит не имел он сила.
77.7968852519989 сек

jax-whisper

{'text': ' печальный демон. Дух изгнания. Летал над грешной землей и лучших дней в воспоминании при днем теснились от толпой. 
Тех дней, когда вжили еще света блисталым, чистый хирувим. Когда бигущая комета, улыбкой ласковой привета любила поменяться с ним. 
Когда сквозь вечная туманы, познания жадный, он следил качющая караваны в пространстве брошенных светил. 
Когда он верил, и любил, счастливый первенец творения. Не знал ни злубы, ни сомнения, и не грозил моего веков бесплодных ряд он и лямного. 
Много всего при помнит не имело населы.'}
49.801395416259766 сек

vosk

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

13.022 сек


Приложения:
welcome.wav
audio_dump.obj
tadjik.wav
demon.wav
— видео, демонстрирующее приведенный в статье код — youtube, — rutube.

Комментарии (3)


  1. vagon333
    27.09.2024 10:37

    У вас получилось использовать результаты ваших тестов в практическом применении?
    На каком железе и какую модель используете?


  1. surefire
    27.09.2024 10:37

    Ещё попробуйте faster-whisper


    1. zoldaten Автор
      27.09.2024 10:37
      +1

      from faster_whisper import WhisperModel from time import time model_size = "tiny" or run on CPU with INT8

      model = WhisperModel(model_size, device="cpu", compute_type="int8")

      ts=time()
      segments, info = model.transcribe("welcome_.wav",language="ru", beam_size=5)
      print("Detected language '%s' with probability %f" % (info.language, info.language_probability))

      for segment in segments:
      print("[%.2fs -> %.2fs] %s" % (segment.start, segment.end, segment.text))

      print(time() -ts)

      Detected language 'ru' with probability 1.000000
      [0.00s -> 2.26s] Добро пожаловать в синтез речи.
      [2.26s -> 4.26s] В welcome to the World of the Switch синтез.
      4.705834627151489

      Действительно, хороший результат!