张海腾:语音识别实践教程
共 9542字,需浏览 20分钟
·
2021-05-10 19:25
每日干货 & 每月组队学习,不错过
作者:张海腾,标贝科技,Datawhale优秀学习者
作为智能语音交互相关的从业者,今天以天池学习赛:《零基础入门语音识别:食物声音识别》为例,带大家梳理一些自动语音识别技术(ASR)关的知识,同时给出线上可运行的完整代码实践,供大家练习。
实践背景
实践地址:(文末阅读全文或复制链接)https://tianchi.aliyun.com/competition/entrance/531887/information
语音相关知识点梳理
一些在我司常听到的关键词
1)波形图
语音的保存形式可用波形图展现,可以看作是上下摆动的数字序列,每一秒的音频用16000个电压数值表示,采样率即为16kHz。
2)采样点
采样点是对波形图的放大,可以看到的更细的单位
3)频谱图
可以变为频谱图,颜色代表频带能量大小,语音的傅立叶变换是按帧进行,短的窗口有着高时域和低频域,长时窗口有低时域和高频域。
4)基本单位
对于语音而言,基本单位是帧(对应文本的token),一帧即是一个向量,整条语音可以表示为以帧为单位的向量组。帧是由ASR的前端声学特征提取模块产生,提取的技术设计“离散傅立叶变换”和”梅尔滤波器组“
整体解决思路
第一种方式:
路线的个人理解大约是,有一个音频,先有声学模型,将对应的音频信号处理为对应的声学特征,再有语言模型,将声学特征的结果得到概率最大的输出字符串。
在上图中,代表的是声学特征向量,代表输出的文本序列,在(2.1)中,代表的是声学模型,代表的是语言模型
第二种方式:
端到端的解决手段,个人印象中在吴恩达的课程里提到,ASR在CTC提出后有一个较大的提升。个人理解是在CTC之前,seq2seq的建模方式比较难处理输出序列远短于输入序列的情况,以及在不同帧出现的相同音素的输出
其他术语
声学模型:常用的话,包括了HMM,GMM,DNN-HM的声学模型。
语言模型:常用的语言模型这里包括了n-gram语言模型以及RNN的语言模型。
解码器:最终目的是取得最大概率的字符输出,解码本质上是一个搜索问题,并可借助加权有限状态转换器(Weighted Finite State Transducer,WFST) 统一进行最优路径搜索。
端到端的方法:seq2seq+CTC 损失函数, RNN Transducer, Transforme,这里需要补充的话 应该要去看李宏毅2020年的人类语言处理的课程。
完整实践代码
数据获取
# 下载数据集
!wget [http://tianchi-competition.oss-cn-hangzhou.aliyuncs.com/531887/train_sample.zip](http://tianchi-competition.oss-cn-hangzhou.aliyuncs.com/531887/train_sample.zip)
!wget [http://tianchi-competition.oss-cn-hangzhou.aliyuncs.com/531887/test_a.zip](http://tianchi-competition.oss-cn-hangzhou.aliyuncs.com/531887/test_a.zip)
# 解压并删除压缩包
!unzip -qq train_sample.zip
!\rm train_sample.zip
!unzip -qq test_a.zip
!\rm test_a.zip
基本库及模型框架导入
环境要求:
TensorFlow的版本:2.0 + keras sklearn librosa
#基本库
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split #数据分割
from sklearn.metrics import classification_report #评价
from sklearn.model_selection import GridSearchCV #网格搜索,最优模型选择
from sklearn.preprocessing import MinMaxScaler #特征标准化
# 加载深度学习框架
# 搭建分类模型所需要的库
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, Flatten, Dense, MaxPool2D, Dropout
from tensorflow.keras.utils import to_categorical
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
# 安装librosa Librosa是一个用于音频、音乐分析、处理的python工具包。
# 一些常见的时频处理、特征提取、绘制声音图形等功能应有尽有,功能十分强大
!pip install librosa --user
# 其他库
#音频处理
import librosa
import librosa.display
#文件处理
import glob
import os
特征提取以及数据集的建立
feature = []
label = []
# 建立类别标签,不同类别对应不同的数字。
label_dict = {'aloe': 0, 'burger': 1, 'cabbage': 2,'candied_fruits':3, 'carrots': 4, 'chips':5,
'chocolate': 6, 'drinks': 7, 'fries': 8, 'grapes': 9, 'gummies': 10, 'ice-cream':11,
'jelly': 12, 'noodles': 13, 'pickles': 14, 'pizza': 15, 'ribs': 16, 'salmon':17,
'soup': 18, 'wings': 19}
# 不同数字对应不同的类别。
label_dict_inv = {v:k for k,v in label_dict.items()}
#特征提取
from tqdm import tqdm #提示进度条
def extract_features(parent_dir, sub_dirs, max_file=10, file_ext="*.wav"):#提取特征以及标签
c = 0
label, feature = [], []
for sub_dir in sub_dirs:
for fn in tqdm(glob.glob(os.path.join(parent_dir, sub_dir, file_ext))[:max_file]): # 遍历每个数据集的所有文件
# segment_log_specgrams, segment_labels = [], []
#sound_clip,sr = librosa.load(fn)
#print(fn)
label_name = fn.split('/')[-2]
label.extend([label_dict[label_name]])
X, sample_rate = librosa.load(fn,res_type='kaiser_fast')
mels = np.mean(librosa.feature.melspectrogram(y=X,sr=sample_rate).T,axis=0) # 计算梅尔频谱(mel spectrogram),并把它作为特征
feature.extend([mels])
return [feature, label]
parent_dir = './train_sample/'
save_dir = "./"
folds = sub_dirs = np.array(['aloe','burger','cabbage','candied_fruits',
'carrots','chips','chocolate','drinks','fries',
'grapes','gummies','ice-cream','jelly','noodles','pickles',
'pizza','ribs','salmon','soup','wings'])
# 获取特征feature以及类别的label
temp = extract_features(parent_dir,sub_dirs,max_file=100)
temp = np.array(temp)#列表转换成矩阵
data = temp.transpose()#矩阵转置
# 获取特征
X = np.vstack(data[:, 0])
#X的特征尺寸是: (1000, 128)
# 获取标签
Y = np.array(data[:, 1])
#Y的特征尺寸是: (1000,)
#数据集划分
#训练集的大小 750
#测试集的大小 250
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, random_state = 1, stratify=Y)
#random_state 是随机数的种子。
建立模型
1、搭建CNN网络
model = Sequential()#多个网络层的线性堆叠
# 输入的大小
input_dim = (16, 8, 1)
model.add(Conv2D(64, (3, 3), padding = "same", activation = "tanh", input_shape = input_dim))# 卷积层
# 输入shape
model.add(MaxPool2D(pool_size=(2, 2)))# 最大池化
model.add(Conv2D(128, (3, 3), padding = "same", activation = "tanh")) #卷积层
model.add(MaxPool2D(pool_size=(2, 2))) # 最大池化层
model.add(Dropout(0.1))
#为输入数据施加Dropout。Dropout将在训练过程中每次更新参数时按一定概率(rate)随机断开输入神经元,Dropout层用于防止过拟合。
model.add(Flatten()) # 展开
model.add(Dense(1024, activation = "tanh"))
model.add(Dense(20, activation = "softmax")) # 输出层:20个units输出20个类的概率
# 编译模型,设置损失函数,优化方法以及评价标准
model.compile(optimizer = 'adam', loss = 'categorical_crossentropy', metrics = ['accuracy'])
model.summary()
# 训练模型
model.fit(X_train, Y_train, epochs = 20, batch_size = 15, validation_data = (X_test, Y_test))
2、预测测试集
#提取测试集数据特征
def extract_features(test_dir, file_ext="*.wav"):
feature = []
for fn in tqdm(glob.glob(os.path.join(test_dir, file_ext))[:]): # 遍历数据集的所有文件
X, sample_rate = librosa.load(fn,res_type='kaiser_fast')
mels = np.mean(librosa.feature.melspectrogram(y=X,sr=sample_rate).T,axis=0) # 计算梅尔频谱(mel spectrogram),并把它作为特征
feature.extend([mels])
return feature
X_test = extract_features('./test_a/')
#输出测试结果
preds = np.argmax(predictions, axis = 1)
preds = [label_dict_inv[x] for x in preds]
path = glob.glob('./test_a/*.wav')
result = pd.DataFrame({'name':path, 'label': preds})
result['name'] = result['name'].apply(lambda x: x.split('/')[-1])
result.to_csv('submit.csv',index=None)
!ls ./test_a/*.wav | wc -l
!wc -l submit.csv
#利用wc指令我们可以计算文件的Byte数、字数、或是列数,若不指定文件名称、或是所给予的文件名为"-",则wc指令会从标准输入设备读取数据。