通用音频分类
- 赛题介绍
- 数据简介
- import的包
- 音频文件读取
- 特征构造
- CNN多分类
- 提取预测结果并写入csv文件
- 改进方向
- 参考文献
博主继续入门了音频分类问题,根据上一个baseline中的改进方向,写了一个基于CNN的baseline,线上分数0.90左右,随便调一下能到0.93
赛题介绍
赛题名:通用音频分类
赛道:训练赛道
背景:随着移动终端的广泛应用以及数据量的不断积累,海量多媒体信息的处理需求日益凸显。作为多媒体信息的重要载体,音频信息处理应用广泛且多样,如自动语音识别、音乐风格识别等。有些声音是独特的,可以立即识别,例如婴儿的笑声或吉他的弹拨声。有些音频背景噪声复杂,很难区分。如果闭上眼睛,您能说出电锯和搅拌机是下面哪种声音?音频分类是音频信息处理领域的一个基本问题,从本质上说,音频分类的性能依赖于音频中的特征提取。传统特征提取算法使用音频特征的统计信息作为分类的依据,使用到的音频特征包括线性预测编码、短时平均能量等。近年来,基于深度学习的音频分类取得了较大进展。基于端到端的特征提取方式,深度学习可以避免繁琐的人工特征设计。音频的多样化给“机器听觉”带来了巨大挑战。如何对音频信息进行有效的分类,从繁芜丛杂的数据集中将具有某种特定形态的音频归属到同一个集合,对于学术研究及工业应用具有重要意义。
任务:基于上述实际需求以及深度学习的进展,本次训练赛旨在构建通用的基于深度学习的自动音频分类系统。通过本赛题建立准确的音频分类模型,希望大家探索更为鲁棒的音频表述方法,以及转移学习、自监督学习等方法在音频分类中的应用。
比赛链接:https://www.datafountain.cn/competitions/486
数据简介
数据整理自网上公开数据集(已脱敏),数据集涵盖5类不同音频,该类数据集广泛应用于音频分类的业务场景。
文件类别
文件名
文件内容
训练集音频文件夹
train
训练数据集音频文件
测试集音频文件夹
test
测试数据集音频文件
字段说明
字段说明.xlsx
训练集/测试集字段的具体说明
提交样例
submission.csv
仅有两个字段file_name\label
对数据的进一步说明:train.zip中包含三十个文件夹,每个文件夹的名称是里面所有音频文件的标签,音频文件的格式是wav格式,时间长度都小于等于1s。test.zip中包含所有测试集的音频文件,一共有6835个。
import的包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
from tqdm import tqdm
from sklearn.preprocessing import LabelEncoder
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2
from sklearn.preprocessing import MinMaxScaler
import lightgbm as lgb
import warnings
from sklearn.model_selection import StratifiedKFold, KFold
from sklearn.metrics import accuracy_score, f1_score, roc_auc_score, log_loss
import time
import os
warnings.filterwarnings('ignore')
import wavio
import librosa
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten,LSTM,TimeDistributed,Bidirectional
from keras.layers import Convolution2D, MaxPooling2D
from keras.utils import to_categorical
from keras.callbacks import LearningRateScheduler
import sklearn
音频文件读取
和之前的baseline一样,音频文件的读取我使用的是os库和librosa库,按顺序读取三十个文件夹,对于每一个文件夹,先读取里面所有的文件名,然后依次用librosa库读取每一个wav文件,具体代码见特征构造章节。
特征构造
baseline选取的特征及其维数如下表所示:
特征名称
特征说明
特征维数
过零率
该特征在语音识别和音乐信息检索中都被大量的使用,对于高冲击声,它通常具有更高的值
(1,44)
光谱质心
它指示声音的“质心”位于何处,并计算为声音中存在的频率的加权平均值
(1,44)
梅尔频率倒谱系数
它是一小组特征(通常10-40),其简明地描述了频谱包络的整体形状
(40,44)
色度频谱
它是音乐音频的一种强大表示,其中整个频谱被投影到12个区间,代表音乐八度音的12个不同的半音(或色度)
(12,44)
谱对比度
详细内容参考文献1
(7,44)
频谱带宽
详细内容参考文献 2
(1,44)
tonnetz
详细内容参考文献3
(6,44)
和之前的baseline不同,我们没有对特征取平均值,因为我们这次使用的是CNN,可以通过卷积提取特征。
所有的特征均可以用librosa自带的函数来计算,具体的音频文件读取和特征提取代码如下,注意路径要根据自己的情况进行修改:
三十个文件夹名称
filename_list = ['bed', 'bird', 'cat', 'dog', 'down', 'eight', 'five', 'four', 'go', 'happy', 'house', 'left', 'marvin', 'nine', 'no', 'off', 'on', 'one', 'right', 'seven', 'sheila', 'six', 'stop', 'three', 'tree', 'two', 'up', 'wow', 'yes', 'zero']
训练集
features,labels = np.empty((0,40,44)),np.empty(0)
for i in range(30):
filePath = "D:\\ccf2020\\%s" % filename_list[i]
fl = os.listdir(filePath)
print(len(fl))
for j in range(len(fl)):
wavpath = filePath + '\\' + fl[j]
sig,sr = librosa.load(wavpath)
#不够长度的信号进行补0
x = np.pad(sig,(0,22050-sig.shape[0]),'constant')
#print(x.shape)
#提取信号的mfcc并进行标准化
a = librosa.feature.mfcc(x,sr,n_mfcc=40)
norm_mfccs = sklearn.preprocessing.scale(a,axis=1)
features = np.append(features,norm_mfccs[None],axis=0)
labels = np.append(labels,int(i))
if j < 2:
print(features.shape)
print('*****%s*****'%i)
这里我们只写了mfcc的提取,其他的特征提取可以同之前的baseline中的一样来做,用np.concatenate拼接一下array即可,如下:
features = np.empty((0,28,44))
for i in range(30):
filePath = "D:\\ccf2020\\%s" % filename_list[i]
fl = os.listdir(filePath)
print(len(fl))
for j in range(len(fl)):
wavpath = filePath + '\\' + fl[j]
x,sr = librosa.load(wavpath)
#不够长度的信号进行补0
sig = np.pad(x,(0,22050-x.shape[0]),'constant')
a = librosa.feature.zero_crossing_rate(sig,sr)
b = librosa.feature.spectral_centroid(sig,sr=sr)[0]
a = np.vstack((a,b))
b = librosa.feature.chroma_stft(sig,sr)
a = np.vstack((a,b))
b = librosa.feature.spectral_contrast(sig,sr)
a = np.vstack((a,b))
b = librosa.feature.spectral_bandwidth(sig,sr)
a = np.vstack((a,b))
b = librosa.feature.tonnetz(sig,sr)
a = np.vstack((a,b))
norm_a = sklearn.preprocessing.scale(a,axis=1)
#print(norm_mfccs.shape)
features = np.append(features,norm_a[None],axis=0)
if j < 2:
print(features.shape)
print('*****%s*****'%i)
训练数据是把上述两段代码获得的特征进行拼接,最终维数是(57886,68,44)
ps:因为博主刚开始写的时候只用了mfcc所以没有把所有特征的提取放一块,大家做的时候可以放在一起提取。
测试集
#测试集
X_test = np.empty((0,40,44))
filePath = "D:\\ccf2020\\test"
fl = os.listdir(filePath)
print(len(fl))
for j in range(len(fl)):
wavpath = filePath + '\\' + fl[j]
sig,sr = librosa.load(wavpath)
#不够长度的信号进行补0
x = np.pad(sig,(0,22050-sig.shape[0]),'constant')
#print(x.shape)
#提取信号的mfc并进行标准化
mfcc = librosa.feature.mfcc(x,sr,n_mfcc=40)
norm_mfccs = sklearn.preprocessing.scale(mfcc,axis=1)
X_test = np.append(X_test,norm_mfccs[None],axis=0)
if j < 2:
print(X_test.shape)
另外的特征:
X_test = np.empty((0,28,44))
filePath = "D:\\ccf2020\\test"
fl = os.listdir(filePath)
print(len(fl))
for j in range(len(fl)):
wavpath = filePath + '\\' + fl[j]
x,sr = librosa.load(wavpath)
#不够长度的信号进行补0
sig = np.pad(x,(0,22050-x.shape[0]),'constant')
a = librosa.feature.zero_crossing_rate(sig,sr)
b = librosa.feature.spectral_centroid(sig,sr=sr)[0]
a = np.vstack((a,b))
b = librosa.feature.chroma_stft(sig,sr)
a = np.vstack((a,b))
b = librosa.feature.spectral_contrast(sig,sr)
a = np.vstack((a,b))
b = librosa.feature.spectral_bandwidth(sig,sr)
a = np.vstack((a,b))
b = librosa.feature.tonnetz(sig,sr)
a = np.vstack((a,b))
norm_a = sklearn.preprocessing.scale(a,axis=1)
#print(norm_mfccs.shape)
X_test = np.append(X_test,norm_a[None],axis=0)
if j < 2:
print(X_test.shape)
拼接上述的两个array,最终测试数据的维数是(6835,68,44)
数据的保存和读取这里不再赘述,不会的小伙伴可以看前面的baseline,保存数据可以方便我们进行操作,避免重复跑特征提取的步骤,比如上面我刚开始用的只是mfcc,后来增加特征的时候我就没有重复计算mfcc,只要把增加的特征拼接上去就行。
CNN多分类
CNN是卷积神经网络,入门可以参考网上的各种介绍或者讲深度学习的书籍,它之所以能够处理音频特征是因为音频的特征本质上是多维时序的,CNN可以通过卷积来提取有效的特征,这样就比我们手工构造特征要有效的多了,本文使用tensorflow的keras构造了一个很简单的CNN(其实是五个,五折交叉验证),最后一层用softmax全连接层进行分类。网络的结构和参数有很大的调整空间,这里交给大家自由发挥。
X_test = X_test.reshape(X_test.shape[0],X_test.shape[1],X_test.shape[2],1)
print(X_test.shape)
nfold = 5
kf = KFold(n_splits=nfold, shuffle=True, random_state=2020)
prediction1 = np.zeros((len(X_test),30 ))
i = 0
for train_index, valid_index in kf.split(features, labels):
print("\nFold {}".format(i + 1))
train_x, train_y = features[train_index],labels[train_index]
val_x, val_y = features[valid_index],labels[valid_index]
train_x = train_x.reshape(train_x.shape[0],train_x.shape[1],train_x.shape[2],1)
val_x = val_x.reshape(val_x.shape[0],val_x.shape[1],val_x.shape[2],1)
print(train_x.shape)
print(val_x.shape)
train_y = to_categorical(train_y,30)
val_y = to_categorical(val_y,30)
print(train_y.shape)
print(val_y.shape)
model = Sequential()
model.add(Convolution2D(32, (3, 3), activation='relu',input_shape = train_x.shape[1:]))
model.add(MaxPooling2D((2, 2)))
model.add(Dropout(0.25))
model.add(Convolution2D(32, (3, 3), activation='relu'))
model.add(MaxPooling2D(2, 2))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(30, activation='softmax'))
model.compile(optimizer='Adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.summary(line_length=80)
history = model.fit(train_x, train_y, epochs=35, batch_size=32, validation_data=(val_x, val_y))
y1 = model.predict(X_test)
prediction1 += ((y1)) / nfold
i += 1
预测结果现在以30维的向量的形式存在prediction1中。
提取预测结果并写入csv文件
这一部分是和之前的baseline一样的,但是为了博客的完整性,我依然放在这里。
由于os读取文件夹下的所有文件获得的list是按字母序排序的,而给我们的提交文件中的file_name字段不是字母序排序的,因此我们需要对其进行处理,即改变我们预测结果的顺序使其与提交文件中的顺序相同。另外,还需要选取预测向量中最大的类作为预测结果。
y_pred=[list(x).index(max(x)) for x in prediction1]
sub = pd.read_csv('submission.csv')
cnt = 0
result = [0 for i in range(6835)]
for i in range(6835):
ss = sub.iloc[i]['file_name']
for j in range(6835):
if fl[j] == ss:
result[i] = y_pred[j]
cnt = cnt+1
print(cnt)
result1 = []
for i in range(len(result)):
result1.append(filename_list[result[i]])
print(result1[0:10])
df = pd.DataFrame({
'file_name':sub['file_name'],'label':result1})
now = time.strftime("%Y%m%d_%H%M%S",time.localtime(time.time()))
fname="submit_"+now+r".csv"
df.to_csv(fname, index=False)
改进方向
- 增加有用的专业特征;
- 调整网络结构和参数;
- 试试其他网络;
- 进行数据增强;
- 模型融合等;
参考文献
- Jiang, Dan-Ning, Lie Lu, Hong-Jiang Zhang, Jian-Hua Tao, and Lian-Hong Cai. “Music type classification by spectral contrast feature.” In Multimedia and Expo, 2002. ICME’02. Proceedings. 2002 IEEE International Conference on, vol. 1, pp. 113-116. IEEE, 2002.
- Klapuri, A., & Davy, M. (Eds.). (2007). Signal processing methods for music transcription, chapter 5. Springer Science & Business Media.
- Harte, C., Sandler, M., & Gasser, M. (2006). “Detecting Harmonic Change in Musical Audio.” In Proceedings of the 1st ACM Workshop on Audio and Music Computing Multimedia (pp. 21-26). Santa Barbara, CA, USA: ACM Press. doi:10.1145/1178723.1178727.