Yardım Kaggle üzerinde TensorFlow ile Büyük Bariyer Resifi korumak Meydan Üyelik

Basit ses tanıma: Anahtar kelimeleri tanıma

TensorFlow.org'da görüntüleyin Google Colab'da çalıştırın Kaynağı GitHub'da görüntüleyin Not defterini indir

Bu eğitimde WAV formatında ve yapı ses dosyalarını ön işlemeden ve temel yetiştirmek gösterilmiştir otomatik konuşma tanıma on farklı kelimeleri tanımak (ASR) modeli. Sen bir bölümünü kullanacak Konuşma Komutları veri kümesi ( Warden 2018 kısa içerir), (bir saniyelik veya daha az) böyle "aşağı", "hayır", "sol" "git", "gibi komutları ses klipleri, sağ", "dur", "yukarı" ve "evet".

Gerçek dünya konuşma ve ses tanıma sistemleri karmaşıktır. Ancak, kim MNIST veri kümesi ile görüntü sınıflandırma , bu örnek, size katılan tekniklerin temel fikir verecektir.

Kurmak

Gerekli modülleri ve bağımlılıkları içe aktarın. Eğer kullanarak olacağım Not Seaborn Bu eğitimde görselleştirme için.

import os
import pathlib

import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import models
from IPython import display

# Set the seed value for experiment reproducibility.
seed = 42
tf.random.set_seed(seed)
np.random.seed(seed)

Mini Konuşma Komutları veri kümesini içe aktarın

Veri yüklemeyle zaman kazanmak için Konuşma Komutları veri kümesinin daha küçük bir sürümüyle çalışacaksınız. Orijinal veri kümesi içinde 105,000 üzerinde ses dosyalarının oluşur WAV (Dalga Formu) ses dosyası formatı 35 farklı kelime söyleyerek insanların. Bu veriler Google tarafından toplandı ve bir CC BY lisansı altında yayınlandı.

İndirme ve ayıklamak mini_speech_commands.zip daha küçük Konuşma Komutları veri setlerini içeren dosyayı tf.keras.utils.get_file :

DATASET_PATH = 'data/mini_speech_commands'

data_dir = pathlib.Path(DATASET_PATH)
if not data_dir.exists():
  tf.keras.utils.get_file(
      'mini_speech_commands.zip',
      origin="http://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip",
      extract=True,
      cache_dir='.', cache_subdir='data')
Downloading data from http://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip
182083584/182082353 [==============================] - 6s 0us/step
182091776/182082353 [==============================] - 6s 0us/step

: Veri kümesinin ses klipleri her konuşma komutuna karşılık gelen sekiz klasörlerinde saklanır no , yes , down , go , left , up , right ve stop :

commands = np.array(tf.io.gfile.listdir(str(data_dir)))
commands = commands[commands != 'README.md']
print('Commands:', commands)
Commands: ['yes' 'go' 'left' 'right' 'up' 'down' 'stop' 'no']

Adlı bir liste halinde ses klipleri Özü filenames ve onu karıştırmak:

filenames = tf.io.gfile.glob(str(data_dir) + '/*/*')
filenames = tf.random.shuffle(filenames)
num_samples = len(filenames)
print('Number of total examples:', num_samples)
print('Number of examples per label:',
      len(tf.io.gfile.listdir(str(data_dir/commands[0]))))
print('Example file tensor:', filenames[0])
Number of total examples: 8000
Number of examples per label: 1000
Example file tensor: tf.Tensor(b'data/mini_speech_commands/up/05739450_nohash_2.wav', shape=(), dtype=string)

Bölünmüş filenames sırasıyla 80:10:10 oranı kullanılarak eğitim, doğrulama ve test setleri halinde:

train_files = filenames[:6400]
val_files = filenames[6400: 6400 + 800]
test_files = filenames[-800:]

print('Training set size', len(train_files))
print('Validation set size', len(val_files))
print('Test set size', len(test_files))
Training set size 6400
Validation set size 800
Test set size 800

Ses dosyalarını ve etiketlerini okuyun

Bu bölümde, dalga formları ve ilgili etiketler için kodu çözülmüş tensörler oluşturarak veri setini önceden işleyeceksiniz. Bunu not et:

  • Her WAV dosyası, saniyede belirli sayıda örnek içeren zaman serisi verileri içerir.
  • Her bir numune, temsil genlik belirli bir zamanda ses sinyalinin.
  • Bir de 16 bit sistemi, mini Konuşma Komutları veri kümesindeki WAV dosyaları gibi genlik değerleri elde -32768 32,767 arasında değişmektedir.
  • Örnek oranı bu veri kümesi için 16kHz olduğunu.

