一篇小论文:VGGish-BiGRU网络

github:在这里(含代码和论文)

目录

一.mel_features.py(定义从音频波形计算mel谱图特征的例程)

二.vggish_params.py(VGGish模型的全局参数)

三.vggish_input.py(从音频波形计算VGGish输入示例)

四.整个程序的流程

一.mel_features.py(定义从音频波形计算mel谱图特征的例程)

其中包含了几个类

1.def frame(data, window_length, hop_length)类:

        将数组转换为连续的可能重叠的帧序列

        输入:维度>=1的数组data

                   每帧中的样本数window_length

                   在每个窗口之间前进(以样本为单位)

        输出:输出为n+1-D维的数组,有多少完整的帧就有多少行提取。

2.def periodic_hann(window_length)类:

        计算一个“周期性”海宁窗(与汉明窗地位相同)

        输入:返回窗口中的点数window_length

        输出:包含周期性通道窗口的1维数组

3.def stft_magnitude(signal, fft_length,hop_length=None,window_length=None)类:

        计算短时傅里叶变化的幅度

        输入:输入时域信号的1维信号signal
                   要应用的fft的大小fft_length
                   传递到FFT的每一帧之间的推进(以样本为单位)hop_length
                   要传递给FFT的每个样本块的长度window_length

        输出:输出2维数组,其中每一行包含对应输入样本帧的fft_length/2+1唯一值的幅度(abs)

4.def hertz_to_mel(frequencies_hertz)类:

        使用HTK公式将频率转换为mel标度。

        输入:以hz为单位的标量 or 频率数组frequencies_hertz

        输出:与包含mel刻度上的相应值frequencies_hertz大小相同的对象

5.def spectrogram_to_mel_matrix(num_mel_bins=20,
                              num_spectrogram_bins=129,
                              audio_sample_rate=8000,
                              lower_edge_hertz=125.0,
                              upper_edge_hertz=3800.0)类:

        返回一个矩阵,该矩阵可以对谱图行进行后乘,进而生成mel

        输入:num_mel_bins:结果mel光谱中有多少个波段。这是 输出矩阵中的列数。

                   num_spectrogram_bins:源频谱图中有多少个bin 数据,理解为fft_size/2 + 1,即频谱                                                            图仅包含非冗余FFT仓。

                   audio_sample_rate:输入端每秒的音频样本数声谱图。我们需要这个来计算出每个声                                                              谱图箱,指示它们如何映射到mel。

                   lower_edge_hertz:mel中包含的频率的下限光谱。这对应于最低三角形的下边缘带       

                   upper_edge_hertz:最高频段的期望顶部边缘

        输出:一个含有(num_spectrogram_bins,num_mel_bins)的数组

6.def log_mel_spectrogram(data,
                        audio_sample_rate=8000,
                        log_offset=0.0,
                        window_length_secs=0.025,
                        hop_length_secs=0.010,
                        **kwargs):

        将波形转换成对数幅度梅尔频谱图

        输入:一维波形数据数组data

                   数据的采样率:audio_sample_rate

                   在取log时将它添加到值中:log_offset

                   每个分析窗口的持续时间:window_length_secs

                   在连续的分析窗口之间前进hop_length_secs

                   传递给spectrogram_to_mel_matrix的附加参数**kwargs:

        输出: 由对数mel滤波器组组成的2维数组(num_frames,num_mel_bins)

二.vggish_params.py(VGGish模型的全局参数)

三.vggish_input.py(从音频波形计算VGGish输入示例)

        将 一 和 二 都导入到 三 中(import mel_features,import vggish_params)

用到了几个类:

1.def wav_read(wav_file):

        将原始音频文件读取,以NumPy数组的形式提供声音文件中的音频数据

        输入:指定的音频文件wav_file,同时指定wav_file为int16类型以方便wav_data的写入(即wav_data是int16的)

        输出:音频数据wav_data 以及 数据采样率(sample_rate)sr

2.def waveform_to_examples(data, sample_rate):

        将音频波形转换为VGGish的示例数组(按VGGish假定的速率重新采样)

        输入:Numpy类型的数组data,采样率sample_rate

        流程:

                samples=data为一维数组

                (一)if 当len(data.shape)>1(实测为2,好像就是维度哎)时,执行按axis=1(第二个维度)取平均(原数值是有+和-的可抵消)生成1行多列(1行*音频个数)(其实每个音频的采样点数被压缩成一个数值了)  由于为1维数组,所以这步骤没执行

                        此时:data为1行多列(1行*音频个数列)的一维数组

                (二)if 采样速率更改为设定值,使用resampy.resample()函数,将原速率改为参数设定的速率,并且数组中值有对应的变换

                关于resample()函数的官方文档:(可以看出采样率改变,数值也会随着改变)                  

