Transformers documentation

Reconhecimento automático de fala

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.1).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Reconhecimento automático de fala

O reconhecimento automático de fala (ASR) converte um sinal de fala em texto, mapeando uma sequência de entradas de áudio para saídas de texto. Assistentes virtuais como Siri e Alexa usam modelos de ASR para ajudar os usuários todos os dias, e existem muitas outras aplicações úteis voltadas ao usuário, como legendagem ao vivo e anotação de reuniões.

Este guia mostrará como:

  1. Ajuste finamente o Wav2Vec2 no conjunto de dados MInDS-14 para transcrever áudio em texto.
  2. Use seu modelo ajustado para inferência.

Para ver todas as arquiteturas e checkpoints compatíveis com esta tarefa, recomendamos consultar a página da tarefa

Antes de começar, verifique se você tem todas as bibliotecas necessárias instaladas:

pip install transformers datasets evaluate jiwer soundfile librosa torchcodec

Recomendamos que você faça login na sua conta do Hugging Face para que possa enviar e compartilhar seu modelo com a comunidade. Quando solicitado, insira seu token para fazer login:

>>> from huggingface_hub import notebook_login

>>> notebook_login()

Carregar o conjunto de dados MInDS-14

Comece carregando um subconjunto menor do conjunto de dados MInDS-14 a partir da biblioteca 🤗 Datasets. Isso lhe dará a oportunidade de experimentar e garantir que tudo funcione antes de gastar mais tempo treinando no conjunto de dados completo.

>>> from datasets import load_dataset, Audio

>>> minds = load_dataset("PolyAI/minds14", name="en-US", split="train[:100]")

Divida o split train do conjunto de dados em um conjunto de treino e um de teste com o método ~Dataset.train_test_split:

>>> minds = minds.train_test_split(test_size=0.2)

Em seguida, examine o conjunto de dados:

>>> 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
    })
})

Embora o conjunto de dados contenha muitas informações úteis, como lang_id e english_transcription, este guia se concentra em audio e transcription. Remova as outras colunas com o método remove_columns:

>>> minds = minds.remove_columns(["english_transcription", "intent_class", "lang_id"])

Revise o exemplo novamente:

>>> 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"}

Há dois campos:

  • audio: um array unidimensional do sinal de fala que deve ser chamado para carregar e reamostrar o arquivo de áudio.
  • transcription: o texto de destino.

Pré-processar

A próxima etapa é carregar um processador Wav2Vec2 para processar o sinal de áudio:

>>> from transformers import AutoProcessor

>>> processor = AutoProcessor.from_pretrained("facebook/wav2vec2-base")

O conjunto de dados MInDS-14 tem uma taxa de amostragem de 8000Hz (você pode encontrar essa informação em seu dataset card), o que significa que você precisará reamostrar o conjunto de dados para 16000Hz para usar o modelo Wav2Vec2 pré-treinado:

>>> 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"}

Como você pode ver na transcription acima, o texto contém uma mistura de caracteres maiúsculos e minúsculos. O tokenizer do Wav2Vec2 é treinado apenas com caracteres maiúsculos, então você precisa garantir que o texto corresponda ao vocabulário do tokenizer:

>>> def uppercase(example):
...     return {"transcription": example["transcription"].upper()}


>>> minds = minds.map(uppercase)

Agora, crie uma função de pré-processamento que:

  1. Chama a coluna audio para carregar e reamostrar o arquivo de áudio.
  2. Extrai o input_values do arquivo de áudio e tokeniza a coluna transcription com o processador.
>>> 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

Para aplicar a função de pré-processamento em todo o conjunto de dados, use a função map do 🤗 Datasets. Você pode acelerar o map aumentando o número de processos com o parâmetro num_proc. Remova as colunas de que você não precisa com o método remove_columns:

>>> encoded_minds = minds.map(prepare_dataset, remove_columns=minds.column_names["train"], num_proc=4)

