用于音视频分类的递归神经网络


图片由作者提供

使用tensorflow进行分类的深度学习入门教程

递归神经网络

RNN或递归神经网络是一种可以记住序列的深度学习算法。

那需要记住哪些序列呢?

  • 手写/语音识别
  • 时间序列
  • 用于自然语言处理的文本
  • 依赖 之前 项目的序列

这些序列是否相当于音频?

是的。 除非音频是一个随机的垃圾流(不是波段),否则音频信息往往都遵循一个模式。

请看以下贝多芬《月光奏鸣曲》的前两节。

图片由作者提供

这么多的重复! 你认为贝多芬在双耳失聪后是如何继续写音乐的? 其实靠得是模式识别和记忆,但他依旧是个天才。

本文介绍了如何根据音视频信息训练RNN来对声音进行分类

以下示例的数据来自Kaggle竞赛中雨林连通物种音频检测的鸟类和青蛙录音。它们是不是很可爱呢?


图片由作者提供

首先,加载必要的导入:

import pandas as pd
import os
import librosa
import librosa.display
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import normalize
import warnings
warnings.filterwarnings('ignore')
from sklearn.model_selection import train_test_split
import tensorflow
from tensorflow.keras.layers import LSTM, Dense

然后开发数据框架:

os.chdir('/kaggle/input/rfcx-species-audio-detection')
df = pd.read_csv('train_tp.csv')

该数据集以csv文件的形式出现,其音频文件的名称列在recording_id下,标签列在species_id下,而音频样本的开始/结束时间列在t_min和t_max下。

df.head()

1_G5MAywdb5jDLlVYmEDhjFA

使用librosa包来加载和显示音频文件,如下所示:

sample_num=3 #pick a file to display
filename=df.recording_id[sample_num]+str('.flac') #get the filename
#define the beginning time of the signal
tstart = df.t_min[sample_num] 
tend = df.t_max[sample_num] #define the end time of the signal
y,sr=librosa.load('train/'+str(filename))
librosa.display.waveplot(y,sr=sr, x_axis='time', color='purple',offset=0.0)

1_zpvqkhMiT0iq1ZDu0fMRpA

创建模型的特点

Librosa此处提供了有关如何提取音频特征的教程。对于RNN,我发现最大的特点是使用梅尔频率倒谱系数(MFCC),它是声音的频谱特点。你可以像以下这样计算:

hop_length = 512 #the default spacing between frames
n_fft = 255 #number of samples 
#cut the sample to the relevant times
y_cut=y[int(round(tstart*sr)):int(round(tend*sr))]
MFCCs = librosa.feature.mfcc(y_cut, n_fft=n_fft,hop_length=hop_length,n_mfcc=128)
fig, ax = plt.subplots(figsize=(20,7))
librosa.display.specshow(MFCCs,sr=sr, cmap='cool',hop_length=hop_length)
ax.set_xlabel('Time', fontsize=15)
ax.set_title('MFCC', size=20)
plt.colorbar()
plt.show()

提取所有文件中的特点和标签并将其存储在numpy数组中:

def get_features(df_in):
    features=[] #list to save features
    labels=[] #list to save labels
    for index in range(0,len(df_in)):
      #get the filename        
      filename = df_in.iloc[index]['recording_id']+str('.flac') 
      #cut to start of signal     
      tstart = df_in.iloc[index]['t_min'] 
      #cut to end of signal
      tend = df_in.iloc[index]['t_max'] 
      #save labels
      species_id = df_in.iloc[index]['species_id'] 
      #load the file        
      y, sr = librosa.load('train/'+filename,sr=28000)
      #cut the file from tstart to tend 
      y_cut = y[round(tstart*sr,ndigits=None)
         :round(tend*sr, ndigits= None)]
      data = np.array([padding(librosa.feature.mfcc(y_cut, 
         n_fft=n_fft,hop_length=hop_length,n_mfcc=128),1,400)])
      features.append(data)
      labels.append(species_id)
    output=np.concatenate(features,axis=0)
    return(np.array(output), labels)
X,y=get_features(df)

规范数据并将其转换为numpy数组

X = np.array((X-np.min(X))/(np.max(X)-np.min(X)))
X = X/np.std(X)
y = np.array(y)

提取训练、测试并验证数据集

#Split twice to get the validation set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=123, stratify=y)
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=123)
#Print the shapes
X_train.shape, X_test.shape, X_val.shape, len(y_train), len(y_test), len(y_val)

1_Ch9Pw2C8ttq9WMbasN744Q

创建一个RNN

在这个示例中,长短期记忆(LSTM)单元是专门用来进行记忆的, Dropout 随机将一部分数据的权重设置为零,以防止过度拟合,而 Dense 单元包含与模型的自由度相关的隐藏层,以尝试和适应数据。数据越复杂,模型需要的自由度就越多,同时要注意避免过度拟合(后面会详细介绍)。最后一个 Dense 层输出24种声音,然后这些音频被记录分类。

