Zobacz na TensorFlow.org | Uruchom w Google Colab | Zobacz na GitHub | Pobierz notatnik | Zobacz model piasty TF |
W tym notebooku, będziemy ładować wstępnie przeszkoleni modelu wav2vec2 z TFHub i dostroić go na LibriSpeech zestaw danych poprzez dołączenie głowę Modeling Language (LM) na szczycie naszej wstępnie przeszkoleni modelu. Zadaniem leżącym u jest zbudowanie modelu Automatic Speech Recognition, tj przyznać pewną mowę, model powinien być w stanie rozpisać je w tekście.
Konfiguracja
Przed uruchomieniem tego notebooka, upewnij się, że jesteś na starcie GPU ( Runtime
> Change runtime type
> GPU
). Poniższy komórka zainstaluje gsoc-wav2vec2
pakietu i jego zależności.
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) ...
Model konfiguracja za pomocą TFHub
Zaczniemy od zaimportowania kilku bibliotek/modułów.
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
Po pierwsze, będziemy pobrać nasz model z TFHub & zawinie naszego modelu podpisu hub.KerasLayer
, aby móc korzystać z tego modelu, jak każdy inny warstwy Keras. Na szczęście hub.KerasLayer
można zrobić zarówno w ciągu zaledwie 1 linii.
pretrained_layer = hub.KerasLayer("https://tfhub.dev/vasudevgupta7/wav2vec2/1", trainable=True)
Można odwołać się do tego scenariusza w przypadku zainteresowania w modelu skryptu wywozu. Obiekt pretrained_layer
jest zamrożoną wersja Wav2Vec2Model
. Te wstępnie przeszkolony ciężary zostały przeliczone z HuggingFace PyTorch wstępnie przeszkolony ciężarów za pomocą tego skryptu .
Pierwotnie wav2vec2 był wstępnie przeszkolony z podejściem do modelowania języka zamaskowanego w celu zidentyfikowania prawdziwej skwantowanej reprezentacji mowy utajonej dla zamaskowanego kroku czasowego. Możesz przeczytać więcej o celu szkolenia w papierniczych wav2vec 2.0: Framework for Self-uczenia nadzorowanego mowy reprezentacjach .
Teraz zdefiniujemy kilka stałych i hiperparametrów, które będą przydatne w kilku następnych komórkach. AUDIO_MAXLEN
jest celowo ustawiony 246000
jako sygnatura modelu akceptuje jedynie statycznego długość sekwencji 246000
.
AUDIO_MAXLEN = 246000
LABEL_MAXLEN = 256
BATCH_SIZE = 2
W poniższym komórki, będziemy zawijać pretrained_layer
i gęsta warstwa (głową LM) z API Functional Keras użytkownika .
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)
Gęsta warstwa (zdefiniowany powyżej) o wymiar wyjściowy vocab_size
ponieważ chcemy przewidywania prawdopodobieństwa każdego znacznika w słowniku w każdym punkcie czasowym.
Konfigurowanie stanu treningu
W TensorFlow, model ciężary są zbudowane wyłącznie gdy model.call
lub model.build
nazywa się po raz pierwszy, więc następujące komórka będzie zbudować model wagi dla nas. Ponadto, będziemy być uruchomiony model.summary()
aby sprawdzić łączną liczbę parametrów wyszkolić.
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 _________________________________________________________________
Teraz musimy określić loss_fn
i Optimizer, aby móc trenować model. Poniższa komórka zrobi to za nas. Będziemy pomocą Adam
optymalizator dla prostoty. CTCLoss
jest powszechnym typem straty, które są wykorzystywane do zadań (np ASR
), w którym wejścia pod-części nie mogą być łatwo dostosowane do SUB części. Możesz przeczytać więcej o CTC-straty z tego wspaniałego blogu .
CTCLoss
(od gsoc-wav2vec2
pakietu) przyjmuje 3 parametry: config
, model_input_shape
i division_factor
. Jeśli division_factor=1
, to po prostu strata będzie się sumuje, więc przechodzą division_factor
odpowiednio uzyskać średnią ponad partię.
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)
Ładowanie i wstępne przetwarzanie danych
Załóżmy teraz pobrać zestaw danych LibriSpeech z oficjalnej strony internetowej i skonfigurować go.
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
Nasz zbiór danych znajduje się w katalogu LibriSpeech. Przyjrzyjmy się tym plikom.
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']
W porządku, więc każdy podkatalog ma wiele .flac
plików i .txt
plik. .txt
plik zawiera transkrypcje tekstowe dla wszystkich próbek mowy (tzn .flac
plików) obecny w tym podkatalogu.
Możemy załadować te dane tekstowe w następujący sposób:
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
Podobnie będziemy zdefiniować funkcję ładowania próbki mowy z .flac
pliku.
REQUIRED_SAMPLE_RATE
jest ustawiony na 16000
jako wav2vec2 wstępnie przeszkolony z 16K
częstotliwości i zaleca się je dostroić bez większych zmian w dystrybucji danych z powodu częstotliwości.
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}
Teraz wybierzemy losowe próbki i spróbujemy je zwizualizować.
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:
Teraz połączymy wszystkie próbki mowy i tekstu i zdefiniujemy w tym celu funkcję (w następnej komórce).
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
Czas rzucić okiem na kilka próbek...
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')]
Przetwórzmy teraz dane !!!
Będziemy najpierw zdefiniować tokenizera i procesor za pomocą gsoc-wav2vec2
pakietu. Następnie wykonamy bardzo proste wstępne przetwarzanie. processor
będzie normalizować surowej mowy wrto klatek osi i tokenizer
przekształci nasze wyjścia modelu w łańcuchu (używając zdefiniowanego słownictwo) i zadba o usunięcie specjalnych żetonów (w zależności od konfiguracji 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
Teraz zdefiniujemy generator Pythona, który będzie wywoływał funkcje przetwarzania wstępnego, które zdefiniowaliśmy w powyższych komórkach.
def inputs_generator():
for speech, text in samples:
yield preprocess_speech(speech), preprocess_text(text)
Konfigurowanie tf.data.Dataset
W następstwie Instalator komórka tf.data.Dataset
obiekt przy jej .from_generator(...)
metody. Będziemy za pomocą generator
obiektu, mamy zdefiniowane w powyższej komórki.
Można odwołać się do tego skryptu uzyskać więcej informacji na temat konwersji danych LibriSpeech do 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)
Przekażemy zestaw danych do wielu partii, więc przygotujmy partie w następnej komórce. Teraz wszystkie sekwencje w partii powinny być dopełnione do stałej długości. Użyjemy .padded_batch(...)
metody dla osiągnięcia tego celu.
dataset = dataset.padded_batch(BATCH_SIZE, padded_shapes=(AUDIO_MAXLEN, LABEL_MAXLEN), padding_values=(0.0, 0))
Akceleratory (takie jak GPU/TPU) są bardzo szybkie i często ładowanie danych (i wstępne przetwarzanie) staje się wąskim gardłem podczas treningu, ponieważ część ładowania danych odbywa się na procesorach. Może to znacznie wydłużyć czas szkolenia, zwłaszcza gdy jest zaangażowanych dużo wstępnego przetwarzania online lub dane są przesyłane strumieniowo online z zasobników GCS. Aby obsługiwać te kwestie, tf.data.Dataset
oferuje .prefetch(...)
metody. Ta metoda pomaga w równoległym przygotowaniu kilku następnych partii (na procesorach), podczas gdy model wykonuje prognozy (na GPU/TPU) w bieżącej partii.
dataset = dataset.prefetch(tf.data.AUTOTUNE)
Od tego notebooka jest wykonany do celów demonstracyjnych, będziemy przyjmować pierwsze num_train_batches
i przeprowadzi szkolenie w ciągu tylko. Zachęcamy jednak do trenowania na całym zbiorze danych. Podobnie, ocenimy tylko 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)
Szkolenie modelowe
Za szkolenie naszego modelu, będziemy bezpośrednio dzwoniąc .fit(...)
metodę po kompilacji naszego modelu z .compile(...)
.
model.compile(optimizer, loss=loss_fn)
Powyższa komórka ustawi nasz stan treningu. Teraz możemy zainicjować szkolenie z .fit(...)
metody.
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]}
Ratujmy nasz model z .save(...)
sposobu, aby móc przeprowadzić wnioskowanie później. Można także eksportować ten SavedModel do TFHub wykonując dokumentację 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
Ocena
Teraz będziemy obliczać wskaźnik błędów słów w zestawie danych walidacyjnych
Stopa błędów słowo (WER) jest częstym metryki do pomiaru wydajności systemu automatycznego rozpoznawania mowy. WER wywodzi się z odległości Levenshteina, pracując na poziomie słowa. Współczynnik błędów słów można obliczyć jako: WER = (S + D + I) / N = (S + D + I) / (S + D + C) gdzie S to liczba podstawień, D to liczba usunięć , I to liczba wstawień, C to liczba poprawnych słów, N to liczba słów w odwołaniu (N=S+D+C). Ta wartość wskazuje procent słów, które zostały błędnie przewidziane.
Można odwołać się do tej pracy , aby dowiedzieć się więcej o Wer.
Użyjemy load_metric(...)
funkcji z HuggingFace zestawów danych biblioteki. Niech najpierw zainstalować datasets
biblioteki przy użyciu pip
a następnie zdefiniować metric
obiekt.
!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)
Nadszedł czas, aby przeprowadzić ocenę na danych walidacyjnych.
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
Używamy tokenizer.decode(...)
sposobu dekodowania nasze przewidywania i etykiety z powrotem do tekstu i doda je do metryki dla WER
obliczeń później.
Teraz obliczmy wartość metryki w następującej komórce:
metric.compute()
1.0
Wnioskowanie
Teraz, że jesteśmy zadowoleni z procesem szkolenia i zapisaniu model w save_dir
, zobaczymy, jak model ten może być używany do wnioskowania.
Po pierwsze, będziemy ładować nasz model używając 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.
Pobierzmy kilka próbek mowy do wnioskowania. Możesz również zastąpić następującą próbkę swoją próbką mowy.
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]
Teraz będziemy czytać próbki mowy za pomocą soundfile.read(...)
i pad go AUDIO_MAXLEN
spełnić podpis modelu. Wtedy będziemy unormować tę próbkę mowy za pomocą Wav2Vec2Processor
instancję i będą karmić go do modelu.
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)>
Numery dekodowania Cofnijmy się do sekwencji tekstu przy użyciu Wav2Vec2tokenizer
instancji, że podane powyżej.
predictions = tf.argmax(outputs, axis=-1)
predictions = [tokenizer.decode(pred) for pred in predictions.numpy().tolist()]
predictions
['']
Ta prognoza jest dość losowa, ponieważ model nigdy nie był trenowany na dużych ilościach danych w tym notatniku (ponieważ ten notatnik nie jest przeznaczony do pełnego trenowania). Uzyskasz dobre prognozy, jeśli wytrenujesz ten model na pełnym zestawie danych LibriSpeech.
Wreszcie dotarliśmy do końca tego notatnika. Ale to nie koniec nauki TensorFlow dla zadań związanych z mowy-to repozytorium zawiera kilka bardziej niesamowite tutoriale. W przypadku, gdy napotkał żadnego błędu w tym notebooku, utwórzcie problem tutaj .