🤗 Transformers não possui um data collator para ASR, portanto, você precisará adaptar o DataCollatorWithPadding para criar um lote de exemplos. Ele também fará o padding dinâmico do seu texto e dos rótulos até o comprimento do elemento mais longo do lote (em vez de todo o conjunto de dados), garantindo que tenham comprimento uniforme. Embora seja possível fazer o padding do texto na função tokenizer definindo padding=True, o padding dinâmico é mais eficiente.

Diferentemente de outros data collators, este data collator específico precisa aplicar um método de padding diferente para input_values e 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

Agora instancie seu DataCollatorCTCWithPadding:

>>> data_collator = DataCollatorCTCWithPadding(processor=processor, padding="longest")

Avaliar

Incluir uma métrica durante o treinamento é frequentemente útil para avaliar o desempenho do seu modelo. Você pode carregar rapidamente um método de avaliação com a biblioteca 🤗 Evaluate. Para esta tarefa, carregue a métrica word error rate (WER) (consulte o quick tour do 🤗 Evaluate para saber mais sobre o carregamento e o cálculo de métricas):

>>> import evaluate

>>> wer = evaluate.load("wer")

Em seguida, crie uma função que passa suas previsões e rótulos para compute para calcular o 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}

Sua função compute_metrics está pronta e você voltará a ela ao configurar o treinamento.

Treinar

Se você não está familiarizado com o ajuste fino de um modelo usando o Trainer, confira o tutorial básico aqui!

Agora você está pronto para começar a treinar seu modelo! Carregue o Wav2Vec2 com AutoModelForCTC. Especifique a redução a ser aplicada com o parâmetro ctc_loss_reduction. Geralmente, é melhor usar a média em vez da soma padrão:

>>> 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,
... )

Neste ponto, restam apenas três etapas:

  1. Defina os hiperparâmetros de treinamento em TrainingArguments. O único parâmetro obrigatório é output_dir, que especifica onde salvar seu modelo. Você enviará este modelo para o Hub definindo push_to_hub=True (é necessário estar conectado ao Hugging Face para enviar seu modelo). No final de cada epoch, o Trainer avaliará o WER e salvará o checkpoint de treinamento.
  2. Passe os argumentos de treinamento para o Trainer junto com o modelo, o conjunto de dados, o tokenizer, o data collator e a função compute_metrics.
  3. Chame train() para fazer o ajuste fino do seu modelo.
>>> 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()

Quando o treinamento for concluído, compartilhe seu modelo no Hub com o método push_to_hub() para que ele fique acessível a todos:

>>> trainer.push_to_hub()

Para um exemplo mais detalhado de como fazer o ajuste fino de um modelo para reconhecimento automático de fala, confira este post para ASR em inglês e este post para ASR multilíngue.

Inferência

Ótimo, agora que você ajustou um modelo, pode usá-lo para inferência!

Carregue um arquivo de áudio no qual você deseja executar inferência. Lembre-se de reamostrar a taxa de amostragem do arquivo de áudio para que ela corresponda à taxa de amostragem do modelo, se necessário!

>>> 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"]

A maneira mais simples de testar seu modelo ajustado para inferência é usá-lo em um pipeline(). Instancie um pipeline para reconhecimento automático de fala com seu modelo e passe seu arquivo de áudio para ele:

>>> 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'}

A transcrição é razoável, mas pode melhorar! Tente fazer o ajuste fino do seu modelo com mais exemplos para obter resultados ainda melhores!

Você também pode replicar manualmente os resultados do pipeline, se desejar:

Carregue um processador para pré-processar o arquivo de áudio e a transcrição e retornar o input como tensores do 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")

Passe suas entradas para o modelo e retorne os logits:

>>> from transformers import AutoModelForCTC

>>> model = AutoModelForCTC.from_pretrained("stevhliu/my_awesome_asr_mind_model")
>>> with torch.no_grad():
...     logits = model(**inputs).logits

Obtenha os input_ids previstos com a maior probabilidade e use o processador para decodificar os input_ids previstos de volta para texto:

>>> 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']
Update on GitHub