כוונון עדין של Wav2Vec2 עם ראש LM

הצג באתר TensorFlow.org הפעל בגוגל קולאב הצג ב-GitHub הורד מחברת ראה דגם TF Hub

במחברת זו, נוכל לטעון את המודל wav2vec2 מראש מאומן מן TFHub ויהיה לכוונן אותו על LibriSpeech במערך ידי צירוף ראש דוגמנות שפה (LM) מעל דגם טרום המיומן שלנו. המשימה העומדת מאחורי היא לבנות מודל עבור זיהוי דיבור אוטומטי כלומר נתון מעט דיבור, המודל צריך להיות מסוגל לתמלל אותו לטקסט.

מגדיר

לפני הפעלת המחשב הנייד הזה, בבקשה להבטיח כי אתה על ריצה GPU ( Runtime > Change runtime type > GPU ). התא שלהלן יתקין gsoc-wav2vec2 חבילה & התלות שלו.

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

התקנת דגם באמצעות TFHub

נתחיל בייבוא ​​מספר ספריות/מודולים.

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

ראשית, נוכל להוריד המודל שלנו TFHub & אעטוף חתימת המודל שלנו עם hub.KerasLayer אוכל להשתמש במודל זה כמו כול שכבת Keras אחרת. למרבה המזל, hub.KerasLayer יכול לעשות הוא רק 1 קו.

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

אתה יכול להתייחס לזה תסריט במקרה אתם מעוניינים התסריט לייצא את המודל. Object pretrained_layer היא הגירסה freezed של Wav2Vec2Model . טרום מאומן אלו משקולות הוסבו HuggingFace PyTorch מראש מאומן משקולות באמצעות סקריפט זה .

במקור, wav2vec2 הוכשר מראש עם גישת מודלים של שפה במסכה במטרה לזהות את ייצוג הדיבור הסמוי המכומתי האמיתי עבור שלב זמן מוסווה. אתה יכול לקרוא עוד על המטרה הכשרה של נייר 2.0 wav2vec: מסגרת למידה עצמית השגחה של ייצוגי דיבור .

כעת, נגדיר כמה קבועים והיפר-פרמטרים שיהיו שימושיים בתאים הבאים. AUDIO_MAXLEN מוגדר בכוונה כדי 246000 כמו חתימת המודל מקבלת רק אורך רצף סטטי של 246000 .

AUDIO_MAXLEN = 246000
LABEL_MAXLEN = 256
BATCH_SIZE = 2

בתא הבא, נוכל לעטוף pretrained_layer & שכבה צפופה (ראש LM) עם API פונקציונלית של 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)

השכבה צפופה (כמוגדר לעיל) הוא בעל מימד הפלט של vocab_size כפי שאנו רוצים לחזות הסתברויות של כל אסימון באוצר המילים בכל שלב זמן.

הגדרת מצב אימון

בשנת TensorFlow, משקולות דגם בנוי רק כאשר model.call או model.build נקרא בפעם הראשונה, כך התא הבא יבנה משקלות המודל בשבילנו. בהמשך, נוכל לפעול model.summary() כדי לבדוק את המספר הכולל של פרמטרים שאפשר לאלף.

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
_________________________________________________________________

עכשיו, אנחנו צריכים להגדיר את loss_fn ו האופטימיזציה כדי להיות מסוגל לאמן את המודל. התא הבא יעשה זאת עבורנו. אנחנו נהיה באמצעות Adam האופטימיזציה עבור פשטות. CTCLoss הוא סוג אובדן נפוץ המשמש למשימות (כמו ASR ) שבו-חלקים תת קלט לא ניתן להתאים אותה בקלות עם חלקים בתת פלט. אתה יכול לקרוא עוד על CTC-הפסד המדהים הזה בבלוג .

CTCLossgsoc-wav2vec2 חבילה) מקבל 3 טיעונים: config , model_input_shape & division_factor . אם division_factor=1 , אז ההפסד יהיה פשוט לקבל סיכם, אז תעבירו division_factor בהתאם כדי לקבל אצווה מעל הממוצע.

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)

טעינה ועיבוד מוקדם של נתונים

בואו עכשיו להוריד את נתוני LibriSpeech מן האתר הרשמי ו להגדיר אותו.

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

מערך הנתונים שלנו נמצא בספריית LibriSpeech. בוא נחקור את הקבצים האלה.

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

בסדר, אז לכל אחד יש תת-ספרייה רבים .flac קבצים וכן .txt קובץ. .txt הקובץ מכיל תעתיקי טקסט עבור כל דגימות הדיבור (כלומר .flac קבצים) נוכח באותה תת-ספריה.

אנו יכולים לטעון את נתוני הטקסט באופן הבא:

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

באופן דומה, נגדיר פונקציה לטעינת מדגם דיבור מתוך .flac קובץ.

REQUIRED_SAMPLE_RATE מוגדר 16000 כפי wav2vec2 היה מראש מאומן עם 16K תדיר וזה מומלץ לכוונן אותו בלי שום שינוי משמעותי בחלוק נתונים בשל תדירות.

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}

כעת, נבחר כמה דוגמאות אקראיות וננסה לדמיין אותן.

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:

כעת, נשלב את כל דוגמאות הדיבור והטקסט ונגדיר את הפונקציה (בתא הבא) למטרה זו.

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

זה הזמן להסתכל על כמה דוגמאות...

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')]

בואו נעבד את הנתונים מראש!!!

