基础语音识别-食物语音识别baseline(CNN)

  • Post category:Python

“基础语音识别-食物语音识别baseline(CNN)”完整攻略

本攻略介绍基于CNN的食物语音识别baseline的构建过程,涉及到数据集下载、特征提取、模型训练和测试等步骤。下面详细讲解每一个步骤。

数据集下载

本baseline使用的是YOHO! FOOD-20 数据集,该数据集包含20种食物,每种食物包含40个样本,共800个样本。数据集分为训练集、测试集和验证集,其中训练集和验证集各包含640个样本,测试集包含160个样本。在数据集中,每个样本是一个2s的音频文件,已经被标注为相应的食物种类。

可以通过如下命令下载数据集:

wget https://jgao.io/resource/2020/11/24/food20.tar.gz
tar -xzvf food20.tar.gz

特征提取

在训练模型之前,需要将音频文件转换为对应的特征。常用的特征包括MFCC(Mel-frequency cepstral coefficients)、Fbank等。本baseline使用MFCC作为特征。

以下是提取MFCC的代码示例:

import librosa

# 预处理参数
sr = 16000         # 采样率
n_fft = 400        # FFT 大小
win_length = 160   # 短时傅里叶窗口长度
hop_length = 80    # 短时傅里叶跳数
n_mels = 128       # 梅尔频带数
mfcc_len = 13      # MFCC 系数个数

def compute_mfcc(audio_file):
    # 读取音频文件
    y, sr = librosa.load(audio_file, sr=sr)

    # 计算MFCC
    mfcc = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=mfcc_len, n_fft=n_fft,
                                hop_length=hop_length, win_length=win_length)
    return mfcc.T

模型训练和测试

在进行模型训练前,需要将MFCC特征转换成对应的矩阵形式。以下是将MFCC特征转换为矩阵形式的代码示例:

import os
import numpy as np

# 标签和对应数字的映射关系
labels = [
    'bread', 'dumpling', 'fried_rice', 'hamburger', 'hot_dog', 'noodles',
    'rice', 'spaghetti', 'steak', 'sushi', 'chicken_wings', 'fish_and_chips',
    'grilled_salmon', 'miso_soup', 'pork_chop', 'spicy_and_sour_soup', 'chicken_curry',
    'beef_curry', 'green_salad', 'oyster_omelette'
]

num_labels = len(labels)

def load_data(data_dir):
    # 读取所有音频文件的MFCC特征
    mfccs = []
    labels = []
    for root, dirs, files in os.walk(data_dir):
        for file in files:
            if file.endswith('.wav'):
                mfcc = compute_mfcc(os.path.join(root, file))
                label = os.path.basename(root)
                mfccs.append(mfcc)
                labels.append(label)

    # 将MFCC特征转换为矩阵形式
    max_timesteps = max(len(mfcc) for mfcc in mfccs)
    pad_mfccs = np.zeros((len(mfccs), max_timesteps, mfcc_len))
    for i, mfcc in enumerate(mfccs):
        pad_len = max_timesteps - len(mfcc)
        pad_mfcc = np.pad(mfcc, ((0, pad_len), (0, 0)), 'constant')
        pad_mfccs[i, :, :] = pad_mfcc

    # 将标签转换为对应的数字
    label2id = {label: i for i, label in enumerate(set(labels))}
    ids = [label2id[label] for label in labels]

    return pad_mfccs, ids

# 加载数据集
train_mfccs, train_ids = load_data('food20/train')
test_mfccs, test_ids = load_data('food20/test')
val_mfccs, val_ids = load_data('food20/val')

接下来是CNN模型的定义和训练代码:

from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.utils import to_categorical
from sklearn.metrics import accuracy_score

# 模型定义
model = Sequential()

model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(train_mfccs.shape[1], train_mfccs.shape[2], 1)))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Conv2D(128, (3, 3), activation='relu'))
model.add(MaxPooling2D((2, 2)))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dense(num_labels, activation='softmax'))

model.compile(optimizer=Adam(lr=0.001), loss='categorical_crossentropy', metrics=['accuracy'])

# 模型训练
train_labels = to_categorical(train_ids, num_classes=num_labels)
val_labels = to_categorical(val_ids, num_classes=num_labels)

model.fit(train_mfccs[:, :, :, np.newaxis], train_labels, epochs=50, batch_size=32, validation_data=(val_mfccs[:, :, :, np.newaxis], val_labels))

# 模型测试
test_labels = to_categorical(test_ids, num_classes=num_labels)
test_pred_probs = model.predict(test_mfccs[:, :, :, np.newaxis])
test_pred = np.argmax(test_pred_probs, axis=1)
test_acc = accuracy_score(test_ids, test_pred)
print('Test accuracy: {:.2f}%'.format(test_acc * 100))

模型训练过程中会输出每个epoch的训练和验证结果,最终会输出测试集的准确率。

示例

以下是一个示例,展示了如何使用训练好的CNN模型来预测一个新音频文件的类别:

import os

# 加载模型
model = keras.models.load_model('food_cnn.h5')

# 预测新样本
audio_file = 'path/to/new/sample.wav'
mfcc = compute_mfcc(audio_file)
max_timesteps = train_mfccs.shape[1]
pad_len = max_timesteps - len(mfcc)
if pad_len > 0:
    pad_mfcc = np.pad(mfcc, ((0, pad_len), (0, 0)), 'constant')
else:
    pad_mfcc = mfcc[:max_timesteps, :]
pred_probs = model.predict(pad_mfcc[np.newaxis, :, :, np.newaxis])
pred_label = labels[np.argmax(pred_probs)]
print('Predicted label:', pred_label)

这段代码会输出预测结果。