40、音频样本分类案例研究

音频样本分类案例研究

在实际的数据科学工作中,我们经常会遇到需要对音频样本进行分类的任务。本文将详细介绍如何构建一个音频样本分类器,从数据集的构建、数据增强、数据预处理到模型的构建和评估,为你提供一个完整的操作指南。

1. 构建数据集

我们要处理的数据集包含10个类别,总共400个样本,每个类别有40个样本,每个样本时长为5秒。由于录制和标注样本既耗时又昂贵,我们只能使用现有的数据。

我们使用的音频数据集是ESC - 10,它需要从更大的ESC - 50数据集中提取。以下是提取ESC - 10数据集的具体步骤:
1. 从 https://github.com/karoldvl/ESC - 50/ 下载数据集的ZIP文件并解压,会生成一个名为 ESC - 50 - master 的目录。
2. 使用以下代码构建ESC - 10数据集:

import sys
import os
import shutil

classes = {
    "rain": 0,
    "rooster": 1,
    "crying_baby": 2,
    "sea_waves": 3,
    "clock_tick": 4,
    "sneezing": 5,
    "dog": 6,
    "crackling_fire": 7,
    "helicopter": 8,
    "chainsaw": 9,
}

with open("ESC - 50 - master/meta/esc50.csv") as f:
    lines = [i[: - 1] for i in f.readlines()]
    lines = lines[1:]

os.system("rm -rf ESC - 10")
os.system("mkdir ESC - 10")
os.system("mkdir ESC - 10/audio")

meta = []
for line in lines:
    t = line.split(",")
    if (t[-3] == 'True'):
        meta.append("ESC - 10/audio/%s %d" % (t[0], classes[t[3]]))
        src = "ESC - 50 - master/audio/" + t[0]
        dst = "ESC - 10/audio/" + t[0]
        shutil.copy(src, dst)

with open("ESC - 10/filelist.txt", "w") as f:
    for m in meta:
        f.write(m + "\n")

运行上述代码后,我们将得到400个时长为5秒的.wav文件,每个类别有40个文件。

2. 数据增强

由于数据集较小,我们需要进行数据增强来扩充数据。数据增强的目标是创建可能来自数据集中类别的新数据样本。对于音频数据,我们可以采用以下四种方法进行增强:
- 时间移位 :类似于将图像左右移动几个像素,我们可以对音频样本进行时间上的移位。
- 添加噪声 :通过向音频信号中添加少量随机噪声来模拟嘈杂环境。
- 音高移位 :使音频的音高升高或降低一定的量。
- 时间伸缩 :延长或压缩音频的时间。

为了方便实现这些增强操作,我们需要安装 librosa 库,使用以下命令进行安装:

sudo pip3 install librosa

以下是增强ESC - 10数据集的代码:

import os
import random
import numpy as np
from scipy.io.wavfile import read, write
import librosa as rosa

N = 8
os.system("rm -rf augmented; mkdir augmented")
os.system("mkdir augmented/train augmented/test")

src_list = [i[: - 1] for i in open("ESC - 10/filelist.txt")]
z = [[] for i in range(10)]
for s in src_list:
    _, c = s.split()
    z[int(c)].append(s)

train = []
test = []
for i in range(10):
    p = z[i]
    random.shuffle(p)
    test += p[:8]
    train += p[8:]

random.shuffle(train)
random.shuffle(test)

def augment_audio(src_list, typ):
    flist = []
    for i, s in enumerate(src_list):
        f, c = s.split()
        wav = read(f)  # (sample rate, data)
        base = os.path.abspath("augmented/%s/%s" % (typ, os.path.basename(f)[: - 4]))
        fname = base + ".wav"
        write(fname, wav[0], wav[1])
        flist.append("%s %s" % (fname, c))
        for j in range(19):
            d = augment(wav)
            fname = base + ("_%04d.wav" % j)
            write(fname, wav[0], d.astype(wav[1].dtype))
            flist.append("%s %s" % (fname, c))
    random.shuffle(flist)
    with open("augmented_%s_filelist.txt" % typ, "w") as f:
        for z in flist:
            f.write("%s\n" % z)

