Vosk vs Whisper — сравнение на raspberry pi 4b

bwtowhgae4zrd9llqfbu2yhrssg.jpeg
В статье предлагается рассмотреть работу младших моделей преобразования речи в текст на 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.


_p0eryj7xkwdcvks3bng5qh_-h8.jpeg

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


vdbfocq-s4ywjxa-a3rucfpzrfk.jpeg
Также устанавливается на 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


dryzzm8qaz68j7kxzhmtoj7pifg.jpeg
Данный пакет построен на достаточно свежей идее 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': "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."}
56.28657627105713
{'text': "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."}
25.147851943969727


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

Воск


y2t3-anaopyjuwrezighqagge3e.jpeg
Запустим из 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.

© Habrahabr.ru