Réglage fin de Wav2Vec2 avec une tête LM

Voir sur TensorFlow.org Exécuter dans Google Colab Voir sur GitHub Télécharger le cahier Voir le modèle TF Hub

Dans ce cahier, nous chargerons le modèle wav2vec2 pré-formé à partir TFHub et perfectionnerons sur dataset LibriSpeech par tête annexant Modeling Language (LM) sur le dessus de notre modèle de pré-formation. La tâche sous - jacente est de construire un modèle pour la reconnaissance automatique de la parole donnée à- dire une parole, le modèle devrait être en mesure de transcrire en texte.

Configuration

Avant d' exécuter ce bloc - notes, s'il vous plaît assurez -vous que vous êtes sur l' exécution du GPU ( Runtime > Change runtime type le GPU Change runtime type > GPU ). La cellule suivante installera gsoc-wav2vec2 package et ses dépendances.

pip3 install -q git+https://github.com/vasudevgupta7/gsoc-wav2vec2@main
sudo apt-get install -y libsndfile1-dev
pip3 install -q SoundFile
The following packages were automatically installed and are no longer required:
  linux-gcp-5.4-headers-5.4.0-1040 linux-gcp-5.4-headers-5.4.0-1043
  linux-gcp-5.4-headers-5.4.0-1044 linux-gcp-5.4-headers-5.4.0-1049
  linux-headers-5.4.0-1049-gcp linux-image-5.4.0-1049-gcp
  linux-modules-5.4.0-1049-gcp linux-modules-extra-5.4.0-1049-gcp
Use 'sudo apt autoremove' to remove them.
The following additional packages will be installed:
  libflac-dev libogg-dev libvorbis-dev libvorbisfile3
The following NEW packages will be installed:
  libflac-dev libogg-dev libsndfile1-dev libvorbis-dev libvorbisfile3
0 upgraded, 5 newly installed, 0 to remove and 143 not upgraded.
Need to get 1040 kB of archives.
After this operation, 4481 kB of additional disk space will be used.
Get:1 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic/main amd64 libogg-dev amd64 1.3.2-1 [156 kB]
Get:2 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic/main amd64 libflac-dev amd64 1.3.2-1 [260 kB]
Get:3 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic/main amd64 libvorbisfile3 amd64 1.3.5-4.2 [16.0 kB]
Get:4 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic/main amd64 libvorbis-dev amd64 1.3.5-4.2 [321 kB]
Get:5 http://asia-east1.gce.archive.ubuntu.com/ubuntu bionic-updates/main amd64 libsndfile1-dev amd64 1.0.28-4ubuntu0.18.04.2 [287 kB]
Fetched 1040 kB in 1s (1041 kB/s)
Selecting previously unselected package libogg-dev:amd64.
(Reading database ... 282211 files and directories currently installed.)
Preparing to unpack .../libogg-dev_1.3.2-1_amd64.deb ...
Unpacking libogg-dev:amd64 (1.3.2-1) ...
Selecting previously unselected package libflac-dev:amd64.
Preparing to unpack .../libflac-dev_1.3.2-1_amd64.deb ...
Unpacking libflac-dev:amd64 (1.3.2-1) ...
Selecting previously unselected package libvorbisfile3:amd64.
Preparing to unpack .../libvorbisfile3_1.3.5-4.2_amd64.deb ...
Unpacking libvorbisfile3:amd64 (1.3.5-4.2) ...
Selecting previously unselected package libvorbis-dev:amd64.
Preparing to unpack .../libvorbis-dev_1.3.5-4.2_amd64.deb ...
Unpacking libvorbis-dev:amd64 (1.3.5-4.2) ...
Selecting previously unselected package libsndfile1-dev.
Preparing to unpack .../libsndfile1-dev_1.0.28-4ubuntu0.18.04.2_amd64.deb ...
Unpacking libsndfile1-dev (1.0.28-4ubuntu0.18.04.2) ...
Setting up libvorbisfile3:amd64 (1.3.5-4.2) ...
Setting up libogg-dev:amd64 (1.3.2-1) ...
Setting up libvorbis-dev:amd64 (1.3.5-4.2) ...
Setting up libflac-dev:amd64 (1.3.2-1) ...
Setting up libsndfile1-dev (1.0.28-4ubuntu0.18.04.2) ...
Processing triggers for libc-bin (2.27-3ubuntu1.2) ...