def augment(wav):
    sr = wav[0]
    d = wav[1].astype("float32")
    if (random.random() < 0.5):
        s = int(sr / 4.0 * (np.random.random() - 0.5))
        d = np.roll(d, s)
        if (s < 0):
            d[s:] = 0
        else:
            d[:s] = 0
    if (random.random() < 0.5):
        d += 0.1 * (d.max() - d.min()) * np.random.random(d.shape[0])
    if (random.random() < 0.5):
        pf = 20.0 * (np.random.random() - 0.5)
        d = rosa.effects.pitch_shift(d, sr, pf)
    if (random.random() < 0.5):
        rate = 1.0 + (np.random.random() - 0.5)
        d = rosa.effects.time_stretch(d, rate)
        if (d.shape[0] > wav[1].shape[0]):
            d = d[:wav[1].shape[0]]
        else:
            w = np.zeros(wav[1].shape[0], dtype="float32")
            w[:d.shape[0]] = d
            d = w.copy()
    return d

augment_audio(train, "train")
augment_audio(test, "test")

运行上述代码后,会创建一个新的增强数据目录,包含 train test 子目录,增强后的数据集将是原来的20倍,总共8000个声音文件,其中6400个用于训练,1600个用于测试。

3. 数据预处理

在构建模型之前,我们需要对原始数据进行预处理,将其转换为可以输入到模型中的形式。原始音频样本是长度为220500(44100×5)的向量,这个长度对于我们的处理来说过长。因此,我们可以只保留每个音频文件的前两秒,并每隔100个样本取一个,这样每个音频文件就变成了一个长度为882的向量。

以下是构建预处理后数据集的代码:

import os
import random
import numpy as np
from scipy.io.wavfile import read

sr = 44100  # Hz
N = 2 * sr
w = 100

