Introdução
Meta AI introduziu wav2vec2 XLS-R ("XLS-R") no final de 2021. XLS-R é um modelo de aprendizado de máquina ("ML") para aprendizagem de representações de fala multilíngues; e foi treinado em mais de 400.000 horas de áudio de fala disponível publicamente em 128 idiomas. Após seu lançamento, o modelo representou um salto em relação ao modelo multilíngue XLSR-53 da Meta AI, que foi treinado em aproximadamente 50.000 horas de áudio de fala em 53 idiomas.
Este guia explica as etapas para ajustar o XLS-R para reconhecimento automático de fala ("ASR") usando um Kaggle Notebook . O modelo será ajustado em espanhol chileno, mas os passos gerais podem ser seguidos para ajustar o XLS-R nos diferentes idiomas que você desejar.
A execução da inferência no modelo ajustado será descrita em um tutorial complementar, tornando este guia a primeira de duas partes. Decidi criar um guia específico de inferência separado, pois este guia de ajuste fino ficou um pouco longo.
Presume-se que você tenha experiência em ML e entenda os conceitos básicos de ASR. Os iniciantes podem ter dificuldade em seguir/compreender as etapas de construção.
Um pouco de experiência no XLS-R
O modelo wav2vec2 original introduzido em 2020 foi pré-treinado em 960 horas de áudio de fala do conjunto de dados Librispeech e aproximadamente 53.200 horas de áudio de fala do conjunto de dados LibriVox . No seu lançamento, dois tamanhos de modelo estavam disponíveis: o modelo BASE com 95 milhões de parâmetros e o modelo LARGE com 317 milhões de parâmetros.
O XLS-R, por outro lado, foi pré-treinado em áudio de fala multilíngue a partir de 5 conjuntos de dados:
- VoxPopuli : Um total de aproximadamente 372.000 horas de discurso em áudio em 23 línguas europeias de discurso parlamentar do Parlamento Europeu.
- Librispeech multilíngue : um total de aproximadamente 50.000 horas de áudio de fala em oito idiomas europeus, com a maioria (~44.000 horas) de dados de áudio em inglês.
- CommonVoice : um total de aproximadamente 7.000 horas de áudio de fala em 60 idiomas.
- VoxLingua107 : Um total de aproximadamente 6.600 horas de áudio de fala em 107 idiomas com base no conteúdo do YouTube.
- BABEL : Um total de aproximadamente 1.100 horas de fala em áudio em 17 idiomas africanos e asiáticos, com base em conversação por telefone.
Existem 3 modelos XLS-R: XLS-R (0,3B) com 300 milhões de parâmetros, XLS-R (1B) com 1 bilhão de parâmetros e XLS-R (2B) com 2 bilhões de parâmetros. Este guia usará o modelo XLS-R (0,3B).
Abordagem
Existem alguns ótimos artigos sobre como ajustar os modelos wav2vev2 , talvez este seja uma espécie de "padrão ouro". É claro que a abordagem geral aqui imita o que você encontrará em outros guias. Você irá:
- Carregue um conjunto de dados de treinamento de dados de áudio e transcrições de texto associadas.
- Crie um vocabulário a partir das transcrições de texto no conjunto de dados.
- Inicialize um processador wav2vec2 que extrairá recursos dos dados de entrada, bem como converterá transcrições de texto em sequências de rótulos.
- Ajuste wav2vec2 XLS-R nos dados de entrada processados.
No entanto, existem três diferenças principais entre este guia e outros:
- O guia não fornece tanta discussão “inline” sobre conceitos relevantes de ML e ASR.
- Embora cada subseção em células individuais do notebook inclua detalhes sobre o uso/finalidade da célula específica, presume-se que você tenha experiência em ML e que entenda os conceitos básicos de ASR.
- O Kaggle Notebook que você construirá organiza métodos utilitários em células de nível superior.
- Considerando que muitos notebooks de ajuste fino tendem a ter um layout do tipo "fluxo de consciência", optei por organizar todos os métodos utilitários juntos. Se você é novo no wav2vec2, pode achar essa abordagem confusa. No entanto, para reiterar, faço o possível para ser explícito ao explicar a finalidade de cada célula na subseção dedicada a cada célula. Se você está apenas aprendendo sobre wav2vec2, pode se beneficiar dando uma rápida olhada em meu artigo HackerNoon wav2vec2 para reconhecimento automático de fala em inglês simples .
- Este guia descreve as etapas apenas para ajuste fino.
- Conforme mencionado na Introdução , optei por criar um guia complementar separado sobre como executar inferência no modelo XLS-R ajustado que você irá gerar. Isto foi feito para evitar que este guia se tornasse excessivamente longo.
Pré-requisitos e antes de começar
Para completar o guia, você precisará ter:
- Uma conta Kaggle existente. Se você não possui uma conta Kaggle, você precisa criar uma.
- Uma conta existente de Pesos e Vieses ("WandB") . Se você não tiver uma conta Weights and Biases, será necessário criar uma.
- Uma chave de API WandB. Se você não tiver uma chave de API WandB, siga as etapas aqui .
- Conhecimento intermediário de Python.
- Conhecimento intermediário de trabalho com Kaggle Notebooks.
- Conhecimento intermediário de conceitos de ML.
- Conhecimento básico dos conceitos de ASR.
Antes de começar a construir o notebook, pode ser útil revisar as duas subseções diretamente abaixo. Eles descrevem:
- O conjunto de dados de treinamento.
- A métrica Word Error Rate ("WER") usada durante o treinamento.
Conjunto de dados de treinamento
Conforme mencionado na Introdução , o modelo XLS-R será aprimorado no espanhol chileno. O conjunto de dados específico é o conjunto de dados de fala do espanhol chileno desenvolvido por Guevara-Rukoz et al. Ele está disponível para download no OpenSLR . O conjunto de dados consiste em dois subconjuntos de dados: (1) 2.636 gravações de áudio de falantes chilenos do sexo masculino e (2) 1.738 gravações de áudio de falantes chilenos do sexo feminino.
Cada subconjunto de dados inclui um arquivo de índice line_index.tsv
. Cada linha de cada arquivo de índice contém um par de nome de arquivo de áudio e uma transcrição do áudio no arquivo associado, por exemplo:
clm_08421_01719502739 Es un viaje de negocios solamente voy por una noche clm_02436_02011517900 Se usa para incitar a alguien a sacar el mayor provecho del dia presente
Carreguei o conjunto de dados da fala em espanhol chileno no Kaggle por conveniência. Há um conjunto de dados Kaggle para gravações de falantes chilenos do sexo masculino e um conjunto de dados Kaggle para gravações de falantes chilenos do sexo feminino . Esses conjuntos de dados Kaggle serão adicionados ao Kaggle Notebook que você construirá seguindo as etapas deste guia.
Taxa de erro de palavras (WER)
WER é uma métrica que pode ser usada para medir o desempenho de modelos automáticos de reconhecimento de fala. O WER fornece um mecanismo para medir o quão próxima uma previsão de texto está de uma referência de texto. O WER faz isso registrando erros de 3 tipos:
substituições (
S
): Um erro de substituição é registrado quando a predição contém uma palavra diferente da palavra análoga na referência. Por exemplo, isso ocorre quando a previsão escreve incorretamente uma palavra na referência.exclusões (
D
): Um erro de exclusão é registrado quando a predição contém uma palavra que não está presente na referência.inserções (
I
): Um erro de inserção é registrado quando a predição não contém uma palavra que esteja presente na referência.
Obviamente, o WER funciona no nível da palavra. A fórmula para a métrica WER é a seguinte:
WER = (S + D + I)/N where: S = number of substition errors D = number of deletion errors I = number of insertion errors N = number of words in the reference
Um exemplo simples de WER em espanhol é o seguinte:
prediction: "Él está saliendo." reference: "Él está saltando."
Uma tabela ajuda a visualizar os erros na previsão:
TEXTO | PALAVRA 1 | PALAVRA 2 | PALAVRA 3 |
---|---|---|---|
predição | Él | está | destacando |
referência | Él | está | saltando |
| correto | correto | substituição |
A previsão contém 1 erro de substituição, 0 erros de exclusão e 0 erros de inserção. Portanto, o WER para este exemplo é:
WER = 1 + 0 + 0 / 3 = 1/3 = 0.33
Deveria ser óbvio que a taxa de erros de palavras não nos diz necessariamente quais erros específicos existem. No exemplo acima, o WER identifica que a PALAVRA 3 contém um erro no texto previsto, mas não nos diz que os caracteres i e e estão errados na previsão. Outras métricas, como a Taxa de Erros de Caracteres ("CER"), podem ser usadas para análises de erros mais precisas.
Construindo o caderno de ajuste fino
Agora você está pronto para começar a construir o notebook de ajuste fino.
- A Etapa 1 e a Etapa 2 orientam você na configuração do ambiente Kaggle Notebook.
- A Etapa 3 orienta você na construção do próprio notebook. Ele contém 32 subetapas que representam as 32 células do caderno de ajuste fino.
- A Etapa 4 orienta você na execução do notebook, no monitoramento do treinamento e no salvamento do modelo.
Etapa 1 – Obtenha sua chave de API WandB
Seu Kaggle Notebook deve ser configurado para enviar dados de execução de treinamento para WandB usando sua chave de API WandB. Para fazer isso, você precisa copiá-lo.
- Faça login no WandB em
www.wandb.com
. - Navegue para
www.wandb.ai/authorize
. - Copie sua chave de API para usar na próxima etapa.
Passo 2 - Configurando Seu Ambiente Kaggle
Passo 2.1 - Criando um novo caderno Kaggle
- Faça login no Kaggle.
- Crie um novo caderno Kaggle.
- Claro, o nome do notebook pode ser alterado conforme desejado. Este guia usa o nome do notebook
xls-r-300m-chilean-spanish-asr
.
Passo 2.2 - Configurando sua chave API WandB
Um segredo Kaggle será usado para armazenar com segurança sua chave API WandB.
- Clique em Complementos no menu principal do Kaggle Notebook.
- Selecione Segredo no menu pop-up.
- Insira o rótulo
WANDB_API_KEY
no campo Rótulo e insira sua chave de API WandB para o valor. - Certifique-se de que a caixa de seleção Anexado à esquerda do campo de rótulo
WANDB_API_KEY
esteja marcada. - Clique em Concluído .
Passo 2.3 - Adicionando os conjuntos de dados de treinamento
O conjunto de dados de fala do espanhol chileno foi carregado no Kaggle como 2 conjuntos de dados distintos:
Adicione esses dois conjuntos de dados ao seu Kaggle Notebook.
Passo 3 - Construindo o Caderno de Ajuste Fino
As 32 subetapas a seguir constroem cada uma das 32 células do notebook de ajuste fino em ordem.
Passo 3.1 - CÉLULA 1: Instalando Pacotes
A primeira célula do notebook de ajuste fino instala dependências. Defina a primeira célula como:
### CELL 1: Install Packages ### !pip install --upgrade torchaudio !pip install jiwer
- A primeira linha atualiza o pacote
torchaudio
para a versão mais recente.torchaudio
será usado para carregar arquivos de áudio e reamostrar dados de áudio. - A segunda linha instala o pacote
jiwer
que é necessário para usar o métodoload_metric
da biblioteca HuggingFaceDatasets
usado posteriormente.
Etapa 3.2 - CÉLULA 2: Importando Pacotes Python
As importações da segunda célula exigiam pacotes Python. Defina a segunda célula como:
### CELL 2: Import Python packages ### import wandb from kaggle_secrets import UserSecretsClient import math import re import numpy as np import pandas as pd import torch import torchaudio import json from typing import Any, Dict, List, Optional, Union from dataclasses import dataclass from datasets import Dataset, load_metric, load_dataset, Audio from transformers import Wav2Vec2CTCTokenizer from transformers import Wav2Vec2FeatureExtractor from transformers import Wav2Vec2Processor from transformers import Wav2Vec2ForCTC from transformers import TrainingArguments from transformers import Trainer
- Você provavelmente já está familiarizado com a maioria desses pacotes. Seu uso no notebook será explicado à medida que as células subsequentes forem construídas.
- Vale a pena mencionar que a biblioteca
transformers
HuggingFace e as classesWav2Vec2*
associadas fornecem a espinha dorsal da funcionalidade usada para ajuste fino.
Etapa 3.3 - CÉLULA 3: Carregando Métrica WER
A terceira célula importa a métrica de avaliação HuggingFace WER. Defina a terceira célula como:
### CELL 3: Load WER metric ### wer_metric = load_metric("wer")
- Conforme mencionado anteriormente, o WER será usado para medir o desempenho do modelo em dados de avaliação/resistência.
Etapa 3.4 - CÉLULA 4: Login no WandB
A quarta célula recupera seu segredo WANDB_API_KEY
que foi definido na Etapa 2.2 . Defina a quarta célula como:
### CELL 4: Login to WandB ### user_secrets = UserSecretsClient() wandb_api_key = user_secrets.get_secret("WANDB_API_KEY") wandb.login(key = wandb_api_key)
- A chave API é usada para configurar o Kaggle Notebook para que os dados da execução de treinamento sejam enviados ao WandB.
Passo 3.5 - CÉLULA 5: Configurando Constantes
A quinta célula define constantes que serão usadas em todo o notebook. Defina a quinta célula como:
### CELL 5: Constants ### # Training data TRAINING_DATA_PATH_MALE = "/kaggle/input/google-spanish-speakers-chile-male/" TRAINING_DATA_PATH_FEMALE = "/kaggle/input/google-spanish-speakers-chile-female/" EXT = ".wav" NUM_LOAD_FROM_EACH_SET = 1600 # Vocabulary VOCAB_FILE_PATH = "/kaggle/working/" SPECIAL_CHARS = r"[\d\,\-\;\!\¡\?\¿\।\'\'\"\–\'\:\/\.\“\”\৷\…\‚\॥\\]" # Sampling rates ORIG_SAMPLING_RATE = 48000 TGT_SAMPLING_RATE = 16000 # Training/validation data split SPLIT_PCT = 0.10 # Model parameters MODEL = "facebook/wav2vec2-xls-r-300m" USE_SAFETENSORS = False # Training arguments OUTPUT_DIR_PATH = "/kaggle/working/xls-r-300m-chilean-spanish-asr" TRAIN_BATCH_SIZE = 18 EVAL_BATCH_SIZE = 10 TRAIN_EPOCHS = 30 SAVE_STEPS = 3200 EVAL_STEPS = 100 LOGGING_STEPS = 100 LEARNING_RATE = 1e-4 WARMUP_STEPS = 800
- O notebook não apresenta todas as constantes concebíveis nesta célula. Alguns valores que poderiam ser representados por constantes foram deixados em linha.
- O uso de muitas das constantes acima deve ser evidente. Caso contrário, seu uso será explicado nas subetapas a seguir.
Etapa 3.6 - CÉLULA 6: Métodos utilitários para leitura de arquivos de índice, limpeza de texto e criação de vocabulário
A sexta célula define métodos utilitários para ler os arquivos de índice do conjunto de dados (consulte a subseção Conjunto de dados de treinamento acima), bem como para limpar o texto da transcrição e criar o vocabulário. Defina a sexta célula como:
### CELL 6: Utility methods for reading index files, cleaning text, and creating vocabulary ### def read_index_file_data(path: str, filename: str): data = [] with open(path + filename, "r", encoding = "utf8") as f: lines = f.readlines() for line in lines: file_and_text = line.split("\t") data.append([path + file_and_text[0] + EXT, file_and_text[1].replace("\n", "")]) return data def truncate_training_dataset(dataset: list) -> list: if type(NUM_LOAD_FROM_EACH_SET) == str and "all" == NUM_LOAD_FROM_EACH_SET.lower(): return else: return dataset[:NUM_LOAD_FROM_EACH_SET] def clean_text(text: str) -> str: cleaned_text = re.sub(SPECIAL_CHARS, "", text) cleaned_text = cleaned_text.lower() return cleaned_text def create_vocab(data): vocab_list = [] for index in range(len(data)): text = data[index][1] words = text.split(" ") for word in words: chars = list(word) for char in chars: if char not in vocab_list: vocab_list.append(char) return vocab_list
O método
read_index_file_data
lê um arquivo de índice do conjunto de dadosline_index.tsv
e produz uma lista de listas com nomes de arquivos de áudio e dados de transcrição, por exemplo:
[ ["/kaggle/input/google-spanish-speakers-chile-male/clm_08421_01719502739", "Es un viaje de negocios solamente voy por una noche"] ... ]
- O método
truncate_training_dataset
trunca os dados de um arquivo de índice de lista usando a constanteNUM_LOAD_FROM_EACH_SET
definida na Etapa 3.5 . Especificamente, a constanteNUM_LOAD_FROM_EACH_SET
é usada para especificar o número de amostras de áudio que devem ser carregadas de cada conjunto de dados. Para os fins deste guia, o número é definido como1600
o que significa que um total de3200
amostras de áudio serão eventualmente carregadas. Para carregar todas as amostras, definaNUM_LOAD_FROM_EACH_SET
como o valor da stringall
. - O método
clean_text
é usado para retirar cada transcrição de texto dos caracteres especificados pela expressão regular atribuída aSPECIAL_CHARS
na Etapa 3.5 . Esses caracteres, inclusive a pontuação, podem ser eliminados, pois não fornecem nenhum valor semântico ao treinar o modelo para aprender mapeamentos entre recursos de áudio e transcrições de texto. - O método
create_vocab
cria um vocabulário a partir de transcrições de texto limpas. Simplesmente, ele extrai todos os caracteres exclusivos do conjunto de transcrições de texto limpas. Você verá um exemplo do vocabulário gerado na Etapa 3.14 .
Etapa 3.7 - CÉLULA 7: Métodos Utilitários para Carregar e Reamostrar Dados de Áudio
A sétima célula define métodos utilitários usando torchaudio
para carregar e reamostrar dados de áudio. Defina a sétima célula como:
### CELL 7: Utility methods for loading and resampling audio data ### def read_audio_data(file): speech_array, sampling_rate = torchaudio.load(file, normalize = True) return speech_array, sampling_rate def resample(waveform): transform = torchaudio.transforms.Resample(ORIG_SAMPLING_RATE, TGT_SAMPLING_RATE) waveform = transform(waveform) return waveform[0]
- O método
read_audio_data
carrega um arquivo de áudio especificado e retorna uma matriz multidimensionaltorch.Tensor
dos dados de áudio junto com a taxa de amostragem do áudio. Todos os arquivos de áudio nos dados de treinamento têm uma taxa de amostragem de48000
Hz. Esta taxa de amostragem "original" é capturada pela constanteORIG_SAMPLING_RATE
na Etapa 3.5 . - O método
resample
é usado para reduzir a resolução de dados de áudio de uma taxa de amostragem de48000
a16000
. wav2vec2 é pré-treinado em áudio amostrado a16000
Hz. Conseqüentemente, qualquer áudio usado para ajuste fino deve ter a mesma taxa de amostragem. Neste caso, os exemplos de áudio devem ser reduzidos de48000
Hz para16000
Hz.16000
Hz são capturados pela constanteTGT_SAMPLING_RATE
na Etapa 3.5 .
Etapa 3.8 - CÉLULA 8: Métodos Utilitários para Preparar Dados para Treinamento
A oitava célula define métodos utilitários que processam os dados de áudio e transcrição. Defina a oitava célula como:
### CELL 8: Utility methods to prepare input data for training ### def process_speech_audio(speech_array, sampling_rate): input_values = processor(speech_array, sampling_rate = sampling_rate).input_values return input_values[0] def process_target_text(target_text): with processor.as_target_processor(): encoding = processor(target_text).input_ids return encoding
- O método
process_speech_audio
retorna os valores de entrada de uma amostra de treinamento fornecida. - O método
process_target_text
codifica cada transcrição de texto como uma lista de rótulos - ou seja, uma lista de índices referentes a caracteres do vocabulário. Você verá um exemplo de codificação na Etapa 3.15 .
Etapa 3.9 - CÉLULA 9: Método utilitário para calcular a taxa de erros de palavras
A nona célula é a célula final do método utilitário e contém o método para calcular a taxa de erro de palavra entre uma transcrição de referência e uma transcrição prevista. Defina a nona célula como:
### CELL 9: Utility method to calculate Word Error Rate def compute_wer(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 = wer_metric.compute(predictions = pred_str, references = label_str) return {"wer": wer}
Etapa 3.10 - CÉLULA 10: Lendo dados de treinamento
A décima célula lê os arquivos de índice de dados de treinamento para as gravações de falantes do sexo masculino e as gravações de falantes do sexo feminino usando o método read_index_file_data
definido na Etapa 3.6 . Defina a décima célula como:
### CELL 10: Read training data ### training_samples_male_cl = read_index_file_data(TRAINING_DATA_PATH_MALE, "line_index.tsv") training_samples_female_cl = read_index_file_data(TRAINING_DATA_PATH_FEMALE, "line_index.tsv")
- Como visto, os dados de formação são geridos em duas listas específicas de género neste momento. Os dados serão combinados na Etapa 3.12 após o truncamento.
Etapa 3.11 - CÉLULA 11: Truncando dados de treinamento
A décima primeira célula trunca as listas de dados de treinamento usando o método truncate_training_dataset
definido na Etapa 3.6 . Defina a décima primeira célula como:
### CELL 11: Truncate training data ### training_samples_male_cl = truncate_training_dataset(training_samples_male_cl) training_samples_female_cl = truncate_training_dataset(training_samples_female_cl)
- Como lembrete, a constante
NUM_LOAD_FROM_EACH_SET
definida na Etapa 3.5 define a quantidade de amostras a serem mantidas em cada conjunto de dados. A constante é definida como1600
neste guia para um total de3200
amostras.
Etapa 3.12 - CÉLULA 12: Combinando dados de amostras de treinamento
A décima segunda célula combina as listas de dados de treinamento truncadas. Defina a décima segunda célula como:
### CELL 12: Combine training samples data ### all_training_samples = training_samples_male_cl + training_samples_female_cl
Etapa 3.13 - CÉLULA 13: Teste de transcrição de limpeza
A décima terceira célula itera sobre cada amostra de dados de treinamento e limpa o texto de transcrição associado usando o método clean_text
definido na Etapa 3.6 . Defina a décima terceira célula como:
for index in range(len(all_training_samples)): all_training_samples[index][1] = clean_text(all_training_samples[index][1])
Passo 3.14 - CÉLULA 14: Criando o Vocabulário
A décima quarta célula cria um vocabulário usando as transcrições limpas da etapa anterior e o método create_vocab
definido na Etapa 3.6 . Defina a décima quarta célula como:
### CELL 14: Create vocabulary ### vocab_list = create_vocab(all_training_samples) vocab_dict = {v: i for i, v in enumerate(vocab_list)}
O vocabulário é armazenado como um dicionário com caracteres como chaves e índices de vocabulário como valores.
Você pode imprimir
vocab_dict
que deve produzir a seguinte saída:
{'l': 0, 'a': 1, 'v': 2, 'i': 3, 'g': 4, 'e': 5, 'n': 6, 'c': 7, 'd': 8, 't': 9, 'u': 10, 'r': 11, 'j': 12, 's': 13, 'o': 14, 'h': 15, 'm': 16, 'q': 17, 'b': 18, 'p': 19, 'y': 20, 'f': 21, 'z': 22, 'á': 23, 'ú': 24, 'í': 25, 'ó': 26, 'é': 27, 'ñ': 28, 'x': 29, 'k': 30, 'w': 31, 'ü': 32}
Etapa 3.15 - CÉLULA 15: Adicionando delimitador de palavras ao vocabulário
A décima quinta célula adiciona o caractere delimitador de palavra |
ao vocabulário. Defina a décima quinta célula como:
### CELL 15: Add word delimiter to vocabulary ### vocab_dict["|"] = len(vocab_dict)
O caractere delimitador de palavra é usado ao tokenizar transcrições de texto como uma lista de rótulos. Especificamente, é usado para definir o final de uma palavra e é usado ao inicializar a classe
Wav2Vec2CTCTokenizer
, como será visto na Etapa 3.17 .Por exemplo, a lista a seguir codifica
no te entiendo nada
usando o vocabulário da Etapa 3.14 :
# Encoded text [6, 14, 33, 9, 5, 33, 5, 6, 9, 3, 5, 6, 8, 14, 33, 6, 1, 8, 1] # Vocabulary {'l': 0, 'a': 1, 'v': 2, 'i': 3, 'g': 4, 'e': 5, 'n': 6, 'c': 7, 'd': 8, 't': 9, 'u': 10, 'r': 11, 'j': 12, 's': 13, 'o': 14, 'h': 15, 'm': 16, 'q': 17, 'b': 18, 'p': 19, 'y': 20, 'f': 21, 'z': 22, 'á': 23, 'ú': 24, 'í': 25, 'ó': 26, 'é': 27, 'ñ': 28, 'x': 29, 'k': 30, 'w': 31, 'ü': 32, '|': 33}
- Uma questão que pode surgir naturalmente é: "Por que é necessário definir um caractere delimitador de palavras?" Por exemplo, o final das palavras escritas em inglês e espanhol são marcados por espaços em branco, portanto, deve ser simples usar o caractere de espaço como delimitador de palavras. Lembre-se que o inglês e o espanhol são apenas duas línguas entre milhares; e nem todas as línguas escritas usam um espaço para marcar os limites das palavras.
Etapa 3.16 - CÉLULA 16: Exportando Vocabulário
A décima sexta célula despeja o vocabulário em um arquivo. Defina a décima sexta célula como:
### CELL 16: Export vocabulary ### with open(VOCAB_FILE_PATH + "vocab.json", "w", encoding = "utf8") as vocab_file: json.dump(vocab_dict, vocab_file)
- O arquivo de vocabulário será usado na próxima etapa, Etapa 3.17 , para inicializar a classe
Wav2Vec2CTCTokenizer
.
Etapa 3.17 - CÉLULA 17: Inicializar o Tokenizer
A décima sétima célula inicializa uma instância de Wav2Vec2CTCTokenizer
. Defina a décima sétima célula como:
### CELL 17: Initialize tokenizer ### tokenizer = Wav2Vec2CTCTokenizer( VOCAB_FILE_PATH + "vocab.json", unk_token = "[UNK]", pad_token = "[PAD]", word_delimiter_token = "|", replace_word_delimiter_char = " " )
O tokenizer é usado para codificar transcrições de texto e decodificar uma lista de rótulos de volta ao texto.
Observe que o
tokenizer
é inicializado com[UNK]
atribuído aunk_token
e[PAD]
atribuído apad_token
, com o primeiro usado para representar tokens desconhecidos em transcrições de texto e o último usado para preencher transcrições ao criar lotes de transcrições com comprimentos diferentes. Esses dois valores serão adicionados ao vocabulário pelo tokenizer.A inicialização do tokenizer nesta etapa também adicionará dois tokens adicionais ao vocabulário, nomeadamente
<s>
e/</s>
que são usados para demarcar o início e o fim das frases, respectivamente.|
é atribuído aword_delimiter_token
explicitamente nesta etapa para refletir que o símbolo de barra vertical será usado para demarcar o final das palavras de acordo com nossa adição do caractere ao vocabulário na Etapa 3.15 . O|
símbolo é o valor padrão paraword_delimiter_token
. Portanto, não precisou ser definido explicitamente, mas foi feito por uma questão de clareza.Da mesma forma que com
word_delimiter_token
, um único espaço é explicitamente atribuído areplace_word_delimiter_char
refletindo que o símbolo de barra vertical|
será usado para substituir caracteres de espaço em branco nas transcrições de texto. Espaço em branco é o valor padrão parareplace_word_delimiter_char
. Portanto, também não precisou ser definido explicitamente, mas foi feito por uma questão de clareza.Você pode imprimir o vocabulário completo do tokenizer chamando o método
get_vocab()
emtokenizer
.
vocab = tokenizer.get_vocab() print(vocab) # Output: {'e': 0, 's': 1, 'u': 2, 'n': 3, 'v': 4, 'i': 5, 'a': 6, 'j': 7, 'd': 8, 'g': 9, 'o': 10, 'c': 11, 'l': 12, 'm': 13, 't': 14, 'y': 15, 'p': 16, 'r': 17, 'h': 18, 'ñ': 19, 'ó': 20, 'b': 21, 'q': 22, 'f': 23, 'ú': 24, 'z': 25, 'é': 26, 'í': 27, 'x': 28, 'á': 29, 'w': 30, 'k': 31, 'ü': 32, '|': 33, '<s>': 34, '</s>': 35, '[UNK]': 36, '[PAD]': 37}
Etapa 3.18 - CÉLULA 18: Inicializando o Extrator de Recursos
A décima oitava célula inicializa uma instância de Wav2Vec2FeatureExtractor
. Defina a décima oitava célula como:
### CELL 18: Initialize feature extractor ### feature_extractor = Wav2Vec2FeatureExtractor( feature_size = 1, sampling_rate = 16000, padding_value = 0.0, do_normalize = True, return_attention_mask = True )
- O extrator de recursos é usado para extrair recursos de dados de entrada que são, obviamente, dados de áudio neste caso de uso. Você carregará os dados de áudio para cada amostra de dados de treinamento na Etapa 3.20 .
- Os valores dos parâmetros passados para o inicializador
Wav2Vec2FeatureExtractor
são todos valores padrão, com exceção dereturn_attention_mask
cujo padrão éFalse
. Os valores padrão são mostrados/passados para maior clareza. - O parâmetro
feature_size
especifica o tamanho da dimensão dos recursos de entrada (ou seja, recursos de dados de áudio). O valor padrão deste parâmetro é1
. -
sampling_rate
informa ao extrator de recursos a taxa de amostragem na qual os dados de áudio devem ser digitalizados. Conforme discutido na Etapa 3.7 , wav2vec2 é pré-treinado em áudio amostrado em16000
Hz e, portanto,16000
é o valor padrão para este parâmetro. - O parâmetro
padding_value
especifica o valor usado ao preencher dados de áudio, conforme necessário ao agrupar amostras de áudio de diferentes durações. O valor padrão é0.0
. -
do_normalize
é usado para especificar se os dados de entrada devem ser transformados em uma distribuição normal padrão. O valor padrão éTrue
. A documentação da classeWav2Vec2FeatureExtractor
observa que "[normalizar] pode ajudar a melhorar significativamente o desempenho de alguns modelos." - Os parâmetros
return_attention_mask
especificam se a máscara de atenção deve ser passada ou não. O valor é definido comoTrue
para este caso de uso.
Etapa 3.19 - CÉLULA 19: Inicializando o Processador
A décima nona célula inicializa uma instância de Wav2Vec2Processor
. Defina a décima nona célula como:
### CELL 19: Initialize processor ### processor = Wav2Vec2Processor(feature_extractor = feature_extractor, tokenizer = tokenizer)
A classe
Wav2Vec2Processor
combinatokenizer
efeature_extractor
da Etapa 3.17 e Etapa 3.18 respectivamente em um único processador.Observe que a configuração do processador pode ser salva chamando o método
save_pretrained
na instância da classeWav2Vec2Processor
.
processor.save_pretrained(OUTPUT_DIR_PATH)
Etapa 3.20 - CÉLULA 20: Carregando Dados de Áudio
A vigésima célula carrega cada arquivo de áudio especificado na lista all_training_samples
. Defina a vigésima célula como:
### CELL 20: Load audio data ### all_input_data = [] for index in range(len(all_training_samples)): speech_array, sampling_rate = read_audio_data(all_training_samples[index][0]) all_input_data.append({ "input_values": speech_array, "labels": all_training_samples[index][1] })
- Os dados de áudio são retornados como
torch.Tensor
e armazenados emall_input_data
como uma lista de dicionários. Cada dicionário contém os dados de áudio de uma amostra específica, juntamente com a transcrição do texto do áudio. - Observe que o método
read_audio_data
também retorna a taxa de amostragem dos dados de áudio. Como sabemos que a taxa de amostragem é de48000
Hz para todos os arquivos de áudio neste caso de uso, a taxa de amostragem é ignorada nesta etapa.
Etapa 3.21 - CÉLULA 21: Convertendo all_input_data
em um Pandas DataFrame
A vigésima primeira célula converte a lista all_input_data
em um Pandas DataFrame para facilitar a manipulação dos dados. Defina a vigésima primeira célula como:
### CELL 21: Convert audio training data list to Pandas DataFrame ### all_input_data_df = pd.DataFrame(data = all_input_data)
Etapa 3.22 - CÉLULA 22: Processamento de dados de áudio e transcrições de texto
A vigésima segunda célula usa o processor
inicializado na Etapa 3.19 para extrair recursos de cada amostra de dados de áudio e codificar cada transcrição de texto como uma lista de rótulos. Defina a vigésima segunda célula para:
### CELL 22: Process audio data and text transcriptions ### all_input_data_df["input_values"] = all_input_data_df["input_values"].apply(lambda x: process_speech_audio(resample(x), 16000)) all_input_data_df["labels"] = all_input_data_df["labels"].apply(lambda x: process_target_text(x))
Etapa 3.23 - CÉLULA 23: Divisão de dados de entrada em conjuntos de dados de treinamento e validação
A vigésima terceira célula divide o DataFrame all_input_data_df
em conjuntos de dados de treinamento e avaliação (validação) usando a constante SPLIT_PCT
da Etapa 3.5 . Defina a vigésima terceira célula como:
### CELL 23: Split input data into training and validation datasets ### split = math.floor((NUM_LOAD_FROM_EACH_SET * 2) * SPLIT_PCT) valid_data_df = all_input_data_df.iloc[-split:] train_data_df = all_input_data_df.iloc[:-split]
- O valor
SPLIT_PCT
é0.10
neste guia, o que significa que 10% de todos os dados de entrada serão mantidos para avaliação e 90% dos dados serão usados para treinamento/ajuste. - Como há um total de 3.200 amostras de treinamento, 320 amostras serão usadas para avaliação e as 2.880 amostras restantes serão usadas para ajustar o modelo.
Etapa 3.24 - CÉLULA 24: Convertendo conjuntos de dados de treinamento e validação em objetos Dataset
A vigésima quarta célula converte os DataFrames train_data_df
e valid_data_df
em objetos Dataset
. Defina a vigésima quarta célula para:
### CELL 24: Convert training and validation datasets to Dataset objects ### train_data = Dataset.from_pandas(train_data_df) valid_data = Dataset.from_pandas(valid_data_df)
Os objetos
Dataset
são consumidos pelas instâncias da classe HuggingFaceTrainer
, como você verá na Etapa 3.30 .Esses objetos contêm metadados sobre o conjunto de dados, bem como sobre o próprio conjunto de dados.
Você pode imprimir
train_data
evalid_data
para visualizar os metadados de ambos os objetosDataset
.
print(train_data) print(valid_data) # Output: Dataset({ features: ['input_values', 'labels'], num_rows: 2880 }) Dataset({ features: ['input_values', 'labels'], num_rows: 320 })
Etapa 3.25 - CÉLULA 25: Inicializando o modelo pré-treinado
A vigésima quinta célula inicializa o modelo XLS-R (0,3) pré-treinado. Defina a vigésima quinta célula para:
### CELL 25: Initialize pretrained model ### model = Wav2Vec2ForCTC.from_pretrained( MODEL, ctc_loss_reduction = "mean", pad_token_id = processor.tokenizer.pad_token_id, vocab_size = len(processor.tokenizer) )
- O método
from_pretrained
chamado emWav2Vec2ForCTC
especifica que queremos carregar os pesos pré-treinados para o modelo especificado. - A constante
MODEL
foi especificada na Etapa 3.5 e definida comofacebook/wav2vec2-xls-r-300m
refletindo o modelo XLS-R (0,3). - O parâmetro
ctc_loss_reduction
especifica o tipo de redução a ser aplicada à saída da função de perda da Classificação Temporal Conexionista ("CTC"). A perda CTC é usada para calcular a perda entre uma entrada contínua, neste caso dados de áudio, e uma sequência alvo, neste caso transcrições de texto. Ao definir o valor comomean
, as perdas de saída para um lote de entradas serão divididas pelos comprimentos alvo. A média do lote é então calculada e a redução é aplicada aos valores de perda. -
pad_token_id
especifica o token a ser usado para preenchimento durante o lote. Ele é definido como o ID[PAD]
definido ao inicializar o tokenizer na Etapa 3.17 . - O parâmetro
vocab_size
define o tamanho do vocabulário do modelo. É o tamanho do vocabulário após a inicialização do tokenizer na Etapa 3.17 e reflete o número de nós da camada de saída da parte direta da rede.
Etapa 3.26 - CÉLULA 26: Pesos do Extrator de Recurso de Congelamento
A vigésima sexta célula congela os pesos pré-treinados do extrator de recursos. Defina a vigésima sexta célula como:
### CELL 26: Freeze feature extractor ### model.freeze_feature_extractor()
Etapa 3.27 - CÉLULA 27: Definindo Argumentos de Treinamento
A vigésima sétima célula inicializa os argumentos de treinamento que serão passados para uma instância Trainer
. Defina a vigésima sétima célula para:
### CELL 27: Set training arguments ### training_args = TrainingArguments( output_dir = OUTPUT_DIR_PATH, save_safetensors = False, group_by_length = True, per_device_train_batch_size = TRAIN_BATCH_SIZE, per_device_eval_batch_size = EVAL_BATCH_SIZE, num_train_epochs = TRAIN_EPOCHS, gradient_checkpointing = True, evaluation_strategy = "steps", save_strategy = "steps", logging_strategy = "steps", eval_steps = EVAL_STEPS, save_steps = SAVE_STEPS, logging_steps = LOGGING_STEPS, learning_rate = LEARNING_RATE, warmup_steps = WARMUP_STEPS )
- A classe
TrainingArguments
aceita mais de 100 parâmetros . - O parâmetro
save_safetensors
quandoFalse
especifica que o modelo ajustado deve ser salvo em um arquivopickle
em vez de usar o formatosafetensors
. - O parâmetro
group_by_length
quandoTrue
indica que amostras de aproximadamente o mesmo comprimento devem ser agrupadas. Isso minimiza o preenchimento e melhora a eficiência do treinamento. -
per_device_train_batch_size
define o número de amostras por minilote de treinamento. Este parâmetro é definido como18
por meio da constanteTRAIN_BATCH_SIZE
atribuída na Etapa 3.5 . Isso implica 160 passos por época. -
per_device_eval_batch_size
define o número de amostras por minilote de avaliação (holdout). Este parâmetro é definido como10
por meio da constanteEVAL_BATCH_SIZE
atribuída na Etapa 3.5 . -
num_train_epochs
define o número de épocas de treinamento. Este parâmetro é definido como30
através da constanteTRAIN_EPOCHS
atribuída na Etapa 3.5 . Isso implica um total de 4.800 passos durante o treinamento. - O parâmetro
gradient_checkpointing
quandoTrue
ajuda a economizar memória ao verificar cálculos de gradiente, mas resulta em passagens reversas mais lentas. - O parâmetro
evaluation_strategy
quando definido comosteps
significa que a avaliação será realizada e registrada durante o treinamento em um intervalo especificado pelo parâmetroeval_steps
. - O parâmetro
logging_strategy
quando definido comosteps
significa que as estatísticas da execução de treinamento serão registradas em um intervalo especificado pelo parâmetrologging_steps
. - O parâmetro
save_strategy
quando definido comosteps
significa que um ponto de verificação do modelo ajustado será salvo em um intervalo especificado pelo parâmetrosave_steps
. -
eval_steps
define o número de etapas entre avaliações de dados de validação. Este parâmetro é definido como100
através da constanteEVAL_STEPS
atribuída na Etapa 3.5 . -
save_steps
define o número de etapas após as quais um ponto de verificação do modelo ajustado é salvo. Este parâmetro é definido como3200
através da constanteSAVE_STEPS
atribuída na Etapa 3.5 . -
logging_steps
define o número de etapas entre os logs das estatísticas da execução de treinamento. Este parâmetro é definido como100
através da constanteLOGGING_STEPS
atribuída na Etapa 3.5 . - O parâmetro
learning_rate
define a taxa de aprendizagem inicial. Este parâmetro é definido como1e-4
por meio da constanteLEARNING_RATE
atribuída na Etapa 3.5 . - O parâmetro
warmup_steps
define o número de etapas para aquecer linearmente a taxa de aprendizado de 0 até o valor definido porlearning_rate
. Este parâmetro é definido como800
através da constanteWARMUP_STEPS
atribuída na Etapa 3.5 .
Etapa 3.28 - CÉLULA 28: Definindo a Lógica do Coletor de Dados
A vigésima oitava célula define a lógica para preencher dinamicamente as sequências de entrada e de destino. Defina a vigésima oitava célula como:
### CELL 28: Define data collator logic ### @dataclass class DataCollatorCTCWithPadding: processor: Wav2Vec2Processor padding: Union[bool, str] = True max_length: Optional[int] = None max_length_labels: Optional[int] = None pad_to_multiple_of: Optional[int] = None pad_to_multiple_of_labels: Optional[int] = None def __call__(self, features: List[Dict[str, Union[List[int], torch.Tensor]]]) -> Dict[str, torch.Tensor]: input_features = [{"input_values": feature["input_values"]} for feature in features] label_features = [{"input_ids": feature["labels"]} for feature in features] batch = self.processor.pad( input_features, padding = self.padding, max_length = self.max_length, pad_to_multiple_of = self.pad_to_multiple_of, return_tensors = "pt", ) with self.processor.as_target_processor(): labels_batch = self.processor.pad( label_features, padding = self.padding, max_length = self.max_length_labels, pad_to_multiple_of = self.pad_to_multiple_of_labels, return_tensors = "pt", ) labels = labels_batch["input_ids"].masked_fill(labels_batch.attention_mask.ne(1), -100) batch["labels"] = labels return batch
- Os pares de rótulos de entrada de treinamento e avaliação são passados em minilotes para a instância
Trainer
que será inicializada momentaneamente na Etapa 3.30 . Como as sequências de entrada e as sequências de rótulos variam em comprimento em cada minilote, algumas sequências devem ser preenchidas para que tenham todas o mesmo comprimento. - A classe
DataCollatorCTCWithPadding
preenche dinamicamente os dados do minilote. O parâmetropadding
, quando definido comoTrue
, especifica que sequências mais curtas de recursos de entrada de áudio e sequências de rótulos devem ter o mesmo comprimento que a sequência mais longa em um minilote. - Os recursos de entrada de áudio são preenchidos com o valor
0.0
definido ao inicializar o extrator de recursos na Etapa 3.18 . - As entradas do rótulo são primeiro preenchidas com o valor de preenchimento definido ao inicializar o tokenizer na Etapa 3.17 . Esses valores são substituídos por
-100
para que esses rótulos sejam ignorados no cálculo da métrica WER.
Etapa 3.29 - CÉLULA 29: Inicializando a Instância do Coletor de Dados
A vigésima nona célula inicializa uma instância do agrupamento de dados definido na etapa anterior. Defina a vigésima nona célula para:
### CELL 29: Initialize instance of data collator ### data_collator = DataCollatorCTCWithPadding(processor = processor, padding = True)
Etapa 3.30 - CÉLULA 30: Inicializando o Trainer
A trigésima célula inicializa uma instância da classe Trainer
. Defina a trigésima célula como:
### CELL 30: Initialize trainer ### trainer = Trainer( model = model, data_collator = data_collator, args = training_args, compute_metrics = compute_wer, train_dataset = train_data, eval_dataset = valid_data, tokenizer = processor.feature_extractor )
- Como visto, a classe
Trainer
é inicializada com:- O
model
pré-treinado foi inicializado na Etapa 3.25 . - O agrupamento de dados foi inicializado na Etapa 3.29 .
- Os argumentos de treinamento inicializados na Etapa 3.27 .
- O método de avaliação WER definido na Etapa 3.9 .
- O objeto
train_data
Dataset
da Etapa 3.24 . - O objeto
valid_data
Dataset
da Etapa 3.24 .
- O
- O parâmetro
tokenizer
é atribuído aprocessor.feature_extractor
e funciona comdata_collator
para preencher automaticamente as entradas para a entrada de comprimento máximo de cada minilote.
Etapa 3.31 - CÉLULA 31: Ajustando o Modelo
A trigésima primeira célula chama o método train
na instância da classe Trainer
para ajustar o modelo. Defina a trigésima primeira célula como:
### CELL 31: Finetune the model ### trainer.train()
Etapa 3.32 - CÉLULA 32: Salve o modelo ajustado
A trigésima segunda célula é a última célula do notebook. Ele salva o modelo ajustado chamando o método save_model
na instância Trainer
. Defina a célula do trigésimo segundo como:
### CELL 32: Save the finetuned model ### trainer.save_model(OUTPUT_DIR_PATH)
Passo 4 – Treinando e Salvando o Modelo
Passo 4.1 – Treinando o Modelo
Agora que todas as células do notebook foram construídas, é hora de começar os ajustes finos.
Configure o Kaggle Notebook para rodar com o acelerador NVIDIA GPU P100 .
Envie o notebook no Kaggle.
Monitore os dados da corrida de treinamento fazendo login em sua conta WandB e localizando a corrida associada.
O treinamento de mais de 30 épocas deve levar cerca de 5 horas usando o acelerador NVIDIA GPU P100. O WER nos dados de validação deve cair para aproximadamente 0,15 no final do treinamento. Não é exatamente um resultado de última geração, mas o modelo ajustado ainda é suficientemente útil para muitas aplicações.
Passo 4.2 - Salvando o Modelo
O modelo ajustado será enviado para o diretório Kaggle especificado pela constante OUTPUT_DIR_PATH
especificada na Etapa 3.5 . A saída do modelo deve incluir os seguintes arquivos:
pytorch_model.bin config.json preprocessor_config.json vocab.json training_args.bin
Esses arquivos podem ser baixados localmente. Além disso, você pode criar um novo modelo Kaggle usando os arquivos de modelo. O modelo Kaggle será usado com o guia de inferência complementar para executar inferência no modelo ajustado.
- Faça login em sua conta Kaggle. Clique em Modelos > Novo Modelo .
- Adicione um título para o seu modelo ajustado no campo Título do modelo .
- Clique em Criar modelo .
- Clique em Ir para a página de detalhes do modelo .
- Clique em Adicionar nova variação em Variações do modelo .
- Selecione Transformers no menu de seleção do Framework .
- Clique em Adicionar nova variação .
- Arraste e solte seus arquivos de modelo ajustados na janela Carregar Dados . Alternativamente, clique no botão Procurar Arquivos para abrir uma janela do explorador de arquivos e selecionar seus arquivos de modelo ajustados.
- Depois que os arquivos forem carregados no Kaggle, clique em Criar para criar o modelo Kaggle .
Conclusão
Parabéns pelo ajuste fino do wav2vec2 XLS-R! Lembre-se de que você pode usar estas etapas gerais para ajustar o modelo em outros idiomas que desejar. Executar inferência no modelo ajustado gerado neste guia é bastante simples. As etapas de inferência serão descritas em um guia separado deste. Pesquise meu nome de usuário HackerNoon para encontrar o guia complementar.