Configuration modèle à l' aide TFHub

Nous allons commencer par importer quelques bibliothèques/modules.

import os

import tensorflow as tf
import tensorflow_hub as hub
from wav2vec2 import Wav2Vec2Config

config = Wav2Vec2Config()

print("TF version:", tf.__version__)
TF version: 2.7.0

Tout d' abord, nous allons télécharger notre modèle de TFHub et se terminera notre signature de modèle avec hub.KerasLayer pour pouvoir utiliser ce modèle comme une autre couche Keras. Heureusement, hub.KerasLayer peut faire les deux en 1 ligne.

pretrained_layer = hub.KerasLayer("https://tfhub.dev/vasudevgupta7/wav2vec2/1", trainable=True)

Vous pouvez vous référer à ce scénario dans le cas où vous êtes intéressé par le modèle de script d' exportation. Object pretrained_layer est la version freezed de Wav2Vec2Model . Ces poids pré-formés ont été convertis à partir HuggingFace PyTorch poids pré-formés en utilisant ce script .

À l'origine, wav2vec2 a été pré-entraîné avec une approche de modélisation du langage masqué dans le but d'identifier la véritable représentation vocale latente quantifiée pour un pas de temps masqué. Vous pouvez en savoir plus sur l'objectif de formation dans le Paper- wav2vec 2.0: Un cadre pour l' apprentissage auto-supervisé des représentations vocales .

Maintenant, nous allons définir quelques constantes et hyper-paramètres qui seront utiles dans les prochaines cellules. AUDIO_MAXLEN est intentionnellement réglé à 246000 en tant que signature de modèle accepte seulement la longueur de la séquence statique de 246000 .

AUDIO_MAXLEN = 246000
LABEL_MAXLEN = 256
BATCH_SIZE = 2

Dans la cellule suivante, nous allons envelopper pretrained_layer et une couche dense (tête LM) avec l' API fonctionnelle de Keras .

inputs = tf.keras.Input(shape=(AUDIO_MAXLEN,))
hidden_states = pretrained_layer(inputs)
outputs = tf.keras.layers.Dense(config.vocab_size)(hidden_states)

model = tf.keras.Model(inputs=inputs, outputs=outputs)

La couche dense (définie ci - dessus) est d' avoir une dimension de sortie de vocab_size que nous voulons prédire les probabilités de chaque jeton dans le vocabulaire à chaque pas de temps.

Configuration de l'état d'entraînement

En tensorflow, le poids des modèles sont construits uniquement lorsque model.call ou model.build est appelé pour la première fois, de sorte que la cellule suivante construira les poids de modèle pour nous. De plus, nous courrons model.summary() pour vérifier le nombre total de paramètres trainable.

model(tf.random.uniform(shape=(BATCH_SIZE, AUDIO_MAXLEN)))
model.summary()
Model: "model"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 input_1 (InputLayer)        [(None, 246000)]          0         
                                                                 
 keras_layer (KerasLayer)    (None, 768, 768)          94371712  
                                                                 
 dense (Dense)               (None, 768, 32)           24608     
                                                                 
=================================================================
Total params: 94,396,320
Trainable params: 94,396,320
Non-trainable params: 0
_________________________________________________________________

Maintenant, nous devons définir le loss_fn et optimiseur pour être en mesure de former le modèle. La cellule suivante le fera pour nous. Nous utiliserons l' Adam optimiseur pour plus de simplicité. CTCLoss est un type de perte commun qui est utilisé pour des tâches (comme ASR ) , où les sous-parties d' entrée ne peuvent pas être facilement alignés avec les sous-parties de sortie. Vous pouvez en savoir plus sur CTC perte de ce incroyable billet de blog .

CTCLoss (de gsoc-wav2vec2 package) accepte 3 arguments: config , model_input_shape & division_factor . Si division_factor=1 , alors la perte sera tout simplement se résumer, donc passer division_factor en conséquence pour obtenir lot moyenne sur.

from wav2vec2 import CTCLoss

LEARNING_RATE = 5e-5

loss_fn = CTCLoss(config, (BATCH_SIZE, AUDIO_MAXLEN), division_factor=BATCH_SIZE)
optimizer = tf.keras.optimizers.Adam(LEARNING_RATE)

Chargement et pré-traitement des données

