Evaluation metrics for ASR
Если вы знакомы с расстоянием Левенштейна из NLP то метрики для оценки систем распознавания речи будут вам знакомы! Не волнуйтесь, если нет, мы рассмотрим объяснения от начала до конца, чтобы убедиться, что вы знаете различные метрики и понимаете, что они означают.
При оценке систем распознавания речи мы сравниваем предсказания системы с транскрипцией целевого текста, аннотируя все имеющиеся ошибки. Мы относим эти ошибки к одной из трех категорий:
- Замены (S - от англ. “Substitutions”): когда мы транскрибируем неправильное слово в нашем предсказании (“sit” вместо “sat”)
- Вставки (I - от англ. “Insertions”): когда мы добавляем дополнительное слово в наше предсказание
- Удаления (D - от англ. “Deletions”): когда мы удаляем слово в нашем предсказании
Эти категории ошибок одинаковы для всех метрик распознавания речи. Различается лишь уровень, на котором мы вычисляем эти ошибки: мы можем вычислять их либо на уровне слова, либо на уровне символа.
Для каждого из определений метрики мы будем использовать свой пример. Ниже мы видим истину или эталонную (reference) текстовую последовательность:
reference = "the cat sat on the mat"
И предсказанную последовательность от системы распознавания речи, которую мы пытаемся оценить:
prediction = "the cat sit on the"
Видно, что предсказание довольно близко, но некоторые слова не совсем верны. Оценим это предсказание в сравнении с эталоном для трех наиболее популярных метрик распознавания речи и посмотрим, какие цифры мы получим для каждой из них.
Частота ошибок в словах (Word Error Rate)
Метрика word error rate (WER) является “фактической” метрикой для распознавания речи. Она рассчитывает замены, вставки и удаления на уровне слова. Это означает, что ошибки аннотируются на уровне каждого слова. Возьмем наш пример:
Эталон: | the | cat | sat | on | the | mat |
---|---|---|---|---|---|---|
Предсказание: | the | cat | sit | on | the | |
Метка: | ✅ | ✅ | S | ✅ | ✅ | D |
Здесь:
- 1 замена (S) (“sit” вместо “sat”)
- 0 вставок
- 1 удаление (D) (“mat” отсутствует)
Это дает 2 ошибки в сумме. Чтобы получить коэффициент ошибок, разделим количество ошибок на общее количество слов в эталонной последовательности (N), которое для данного примера равно 6:
Отлично! Итак, WER равен 0,333, или 33,3%. Обратите внимание, что в слове “sit” ошибочным является только один символ, но все слово помечено как неправильное. Это является отличительной особенностью WER: орфографические ошибки сильно штрафуются, какими бы незначительными они ни были.
WER определяется так: чем меньше WER, тем меньше ошибок в прогнозе, поэтому для идеальной системы распознавания речи WER был бы равен нулю (отсутствие ошибок).
Рассмотрим, как можно вычислить WER с помощью 🤗 Evaluate. Для вычисления метрики WER нам понадобятся два пакета: 🤗 Evaluate для интерфейса API и JIWER для выполнения тяжелой работы по вычислению:
pip install --upgrade evaluate jiwer
Отлично! Теперь мы можем загрузить метрику WER и вычислить показатель для нашего примера:
from evaluate import load
wer_metric = load("wer")
wer = wer_metric.compute(references=[reference], predictions=[prediction])
print(wer)
Print Output:
0.3333333333333333
0,33, или 33,3%, как и ожидалось! Теперь мы знаем, как именно производится расчет WER.
А теперь кое-что, что сбивает с толку… Как Вы думаете, какова верхняя граница WER? Вы ожидаете, что он будет равен 1 или 100%, верно? Так как WER - это отношение количества ошибок к количеству слов (N), то верхнего предела для WER не существует! Возьмем пример, когда мы предсказали 10 слов, а у целевой фразы только 2 слова. Если бы все наши прогнозы оказались неверными (10 ошибок), то WER был бы равен 10 / 2 = 5, или 500%! Об этом следует помнить, если вы обучаете ASR-систему и видите, что WER превышает 100%. Хотя если вы видите это, то, скорее всего, что-то пошло не так… 😅
Точность слов (Word Accuracy)
Мы можем перевернуть WER, чтобы получить метрику, в которой больше - лучше. Вместо того чтобы измерять частоту ошибок в словах, мы можем измерить точность слов (WAcc) нашей системы:
WAcc также измеряется на уровне слов, просто WER представлен (сформулирован) как метрика точности, а не метрика ошибки. WAcc очень редко встречается в речевой литературе - мы рассматриваем предсказания нашей системы в терминах ошибок в словах, и поэтому предпочитаем метрики ошибок, которые больше ассоциируются с этими ошибками.
Частота ошибок в символах (Character Error Rate)
Кажется немного несправедливым, что мы пометили все слово “sit” ошибочным, когда на самом деле неправильной была только одна буква. Это объясняется тем, что мы оценивали нашу систему на уровне слов, тем самым аннотируя ошибки пословно (word-by-word). Показатель частота ошибок в символах (CER) оценивает системы на символьном уровне. Это означает, что мы разбиваем слова на отдельные символы и аннотируем ошибки по каждому символу:
Эталон: | t | h | e | c | a | t | s | a | t | o | n | t | h | e | m | a | t | |||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Предсказание: | t | h | e | c | a | t | s | i | t | o | n | t | h | e | ||||||||
Метка: | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | S | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | D | D | D |
Теперь мы видим, что в слове “sit” буквы “s” и “t” отмечены как правильные. И только “i” помечается как ошибка замены символа (S). Таким образом, мы вознаграждаем нашу систему за частично верное предсказание 🤝.
В нашем примере мы имеем 1 замену символов, 0 вставок и 3 удаления. Всего у нас 14 символов. Таким образом, наш CER имеет вид:
Отлично! Мы получили CER, равный 0,286, или 28,6%. Обратите внимание, что это меньше, чем WER - мы гораздо меньше наказывали за орфографическую ошибку.
Какую метрику следует использовать?
В целом для оценки речевых систем WER используется гораздо чаще, чем CER. Это объясняется тем, что WER требует от систем более глубокого понимания контекста прогнозов. В нашем примере слово “sit” находится в неправильном времени. Система, понимающая связь между глаголом и временем, в котором употребляется слово, предсказала бы правильное время глагола “sat”. Мы хотим поощрять такой уровень понимания со стороны наших речевых систем. Таким образом, хотя WER менее щадящим, чем CER, он также более благоприятен для тех видов разборчивых систем, которые мы хотим разработать. Поэтому мы обычно используем WER и рекомендуем вам это делать! Однако существуют обстоятельства, при которых использование WER невозможно. В некоторых языках, таких как мандаринский (севернокитайский язык) и японский, понятие “слова” отсутствует, и поэтому WER не имеет смысла. Здесь мы возвращаемся к использованию CER.
В нашем примере при расчете WER мы использовали только одно предложение. При оценке реальной системы мы обычно используем целый тестовый набор, состоящий из нескольких тысяч предложений. При оценке по нескольким предложениям мы суммируем S, I, D и N по всем предложениям, а затем вычисляем WER в соответствии с формулой, приведенной выше. Это дает более точную оценку WER для данных, которые не были использованы ранее.
Нормализация
Если мы обучим модель ASR на данных с пунктуацией и регистром букв, она научится предсказывать регистр и пунктуацию в своих транскрипциях. Это отлично работает, когда нам нужно использовать нашу модель для реальных приложений распознавания речи, таких как транскрибирование совещаний или диктовка, поскольку предсказанные транскрипции будут полностью отформатированы с учетом регистра и пунктуации, стиля, называемого орфографическим.
Однако у нас также есть возможность нормализовать набор данных, чтобы убрать регистр и пунктуацию. Нормализация набора данных делает задачу распознавания речи проще: модели больше не нужно различать символы верхнего и нижнего регистра или предсказывать пунктуацию только на основе аудиоданных (например, какой звук издает точка с запятой?). Из-за этого показатели ошибки слов снижаются естественным образом (что означает, что результаты лучше). В статье о модели Whisper продемонстрировано радикальное воздействие нормализации транскрипций на результаты WER (см. раздел 4.4 в статье Whisper). Несмотря на более низкие показатели WER, модель не обязательно становится лучше для промышленного использования. Отсутствие регистра и пунктуации делает предсказанный текст от модели значительно труднее для чтения. Возьмем пример из предыдущего раздела, где мы применили модели Wav2Vec2 и Whisper к одному и тому же аудиофрагменту из набора данных LibriSpeech. Модель Wav2Vec2 не предсказывает ни пунктуацию, ни регистр, в то время как Whisper предсказывает оба эти элемента. Сравнив транскрипции рядом, мы видим, что транскрипция Whisper гораздо проще для чтения:
Wav2Vec2: HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH CHRISTMAUS AND ROSE BEEF LOOMING BEFORE US SIMALYIS DRAWN FROM EATING AND ITS RESULTS OCCUR MOST READILY TO THE MIND
Whisper: He tells us that at this festive season of the year, with Christmas and roast beef looming before us, similarly is drawn from eating and its results occur most readily to the mind.
Транскрипция Whisper с соблюдением орфографии и, следовательно, готова к использованию - она отформатирована так, как мы ожидаем для транскрипции совещания или диктовки, с пунктуацией и регистром букв. Напротив, для восстановления пунктуации и регистра в наших предсказаниях Wav2Vec2 нам потребуется дополнительная постобработка, если мы хотим использовать их в дальнейшем при разработке приложений.
Существует золотая середина между нормализацией и отсутствием нормализации: мы можем обучать наши системы на орфографических транскрипциях, а затем нормализовать предсказания и целевые метки перед вычислением WER. Таким образом, мы обучаем наши системы предсказывать полностью отформатированный текст, но также получаем выгоду от улучшений WER, которые мы получаем, нормализуя транскрипции.
Модель Whisper была выпущена с нормализатором, который эффективно обрабатывает нормализацию регистра, пунктуации и форматирования чисел, среди прочего. Давайте применим нормализатор к транскрипциям Whisper, чтобы продемонстрировать, как мы можем их нормализовать:
from transformers.models.whisper.english_normalizer import BasicTextNormalizer
normalizer = BasicTextNormalizer()
prediction = " He tells us that at this festive season of the year, with Christmas and roast beef looming before us, similarly is drawn from eating and its results occur most readily to the mind."
normalized_prediction = normalizer(prediction)
normalized_prediction
Output:
' he tells us that at this festive season of the year with christmas and roast beef looming before us similarly is drawn from eating and its results occur most readily to the mind '
Отлично! Мы видим, что текст был полностью приведен к нижнему регистру и удалена вся пунктуация. Теперь давайте определим эталонную транскрипцию и затем вычислим нормализованный WER между эталоном и предсказанием:
reference = "HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH CHRISTMAS AND ROAST BEEF LOOMING BEFORE US SIMILES DRAWN FROM EATING AND ITS RESULTS OCCUR MOST READILY TO THE MIND"
normalized_referece = normalizer(reference)
wer = wer_metric.compute(
references=[normalized_referece], predictions=[normalized_prediction]
)
wer
Output:
0.0625
6,25% - это примерно то, что мы ожидаем для базовой модели Whisper на наборе данных LibriSpeech для валидационной выборки. Как мы видим здесь, мы предсказали орфографическую транскрипцию, но в то же время получили улучшение WER, полученное благодаря нормализации эталона и предсказания перед вычислением WER.
Выбор способа нормализации транскрипций в конечном итоге зависит от ваших потребностей. Мы рекомендуем обучать модель на орфографическом тексте и оценивать на нормализованном тексте, чтобы получить лучшее из обоих приемов.
Собираем все воедино
Хорошо! Мы рассмотрели три темы в этом разделе: предварительно обученные модели, выбор набора данных и оценку. Давайте весело проведем время и объединим их в одном примере end-to-end 🚀 Мы будем готовиться к следующему разделу по настройке модели путем оценки предварительно обученной модели Whisper на тестовом наборе данных Common Voice 13 на Дивехи. Мы используем полученное число WER как baseline для нашего процесса дообучения или как целевое значение, которое мы постараемся превзойти 🥊.
Сначала мы загрузим предварительно обученную модель Whisper с помощью pipeline()
. Этот процесс вам уже должен быть крайне знаком!
Единственное новое, что мы сделаем - это загрузим модель с использованием половинной точности (float16), если запускаем на GPU.
Это ускорит вывод, почти не влияя на точность WER.
from transformers import pipeline
import torch
if torch.cuda.is_available():
device = "cuda:0"
torch_dtype = torch.float16
else:
device = "cpu"
torch_dtype = torch.float32
pipe = pipeline(
"automatic-speech-recognition",
model="openai/whisper-small",
torch_dtype=torch_dtype,
device=device,
)
Затем мы загрузим тестовую часть Дивехи из набора данных Common Voice 13. Вы помните из предыдущего раздела, что Common Voice 13 является ограниченным, что означает, что мы должны согласиться с условиями использования набора данных, прежде чем получить доступ к нему. Теперь мы можем связать нашу учетную запись Hugging Face с нашим блокнотом, чтобы получить доступ к набору данных с машины, которую мы сейчас используем.
Связать блокнот с Hugging Face Hub очень просто - это требует ввода вашего токена аутентификации, когда вас попросят. Найдите ваш токен аутентификации Hugging Face Hub здесь и введите его, когда вас попросят:
from huggingface_hub import notebook_login
notebook_login()
Отлично! После того как мы свяжем блокнот с нашей учетной записью Hugging Face, мы можем продолжить с загрузкой набора данных Common Voice. Это займет несколько минут на загрузку и предварительную обработку, данные будут получены с Hub Hugging Face и подготовлены автоматически в вашем блокноте:
from datasets import load_dataset
common_voice_test = load_dataset(
"mozilla-foundation/common_voice_13_0", "dv", split="test"
)
Оценка по всему набору данных может быть выполнена так же, как и для одного примера - все, что нам нужно сделать, это циклически пройти по
входным аудиофайлам, вместо вывода только одного образца. Для этого мы сначала преобразуем наш набор данных в KeyDataset
. При этом выбирается
определенный столбец набора данных, который мы хотим передать модели (в нашем случае это столбец "audio"
), игнорируя остальные (например,
целевые транскрипции, которые мы не хотим использовать для вывода). Затем мы перебираем этот преобразованный набор данных, добавляя выходы
модели в список для сохранения предсказаний. Этот блок кода будет выполняться около пяти минут при использовании GPU с половинной точностью
и максимальной памятью 12 ГБ:
from tqdm import tqdm
from transformers.pipelines.pt_utils import KeyDataset
all_predictions = []
# run streamed inference
for prediction in tqdm(
pipe(
KeyDataset(common_voice_test, "audio"),
max_new_tokens=128,
generate_kwargs={"task": "transcribe"},
batch_size=32,
),
total=len(common_voice_test),
):
all_predictions.append(prediction["text"])
И, наконец, мы можем вычислить WER. Давайте сначала вычислим орфографический WER, то есть WER без какой-либо дополнительной обработки:
from evaluate import load
wer_metric = load("wer")
wer_ortho = 100 * wer_metric.compute(
references=common_voice_test["sentence"], predictions=all_predictions
)
wer_ortho
Output:
167.29577268612022
Ладно… 167% в основном означает, что наша модель выдает мусор 😜 Не беспокойтесь, нашей целью будет улучшить это путем настройки модели на обучающем выборке Дивехи!
Затем мы оценим нормализованный WER, то есть WER с постобработкой в части нормализации. Нам придется исключить выборки, которые были бы пустыми после нормализации, так как в противном случае общее количество слов в нашем эталоне (N) будет равно нулю, что вызовет ошибку деления на ноль в нашем вычислении:
from transformers.models.whisper.english_normalizer import BasicTextNormalizer
normalizer = BasicTextNormalizer()
# compute normalised WER
all_predictions_norm = [normalizer(pred) for pred in all_predictions]
all_references_norm = [normalizer(label) for label in common_voice_test["sentence"]]
# filtering step to only evaluate the samples that correspond to non-zero references
all_predictions_norm = [
all_predictions_norm[i]
for i in range(len(all_predictions_norm))
if len(all_references_norm[i]) > 0
]
all_references_norm = [
all_references_norm[i]
for i in range(len(all_references_norm))
if len(all_references_norm[i]) > 0
]
wer = 100 * wer_metric.compute(
references=all_references_norm, predictions=all_predictions_norm
)
wer
Output:
125.69809089960707
Снова мы видим резкое снижение WER при нормализации наших эталонов и предсказаний: базовая модель достигает орфографического тестового WER 168%, в то время как нормализованный WER составляет 126%.
Итак, именно эти показатели мы хотим превзойти, когда будем дообучать модель, чтобы улучшить модель Whisper для распознавания речи для Дивехи. Продолжайте чтение, чтобы получить практический опыт с примером дообучения модели 🚀.
< > Update on GitHub