afiles = [i[: - 1] for i in open("augmented_train_filelist.txt")]
trn = np.zeros((len(afiles), N // w, 1), dtype="int16")
lbl = np.zeros(len(afiles), dtype="uint8")
for i, t in enumerate(afiles):
    f, c = t.split()
    trn[i, :, 0] = read(f)[1][:N:w]
    lbl[i] = int(c)
np.save("esc10_raw_train_audio.npy", trn)
np.save("esc10_raw_train_labels.npy", lbl)

afiles = [i[: - 1] for i in open("augmented_test_filelist.txt")]
tst = np.zeros((len(afiles), N // w, 1), dtype="int16")
lbl = np.zeros(len(afiles), dtype="uint8")
for i, t in enumerate(afiles):
    f, c = t.split()
    tst[i, :, 0] = read(f)[1][:N:w]
    lbl[i] = int(c)
np.save("esc10_raw_test_audio.npy", tst)
np.save("esc10_raw_test_labels.npy", lbl)

运行上述代码后,我们将得到训练集和测试集的NumPy文件,包含处理后的特征向量和对应的标签。

4. 音频特征分类

我们已经准备好了训练集和测试集,接下来可以构建一些模型并评估它们的性能。由于我们有特征向量,我们可以先从经典模型开始,然后尝试构建一维卷积神经网络,看看是否能提高性能。

4.1 使用经典模型

我们可以使用之前在处理乳腺癌数据集时使用过的经典模型,以下是设置代码:

import numpy as np
from sklearn.neighbors import NearestCentroid
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import LinearSVC

x_train = np.load("esc10_raw_train_audio.npy")[:, :, 0]
y_train = np.load("esc10_raw_train_labels.npy")
x_test = np.load("esc10_raw_test_audio.npy")[:, :, 0]
y_test = np.load("esc10_raw_test_labels.npy")

x_train = (x_train.astype('float32') + 32768) / 65536
x_test = (x_test.astype('float32') + 32768) / 65536

def run(x_train, y_train, x_test, y_test, clf):
    clf.fit(x_train, y_train)
    score = 100.0 * clf.score(x_test, y_test)
    print("score = %0.2f%%" % score)

def train(x_train, y_train, x_test, y_test):
    print("Nearest Centroid : ", end='')
    run(x_train, y_train, x_test, y_test, NearestCentroid())
    print("k - NN classifier (k = 3) : ", end='')
    run(x_train, y_train, x_test, y_test, KNeighborsClassifier(n_neighbors = 3))
    print("k - NN classifier (k = 7) : ", end='')
    run(x_train, y_train, x_test, y_test, KNeighborsClassifier(n_neighbors = 7))
    print("Naive Bayes (Gaussian) : ", end='')
    run(x_train, y_train, x_test, y_test, GaussianNB())
    print("Random Forest (trees = 5) : ", end='')
    run(x_train, y_train, x_test, y_test, RandomForestClassifier(n_estimators = 5))
    print("Random Forest (trees = 50) : ", end='')
    run(x_train, y_train, x_test, y_test, RandomForestClassifier(n_estimators = 50))
    print("Random Forest (trees = 500) : ", end='')
    run(x_train, y_train, x_test, y_test, RandomForestClassifier(n_estimators = 500))
    print("Random Forest (trees = 1000) : ", end='')
    run(x_train, y_train, x_test, y_test, RandomForestClassifier(n_estimators = 1000))
    print("LinearSVM (C = 0.01) : ", end='')
    run(x_train, y_train, x_test, y_test, LinearSVC(C = 0.01))
    print("LinearSVM (C = 0.1) : ", end='')
    run(x_train, y_train, x_test, y_test, LinearSVC(C = 0.1))
    print("LinearSVM (C = 1.0) : ", end='')
    run(x_train, y_train, x_test, y_test, LinearSVC(C = 1.0))
    print("LinearSVM (C = 10.0) : ", end='')
    run(x_train, y_train, x_test, y_test, LinearSVC(C = 10.0))

train(x_train, y_train, x_test, y_test)

运行上述代码后,我们可以得到各个经典模型的分类准确率,结果如下表所示:
| 模型名称 | 准确率 |
| ---- | ---- |
| Nearest Centroid | 11.9% |
| k - NN classifier (k = 3) | 12.1% |
| k - NN classifier (k = 7) | 10.5% |
| Naive Bayes (Gaussian) | 28.1% |
| Random Forest (trees = 5) | 22.6% |
| Random Forest (trees = 50) | 30.8% |
| Random Forest (trees = 500) | 32.8% |
| Random Forest (trees = 1000) | 34.4% |
| LinearSVM (C = 0.01) | 16.5% |
| LinearSVM (C = 0.1) | 17.5% |
| LinearSVM (C = 1.0) | 13.4% |
| LinearSVM (C = 10.0) | 10.2% |

从结果可以看出,经典模型的性能普遍较差,很多模型几乎是在随机猜测类别标签。其中表现最好的是具有1000棵树的随机森林模型,但准确率也只有34.4%,远低于我们在大多数情况下可以接受的水平。最近质心、k - NN和线性SVM模型的表现最差,这可能是因为输入的维度较高(882个元素),而训练集中的样本数量相对较少(6400个),导致特征空间过于稀疏,最近邻分类器难以有效利用。

以下是整个流程的mermaid流程图:

graph TD;
    A[构建数据集] --> B[数据增强];
    B --> C[数据预处理];
    C --> D[音频特征分类];
    D --> E[使用经典模型];

通过以上步骤,我们完成了一个音频样本分类器的构建过程,从数据集的准备到模型的评估,每个环节都至关重要。在实际应用中,我们可以根据具体情况对模型进行进一步的优化和改进。

音频样本分类案例研究

5. 使用一维卷积神经网络

由于经典模型的表现不佳,我们可以尝试使用一维卷积神经网络(1D CNN)来提高音频分类的性能。一维卷积神经网络在处理序列数据(如音频信号)方面具有很好的效果。

以下是使用Keras构建一维卷积神经网络的示例代码:

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense
from tensorflow.keras.utils import to_categorical

# 加载数据
x_train = np.load("esc10_raw_train_audio.npy")
y_train = np.load("esc10_raw_train_labels.npy")
x_test = np.load("esc10_raw_test_audio.npy")
y_test = np.load("esc10_raw_test_labels.npy")

# 数据预处理
x_train = (x_train.astype('float32') + 32768) / 65536
x_test = (x_test.astype('float32') + 32768) / 65536

y_train = to_categorical(y_train, 10)
y_test = to_categorical(y_test, 10)

# 构建模型
model = Sequential()
model.add(Conv1D(filters=32, kernel_size=3, activation='relu', input_shape=(882, 1)))
model.add(MaxPooling1D(pool_size=2))
model.add(Conv1D(filters=64, kernel_size=3, activation='relu'))
model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(10, activation='softmax'))

# 编译模型
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

# 训练模型
model.fit(x_train, y_train, epochs=10, batch_size=32, validation_data=(x_test, y_test))

# 评估模型
loss, accuracy = model.evaluate(x_test, y_test)
print(f"Test loss: {loss}, Test accuracy: {accuracy}")

在上述代码中,我们首先加载并预处理了训练集和测试集数据。然后,我们使用Keras构建了一个简单的一维卷积神经网络,包含两个卷积层、两个池化层、一个全连接层和一个输出层。接着,我们编译模型并使用训练数据进行训练。最后,我们使用测试数据评估模型的性能。

6. 模型集成

为了进一步提高模型的性能,我们可以尝试将多个模型进行集成。模型集成是指将多个不同的模型组合在一起,利用它们的相对优势来提高整体性能。

以下是一个简单的模型集成示例,我们将之前的随机森林模型和一维卷积神经网络模型进行集成:

from sklearn.ensemble import RandomForestClassifier
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv1D, MaxPooling1D, Flatten, Dense
from tensorflow.keras.utils import to_categorical

# 加载数据
x_train = np.load("esc10_raw_train_audio.npy")[:, :, 0]
y_train = np.load("esc10_raw_train_labels.npy")
x_test = np.load("esc10_raw_test_audio.npy")[:, :, 0]
y_test = np.load("esc10_raw_test_labels.npy")

# 随机森林模型
rf = RandomForestClassifier(n_estimators=1000)
rf.fit(x_train, y_train)
rf_pred = rf.predict(x_test)

# 一维卷积神经网络模型
x_train_cnn = np.load("esc10_raw_train_audio.npy")
y_train_cnn = np.load("esc10_raw_train_labels.npy")
x_test_cnn = np.load("esc10_raw_test_audio.npy")
y_test_cnn = np.load("esc10_raw_test_labels.npy")

x_train_cnn = (x_train_cnn.astype('float32') + 32768) / 65536
x_test_cnn = (x_test_cnn.astype('float32') + 32768) / 65536

y_train_cnn = to_categorical(y_train_cnn, 10)
y_test_cnn = to_categorical(y_test_cnn, 10)

model = Sequential()
model.add(Conv1D(filters=32, kernel_size=3, activation='relu', input_shape=(882, 1)))
model.add(MaxPooling1D(pool_size=2))
model.add(Conv1D(filters=64, kernel_size=3, activation='relu'))
model.add(MaxPooling1D(pool_size=2))
model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(Dense(10, activation='softmax'))

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train_cnn, y_train_cnn, epochs=10, batch_size=32, validation_data=(x_test_cnn, y_test_cnn))

cnn_pred_probs = model.predict(x_test_cnn)
cnn_pred = np.argmax(cnn_pred_probs, axis=1)

# 模型集成
ensemble_pred = []
for i in range(len(x_test)):
    if rf_pred[i] == cnn_pred[i]:
        ensemble_pred.append(rf_pred[i])
    else:
        # 这里可以根据实际情况进行更复杂的决策,例如根据模型的置信度
        ensemble_pred.append(rf_pred[i])

ensemble_pred = np.array(ensemble_pred)
accuracy = np.mean(ensemble_pred == y_test)
print(f"Ensemble accuracy: {accuracy}")

在上述代码中,我们首先训练了一个随机森林模型和一个一维卷积神经网络模型。然后,我们分别使用这两个模型对测试数据进行预测。最后,我们将两个模型的预测结果进行集成,简单地采用了多数表决的方法(当两个模型预测结果相同时采用该结果,不同时暂时采用随机森林的预测结果)。

7. 总结与展望

通过以上的实验,我们可以得出以下结论:
- 经典模型在处理音频分类任务时表现不佳,尤其是在高维输入和相对较少的训练样本情况下,容易受到维度诅咒的影响。
- 一维卷积神经网络在处理音频数据方面具有一定的优势,能够自动提取音频信号中的特征,从而提高分类性能。
- 模型集成可以进一步提高模型的性能,通过结合不同模型的优势,减少单个模型的局限性。

在未来的工作中,我们可以从以下几个方面进行改进和优化:
- 数据方面 :尝试获取更多的音频数据,或者采用更复杂的数据增强方法,进一步扩充数据集,提高模型的泛化能力。
- 模型方面 :探索更复杂的神经网络架构,如二维卷积神经网络(将音频数据转换为图像)、循环神经网络(处理序列数据的能力更强)等。
- 集成方法方面 :研究更复杂的模型集成策略,如加权投票、堆叠等,充分发挥不同模型的优势。

以下是整个音频样本分类流程的详细mermaid流程图:

graph TD;
    A[构建数据集] --> B[数据增强];
    B --> C[数据预处理];
    C --> D[音频特征分类];
    D --> E[使用经典模型];
    D --> F[使用一维卷积神经网络];
    E --> G[模型集成];
    F --> G[模型集成];

通过不断地探索和实践,我们有望构建出性能更优的音频样本分类器,应用于各种实际场景中,如语音识别、环境声音监测等。

【四轴飞行器】非线性三自由度四轴飞行器模拟器研究(Matlab代码实现)内容概要:本文围绕非线性三自由度四轴飞行器的建模与仿真展开,重点介绍了基于Matlab的飞行器动力学模型构建与控制系统设计方法。通过对四轴飞行器非线性运动方程的推导,建立其在三维空间中的姿态与位置动态模型,并采用数值仿真手段实现飞行器在复杂环境下的行为模拟。文中详细阐述了系统状态方程的构建、控制输入设计以及仿真参数设置,并结合具体代码实现展示了如何对飞行器进行稳定控制与轨迹跟踪。此外,文章还提到了多种优化与控制策略的应用背景,如模型预测控制、PID控制等,突出了Matlab工具在无人机系统仿真中的强大功能。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的高校学生、科研人员及从事无人机系统开发的工程师;尤其适合从事飞行器建模、控制算法研究及相关领域研究的专业人士。; 使用场景及目标:①用于四轴飞行器非线性动力学建模的教学与科研实践;②为无人机控制系统设计(如姿态控制、轨迹跟踪)提供仿真验证平台;③支持高级控制算法(如MPC、LQR、PID)的研究与对比分析; 阅读建议:建议读者结合文中提到的Matlab代码与仿真模型,动手实践飞行器建模与控制流程,重点关注动力学方程的实现与控制器参数调优,同时可拓展至多自由度或复杂环境下的飞行仿真研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值