ปรับแต่ง Wav2Vec2 ด้วยหัว LM

ดูบน TensorFlow.org ทำงานใน Google Colab ดูบน GitHub ดาวน์โหลดโน๊ตบุ๊ค ดูรุ่น TF Hub

ในสมุดบันทึกนี้เราจะโหลดรูปแบบ wav2vec2 ก่อนได้รับการฝึกฝนจาก TFHub และจะปรับแต่งได้ใน LibriSpeech ชุดข้อมูล โดยการผนวก Modeling Language หัว (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)

คุณสามารถอ้างถึงนี้ สคริปต์ ในกรณีที่คุณสนใจในรูปแบบสคริปต์การส่งออก วัตถุ pretrained_layer เป็นรุ่น freezed ของ Wav2Vec2Model เหล่านี้น้ำหนักก่อนการฝึกอบรมได้รับการดัดแปลงมาจาก HuggingFace PyTorch น้ำหนักก่อนการฝึกอบรม การใช้ สคริปต์นี้

ในขั้นต้น wav2vec2 ได้รับการฝึกอบรมล่วงหน้าด้วยวิธีการสร้างแบบจำลองภาษาที่ปิดบัง โดยมีวัตถุประสงค์เพื่อระบุการแสดงคำพูดแฝงเชิงปริมาณที่แท้จริงสำหรับขั้นตอนเวลาที่ปิดบัง คุณสามารถอ่านเพิ่มเติมเกี่ยวกับวัตถุประสงค์ของการฝึกอบรมในกระดาษ wav2vec 2.0: กรอบสำหรับการเรียนรู้ภายใต้การดูแลตัวเองในการพูดการรับรอง

ตอนนี้ เราจะกำหนดค่าคงที่และพารามิเตอร์ไฮเปอร์สองสามตัว ซึ่งจะเป็นประโยชน์ในเซลล์ถัดไป 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 การสูญเสียจากการที่น่าตื่นตาตื่นใจนี้ โพสต์บล็อก

CTCLoss (จาก gsoc-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']

Alright ดังนั้นแต่ละไดเรกทอรีย่อยมีหลาย .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 ถูก pre-รับการฝึกฝนกับ 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))

ตัวเร่งความเร็ว (เช่น GPU/TPU) นั้นเร็วมาก และบ่อยครั้งที่การโหลดข้อมูล (& การประมวลผลล่วงหน้า) จะกลายเป็นคอขวดระหว่างการฝึก เนื่องจากส่วนการโหลดข้อมูลเกิดขึ้นกับ CPU การทำเช่นนี้สามารถเพิ่มเวลาการฝึกอบรมได้อย่างมาก โดยเฉพาะอย่างยิ่งเมื่อมีการประมวลผลล่วงหน้าออนไลน์ที่เกี่ยวข้องเป็นจำนวนมาก หรือมีการสตรีมข้อมูลออนไลน์จากบัคเก็ต GCS การจัดการปัญหาเหล่านั้น tf.data.Dataset มี .prefetch(...) วิธีการ วิธีนี้ช่วยในการเตรียมแบตช์สองสามชุดถัดไปแบบขนาน (บน CPU) ในขณะที่โมเดลกำลังคาดการณ์ (บน GPU/TPU) ในชุดปัจจุบัน

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

Let 's บันทึกรูปแบบของเราที่มี .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 Error Rate เหนือชุดข้อมูลการตรวจสอบความถูกต้อง

อัตราความผิดพลาด Word (WER) เป็นตัวชี้วัดที่พบบ่อยสำหรับการวัดประสิทธิภาพการทำงานของระบบการรู้จำเสียงพูดอัตโนมัติ WER มาจากระยะทาง Levenshtein ซึ่งทำงานที่ระดับคำ อัตราความผิดพลาดของคำสามารถคำนวณได้ดังนี้: WER = (S + D + I) / N = (S + D + I) / (S + D + C) โดยที่ S คือจำนวนการแทนที่ D คือจำนวนการลบ , I คือจำนวนการแทรก, C คือจำนวนคำที่ถูกต้อง, N คือจำนวนคำในการอ้างอิง (N=S+D+C) ค่านี้ระบุเปอร์เซ็นต์ของคำที่คาดเดาไม่ถูกต้อง

คุณสามารถอ้างถึง บทความนี้ เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับ WER

เราจะใช้ load_metric(...) ฟังก์ชั่นจาก HuggingFace ชุดข้อมูล ห้องสมุด Let 's แรกติดตั้ง 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)>

Let 's หมายเลขถอดรหัสกลับเข้ามาในลำดับข้อความโดยใช้ Wav2Vec2tokenizer เช่นเรากำหนดไว้ข้างต้น

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

การคาดคะเนนี้ค่อนข้างสุ่มเนื่องจากตัวแบบไม่เคยฝึกกับข้อมูลขนาดใหญ่ในสมุดบันทึกนี้ (เนื่องจากสมุดบันทึกนี้ไม่ได้มีไว้สำหรับทำการฝึกทั้งหมด) คุณจะได้รับการคาดการณ์ที่ดี หากคุณฝึกโมเดลนี้กับชุดข้อมูล LibriSpeech ที่สมบูรณ์

ในที่สุด เราก็มาถึงจุดสิ้นสุดของสมุดบันทึกเล่มนี้ แต่มันไม่ได้ในตอนท้ายของการเรียนรู้ TensorFlow สำหรับงานคำพูดที่เกี่ยวข้องกับการนี้ พื้นที่เก็บข้อมูล มีบทเรียนที่น่าตื่นตาตื่นใจมากขึ้นบางส่วน ในกรณีที่คุณพบข้อผิดพลาดใด ๆ ในสมุดบันทึกนี้โปรดสร้างปัญหา ที่นี่