RNN模型架构样本

1_LZUF32AYHYXIL1WBuyAneg
图片由作者提供

在tensorflow中,你可以像以下这样创建上面提到的RNN模型:

input_shape=(128,1000)
model = keras.Sequential()
model.add(LSTM(128,input_shape=input_shape))
model.add(Dropout(0.2))
model.add(Dense(128, activation='relu'))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(48, activation='relu'))
model.add(Dropout(0.4))
model.add(Dense(24, activation='softmax'))
model.summary()

激活 功能将非线性特征添加到模型中。此处使用了 relu 函数,该函数将负权重归零。最后一个 Dense 层的激活函数是 softmax ,它为每个类输出一个概率。此外,Tensorflow还有其他激活功能,你可以点击此处进行阅读。

输入形状可能 会引起混乱,因为它看起来是 2D ,实际上却是 3D的 。由于是在创建它们时选择的参数,导致这些MFCC的形状恰巧是高度为128,长度为1000,并且它们与音频文件一样大。如果仅提取dataframe.head()图中所示的5个音频文件的功能,则输入的形状将为5x128x1000,我们把这个参数称为 批处理大小 ,它不包含在输入形状中。

编译模型

model.compile(optimizer='adam',loss='SparseCategoricalCrossentropy',metrics=['acc'])

Adam 优化管理随机梯度下降的学习率,这是一个很好的开始。 损失 函数是 SparseCategoricalCrossentropy ,它在每个样品只属于一个标签.), 并且 它不是二元分类时才能被使用。这适用于每个音频样本都属于一个声音类别的情况。

拟合模型

history = model.fit(X_train, y_train, epochs=50, batch_size=72, 
                    validation_data=(X_val, y_val), shuffle=False)

关于过度拟合的讲解

1_CaTopUam7cFRGRc84LDjmw
图片由作者提供

但是你 必须 暂时 进行过度拟合的操作,以了解过度拟合和欠拟合之间的界限(F.Chollet,2018)。

从最简单的模型开始,然后逐步推进

试试这个:

input_shape=(128,1000)
model = tensorflow.keras.Sequential()
model.add(LSTM(NUM,input_shape=input_shape))
model.add(Dense(24, activation='softmax'))
model.summary()

(其中 NUM 比输出图层大一些),需不断添加图层直到模型开始过度拟合数据为止。

什么时候发生过拟合呢?

评估模型训练 验证集

1.如果训练和测试集之间的性能不同(例如,训练精度为99%,测试为89%),则说明数据过拟合。

2.当所选择的验证措施(精度在这种情况下)开始减小,停止迭代。在下图中,这大约发生了50个纪元。

#Adapted from Deep Learning with Python by Francois Chollet, 2018
history_dict=history.history
loss_values=history_dict['loss']
acc_values=history_dict['acc']
val_loss_values = history_dict['val_loss']
val_acc_values=history_dict['val_acc']
epochs=range(1,51)
fig,(ax1,ax2)=plt.subplots(1,2,figsize=(15,5))
ax1.plot(epochs,loss_values,'co',label='Training Loss')
ax1.plot(epochs,val_loss_values,'m', label='Validation Loss')
ax1.set_title('Training and validation loss')
ax1.set_xlabel('Epochs')
ax1.set_ylabel('Loss')
ax1.legend()
ax2.plot(epochs,acc_values,'co', label='Training accuracy')
ax2.plot(epochs,val_acc_values,'m',label='Validation accuracy')
ax2.set_title('Training and validation accuracy')
ax2.set_xlabel('Epochs')
ax2.set_ylabel('Accuracy')
ax2.legend()
plt.show()

1_BJoosS7Z7yAJaLg67Xvbew

使用混淆矩阵检查模型的预测效果:

如果所有条目都在矩阵的对角线上对齐,则该模型已对测试集做出了完美的预测,而其他东西都已进行误分类。

TrainLoss, Trainacc = model.evaluate(X_train,y_train)
TestLoss, Testacc = model.evaluate(X_test, y_test)
y_pred=model.predict(X_test)
print('Confusion_matrix: ',tf.math.confusion_matrix(y_test, np.argmax(y_pred,axis=1)))

1_Mka80Z27587-JW8EORvysg

到这里就差不多完成了

现在,你就知道如何用音视频数据创建RNN,从一个简单的模型开始,添加图层,直到它能够最大程度地预测数据; 修改架构,直到你的模型开始过度拟合数据以了解该边界的位置,然后返回并删除图层。寻找训练数据与测试数据之间的性能差异,并添加Dropout层以防止过度拟合训练数据。在验证数据中查找衰弱的性能,以了解何时停止迭代。

原文作者 Papia Nandi

原文链接 https://towardsdatascience.com/recurrent-neural-nets-for-audio-classification-81cb62327990

very nice