Tarafından döndürülen tensörünün şekil tf.audio.decode_wav olan [samples, channels] , channels ise 1 mono ya da 2 stereo. Mini Konuşma Komutları veri kümesi yalnızca mono kayıtları içerir.

test_file = tf.io.read_file(DATASET_PATH+'/down/0a9f9af7_nohash_0.wav')
test_audio, _ = tf.audio.decode_wav(contents=test_file)
test_audio.shape
TensorShape([13654, 1])

Şimdi, veri kümesinin ham WAV ses dosyalarını ses tensörlerine önişleyen bir işlev tanımlayalım:

def decode_audio(audio_binary):
  # Decode WAV-encoded audio files to `float32` tensors, normalized
  # to the [-1.0, 1.0] range. Return `float32` audio and a sample rate.
  audio, _ = tf.audio.decode_wav(contents=audio_binary)
  # Since all the data is single channel (mono), drop the `channels`
  # axis from the array.
  return tf.squeeze(audio, axis=-1)

Her dosya için üst dizinleri kullanarak etiketler oluşturan bir işlev tanımlayın:

  • İçine dosya yolları bölme tf.RaggedTensor (dağınık boyutları-ile dilimleri farklı uzunluklara sahip olabilir ile tensörlerle) s.
def get_label(file_path):
  parts = tf.strings.split(
      input=file_path,
      sep=os.path.sep)
  # Note: You'll use indexing here instead of tuple unpacking to enable this
  # to work in a TensorFlow graph.
  return parts[-2]

Başka bir yardımcı fonksiyonu-Define get_waveform_and_label hep birlikte -yani koyar o:

  • Giriş, WAV ses dosyası adıdır.
  • Çıktı, denetimli öğrenmeye hazır ses ve etiket tensörlerini içeren bir demettir.
def get_waveform_and_label(file_path):
  label = get_label(file_path)
  audio_binary = tf.io.read_file(file_path)
  waveform = decode_audio(audio_binary)
  return waveform, label

Ses etiketi çiftlerini çıkarmak için eğitim setini oluşturun:

Daha sonra benzer bir prosedür kullanarak doğrulama ve test setlerini oluşturacaksınız.

AUTOTUNE = tf.data.AUTOTUNE

files_ds = tf.data.Dataset.from_tensor_slices(train_files)

waveform_ds = files_ds.map(
    map_func=get_waveform_and_label,
    num_parallel_calls=AUTOTUNE)

Birkaç ses dalga biçimi çizelim:

rows = 3
cols = 3
n = rows * cols
fig, axes = plt.subplots(rows, cols, figsize=(10, 12))

for i, (audio, label) in enumerate(waveform_ds.take(n)):
  r = i // cols
  c = i % cols
  ax = axes[r][c]
  ax.plot(audio.numpy())
  ax.set_yticks(np.arange(-1.2, 1.2, 0.2))
  label = label.numpy().decode('utf-8')
  ax.set_title(label)

plt.show()

png

Dalga formlarını spektrogramlara dönüştürün

Veri kümesindeki dalga biçimleri zaman alanında temsil edilir. Daha sonra, işlem ile zaman-frekans-alan sinyallerine dönüştürmek için zaman alanlı sinyallerinden dalga biçimlerini dönüştürmek gerekir kısa zaman Fourier dönüşümü (STFT) şu şekilde dalga biçimlerini dönüştürmek için spektrogramlarda zaman frekans değişiklikleri göstermektedir ve bunlarla 2D görüntüler olarak temsil edilir. Modeli eğitmek için spektrogram görüntülerini sinir ağınıza besleyeceksiniz.

Bir Fourier dönüşümü ( tf.signal.fft ) bileşen frekansları için bir sinyal dönüştürür, ancak her zaman bilgilerini kaybeder. Buna karşılık, KZFD ( tf.signal.stft ) zamanın pencerelerin içine sinyalini böler ve bir Fourier bazı zaman bilgilerini koruyarak ve standart helezonlar çalışabileceği bir 2D tensörünü dönen, her pencere üzerinde dönüşümü çalışır.

