大家好,音频分类是机器学习的一种应用,它将不同的声音归入特定的类别。在本项目中,我们在本文中使用了机器学习和深度学习算法,从零开始构建一个完整的音乐流派分类项目。
目录
音乐流派分类简介
与图像处理和其他分类技术相比,音频处理是数据科学中最复杂的任务之一。音乐流派分类就是这样一种应用,它旨在将音频文件归类到它们所属的特定声音类别中。这项应用非常重要,需要自动化来减少人工错误和时间,因为如果我们必须手动对音乐进行分类,就必须在完整的播放过程中聆听每个文件。因此,为了实现这一过程的自动化,我们在本文中使用了机器学习和深度学习算法。
项目概述和方法
简而言之,我们可以将项目问题陈述定义为给定多个音频文件,任务是将每个音频文件归类到某个类别中,例如音频属于迪斯科、嘻哈等。音乐流派分类可以使用不同的方法来构建,其中最常用的 4 种方法如下所示。
我们将使用 K-Nearest Neighbors 算法,因为各种研究证明它是提供良好性能的最佳算法之一,并且到目前为止,组织与优化模型一起在推荐系统中使用该算法作为支持。
K近邻算法 ( KNN) 是一种用于回归和分类的机器学习算法。它也被称为懒惰学习算法。它使用基于距离的方法来找到与新数据相似的K个邻居,以及大多数邻居所在的类别,并将该类别作为输出。现在,让我们准备好系统,进行项目实施。
推荐阅读:机器学习 | KNN, K近邻算法
数据集概述
我们将使用的数据集名为 GTZAN 流派集合数据集,这是一个非常流行的音频集合数据集。它包含大约 1000 个音频文件,属于 10 个不同的类别。每个音频文件的扩展名为 .wav。音频文件所属的类别包括Blues, Hip-hop, classical, pop, Disco, Country, Metal, Jazz, Reggae, 和 Rock.
。你可以在 Kaggle 上找到该数据集,并从此处下载:https://www.kaggle.com/datasets/andradaolteanu/gtzan-dataset-music-genre-classification。
库安装
在加载数据集和构建模型之前,安装一些库非常重要。在上一篇博客中,我们使用了 librosa 来提取特征。现在,我们将使用 Python 语音特征库来提取特征,并尝试不同的方法。此外,为了加载 WAV 格式的数据集,我们将使用 scipy 库,因此我们需要安装这两个库。
!pip install python_speech_features
!pip install scipy
音乐流派分类的实际实现
步骤 1)导入所需的库
前往 Jupyter 笔记本或新创建的 Kaggle 笔记本,首先要进行必要的导入以处理数据。
import numpy as np
import pandas as pd
import scipy.io.wavfile as wav
from python_speech_features import mfcc
from tempfile import TemporaryFile
import os
import math
import pickle
import random
import operator
步骤2)定义一个函数来计算特征向量之间的距离,并找到邻居。
我们知道 KNN 的工作原理是计算距离并找到 K 个邻居。为了实现每个功能,我们将实现不同的函数。首先,我们将实现一个函数,该函数接受训练数据、当前实例和所需的邻居数量。它将计算训练数据中每个点与其他点的距离,然后我们找到所有最近的 K 个邻居并返回所有邻居。为了计算两点之间的距离,我们将在解释一些步骤后实现一个函数,以使项目工作流程简单易懂。
#定义一个函数来获取特征向量之间的距离并找到邻居
def getNeighbors(trainingset, instance, k):
distances = []
for x in range(len(trainingset)):
dist = distance(trainingset[x], instance, k) + distance(instance,trainingset[x],k)
distances.append((trainingset[x][2], dist))
distances.sort(key=operator.itemgetter(1))
neighbors = []
for x in range(k):
neighbors.append(distances[x][0])
return neighbors
步骤3)确定最近邻居的类别
现在我们有一个邻居列表,我们需要找出邻居数量最多的一个类。因此,我们声明一个字典来存储该类及其对应的邻居数量。创建频率图后,我们根据邻居数量对图进行降序排序,并返回第一个类。
# 识别最近邻居的函数
def nearestclass(neighbors):
classVote = {}
for x in range(len(neighbors)):
response = neighbors[x]
if response in classVote:
classVote[response] += 1
else:
classVote[response] = 1
sorter = sorted(classVote.items(), key=operator.itemgetter(1), reverse=True)
return sorter[0][0]
步骤4)模型评估
我们还需要一个评估模型的函数来检查我们构建的算法的准确性和性能。因此,我们将构建一个相当简单的准确度计算器函数,它将正确预测的总数除以预测的总数。
def getAccuracy(testSet, prediction):
correct = 0
for x in range(len(testSet)):
if testSet[x][-1] == prediction[x]:
correct += 1
return 1.0 * correct / len(testSet)
步骤5)特征提取
你可能会想,我们已经实现了模型,现在要从数据中提取特征。由于我们使用了 KNN 分类器,并且只是从头实现了算法,以便让你了解项目的运行方式。到目前为止,我希望你已经对项目的工作原理有了 70% 的了解。现在,我们将加载所有 10 个文件夹(每个文件夹对应一个类别)的数据,并从每个音频文件中提取特征,并将提取的特征以二进制形式保存为 DAT 扩展格式。
梅尔频率倒谱系数
特征提取是从数据中提取重要特征的过程。它包括识别语言数据并避免任何类型的噪声。音频特征分为三类:高级、中级和低级音频特征。
- 中级特征包括节拍级别属性、音高波动模式和 MFCC。
- 低级特征包括能量、零交叉率,这些都是在特征提取期间从音频中提取的统计测量。
因此,为了生成这些特征,我们使用一组特定的步骤,并将其组合在一个名称下,即 MFCC,它有助于提取中级和低级音频特征。下面讨论了 MFCC 在特征提取中的工作步骤。
- 音频文件有一定的长度(时长),以秒或分钟为单位。音高或频率不断变化,因此为了理解这一点,我们首先将音频文件分成大约 20 到 40 毫秒长的小帧。
- 划分成帧后,我们尝试从每帧中识别并提取不同的频率。当我们在如此小的帧中进行划分时,假设每帧划分成一个单一的频率。
- 要消除任何类型的噪声,请对频率进行离散余弦变换 (DCT)。具有工程背景的学生可能了解余弦变换,并在离散数学科目中学习过它。
现在我们无需单独实现所有这些步骤,MFCC 已经为我们提供了所有这些步骤,我们已经从 Python 语音特征库中导入了它们。我们将遍历每个类别文件夹,读取音频文件,提取 MFCC 特征,并使用 pickle 模块将其转储到二进制文件中。我建议在加载大型数据集时始终使用 try-catch 来理解并控制是否发生任何异常。
directory = '../input/gtzan-dataset-music-genre-classification/Data/genres_original'
f = open("mydataset.dat", "wb")
i = 0
for folder in os.listdir(directory):
#print(folder)
i += 1
if i == 11:
break
for file in os.listdir(directory+"/"+folder):
#print(file)
try:
(rate, sig) = wav.read(directory+"/"+folder+"/"+file)
mfcc_feat = mfcc(sig, rate, winlen = 0.020, appendEnergy=False)
covariance = np.cov(np.matrix.transpose(mfcc_feat))
mean_matrix = mfcc_feat.mean(0)
feature = (mean_matrix, covariance, i)
pickle.dump(feature, f)
except Exception as e:
print("Got an exception: ", e, 'in folder: ', folder, ' filename: ', file)
f.close()
步骤6)训练测试分割数据集
现在我们已经从音频文件中提取了特征,该文件以二进制格式转储为我的数据集的文件名。现在我们将实现一个接受文件名并以数据框的形式复制所有数据的函数。之后,基于一定的阈值,我们将数据随机分成训练集和测试集,因为我们希望两组中都混合不同的类型。有不同的方法来进行训练测试分割。在这里,我使用一个随机模块并运行一个循环直到数据集的长度并生成一个介于 0-1 之间的随机小数,如果它小于 66,则在训练测试中添加一行,否则在测试集中添加一行。
dataset = []
def loadDataset(filename, split, trset, teset):
with open('my.dat','rb') as f:
whileTrue:
try:
dataset.append(pickle.load(f))
except EOFError:
f.close()
break
for x in range(len(dataset)):
if random.random() < split:
trset.append(dataset[x])
else:
teset.append(dataset[x])
trainingSet = []
testSet = []
loadDataset('my.dat', 0.68, trainingSet, testSet)
步骤 7)计算两个实例之间的距离
我们必须在顶部实现此函数来计算两点之间的距离,但为了向你解释项目的完整工作流程和算法,我在主要步骤之后解释了支持函数。但你需要在顶部添加该函数。因此,该函数接受两个数据点(X 和 y 坐标)来计算它们之间的实际距离。我们使用 numpy 线性代数包,它提供了标准线性代数的低级实现。因此,我们首先找到两个点的 XX 和 YY 坐标之间的点积以了解实际距离,然后我们提取两个点的结果数组的行列式并得到距离。
def distance(instance1, instance2, k):
distance = 0
mm1 = instance1[0]
cm1 = instance1[1]
mm2 = instance2[0]
cm2 = instance2[1]
distance = np.trace(np.dot(np.linalg.inv(cm2), cm1))
distance += (np.dot(np.dot((mm2-mm1).transpose(), np.linalg.inv(cm2)), mm2-mm1))
distance += np.log(np.linalg.det(cm2)) - np.log(np.linalg.det(cm1))
distance -= k
return distance
步骤 8)训练模型并做出预测
大家期待已久的步骤已经到来:将数据输入 KNN 算法,进行所有预测,并在测试数据集上获得准确率。这一步的代码看起来很长,但实际上非常短,因为我们采用函数式编程的方法,逐步完成,所以只需要调用函数即可。第一步是获取邻居,提取类别,并检查模型的准确率。
# 使用 KNN(K 最近邻)进行预测
# Make the prediction using KNN(K nearest Neighbors)
length = len(testSet)
predictions = []
for x in range(length):
predictions.append(nearestclass(getNeighbors(trainingSet, testSet[x], 5)))
accuracy1 = getAccuracy(testSet, predictions)
print(accuracy1)
步骤 9)使用新的音频文件测试分类器
现在我们已经实现并训练好了模型,是时候检查新数据了,看看我们的模型在预测新音频文件方面有多准确。我们把所有标签(类别)都保存成数字形式,我们需要检查类别名称,因此首先,我们将实现一个字典,其中键是数字标签,值是类别名称。
from collections import defaultdict
results = defaultdict(int)
directory = "../input/gtzan-dataset-music-genre-classification/Data/genres_original"
i = 1
for folder in os.listdir(directory):
results[i] = folder
i += 1
现在我们可以预测一个新的音频文件并为其获取标签,并使用结果字典打印类别的名称。
pred = nearestclass(getNeighbors(dataset, feature, 5))
print(results[pred])
结论
太棒了!如果你完成了这个项目,恭喜你!我们完成了初始设置,并使用 MFCC 从音频文件中提取特征。之后,我们从零开始构建了一个 KNN 分类器,它根据特征找到 K 个最近邻,并将属于特定类别的最大邻居作为输出。我们在该模型上获得了大约 70% 的准确率。让我们总结一下我们在实施这个项目过程中获得的主要经验教训,以及项目未来的发展方向。
- 识别和划分音频不同特征的主要依据是短时间内变化的幅度和频率。
- 我们可以将幅度和频率随时间变化的音频波以波形图的形式进行可视化,并且可以使用 librosa 轻松绘制。
- MFCC 总共提供了 39 个与频率和幅度相关的特征。其中 12 个参数与频率的幅度相关。这意味着它为我们提供了足够的频率通道来分析音频,这也是 MFCC 被广泛用于音频特征提取的原因。
-
MFCC 的关键工作是通过将音频分成帧来去除声音激励(音调信息),使提取的特征独立,根据人类调整声音的响度和频率,并捕捉上下文。