博客 / 詳情

返回

AI實戰:用 TensorFlow 識別數字 0-9

摘要

本項目的目標是使用深度學習來檢測數字 0-9 的語音。

我們將利用深度學習技術,把語音文件轉譯為文本數據,例如把英語 three 的發音轉譯為文本 "three"。

我們將使用 TensorFlow/Keras 來創建模型、訓練模型,再使用測試數據評估它的性能。

本教程的 Jupyter 文件地址:
https://openbayes.com/console/public/tutorials/Y9mnsBbqufM

本教程的視頻地址:
https://www.bilibili.com/video/BV16n4y197zD

運行環境

因為 AI 需要在 GPU 上運算,而一般的 PC 是沒有 GPU 的,所以我們要借用雲端的算力。

我選擇的雲端算力平台是 OpenBayes,你使用下面的鏈接進行註冊,將可以獲得免費 4 小時 RTX-4090 顯卡的使用時長。

註冊鏈接如下:
https://openbayes.com/console/signup?r=comehope_JrJj

點擊它,會出現下面的登錄界面,填寫用户名、郵箱、密碼、手機號和短信驗證碼,就可以完成註冊,如下圖所示。

<圖1>

克隆教程

註冊成功之後,進入到個人控制枱,在左側菜單中選擇“公共資源/公共教程”,搜索“0-9”,找到“語音識別入門教程:用 TensorFlow 識別數字 0-9”這篇教程,如下圖所示。

<圖2>

打開這篇教程,點擊右上角的“克隆”按鈕,如下圖所示。

<圖3>

在接下來“從模板創建:基本信息”的界面中點擊“下一步:選擇算力”按鈕,如下圖所示。

<圖4>

所謂算力,就是顯卡類型,請選擇“RTX 4090”,這裏會顯示您獲贈的時長。再選擇鏡像類型中,選擇“TensorFlow”,然後,顯示右下角的“下一步:審核”按鈕,如下圖所示。

<圖5>

接下來列出了剛才選擇過的算力和鏡像,點擊右下角的“繼續執行”按鈕,如下圖所示。

<圖6>

接下來,系統會自動分配資源,稍待片刻,等到頁面中顯示“打開工作空間”按鈕,點擊它,就可以進入運行中的教程了,如下圖所示。

<圖7>

工作空間的界面如下圖所示。

<圖8>

接下來,運行“教程.jpynb”文件即可。以下內容與 “教程.jpynb” 的內容完全相同,建議您在 Jupyter 中運行,可以實時看到運行結果。

教程正文

先安裝庫文件,所有依賴都保存在 requirements.txt 中,其中主要是 librosa 庫,是一個提取語音特徵的庫。

!pip install -r /openbayes/home/requirements.txt -q

數據集包含 1700 個語音文件,錄製了多個人的英語數字發音,每個錄音大約 1 秒到 2 秒時長。

數據集已經下載到 data 文件夾中。

接下來我們開始正式編碼。

首先,定義數據集的文件夾路徑,每個數字的語音都保存在以它的英語單詞命名的文件夾中。

file_paths = {
    '0': 'zero',
    '1': 'one',
    '2': 'two',
    '3': 'three',
    '4': 'four',
    '5': 'five',
    '6': 'six',
    '7': 'seven',
    '8': 'eight',
    '9': 'nine'
}

初始化 2 個列表 audio_data 和 labels,用於保存音頻數據和音頻對應的標籤。

audio_data = []
labels = []

使用 librosa 庫提取語音特徵,即所有音頻文件的 MFCC 特徵,並且使幀長固定為 40。MFCC(梅爾頻率倒譜系數)適合描繪人類的語音特徵。

使用 librosa 庫提取語音特徵,即所有音頻文件的 MFCC 特徵,並且使幀長固定為 40。MFCC(梅爾頻率倒譜系數)適合描繪人類的語音特徵。

import os
import numpy as np

n_frames = 40
for label, file_path in file_paths.items():
    print("processing: ", label, file_path)
    for file_name in os.listdir('data/' + file_path):
        file_path_full = os.path.join('data/' + file_path, file_name)
        audio, sr = librosa.load(file_path_full, sr=16000)
        mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=n_frames)
        if mfccs.shape[1] < n_frames:
            mfccs = np.pad(mfccs, ((0, 0), (0, n_frames - mfccs.shape[1])), mode='constant')
        else:
            mfccs = mfccs[:, :n_frames]
        mfccs_normalized = (mfccs - np.mean(mfccs)) / np.std(mfccs)
        mfccs_reshaped = mfccs_normalized.reshape((mfccs_normalized.shape[0], mfccs_normalized.shape[1], 1))
        audio_data.append(mfccs_reshaped)
        labels.append(label)

將之前定義的列表 audio_data 和 labels 轉換成 numpy 數組,便於後續進行機器學習。

並且提高數據的精度,把數據類型轉為 float64。

audio_data = np.array(audio_data, dtype=object)
labels = np.array(labels)

audio_data = audio_data.astype('float64')
labels = labels.astype('float64')