>>> sr_orig = 44100.0
>>> x = np.sin(2 * np.pi * 440.0 / sr_orig * np.arange(5 * sr_orig))
>>> x
array([ 0.   ,  0.063, ..., -0.125, -0.063])
>>> # Resample to 22050 with default parameters
>>> resampy.resample(x, sr_orig, 22050)
array([ 0.011,  0.123, ..., -0.193, -0.103])

                        此时:data为行多列的一维数组,并且data.shape=(320000,)但是里面的数值改变

                (三)使用mel_features中的log_mel_spectrogram()函数求log_mel

                关于log_mel_spectrogram()函数:

                        1.窗口处的长度的采样率=音频采样率*窗口持续的时间

                        2.两个连续窗口前进的采样率=音频采样率*两个连续窗口前进持续的时间

                        3.快速傅里叶变换的持续长度=2的int{【[log向上取整(窗口处的长度的采样率)/log(2)]】}次幂

                        4.stft_magnitude()函数:.shape=(1998,257)

                        5.dot()内积函数:.shape=(1998,64)

                        6.将上一步取对数log

                         此时:log_mel为  1998行*64列  的二维数组

                (四).求log_mel_examples

                        此时:log_mel_examples   .shape=(20,96,64)

                则:ex.shape==(20,96,64),可以理解为有20个96*64的矩阵 

        输出:三维的log_mel_examples

3.def wavfile_to_examples(wav_file):

        一个通用WAV格式的waveform_to_examples()包装器

        输入:指定的音频文件wav_file,文件假定包含带符号16位(程序设)PCM样本的WAV音频数据

        流程:

                        a.看到第一行为wav_read(),跳转到它:它的执行如 三.1所示,输出wav_data(检验为二维数组(音频个数*采样点数))和sr

                        b.有一个判断:wav_data的dtype是不是int16的,否则输出“这是错误的样本类型”

                        c.wav_data中的数据wave_data除以32768.0==samples,归到[-1.0,+1.0]之间

        输出:waveform_to_examples(samples, sr)

四.整个程序的流程

在执行程序的时候,先执行RNN.ipynb

由于.ipynb文件中的程序是分模块的,因为我们分模块进行梳理

模块1:

        sstep1:

                import glob,numpy,vggish_input(其中,vggish_input里已经导入了mel_features和vggish_params)

        sstep2:

                glob.glob遍历所有的音频文件f(仅两类:healthy和copd,二者的代码段相同),下边以healthy举例子。

        sstep3:调用vggish_input中的wavfile_to_examples(f)

                Step1 进入wavfile_to_examples()类查看,输出为waveform_to_examples(samples, sr)

                Step2 进入waveform_to_examples()类查看

        sstep4:

                则结果:ex.shape==(20,96,64),可以理解为有20个96*64的矩阵 

        sstep5:

        对于health录音:

                Step1 ex[10:]是第11个到第20个矩阵

                           np.reshape():将ex[10:]   改为   (10,96,64,1)的形状shape(一个整体)

                           append():添加到all_examples

                Step2 ex[-10:]是第11个到第20个矩阵(结果与ex[10:]一样)

                          np.reshape():将ex[-10:]   改为   (10,96,64,1)的形状shape(一个整体)

                          append():添加到all_examples

                Step3 而healthy共有35个录音,则有70个整体

        sstep6: 

                而copd也存在着35个录音,同理则也有70个整体。因此all_examples中有140个整体

        sstep7:

                        将all_examples从list改为array: 其.shape==(140,10,96,64,1)

                        healthy_labels是70个[1,0]

                        copd_labels是70个[0,1]

                        all_labels是先70行[1,0],再接着70行[0,1],因此.shape==(140,2)

                        总结:all_examples.shape==(140,10,96,64,1),all_labels.shape==(140,2)

模块2     

        sstep1:

                labeled_examples是一个140行,2列的list(因为从len[0]到len[139]都是2,并且len[140]超范围了。也可以根据zip()函数分析出来)

                其中list中的第一列中的一个数据的.shape==(10,96,64,1)——>这个是呼吸音数据

                其中list中的第二列中的一个数据的.shape==(2,)——>这个是标签(可能是[1,0]代表health,[0,1]代表copd)

        sstep2:

                shuffle(labeled_examples)是将list按照行(每行里边的值即列不洗牌)进行洗牌

                一个小例子可说明:

                ​​​​​​

        sstep3:

                features是洗牌后的list中的第一列数据(即呼吸音特征)整合在一起 .shape()==(10,96,64,1)

                labels是洗牌后的list中的第二列数据(即标签)整合在一起.shape==(2,)