Nous allons maintenant télécharger le jeu de données LibriSpeech du site officiel et mis en place.

wget https://www.openslr.org/resources/12/dev-clean.tar.gz -P ./data/train/
tar -xf ./data/train/dev-clean.tar.gz -C ./data/train/
--2021-11-05 11:43:09--  https://www.openslr.org/resources/12/dev-clean.tar.gz
Resolving www.openslr.org (www.openslr.org)... 46.101.158.64
Connecting to www.openslr.org (www.openslr.org)|46.101.158.64|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 337926286 (322M) [application/x-gzip]
Saving to: ‘./data/train/dev-clean.tar.gz’

dev-clean.tar.gz    100%[===================>] 322.27M  11.6MB/s    in 31s     

2021-11-05 11:43:42 (10.3 MB/s) - ‘./data/train/dev-clean.tar.gz’ saved [337926286/337926286]
ls ./data/train/
LibriSpeech/  dev-clean.tar.gz

Notre jeu de données se trouve dans le répertoire LibriSpeech. Explorons ces fichiers.

data_dir = "./data/train/LibriSpeech/dev-clean/2428/83705/"
all_files = os.listdir(data_dir)

flac_files = [f for f in all_files if f.endswith(".flac")]
txt_files = [f for f in all_files if f.endswith(".txt")]

print("Transcription files:", txt_files, "\nSound files:", flac_files)
Transcription files: ['2428-83705.trans.txt'] 
Sound files: ['2428-83705-0015.flac', '2428-83705-0004.flac', '2428-83705-0006.flac', '2428-83705-0026.flac', '2428-83705-0023.flac', '2428-83705-0001.flac', '2428-83705-0005.flac', '2428-83705-0040.flac', '2428-83705-0038.flac', '2428-83705-0042.flac', '2428-83705-0008.flac', '2428-83705-0019.flac', '2428-83705-0021.flac', '2428-83705-0002.flac', '2428-83705-0039.flac', '2428-83705-0034.flac', '2428-83705-0028.flac', '2428-83705-0000.flac', '2428-83705-0029.flac', '2428-83705-0041.flac', '2428-83705-0035.flac', '2428-83705-0032.flac', '2428-83705-0020.flac', '2428-83705-0025.flac', '2428-83705-0010.flac', '2428-83705-0014.flac', '2428-83705-0003.flac', '2428-83705-0031.flac', '2428-83705-0017.flac', '2428-83705-0027.flac', '2428-83705-0012.flac', '2428-83705-0043.flac', '2428-83705-0030.flac', '2428-83705-0022.flac', '2428-83705-0016.flac', '2428-83705-0037.flac', '2428-83705-0011.flac', '2428-83705-0036.flac', '2428-83705-0009.flac', '2428-83705-0013.flac', '2428-83705-0007.flac', '2428-83705-0018.flac', '2428-83705-0024.flac', '2428-83705-0033.flac']

D' accord, donc chaque sous-répertoire a beaucoup .flac fichiers et un .txt fichier. Le .txt fichier contient des transcriptions de texte pour tous les échantillons vocaux (c. -à- .flac fichiers) présents dans ce sous-répertoire.

Nous pouvons charger ces données textuelles comme suit :

def read_txt_file(f):
  with open(f, "r") as f:
    samples = f.read().split("\n")
    samples = {s.split()[0]: " ".join(s.split()[1:]) for s in samples if len(s.split()) > 2}
  return samples

De même, nous allons définir une fonction de chargement d' un échantillon de parole d'un .flac fichier.

REQUIRED_SAMPLE_RATE est réglé sur 16000 comme wav2vec2 a été pré-formé avec 16K fréquence et il est recommandé de régler fine sans aucun changement majeur de la distribution de données en raison de la fréquence.

import soundfile as sf

REQUIRED_SAMPLE_RATE = 16000

def read_flac_file(file_path):
  with open(file_path, "rb") as f:
      audio, sample_rate = sf.read(f)
  if sample_rate != REQUIRED_SAMPLE_RATE:
      raise ValueError(
          f"sample rate (={sample_rate}) of your files must be {REQUIRED_SAMPLE_RATE}"
      )
  file_id = os.path.split(file_path)[-1][:-len(".flac")]
  return {file_id: audio}

Maintenant, nous allons choisir des échantillons aléatoires et essayer de les visualiser.

from IPython.display import Audio
import random