將 labels 列表轉換成獨熱編碼(one-hot encoding)。獨熱編碼用於在分類任務中對數據進行預處理,本項目要處理的問題可以看作是一個對語音進行分類的問題,數字 0-9 一共是 10 個分類。

from tensorflow import keras

labels_one_hot = keras.utils.to_categorical(labels)

把數據分為訓練集和測試集,測試集佔比 20%。其中,X_train 和 y_train 是訓練集的特徵數據和標籤數據,X_test 和 y_test 是測試集的特徵數據和標籤數據。

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(audio_data, labels_one_hot, test_size=0.2, random_state=42)

構建卷積神經網絡模型,模型一共 9 層,第一層的輸出會成為下一層的輸入。

先是一個二維卷積層,接着是一個二維最大池化層。接下來的幾層重複了卷積和池化的過程,卷積核的數量從 32 增加到 64,再到 128,這有助於模型學習更復雜的特徵。

再接下來將二維的輸入一維化,交給下一個全連接層處理,使用 relu 激活函數。

最後一層也是全連接層,它有10個神經元,對應於10個分類類別,使用 softmax 激活函數,將輸出轉換為概率分佈。

model = keras.models.Sequential([
    keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=X_train.shape[1:]),
    keras.layers.MaxPooling2D((2,2)),
    keras.layers.Conv2D(64, (3,3), activation='relu'),
    keras.layers.MaxPooling2D((2,2)),
    keras.layers.Conv2D(128, (3,3), activation='relu'),
    keras.layers.MaxPooling2D((2,2)),
    keras.layers.Flatten(),
    keras.layers.Dense(64, activation='relu'),
    keras.layers.Dense(10, activation='softmax')
])

編譯模型。優化器為 adam,這是一種流行的梯度下降優化算法;損失函數為與獨熱編碼匹配的 categorical_crossentropy;評估指標只使用準確率 accuracy。

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

定義 2 個回調函數,用於在模型訓練過程中應用特定的策略,ReduceLROnPlateau 用於調整學習率,EarlyStopping 用於防止過擬合。

from tensorflow.keras.callbacks import ReduceLROnPlateau
from tensorflow.keras.callbacks import EarlyStopping

reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=3, verbose=1, min_lr=0.0001)
early_stop = EarlyStopping(monitor='val_loss', patience=5, verbose=1)

定義數據生成器。儘管我們處理的是音頻而不是圖像,但此前已經將音頻特徵轉換為二維圖像數據,所以使用圖像數據增強工具來提高模型的泛化能力。

from keras.preprocessing.image import ImageDataGenerator

datagen = ImageDataGenerator(
    width_shift_range=0.1,
    height_shift_range=0.1,
    zoom_range=0.1,
    shear_range=0.1,
    rotation_range=10
)

接下來開始訓練模型。

訓練中使用了數據增強和回調函數來優化訓練過程,一共訓練 30 輪。

訓練過程中的所有信息記錄在 history 變量中,後面我們可以用它來查看訓練過程中的性能變化。

在 RTX 4090 顯卡上,訓練大約需要 3 分鐘。

history = model.fit(
    datagen.flow(X_train, y_train, batch_size=32),
    epochs=30,
    validation_data=(X_test, y_test),
    steps_per_epoch=len(X_train) // 32,
    callbacks=[reduce_lr, early_stop]
)

在測試集上進行性能評估,並查看準確率。

_, test_accuracy = model.evaluate(X_test, y_test)
print('Test accuracy:', test_accuracy)

準確率大約 95%。

再把訓練過程中關鍵指標的變化數據繪製成圖看一看。

import matplotlib.pyplot as plt

plt.plot(history.history['accuracy'], label='Training Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.show()

可以看到準確率一直在提升,而損失值一直在下降,這説明我們的訓練是有效的。

現在,我們可以用自己錄製的音頻來實測一下效果了。

定義一個函數 predict() 實現語音到文字的轉譯,它先提取出音頻文件的特徵,然後調用模型進行預測,返回概率最高的分類。

def predict(audio, sr):
    mfccs = librosa.feature.mfcc(y=audio, sr=sr, n_mfcc=n_frames)
    if mfccs.shape[1] < n_frames:
        mfccs = np.pad(mfccs, ((0, 0), (0, n_frames - mfccs.shape[1])), mode='constant')
    else:
        mfccs = mfccs[:, :n_frames]
    mfccs_normalized = (mfccs - np.mean(mfccs)) / np.std(mfccs)
    mfccs_reshaped = mfccs_normalized.reshape((1, mfccs_normalized.shape[0], mfccs_normalized.shape[1], 1))

    predictions = model.predict(mfccs_reshaped)
    predicted_class = np.argmax(predictions)
    return 'Predicted class: ' + str(predicted_class)

我一共錄製了 3 小段音頻,下面是測試其中 1 段音頻的代碼。

audio, sr = librosa.load('audio1.wav', sr=16000)

predict(audio, sr)

可以看到,打印出的結果和讀音是一致的。

是不是很有意思?

你也來試試吧!

記得使用我的註冊鏈接哦,可以獲得免費 4 小時 4090 時長呢~

https://openbayes.com/console/signup?r=comehope_JrJj

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.