模块3vggish的网络结构)

        输入为input_shape=(96,64,1)        

        Block1:(一)Conv2D中,64为filters的个数,(3,3)为filters的大小,padding=same为扩充

                          此时输出output.shape==(96,64,64)

                    (二)MaxPooling2D

                          此时输出output.shape==(48,32,64)       

        Block2,Block3,Block4中的函数都没变,都是同理的

                          此时输出output.shape==(6,4,512)

        FC block:(一)Flatten()  使得前边的(6,4,512)被压缩成6*4*512==12288,变成一维,从卷积层到全连接层的过渡

                       (二)Dense() 全连接层。     (三)同理

                       (四)Dense()用到了定义的参数128。到这为止,网络model搭建完毕

        最后:通过load_weights函数将.h5文件中的 权重 写入进去(函数使用方法在这)

网络model一览表:(None表示batch的维度)

                                          

 模块4 (Bi-GRU网络结构)

        sstep1:           input_shape==(10,96,64,1)进行更改。

                首先,vggish_model可以将(96,64,1)改为(128,)

                然后,通过TimeDistributed可以将(10,96,64,1)后三项应用第一步进行替换

                最后,结果为(10,128)

        sstep2:        

                首先,GRU()函数实现GRU网络结构

                        

                 然后,Bidirectional()函数,使用具体方法在这里,简单来说是为了实现RNN,LSTM,GRU的双向构造

                 接着,全连接层实现一个二分类

一览表:(至此,VGGish和BiGRU完成结合)

        sstep3:

                 首先,采用Adam进行优化

                 然后,使用compile(),使用方法在这里,只是一步固定的书写,不用太注重

模块5

                 首先,采用fit(),使用方法在这里,只是一步固定的书写,不用太注重。里边标定了x,y,batch_size,epochs等参数。需要注意的是:val集是随机从train集划分的15%数据(结合前边的shuffle,所以每次数据都不一样)

                 然后,save_weight保存训练模型

模块6

                 分别将train和val的loss、acc作图

模块7

                 predict(features)是test使用。用法在这里,本例子中是输入train中的数据以生成predict,进而和train中的label相比较。features经过model.predict后变成label的shape。可能会存在label预测错误的现象。因此我们要看label的acc等评价指标。                 

                 (不过,这个将train集直接作为test集进行test好像是不太对的。)

                 argmax()在上一步中的数据中的 每行找到最大值所对应的位置,使用方法在这里

举个例子:

        第一个呼吸音经过predict()后,变为

[8.9729613e-01 1.0270386e-01]

        然后,再经过argmax(),由于第一个数比较大,也就是0位置,因此变为

0

        接着,health的标签为[1,0],labels的标签为[0,1],所以经过argmax()后,health变为0,lables变为1

        所以将上步骤和上上步骤的值,我列出来:

[0 0 1 1 1 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 0 1 0 1 0 1
 1 0 0 1 1 0 1 1 1 1 0 0 1 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 0
 0 0 1 1 1 1 1 0 0 1 0 0 1 1 0 1 0 0 1 0 0 0 1 0 0 1 0 1 0 0 1 0 0 0 0 1 1
 1 0 1 1 1 0 1 1 0 0 0 0 1 1 1 1 0 1 0 0 0 1 0 0 1 1 0 0 0]
---------------------------------------
[0 0 1 1 1 0 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 0 1 1 0 0 1 0 1 0 1 0 1
 1 1 0 1 1 0 1 1 1 1 0 0 1 0 0 0 1 0 0 1 0 0 0 0 1 1 1 0 1 1 1 1 1 1 1 1 1
 0 0 0 1 1 0 1 1 1 1 0 0 1 1 0 1 0 0 1 1 0 0 1 1 0 1 0 1 1 0 1 0 0 0 0 1 1
 1 0 1 1 0 0 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 1 0 0 0 1 0 0 0]        

        下边再利用test的评价指标进行评价:

        使用classification_report, confusion_matrix函数生成预测的值,关于函数用法在这里在这里(混淆矩阵)

        结果如下:(下边的小矩阵就是混淆矩阵,数值为TP,TN,FP,FN)

                 

                 

        

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值