В статье предлагается рассмотреть работу младших моделей преобразования речи в текст на 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)
surefire
27.09.2024 10:37Ещё попробуйте faster-whisper
zoldaten Автор
27.09.2024 10:37+1from 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Действительно, хороший результат!
vagon333
У вас получилось использовать результаты ваших тестов в практическом применении?
На каком железе и какую модель используете?