file_id = random.choice([f[:-len(".flac")] for f in flac_files])
flac_file_path, txt_file_path = os.path.join(data_dir, f"{file_id}.flac"), os.path.join(data_dir, "2428-83705.trans.txt")

print("Text Transcription:", read_txt_file(txt_file_path)[file_id], "\nAudio:")
Audio(filename=flac_file_path)
Text Transcription: HE HAS GIVEN US FREE PASSES ALL THE WAY TO THE END OF OUR JOURNEY AND ALL THE WAY BACK AGAIN AND COUPONS FOR FREE BOARD AND LODGING AT THE HOTEL IT'S A WEDDING PRESENT 
Audio:

Maintenant, nous allons combiner tous les échantillons de parole et de texte et définir la fonction (dans la cellule suivante) à cette fin.

def fetch_sound_text_mapping(data_dir):
  all_files = os.listdir(data_dir)

  flac_files = [os.path.join(data_dir, f) for f in all_files if f.endswith(".flac")]
  txt_files = [os.path.join(data_dir, f) for f in all_files if f.endswith(".txt")]

  txt_samples = {}
  for f in txt_files:
    txt_samples.update(read_txt_file(f))

  speech_samples = {}
  for f in flac_files:
    speech_samples.update(read_flac_file(f))

  assert len(txt_samples) == len(speech_samples)

  samples = [(speech_samples[file_id], txt_samples[file_id]) for file_id in speech_samples.keys() if len(speech_samples[file_id]) < AUDIO_MAXLEN]
  return samples

Il est temps de jeter un œil à quelques échantillons...

samples = fetch_sound_text_mapping(data_dir)
samples[:5]
[(array([ 6.10351562e-05,  9.15527344e-05,  9.15527344e-05, ...,
         -3.05175781e-04, -5.79833984e-04, -8.23974609e-04]),
  'WHEN SHE HEARD OF MY ENGAGEMENT WITH MARY ANN SHE WROTE AND SUGGESTED THAT WE SHOULD SPEND OUR HONEYMOON IN HER COTTAGE OR PIGSTYE AND THAT I SHOULD PAY HER RENT FOR IT'),
 (array([-0.00112915, -0.00131226, -0.00158691, ...,  0.00067139,
          0.00091553,  0.00100708]),
  "IT MIGHT JUST AS WELL BE SOME ONE ELSE'S WEDDING SO UNIMPORTANT IS THE PART WHICH I AM SET TO PLAY IN IT"),
 (array([ 3.05175781e-05, -6.10351562e-05,  2.13623047e-04, ...,
         -5.18798828e-04, -2.13623047e-04, -2.74658203e-04]),
  'THE ACCIDENT IN QUESTION OCCURRED UPON THE SUNDAY EVENING'),
 (array([ 3.05175781e-04,  3.05175781e-05, -1.83105469e-04, ...,
          7.62939453e-04,  6.10351562e-04,  5.79833984e-04]),
  "OF COURSE THERE ARE SOME PEOPLE WITH WHOM YOU CAN'T BE PERFECTLY PLAIN BUT I SHALL BE AS PLAIN AS I CAN THERE'S A WAY AND A MANNER OF DOING THAT KIND OF THING"),
 (array([ 6.10351562e-05, -3.05175781e-05,  0.00000000e+00, ...,
         -3.66210938e-04, -7.93457031e-04, -1.19018555e-03]),
  'I KNOW WHAT MAMMA CAN AFFORD TO GIVE AND I WILL SEE SHE GIVES IT')]

Pré-traitons les données maintenant !!!

Nous allons d' abord définir le tokenizer et processeur à l' aide gsoc-wav2vec2 package. Ensuite, nous ferons un pré-traitement très simple. processor normalise la parole brute WRTO cadres axe et tokenizer convertiront nos sorties de modèle dans la chaîne ( en utilisant le vocabulaire défini) et se chargeront de la suppression des jetons spéciaux ( en fonction de la configuration de votre tokenizer).

from wav2vec2 import Wav2Vec2Processor
tokenizer = Wav2Vec2Processor(is_tokenizer=True)
processor = Wav2Vec2Processor(is_tokenizer=False)

def preprocess_text(text):
  label = tokenizer(text)
  return tf.constant(label, dtype=tf.int32)

def preprocess_speech(audio):
  audio = tf.constant(audio, dtype=tf.float32)
  return processor(tf.transpose(audio))
Downloading `vocab.json` from https://github.com/vasudevgupta7/gsoc-wav2vec2/raw/main/data/vocab.json ... DONE

Maintenant, nous allons définir le générateur python pour appeler les fonctions de prétraitement que nous avons définies dans les cellules ci-dessus.

def inputs_generator():
  for speech, text in samples:
    yield preprocess_speech(speech), preprocess_text(text)

Mise en place tf.data.Dataset

À la suite de l' installation de la volonté de la cellule tf.data.Dataset objet en utilisant son .from_generator(...) méthode. Nous allons utiliser le generator objet, nous avons défini dans la cellule ci - dessus.

Vous pouvez vous référer à ce script pour plus de détails sur la façon de convertir les données en LibriSpeech tfrecords.

output_signature = (
    tf.TensorSpec(shape=(None),  dtype=tf.float32),
    tf.TensorSpec(shape=(None), dtype=tf.int32),
)

dataset = tf.data.Dataset.from_generator(inputs_generator, output_signature=output_signature)
BUFFER_SIZE = len(flac_files)
SEED = 42

dataset = dataset.shuffle(BUFFER_SIZE, seed=SEED)

Nous allons transmettre l'ensemble de données en plusieurs lots, alors préparons les lots dans la cellule suivante. Maintenant, toutes les séquences d'un lot doivent être rembourrées à une longueur constante. Nous utiliserons le .padded_batch(...) méthode à cette fin.

dataset = dataset.padded_batch(BATCH_SIZE, padded_shapes=(AUDIO_MAXLEN, LABEL_MAXLEN), padding_values=(0.0, 0))

Les accélérateurs (comme les GPU/TPU) sont très rapides et souvent le chargement des données (et le pré-traitement) devient le goulot d'étranglement pendant la formation car la partie de chargement des données se produit sur les CPU. Cela peut augmenter considérablement le temps de formation, en particulier lorsque de nombreux prétraitements en ligne sont impliqués ou que les données sont diffusées en ligne à partir de compartiments GCS. Pour faire face à ces problèmes, tf.data.Dataset offre la .prefetch(...) méthode. Cette méthode aide à préparer les prochains lots en parallèle (sur les CPU) pendant que le modèle fait des prédictions (sur les GPU/TPU) sur le lot en cours.

dataset = dataset.prefetch(tf.data.AUTOTUNE)

Étant donné que ce portable est faite à des fins de démonstration, nous allons prendre les premiers num_train_batches et remplirai formation sur seulement. Cependant, vous êtes encouragé à vous entraîner sur l'ensemble de données. De même, nous évaluerons seulement num_val_batches .

num_train_batches = 10
num_val_batches = 4

train_dataset = dataset.take(num_train_batches)
val_dataset = dataset.skip(num_train_batches).take(num_val_batches)

Formation de modèle

Pour la formation de notre modèle, nous allons appeler directement .fit(...) méthode après la compilation de notre modèle avec .compile(...) .

model.compile(optimizer, loss=loss_fn)

La cellule ci-dessus configurera notre état d'entraînement. Maintenant , nous pouvons commencer la formation avec le .fit(...) méthode.