אנחנו ראשונים נגדיר את tokenizer & מעבד באמצעות gsoc-wav2vec2 חבילה. לאחר מכן, נבצע עיבוד מקדים פשוט מאוד. processor יהיה לנרמל דיבור גלם wrto מסגרות ציר tokenizer ימיר פלטי המודל שלנו לתוך המחרוזת (באמצעות אוצר המילים המוגדרות) & ידאג הסרת אסימונים מיוחדים (בהתאם לתצורת 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

כעת, נגדיר את מחולל הפיתון שיקרא לפונקציות העיבוד המקדים שהגדרנו בתאים לעיל.

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

הגדרת tf.data.Dataset

תא רצון בעקבות התקנת tf.data.Dataset אובייקט באמצעות שלה .from_generator(...) השיטה. אנחנו נהיה באמצעות generator אובייקט, הגדרנו בתא לעיל.

אתה יכול להתייחס התסריט הזה לפרטים נוספים על איך להמיר נתוני 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)

נעביר את מערך הנתונים למספר אצוות, אז בואו נכין אצוות בתא הבא. כעת, כל הרצפים באצווה צריכים להיות מרופדים לאורך קבוע. נשתמש .padded_batch(...) שיטה למטרה זו.

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

מאיצים (כמו GPUs/TPUs) מהירים מאוד ולעתים קרובות טעינת נתונים (ועיבוד מקדים) הופכת לצוואר הבקבוק במהלך האימון, כאשר החלק של טעינת הנתונים מתרחש במעבדים. זה יכול להגדיל את זמן האימון באופן משמעותי במיוחד כאשר יש הרבה עיבוד מקדים מקוון מעורב או נתונים מוזרמים באינטרנט מדליי GCS. כדי להתמודד עם סוגיות אלה, tf.data.Dataset מציעה את .prefetch(...) שיטה. שיטה זו מסייעת בהכנת האצוות הבאות במקביל (במעבדים) בזמן שהמודל מבצע תחזיות (על GPUs/TPUs) על האצווה הנוכחית.

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

מאז המחברת הזאת נעשית למטרות הדגמה, ננקוט הראשון num_train_batches ו נבצע אימונים מעל היחיד. עם זאת, מומלץ להתאמן על כל מערך הנתונים. באופן דומה, נוכל להעריך רק 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)

אימון דוגמניות

לאימוני המודל שלנו, אנחנו נהיה ישירות קוראים .fit(...) שיטה לאחר קומפילצית המודל שלנו עם .compile(...) .

model.compile(optimizer, loss=loss_fn)

התא לעיל יגדיר את מצב האימון שלנו. עכשיו אנחנו יכולים ליזום הכשרה עם .fit(...) השיטה.

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

בואו נשמור המודל שלנו עם .save(...) שיטה כדי להיות מסוגל לבצע היקש מאוחר. ניתן גם לייצא SavedModel זה TFHub ידי ביצוע תיעוד 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

הַעֲרָכָה

כעת נחשוב את שיעור השגיאות של Word על פני מערך האימות

שיעור שגיאה Word (WER) הוא מדד מקובל למדידת הביצועים של מערכת זיהוי דיבור אוטומטי. ה-WER נגזר ממרחק לוונשטיין, עובד ברמת המילה. לאחר מכן ניתן לחשב שיעור שגיאות מילים כך: WER = (S + D + I) / N = (S + D + I) / (S + D + C) כאשר S הוא מספר ההחלפות, D הוא מספר המחיקות , I הוא מספר ההוספות, C הוא מספר המילים הנכונות, N הוא מספר המילים בהפניה (N=S+D+C). ערך זה מציין את אחוז המילים שנחזו בצורה שגויה.

אתה יכול להתייחס במאמר זה כדי ללמוד עוד על WER.

נשתמש load_metric(...) פונקציה מ מערכי נתונים HuggingFace הספרייה. בואו ראשון להתקין את datasets הספרייה באמצעות pip ולאחר מכן להגדיר את metric האובייקט.

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

הגיע הזמן להפעיל את ההערכה על נתוני אימות עכשיו.

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

אנחנו משתמשים tokenizer.decode(...) שיטה לפענוח תחזיות ותוויות שלנו בחזרה לתוך הטקסט יהיה להוסיף אותם מטרי עבור WER חישוב מאוחר.

כעת, בואו נחשב את הערך המטרי בתא הבא:

metric.compute()
1.0

הסקה

עכשיו אנחנו מרוצים מתהליך ההכשרה & שמרת מודל save_dir , נוכל לראות איך המודל הזה יכול לשמש היקש.

ראשית, נוכל לטעון המודל שלנו באמצעות 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.

בוא נוריד כמה דוגמאות דיבור לביצוע מסקנות. אתה יכול להחליף את הדוגמה הבאה גם בדוגמה של הדיבור שלך.

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]

עכשיו, נוכל לקרוא את דגימת הדיבור באמצעות soundfile.read(...) ועל משטח אותו AUDIO_MAXLEN כדי לספק את חתימת המודל. ואז נוכל לנרמל כי דגימת דיבור באמצעות Wav2Vec2Processor למשל & נאכיל אותו לתוך המודל.

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

מספרים לפענח בואו לגבות לתוך רצף טקסט באמצעות Wav2Vec2tokenizer למשל, הגדרנו לעיל.

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

תחזית זו היא אקראית למדי מכיוון שהמודל מעולם לא הוכשר על נתונים גדולים במחברת זו (מכיוון שהמחברת הזו לא מיועדת לאימון מלא). תקבל תחזיות טובות אם תאמן את המודל הזה על מערך הנתונים המלא של LibriSpeech.

לבסוף, הגענו לקצה המחברת הזו. אבל זה לא קץ של למידת TensorFlow למשימות הקשורות לדיבור, זה מאגר המכיל כמה מדריכים מדהימים יותר. במקרה נתקל באג במחברת זו, אנא צור בעיה כאן .