Transformers documentation
Автоматическое распознавание речи
Автоматическое распознавание речи
Automatic speech recognition (ASR) преобразует речевой сигнал в текст, сопоставляя последовательность аудиовходов с текстовыми выводами. Виртуальные ассистенты, такие как Siri и Alexa, ежедневно используют модели ASR для помощи пользователям, а также существует множество других полезных приложений для конечных пользователей, таких как живые субтитры и ведение записей во время совещаний.
В этом руководстве показано, как:
- Настройте Wav2Vec2 на датасете MInDS-14 для транскрибации аудио в текст.
- Используйте дообученную модель для инференса.
Чтобы увидеть все архитектуры и контрольные точки, совместимые с этой задачей, рекомендуем обратиться к странице задачи
Прежде чем начать, убедитесь, что у вас установлены все необходимые библиотеки:
pip install transformers datasets evaluate jiwer soundfile librosa torchcodec
Мы рекомендуем вам войти в свой аккаунт Hugging Face, чтобы вы могли загрузить свою модель и поделиться ею с сообществом. При появлении запроса введите токен для входа:
>>> from huggingface_hub import notebook_login
>>> notebook_login()Загрузка набора данных MInDS-14
Начните с загрузки небольшой подвыборки набора данных MInDS-14 из библиотеки 🤗 Datasets. Это позволит вам провести эксперименты и убедиться, что всё работает, прежде чем тратить время на обучение на полном наборе данных.
>>> from datasets import load_dataset, Audio
>>> minds = load_dataset("PolyAI/minds14", name="en-US", split="train[:100]")Разбейте train-подмножество датасета на обучающую и тестовую выборки с помощью метода ~Dataset.train_test_split:
>>> minds = minds.train_test_split(test_size=0.2)Затем посмотрите на набор данных:
>>> minds
DatasetDict({
train: Dataset({
features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
num_rows: 16
})
test: Dataset({
features: ['path', 'audio', 'transcription', 'english_transcription', 'intent_class', 'lang_id'],
num_rows: 4
})
})Хотя набор данных содержит много полезной информации, например lang_id и english_transcription, в этом руководстве мы сосредоточимся на audio и transcription. Удалите остальные столбцы с помощью метода remove_columns:
>>> minds = minds.remove_columns(["english_transcription", "intent_class", "lang_id"])Рассмотрим пример ещё раз:
>>> minds["train"][0]
{'audio': {'array': array([-0.00024414, 0. , 0. , ..., 0.00024414,
0.00024414, 0.00024414], dtype=float32),
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
'sampling_rate': 8000},
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
'transcription': "hi I'm trying to use the banking app on my phone and currently my checking and savings account balance is not refreshing"}Есть два поля:
audio: одномерныйarrayс речевым сигналом, который необходимо вызвать для загрузки и ресемплинга аудиофайла.transcription: целевой текст.
Предобработка
Следующий шаг — загрузить процессор Wav2Vec2 для обработки аудиосигнала:
>>> from transformers import AutoProcessor
>>> processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base")Набор данных MInDS-14 имеет частоту дискретизации 8000 Гц (эту информацию можно найти в его карточке набора данных), поэтому для использования предобученной модели Wav2Vec2 необходимо пересэмплировать набор данных до 16000 Гц:
>>> minds = minds.cast_column("audio", Audio(sampling_rate=16_000))
>>> minds["train"][0]
{'audio': {'array': array([-2.38064706e-04, -1.58618059e-04, -5.43987835e-06, ...,
2.78103951e-04, 2.38446111e-04, 1.18740834e-04], dtype=float32),
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
'sampling_rate': 16000},
'path': '/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-US~APP_ERROR/602ba9e2963e11ccd901cd4f.wav',
'transcription': "hi I'm trying to use the banking app on my phone and currently my checking and savings account balance is not refreshing"}Как видно из transcription выше, текст содержит смесь заглавных и строчных букв. Токенайзер Wav2Vec2 обучен только на заглавных буквах, поэтому необходимо убедиться, что текст соответствует словарю токенайзера:
>>> def uppercase(example):
... return {"transcription": example["transcription"].upper()}
>>> minds = minds.map(uppercase)Теперь создайте функцию предобработки, которая:
- Вызывает колонку
audioдля загрузки и ресемплинга аудиофайла. - Извлекает
input_valuesиз аудиофайла и токенизирует столбецtranscriptionс помощью процессора.
>>> def prepare_dataset(batch):
... audio = batch["audio"]
... batch = processor(audio["array"], sampling_rate=audio["sampling_rate"], text=batch["transcription"])
... batch["input_length"] = len(batch["input_values"][0])
... return batchЧтобы применить функцию предобработки ко всему набору данных, используйте функцию map из 🤗 Datasets. Вы можете ускорить map, увеличив количество процессов с помощью параметра num_proc. Удалите ненужные столбцы с помощью метода remove_columns:
>>> encoded_minds = minds.map(prepare_dataset, remove_columns=minds.column_names["train"], num_proc=4)🤗 Transformers не содержит collator данных для ASR, поэтому вам нужно адаптировать DataCollatorWithPadding, чтобы формировать батчи примеров. Он также динамически дополняет текст и метки до длины самого длинного элемента в текущем батче (а не во всём датасете), чтобы все элементы имели одинаковую длину. Хотя можно дополнить текст в функции tokenizer, установив padding=True, динамическое дополнение эффективнее.
В отличие от других collator'ов данных, этот конкретный collator данных должен применять разные методы дополнения (padding) для input_values и labels:
>>> import torch
>>> from dataclasses import dataclass, field
>>> from typing import Any, Dict, List, Optional, Union
>>> @dataclass
... class DataCollatorCTCWithPadding:
... processor: AutoProcessor
... padding: Union[bool, str] = "longest"
... def __call__(self, features: list[dict[str, Union[list[int], torch.Tensor]]]) -> dict[str, torch.Tensor]:
... # split inputs and labels since they have to be of different lengths and need
... # different padding methods
... input_features = [{"input_values": feature["input_values"][0]} for feature in features]
... label_features = [{"input_ids": feature["labels"]} for feature in features]
... batch = self.processor.pad(input_features, padding=self.padding, return_tensors="pt")
... labels_batch = self.processor.pad(labels=label_features, padding=self.padding, return_tensors="pt")
... # replace padding with -100 to ignore loss correctly
... labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100)
... batch["labels"] = labels
... return batchТеперь создайте экземпляр вашего DataCollatorCTCWithPadding:
>>> data_collator = DataCollatorCTCWithPadding(processor=processor, padding="longest")Оценка
Добавление метрики в процесс обучения часто помогает оценить качество модели. Вы можете быстро загрузить метод оценки с помощью библиотеки 🤗 Evaluate. Для этой задачи загрузите метрику word error rate (WER) (ознакомьтесь с быстрым обзором 🤗 Evaluate, чтобы узнать больше о загрузке и вычислении метрик):
>>> import evaluate
>>> wer = evaluate.load("wer")Затем создайте функцию, которая передаёт ваши предсказания и метки в compute для расчёта WER:
>>> import numpy as np
>>> def compute_metrics(pred):
... pred_logits = pred.predictions
... pred_ids = np.argmax(pred_logits, axis=-1)
... pred.label_ids[pred.label_ids == -100] = processor.tokenizer.pad_token_id
... pred_str = processor.batch_decode(pred_ids)
... label_str = processor.batch_decode(pred.label_ids, group_tokens=False)
... wer_score = wer.compute(predictions=pred_str, references=label_str)
... return {"wer": wer_score}Ваша функция compute_metrics готова, и вы вернётесь к ней при настройке обучения.
Обучение
Если вы не знакомы с дообучением модели с помощью Trainer, загляните в базовое руководство здесь!
Теперь вы готовы приступить к обучению модели! Загрузите Wav2Vec2 с помощью AutoModelForCTC. Укажите применяемое сокращение с помощью параметра ctc_loss_reduction. Часто лучше использовать среднее значение, а не суммирование по умолчанию:
>>> from transformers import AutoModelForCTC, TrainingArguments, Trainer
>>> model = AutoModelForCTC.from_pretrained(
... "facebook/wav2vec2-base",
... ctc_loss_reduction="mean",
... pad_token_id=processor.tokenizer.pad_token_id,
... )На этом этапе осталось выполнить только три шага:
- Определите гиперпараметры обучения в TrainingArguments. Единственный обязательный параметр —
output_dir, который указывает, куда сохранять модель. Чтобы загрузить модель на Hub, установитеpush_to_hub=True(для загрузки модели необходимо войти в аккаунт Hugging Face). В конце каждой эпохи Trainer вычисляет WER и сохраняет контрольную точку обучения. - Передайте аргументы обучения в Trainer вместе с моделью, набором данных, токенизатором, data collator и функцией
compute_metrics. - Вызовите train(), чтобы выполнить дообучение модели.
>>> training_args = TrainingArguments(
... output_dir="my_awesome_asr_mind_model",
... per_device_train_batch_size=8,
... gradient_accumulation_steps=2,
... learning_rate=1e-5,
... warmup_steps=500,
... max_steps=2000,
... gradient_checkpointing=True,
... fp16=True,
... train_sampling_strategy="group_by_length",
... eval_strategy="steps",
... per_device_eval_batch_size=8,
... save_steps=1000,
... eval_steps=1000,
... logging_steps=25,
... load_best_model_at_end=True,
... metric_for_best_model="wer",
... greater_is_better=False,
... push_to_hub=True,
... report_to="trackio",
... )
>>> trainer = Trainer(
... model=model,
... args=training_args,
... train_dataset=encoded_minds["train"],
... eval_dataset=encoded_minds["test"],
... processing_class=processor,
... data_collator=data_collator,
... compute_metrics=compute_metrics,
... )
>>> trainer.train()После завершения обучения используйте метод push_to_hub(), чтобы опубликовать модель на Hub и сделать её доступной всем:
>>> trainer.push_to_hub()Для более подробного примера дообучения модели для автоматического распознавания речи ознакомьтесь с этой статьей по ASR для английского языка и этой статьей по многоязычному ASR.
Вывод
Отлично, теперь, когда вы дообучили модель, вы можете использовать её для инференса!
Загрузите аудиофайл, для которого вы хотите выполнить инференс. Не забудьте при необходимости пересэмплировать частоту дискретизации аудиофайла, чтобы она соответствовала частоте дискретизации модели!
>>> from datasets import load_dataset, Audio
>>> dataset = load_dataset("PolyAI/minds14", "en-US", split="train")
>>> dataset = dataset.cast_column("audio", Audio(sampling_rate=16000))
>>> sampling_rate = dataset.features["audio"].sampling_rate
>>> audio_file = dataset[0]["audio"]["path"]Самый простой способ проверить вашу дообученную модель на инференсе — использовать её в pipeline(). Создайте экземпляр pipeline для автоматического распознавания речи с вашей моделью и передайте в него аудиофайл:
>>> from transformers import pipeline
>>> transcriber = pipeline("automatic-speech-recognition", model="stevhliu/my_awesome_asr_minds_model")
>>> transcriber(audio_file)
{'text': 'I WOUD LIKE O SET UP JOINT ACOUNT WTH Y PARTNER'}Распознавание текста приемлемое, но его можно улучшить! Попробуйте дообучить модель на большем количестве примеров, чтобы получить еще лучшие результаты!
Вы также можете вручную воспроизвести результаты pipeline, если хотите:
Загрузите процессор для предобработки аудиофайла и транскрипции и верните input в виде тензоров PyTorch:
>>> from transformers import AutoProcessor
>>> processor = AutoProcessor.from_pretrained("stevhliu/my_awesome_asr_mind_model")
>>> inputs = processor(dataset[0]["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")Передайте входные данные в модель и получите логиты:
>>> from transformers import AutoModelForCTC
>>> model = AutoModelForCTC.from_pretrained("stevhliu/my_awesome_asr_mind_model")
>>> with torch.no_grad():
... logits = model(**inputs).logitsПолучите input_ids с наивысшей вероятностью и используйте процессор, чтобы декодировать предсказанные input_ids обратно в текст:
>>> import torch
>>> predicted_ids = torch.argmax(logits, dim=-1)
>>> transcription = processor.batch_decode(predicted_ids)
>>> transcription
['I WOUL LIKE O SET UP JOINT ACOUNT WTH Y PARTNER']