history = model.fit(train_dataset, validation_data=val_dataset, epochs=3)
history.history
Epoch 1/3
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/ctc_ops.py:1447: alias_inplace_add (from tensorflow.python.ops.inplace_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Prefer tf.tensor_scatter_nd_add, which offers the same functionality with well-defined read-write semantics.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/ctc_ops.py:1447: alias_inplace_add (from tensorflow.python.ops.inplace_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Prefer tf.tensor_scatter_nd_add, which offers the same functionality with well-defined read-write semantics.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/ctc_ops.py:1430: alias_inplace_update (from tensorflow.python.ops.inplace_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Prefer tf.tensor_scatter_nd_update, which offers the same functionality with well-defined read-write semantics.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/ctc_ops.py:1430: alias_inplace_update (from tensorflow.python.ops.inplace_ops) is deprecated and will be removed in a future version.
Instructions for updating:
Prefer tf.tensor_scatter_nd_update, which offers the same functionality with well-defined read-write semantics.
WARNING:tensorflow:Gradients do not exist for variables ['wav2vec2/masked_spec_embed:0'] when minimizing the loss. If you're using `model.compile()`, did you forget to provide a `loss`argument?
WARNING:tensorflow:Gradients do not exist for variables ['wav2vec2/masked_spec_embed:0'] when minimizing the loss. If you're using `model.compile()`, did you forget to provide a `loss`argument?
WARNING:tensorflow:Gradients do not exist for variables ['wav2vec2/masked_spec_embed:0'] when minimizing the loss. If you're using `model.compile()`, did you forget to provide a `loss`argument?
WARNING:tensorflow:Gradients do not exist for variables ['wav2vec2/masked_spec_embed:0'] when minimizing the loss. If you're using `model.compile()`, did you forget to provide a `loss`argument?
10/10 [==============================] - 32s 2s/step - loss: 649.3215 - val_loss: 315.0721
Epoch 2/3
10/10 [==============================] - 17s 2s/step - loss: 242.1202 - val_loss: 336.5721
Epoch 3/3
10/10 [==============================] - 17s 2s/step - loss: 222.1239 - val_loss: 253.0467
{'loss': [649.321533203125, 242.1201629638672, 222.1239013671875],
 'val_loss': [315.0721435546875, 336.5721130371094, 253.0466766357422]}

Sauvons notre modèle avec .save(...) méthode pour être en mesure d'effectuer l' inférence plus tard. Vous pouvez également exporter ce SavedModel à TFHub en suivant la documentation TFHub .

save_dir = "finetuned-wav2vec2"
model.save(save_dir, include_optimizer=False)
2021-11-05 11:44:54.280793: W tensorflow/python/util/util.cc:368] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Found untraced functions such as restored_function_body, restored_function_body, restored_function_body, restored_function_body, restored_function_body while saving (showing 5 of 855). These functions will not be directly callable after loading.
INFO:tensorflow:Assets written to: finetuned-wav2vec2/assets
INFO:tensorflow:Assets written to: finetuned-wav2vec2/assets

Évaluation

Nous allons maintenant calculer le taux d'erreur de mot sur l'ensemble de données de validation

Taux d'erreur mot (REH) est une mesure commune pour mesurer la performance d'un système de reconnaissance automatique de la parole. Le WER est dérivé de la distance de Levenshtein, fonctionnant au niveau du mot. Le taux d'erreur sur les mots peut alors être calculé comme : WER = (S + D + I) / N = (S + D + I) / (S + D + C) où S est le nombre de substitutions, D est le nombre de suppressions , I est le nombre d'insertions, C est le nombre de mots corrects, N est le nombre de mots dans la référence (N=S+D+C). Cette valeur indique le pourcentage de mots qui ont été mal prédits.

Vous pouvez consulter cet article pour en savoir plus sur REH.

Nous utiliserons load_metric(...) fonction de jeux de données HuggingFace bibliothèque. Nous allons d' abord installer les datasets de pip metric datasets bibliothèque à l' aide pip puis définir la metric objet.

!pip3 install -q datasets

from datasets import load_metric
metric = load_metric("wer")
Downloading:   0%|          | 0.00/1.95k [00:00<?, ?B/s]
@tf.function(jit_compile=True)
def eval_fwd(batch):
  logits = model(batch, training=False)
  return tf.argmax(logits, axis=-1)

Il est temps d'exécuter l'évaluation sur les données de validation maintenant.

from tqdm.auto import tqdm

for speech, labels in tqdm(val_dataset, total=num_val_batches):
    predictions  = eval_fwd(speech)
    predictions = [tokenizer.decode(pred) for pred in predictions.numpy().tolist()]
    references = [tokenizer.decode(label, group_tokens=False) for label in labels.numpy().tolist()]
    metric.add_batch(references=references, predictions=predictions)
0%|          | 0/4 [00:00<?, ?it/s]
2021-11-05 11:45:11.575128: W tensorflow/compiler/tf2xla/kernels/random_ops.cc:57] Warning: Using tf.random.uniform with XLA compilation will ignore seeds; consider using tf.random.stateless_uniform instead if reproducible behavior is desired. model/keras_layer/StatefulPartitionedCall/StatefulPartitionedCall/wav2vec2/encoder/layers/0/stochastic_depth/random_uniform/RandomUniform

Nous utilisons le tokenizer.decode(...) méthode pour décoder nos prévisions et contre- étiquettes dans le texte et les ajoutent à la métrique pour WER calcul plus tard.

Calculons maintenant la valeur de la métrique dans la cellule suivante :

metric.compute()
1.0

Inférence

Maintenant que nous sommes satisfaits du processus de formation et avons enregistré le modèle save_dir , nous verrons comment ce modèle peut être utilisé pour l' inférence.

Tout d' abord, nous allons charger notre modèle en utilisant tf.keras.models.load_model(...) .

finetuned_model = tf.keras.models.load_model(save_dir)
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.
WARNING:tensorflow:No training configuration found in save file, so the model was *not* compiled. Compile it manually.

Téléchargeons quelques exemples de discours pour effectuer l'inférence. Vous pouvez également remplacer l'exemple suivant par votre exemple de discours.

wget https://github.com/vasudevgupta7/gsoc-wav2vec2/raw/main/data/SA2.wav
--2021-11-05 11:45:28--  https://github.com/vasudevgupta7/gsoc-wav2vec2/raw/main/data/SA2.wav
Resolving github.com (github.com)... 13.114.40.48
Connecting to github.com (github.com)|13.114.40.48|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://raw.githubusercontent.com/vasudevgupta7/gsoc-wav2vec2/main/data/SA2.wav [following]
--2021-11-05 11:45:28--  https://raw.githubusercontent.com/vasudevgupta7/gsoc-wav2vec2/main/data/SA2.wav
Resolving raw.githubusercontent.com (raw.githubusercontent.com)... 185.199.108.133, 185.199.111.133, 185.199.109.133, ...
Connecting to raw.githubusercontent.com (raw.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 94252 (92K) [audio/wav]
Saving to: ‘SA2.wav’

SA2.wav             100%[===================>]  92.04K  --.-KB/s    in 0.02s   

2021-11-05 11:45:29 (5.38 MB/s) - ‘SA2.wav’ saved [94252/94252]

Maintenant, nous allons lire l'échantillon de parole en utilisant soundfile.read(...) et un tampon à AUDIO_MAXLEN pour satisfaire la signature du modèle. Ensuite , nous allons normaliser cet échantillon de la parole en utilisant l' Wav2Vec2Processor exemple et nourrirons dans le modèle.

import numpy as np

speech, _ = sf.read("SA2.wav")
speech = np.pad(speech, (0, AUDIO_MAXLEN - len(speech)))
speech = tf.expand_dims(processor(tf.constant(speech)), 0)

outputs = finetuned_model(speech)
outputs
<tf.Tensor: shape=(1, 768, 32), dtype=float32, numpy=
array([[[ 5.5087714 , -1.0872856 , -1.0728477 , ..., -1.3125695 ,
         -0.7992846 , -0.94512135],
        [ 5.508977  , -1.0873723 , -1.0727195 , ..., -1.3125291 ,
         -0.79928476, -0.9449429 ],
        [ 5.5091047 , -1.0871643 , -1.0728203 , ..., -1.312533  ,
         -0.7992611 , -0.94483167],
        ...,
        [ 5.5094743 , -1.0874028 , -1.0729864 , ..., -1.3126655 ,
         -0.7994431 , -0.9449925 ],
        [ 5.509465  , -1.0873648 , -1.072943  , ..., -1.3126557 ,
         -0.79943836, -0.94500387],
        [ 5.509408  , -1.0872416 , -1.0728781 , ..., -1.3125473 ,
         -0.7993649 , -0.9449776 ]]], dtype=float32)>

Les numéros de décodage de laisser revenir en séquence de texte à l' aide du Wav2Vec2tokenizer exemple, nous avons défini ci - dessus.

predictions = tf.argmax(outputs, axis=-1)
predictions = [tokenizer.decode(pred) for pred in predictions.numpy().tolist()]
predictions
['']

Cette prédiction est assez aléatoire car le modèle n'a jamais été formé sur des données volumineuses dans ce bloc-notes (car ce bloc-notes n'est pas conçu pour effectuer un entraînement complet). Vous obtiendrez de bonnes prédictions si vous entraînez ce modèle sur un ensemble de données LibriSpeech complet.

Enfin, nous avons atteint la fin de ce cahier. Mais ce n'est pas une fin d'apprentissage tensorflow pour les tâches liées à la parole, ce référentiel contient quelques tutoriels plus étonnants. Si vous rencontrez un bogue dans ce bloc - notes, s'il vous plaît créer un problème ici .