Dalga biçimlerini spektrogramlara dönüştürmek için bir yardımcı program işlevi oluşturun:

  • Dalga biçimlerinin aynı uzunlukta olması gerekir, böylece onları spektrogramlara dönüştürdüğünüzde sonuçlar benzer boyutlara sahip olur. Bu sadece daha kısa bir ikinci (kullanarak olan ses klipleri sıfır doldurma yapılabilir tf.zeros ).
  • Çağrılırken tf.signal.stft , seçim frame_length ve frame_step oluşturulan spektrogram "görüntü" neredeyse kare olduğunu parametreler,. KZFD parametreleri seçimine daha fazla bilgi için bakınız bu Coursera videonun ses sinyali işleme ve KZFD üzerinde.
  • STFT, büyüklük ve fazı temsil eden bir dizi karmaşık sayı üretir. Ancak bu eğitimde yalnızca uygulayarak türetebilirsiniz büyüklüğünü, kullanacağız tf.abs çıkışındaki tf.signal.stft .
def get_spectrogram(waveform):
  # Zero-padding for an audio waveform with less than 16,000 samples.
  input_len = 16000
  waveform = waveform[:input_len]
  zero_padding = tf.zeros(
      [16000] - tf.shape(waveform),
      dtype=tf.float32)
  # Cast the waveform tensors' dtype to float32.
  waveform = tf.cast(waveform, dtype=tf.float32)
  # Concatenate the waveform with `zero_padding`, which ensures all audio
  # clips are of the same length.
  equal_length = tf.concat([waveform, zero_padding], 0)
  # Convert the waveform to a spectrogram via a STFT.
  spectrogram = tf.signal.stft(
      equal_length, frame_length=255, frame_step=128)
  # Obtain the magnitude of the STFT.
  spectrogram = tf.abs(spectrogram)
  # Add a `channels` dimension, so that the spectrogram can be used
  # as image-like input data with convolution layers (which expect
  # shape (`batch_size`, `height`, `width`, `channels`).
  spectrogram = spectrogram[..., tf.newaxis]
  return spectrogram

Ardından, verileri keşfetmeye başlayın. Bir örneğin gerginleştirilmiş dalga formunun ve ilgili spektrogramın şekillerini yazdırın ve orijinal sesi çalın:

for waveform, label in waveform_ds.take(1):
  label = label.numpy().decode('utf-8')
  spectrogram = get_spectrogram(waveform)

print('Label:', label)
print('Waveform shape:', waveform.shape)
print('Spectrogram shape:', spectrogram.shape)
print('Audio playback')
display.display(display.Audio(waveform, rate=16000))
Label: up
Waveform shape: (11606,)
Spectrogram shape: (124, 129, 1)
Audio playback

Şimdi, bir spektrogramı görüntülemek için bir fonksiyon tanımlayın:

def plot_spectrogram(spectrogram, ax):
  if len(spectrogram.shape) > 2:
    assert len(spectrogram.shape) == 3
    spectrogram = np.squeeze(spectrogram, axis=-1)
  # Convert the frequencies to log scale and transpose, so that the time is
  # represented on the x-axis (columns).
  # Add an epsilon to avoid taking a log of zero.
  log_spec = np.log(spectrogram.T + np.finfo(float).eps)
  height = log_spec.shape[0]
  width = log_spec.shape[1]
  X = np.linspace(0, np.size(spectrogram), num=width, dtype=int)
  Y = range(height)
  ax.pcolormesh(X, Y, log_spec)

Örneğin zaman içindeki dalga biçimini ve karşılık gelen spektrogramı (zaman içindeki frekanslar) çizin:

fig, axes = plt.subplots(2, figsize=(12, 8))
timescale = np.arange(waveform.shape[0])
axes[0].plot(timescale, waveform.numpy())
axes[0].set_title('Waveform')
axes[0].set_xlim([0, 16000])

plot_spectrogram(spectrogram.numpy(), axes[1])
axes[1].set_title('Spectrogram')
plt.show()

png

Şimdi, dalga biçimi veri kümesini spektrogramlara ve bunlara karşılık gelen etiketleri tamsayı kimlikleri olarak dönüştüren bir işlev tanımlayın:

def get_spectrogram_and_label_id(audio, label):
  spectrogram = get_spectrogram(audio)
  label_id = tf.argmax(label == commands)
  return spectrogram, label_id

Harita get_spectrogram_and_label_id ile veri kümesinin elemanları arasında Dataset.map :

spectrogram_ds = waveform_ds.map(
  map_func=get_spectrogram_and_label_id,
  num_parallel_calls=AUTOTUNE)

Veri kümesinin farklı örnekleri için spektrogramları inceleyin:

rows = 3
cols = 3
n = rows*cols
fig, axes = plt.subplots(rows, cols, figsize=(10, 10))

for i, (spectrogram, label_id) in enumerate(spectrogram_ds.take(n)):
  r = i // cols
  c = i % cols
  ax = axes[r][c]
  plot_spectrogram(spectrogram.numpy(), ax)
  ax.set_title(commands[label_id.numpy()])
  ax.axis('off')

plt.show()

png

Modeli oluşturun ve eğitin

Doğrulama ve test setlerinde eğitim seti ön işlemesini tekrarlayın:

def preprocess_dataset(files):
  files_ds = tf.data.Dataset.from_tensor_slices(files)
  output_ds = files_ds.map(
      map_func=get_waveform_and_label,
      num_parallel_calls=AUTOTUNE)
  output_ds = output_ds.map(
      map_func=get_spectrogram_and_label_id,
      num_parallel_calls=AUTOTUNE)
  return output_ds
train_ds = spectrogram_ds
val_ds = preprocess_dataset(val_files)
test_ds = preprocess_dataset(test_files)

Model eğitimi için eğitim ve doğrulama setlerini toplu halde toplayın:

batch_size = 64
train_ds = train_ds.batch(batch_size)
val_ds = val_ds.batch(batch_size)

Ekle Dataset.cache ve Dataset.prefetch modeli eğitim sırasında okuma gecikmesini azaltmak için operasyonlarını:

train_ds = train_ds.cache().prefetch(AUTOTUNE)
val_ds = val_ds.cache().prefetch(AUTOTUNE)

Ses dosyalarını spektrogram görüntülerine dönüştürdüğünüz için model için basit bir evrişimli sinir ağı (CNN) kullanacaksınız.

Kişisel tf.keras.Sequential modeli aşağıdaki Keras ön işleme katmanları kullanacağız:

İçin Normalization tabakası, onun adapt yöntem, ilk olarak genel istatistikler hesaplamak amacıyla eğitim verileri olarak adlandırılır olması gerekir (olduğundan, ortalama ve standart sapma).

for spectrogram, _ in spectrogram_ds.take(1):
  input_shape = spectrogram.shape
print('Input shape:', input_shape)
num_labels = len(commands)

# Instantiate the `tf.keras.layers.Normalization` layer.
norm_layer = layers.Normalization()
# Fit the state of the layer to the spectrograms
# with `Normalization.adapt`.
norm_layer.adapt(data=spectrogram_ds.map(map_func=lambda spec, label: spec))

model = models.Sequential([
    layers.Input(shape=input_shape),
    # Downsample the input.
    layers.Resizing(32, 32),
    # Normalize.
    norm_layer,
    layers.Conv2D(32, 3, activation='relu'),
    layers.Conv2D(64, 3, activation='relu'),
    layers.MaxPooling2D(),
    layers.Dropout(0.25),
    layers.Flatten(),
    layers.Dense(128, activation='relu'),
    layers.Dropout(0.5),
    layers.Dense(num_labels),
])

model.summary()
Input shape: (124, 129, 1)
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 resizing (Resizing)         (None, 32, 32, 1)         0         
                                                                 
 normalization (Normalizatio  (None, 32, 32, 1)        3         
 n)                                                              
                                                                 
 conv2d (Conv2D)             (None, 30, 30, 32)        320       
                                                                 
 conv2d_1 (Conv2D)           (None, 28, 28, 64)        18496     
                                                                 
 max_pooling2d (MaxPooling2D  (None, 14, 14, 64)       0         
 )                                                               
                                                                 
 dropout (Dropout)           (None, 14, 14, 64)        0         
                                                                 
 flatten (Flatten)           (None, 12544)             0         
                                                                 
 dense (Dense)               (None, 128)               1605760   
                                                                 
 dropout_1 (Dropout)         (None, 128)               0         
                                                                 
 dense_1 (Dense)             (None, 8)                 1032      
                                                                 
=================================================================
Total params: 1,625,611
Trainable params: 1,625,608
Non-trainable params: 3
_________________________________________________________________

Keras modelini Adam optimize edici ve çapraz entropi kaybıyla yapılandırın:

model.compile(
    optimizer=tf.keras.optimizers.Adam(),
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy'],
)

Gösteri amacıyla modeli 10 çağdan fazla eğitin:

EPOCHS = 10
history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=EPOCHS,
    callbacks=tf.keras.callbacks.EarlyStopping(verbose=1, patience=2),
)
Epoch 1/10
100/100 [==============================] - 13s 40ms/step - loss: 1.7404 - accuracy: 0.3823 - val_loss: 1.3372 - val_accuracy: 0.5550
Epoch 2/10
100/100 [==============================] - 0s 4ms/step - loss: 1.1776 - accuracy: 0.5903 - val_loss: 0.9747 - val_accuracy: 0.6600
Epoch 3/10
100/100 [==============================] - 0s 4ms/step - loss: 0.9027 - accuracy: 0.6778 - val_loss: 0.8096 - val_accuracy: 0.7150
Epoch 4/10
100/100 [==============================] - 0s 4ms/step - loss: 0.7647 - accuracy: 0.7316 - val_loss: 0.7325 - val_accuracy: 0.7625
Epoch 5/10
100/100 [==============================] - 0s 4ms/step - loss: 0.6492 - accuracy: 0.7658 - val_loss: 0.6697 - val_accuracy: 0.7688
Epoch 6/10
100/100 [==============================] - 0s 5ms/step - loss: 0.5796 - accuracy: 0.7937 - val_loss: 0.6108 - val_accuracy: 0.7875
Epoch 7/10
100/100 [==============================] - 0s 4ms/step - loss: 0.5261 - accuracy: 0.8117 - val_loss: 0.5708 - val_accuracy: 0.8087
Epoch 8/10
100/100 [==============================] - 0s 4ms/step - loss: 0.4747 - accuracy: 0.8267 - val_loss: 0.5429 - val_accuracy: 0.8163
Epoch 9/10
100/100 [==============================] - 0s 4ms/step - loss: 0.4427 - accuracy: 0.8428 - val_loss: 0.5379 - val_accuracy: 0.8175
Epoch 10/10
100/100 [==============================] - 0s 4ms/step - loss: 0.3927 - accuracy: 0.8637 - val_loss: 0.5320 - val_accuracy: 0.8213

Modelinizin eğitim sırasında nasıl geliştiğini kontrol etmek için eğitim ve doğrulama kaybı eğrilerini çizelim:

metrics = history.history
plt.plot(history.epoch, metrics['loss'], metrics['val_loss'])
plt.legend(['loss', 'val_loss'])
plt.show()

png

Model performansını değerlendirin

Modeli test setinde çalıştırın ve modelin performansını kontrol edin:

test_audio = []
test_labels = []

for audio, label in test_ds:
  test_audio.append(audio.numpy())
  test_labels.append(label.numpy())

test_audio = np.array(test_audio)
test_labels = np.array(test_labels)
y_pred = np.argmax(model.predict(test_audio), axis=1)
y_true = test_labels

test_acc = sum(y_pred == y_true) / len(y_true)
print(f'Test set accuracy: {test_acc:.0%}')
Test set accuracy: 84%

Bir karışıklık matrisi göster

Bir kullan karışıklık matrisi modeli testi setinde komutların her sınıflandırma yaptım ne kadar iyi kontrol etmek:

confusion_mtx = tf.math.confusion_matrix(y_true, y_pred)
plt.figure(figsize=(10, 8))
sns.heatmap(confusion_mtx,
            xticklabels=commands,
            yticklabels=commands,
            annot=True, fmt='g')
plt.xlabel('Prediction')
plt.ylabel('Label')
plt.show()

png

Bir ses dosyasında çıkarımı çalıştır

Son olarak, "hayır" diyen birinin giriş ses dosyasını kullanarak modelin tahmin çıktısını doğrulayın. Modeliniz ne kadar iyi performans gösteriyor?

sample_file = data_dir/'no/01bb6a2a_nohash_0.wav'

sample_ds = preprocess_dataset([str(sample_file)])

for spectrogram, label in sample_ds.batch(1):
  prediction = model(spectrogram)
  plt.bar(commands, tf.nn.softmax(prediction[0]))
  plt.title(f'Predictions for "{commands[label[0]]}"')
  plt.show()

png

Çıktının önerdiği gibi, modelinizin sesli komutu "hayır" olarak tanıması gerekir.

Sonraki adımlar

Bu öğretici, TensorFlow ve Python ile evrişimli bir sinir ağı kullanarak basit ses sınıflandırmasının/otomatik konuşma tanımanın nasıl gerçekleştirileceğini gösterdi. Daha fazla bilgi edinmek için aşağıdaki kaynakları göz önünde bulundurun: