当前位置: 首页 > news >正文

人工智能开发实时语音识别系统应用

内容提要

  1. 项目分析
  2. 预备知识
  3. 项目实战

一、项目分析

1、问题提出

数字0-9是我们生活中常见的10个基数,在医院、银行、饭店等场所,由于资源和人手的受限,人们必须排队等候服务,叫号系统应运而生。

任何一个数字,都是由10个基数构成的,英文叫号系统在播报序号时,如果能将对应的阿拉伯数字及时展示在大屏上,这对于以非英语为母语的顾客而言,无疑是一个很好的福音,能帮助他们不会因语言障碍而错过漫长的排队。因此,有必要借助于机器来实现英语数字的识别。

下面,我们利用语音特征提取技术和卷积神经网络模型,对数字语音进行识别以解决上述问题。

2、解决方案

为识别出一段语音中的数字,一种简单的实现方法是首先将语音进行分段切分,按说话的停顿切分出每个单词,然后提取每个单词的语音特征。

其次构建一个多层CNN分类器,利用0-9的语音样本集对模型进行训练,得到满足精度要求的模型。

最后利用训练好的模型逐个对提取的单词语音特征进行分类,看它属于0-9中的那个数字,然后将分类出的数字组合起来就得到最终的识别结果。

二、预备知识

语音识别过程中,要用到语音检测模块webrtcvad、语音特征提取模块python_speech_features和飞桨框架paddlepaddle。

1、webrtcvad模块

webrtcvad模块是一个语音活动检测器的python接口,通过VAD(Voice Activity Detection)算法将音频数据分类为有声或无声,据此来判断语音的开始和结束,也就能从数字语音中切分出一个个的单词。

【案例1】切分音频文件中有效的语音数据

编程前要使用如下命令先安装webrtcvad模块:

pip3 install webrtcvad

然后编程完成语音切分,实现的源代码(case1.ipynb)如下。

1	import scipy.io.wavfile as wav
2	import webrtcvad
3	import numpy as np
4	samp_rate, signal_data = wav.read('data/1_5.wav')
5	vad = webrtcvad.Vad(mode=3)
6	signal= np.pad(signal_data,(0,160-(signal_data.shape[0]%int(samp_rate*0.02))),'constant')
7	lens = signal.shape[0]
8	signals = np.split(signal, lens//int(samp_rate*0.02))
9	audio = [];audios = []
10	for signal_item in signals:
11	    if vad.is_speech(signal_item,samp_rate):
12	        audio.append(signal_item)
13	    elif len(audio)>0 and (not vad.is_speech(signal_item,samp_rate)):
14	        audios.append(np.concatenate(audio, 0))
15	        audio= []

代码行4 是读取音频文件1_5 .wav 的采样频率和音频数据, 代码行5 是构建一个激进模式为3 的声音分类对象vad , 代码行6 是以帧长为20ms 来分帧, 对最后一帧长度不足160 的部分进行补0 , 然后在代码行8 中对语音信号进行分割, 形成一个个长度为160 的数据帧。

代码11一15行是对分割后的数据帧进行判断, 如果是语音帧,则在变量audio 中进行累计, 如果不是语音帧且语音结束, 则将语音帧统一转换成一维数组audios 输出。

audios 的内容如下图所示。

从上图可以看出, 英文数字1 和5 的语音信号被成功切分出来, 分别保存到两个一维数组中。

2、python_speech_features模块

有效音频信号被切分出来后,如何辨别这些音频信号具有独特的特征呢?

这时就要用到python_speech_features模块,该模块提供了计算一个音频信号的梅尔频率倒谱系数MFCC(Mel Frequency Cepstral Coefficients)特征和一阶、二阶差分系数的方法。

MFCC特征向量描述了一帧语音的静态特征,一阶差分系数、二阶差分系数描述了帧之间的动态信息,三者的结合就比较完整地描述了音频信号的全部特征。

【案例2】先使用如下命令安装python_speech_features模块。

pip3 install python_speech_features

然后编写如下代码,实现语音特征的提取。

1	from python_speech_features import mfcc,delta
2	wav_feature = mfcc(audios[0],8000)
3	d_mfcc_feat = delta(wav_feature,1)
4	d_mfcc_feat2 = delta(wav_feature,2)
5	feature = np.concatenate([wav_feature.reshape(1,-1,13),d_mfcc_feat.reshape(1,-1,13),d_mfcc_feat2.reshape(1,-1,13)], 0)
6	if feature.shape[1]>64:
7	    feature = feature[:,:64,:]
8	else:
9	    feature = np.pad(feature,((0,0),(0,64-feature.shape[1]),(0,0)),'constant')
10	feature = feature.transpose((2,0,1))
11	feature = feature[np.newaxis,:]

代码行2计算案例1中切分出来的第一个语音信号audios[0]的MFCC特征值,代码行3-4分别计算这些语音帧的一阶、二阶差分系数。

代码行5将所有特征值转换成三维矩阵并合并,合并后的三维矩阵含有3个多行13列的二维矩阵。

代码行6-9对每个二维特征矩阵的行数(高度)进行截取或填充,不足64行的在后面填充0,以保证经处理后的特征矩阵feature是一个3通道64×13的矩阵。

代码行10将特征矩阵feature进行转置,把原来的矩阵形状(0,1,2)转变为(2,0,1),即三维数组中某一元素原来的索引坐标(x,y,z)调换为(z,x,y),变换后的矩阵则是一个13通道3×64的矩阵。

代码行11是把特征矩阵feature增加一个新的维度,由原来的三维变成四维,特征矩阵转换的目的是满足网络模型对输入数据体的要求。提取后的特征feature如图所示。

3、paddlepaddle框架

Paddlepaddle(飞桨)是百度公司提供的开源开放的一个产业级深度学习框架,有全面的官方支持的工业级应用模型,涵盖自然语言处理、计算机视觉、推荐引擎等多个领域,并开放多个领先的预训练模型。

飞桨同时支持稠密参数和稀疏参数场景的大规模深度学习并行训练,支持千亿规模参数、数百个节点的高效并行训练。

另外,飞桨拥有多端部署能力,支持服务器端、移动端等多种异构硬件设备的高速推理,预测性能有显著优势。目前PaddlePaddle已经实现了API的稳定和向后兼容,具有完善的中英双语使用文档。

飞桨的应用框架如图所示:

示意图的上半部分是从开发、训练到部署的全流程工具,下半部分是预训练模型、各领域的开发套件和模型库等模型资源。

飞桨除提供用于模型研发的基础框架外,还推出了一系列的工具组件,来支持深度学习模型从训练到部署的全流程。

由此可见,利用百度飞桨能节省编写大量底层代码的精力,用户只需关注模型的逻辑结构即可。

同时,深度学习工具简化了计算,降低了深度学习入门门槛,这对于学习者来说,无疑是个很大的福音。另外,利用飞桨具备灵活移植性的特点,可将代码部署到CPU/GPU/移动端上,选择具有分布式性能的深度学习工具会使模型训练更高效,省去了部署和适配环境的烦恼。

【案例3】搭建一个房价预测的神经网络模型。

1	import paddle.fluid as fluid
2	from paddle.fluid.dygraph import Linear
3	class Regressor(fluid.dygraph.Layer):
4	    def __init__(self):
5	        super().__init__()
6	        self.fc=Linear(input_dim=1,output_dim=1,act=None)
7	    def forward(self,inputs):
8	        x=self.fc(inputs)
9		    return x

代码行1导入飞桨的主包fluid,目前大部分的实用函数均在paddle.fluid包内。

代码行2从动态图的类库dygraph中导入全连接线性变换类Linear。

代码行3-9是定义一个线性回归网络Regressor,其中中间只有一个全连接层fc,输入维度为1(房屋面积),输出维度为1(房屋价格),因为模型只是一个线性回归模型,所以定义激活函数为None,通过前向计算函数来构建网络结构,实现前向计算过程,并返回预测结果,在本引例中是返回房价预测结果。

三、项目实战

3.1 提取音频的语音特征数据

我们事先录制了一段单声道、8k、16bit的数字语音audio.wav,为方便提取语音特征,减少代码冗余和提高代码的可移植性。

我们将上一节中的案例1和案例2的代码封装在类VioceFeature中,通过调用语音切分方法vad和特征提取方法get_mfccw来完成音频文件的特征数据提取任务,为后续进一步的语音识别做好数据准备工作。

新建文件task1.ipynb,根据任务目标,按照以下步骤和操作,完成任务一。

任务目标:

提取音频文件audio.wav的语音特征数据,按后续语音识别网络模型的输入数据格式要求,得到一个形状为(n,13,3,64)的特征数据矩阵,其中n指音频中包含的数字个数。

完成步骤:

(1)设计特征提取类VioceFeature

(2)提取语音特征数据

1、设计特征提取类VioceFeature

定义类VioceFeature,主要包含两个成员方法vad和get_mfcc,分别对应音频切分和特征数据提取功能,具体的代码见前面的案例1和案例2。

为方便模块的调用,需要在jupyter环境中将类VioceFeature另存为VioceFeature.py文件,操作方法如图所示。

2、提取语音特征数据

在文件task1.ipynb中调用模块VioceFeature,编写以下代码,得到满足网络模型输入格式的特征数据。

1	from VioceFeature import *
2	voicefeature=VioceFeature()
3	audios,samp_rate=voicefeature.vad('data\\audio.wav')
4	features = []
5	for audio in audios:
6	    feature = voicefeature.get_mfcc(audio, samp_rate)
7	    features.append(feature)
8	features = np.concatenate(features, 0).astype('float32')

代码行1导入VioceFeature模块中所有类,代码行2创建对象voicefeature,代码行3调用对象voicefeature的方法vad完成音频切分。

代码行4-8对切分出的音频数据集audios,采用MFCC算法进行特征提取,提取后的结果保存在矩阵变量features中。执行如下命令查看features的矩阵形状如图所示。

3.2 构建语音数字识别神经网络模型

前面已经提到,利用多层卷积神经网络不仅能进行图像分类,也可以完成语音识别。

因为我们可以根据任务一提取到的每个英文数字发音的特征数据,通过普通的二维卷积进行处理,将其分类到0-9十个类别上。

根据任务目标,按照以下步骤和操作,完成任务二。

任务目标:

设计一个多层卷积神经网络模型,对其进行训练并保存最优模型。

完成步骤:

(1)定义多层神经网络模型

(2)模型训练及保存最优训练模型

1、定义多层神经网络模型

该模型就是一个分类器,它的输入就是n×13×3×64的四维语音矩阵,它的输出是10维向量,即Y=(y0,y1,…,y9),第i维是语音片段被分类为第i个数字的概率,如Y=(0,1,…,0),则表示该语音片段对应的数字是1。

为简化网络模型,我们采用多层卷积神经网络CNN和全连接层来构架一个分类器,其网络结构如图所示。

在上图中,每两层卷积层为一个块,前一层负责提取特征,后一层负责下采样,经过6层卷积操作后,形成1×8×64单通道特征输出,再经过2层的全连接进行分类,最终得到识别结果。

模型的实现代码如下。

1	class AudioCNN(fluid.dygraph.Layer):
2	    def __init__(self):
3	        super().__init__()
4	        self.conv1 = Conv2D(num_channels=13,num_filters=16,filter_size=3,stride=1,padding=1)
5	        self.conv2 = Conv2D(16,16,(3,2),(1,2),(1,0))
6	        self.conv3 = Conv2D(16,32,3,1,1)
7	        self.conv4 = Conv2D(32,32,(3,2),(1,2),(1,0))
8	        self.conv5 = Conv2D(32,64,3,1,1)
9	        self.conv6 = Conv2D(64,64,(3,2),2)
10	        self.fc1 = Linear(input_dim=1*8*64,output_dim=128,act='relu')
11	        self.fc2 = Linear(128,10,act='softmax')
12	    # 定义前向网络
13	    def forward(self, inputs, labels=None):
14		    out = self.conv1(inputs)
15	        out = self.conv2(out)
16	        out = self.conv3(out)
17	        out = self.conv4(out)
18	        out = self.conv5(out)
19	        out = self.conv6(out)
20	        out = reshape(out, [-1,8*64])
21	        out = self.fc1(out)
22	        out = self.fc2(out)
23	        if labels is not None:
24	            loss = softmax_with_cross_entropy(out, labels)
25	            acc = accuracy(out, labels)
26	            return loss, acc
27	        else:
28			    return out

代码行4定义的二维卷积层的输入通道数与输入数据的通道格式一致(=13),采用16个卷积核、卷积大小即滤波器尺寸为3×3、步长为1、填充尺寸为1进行特征提取。

在代码行5中,紧接着利用尺寸为3×2的滤波器,按水平、垂直方向步长分别为1和2、无填充来实现下采样的效果。

代码6-9又完成两组特征提取和下采样操作,代码行10对主要对卷积后的特征数据进行降维,形成一个1×128的向量,最后在代码行11完成分类操作。

代码行13-28是定义网络的前向计算过程,其中代码行14-22采用初始化函数__init__中定义好的网络层依次对输入数据inputs进行前向处理,代码行23-28是返回处理后的结果,如果样本带有标签,则计算分类误差loss和分类精度acc,否则,直接返回分类结果out。

2、模型训练及保存最优训练模型

语音样本集采用Free-Spoken-Digit-Dataset语音集,该语句集一共有3000条数据,从百度官网:https://aistudio.baidu.com/aistudio/datasetdetail/23050下载。

模型的训练过程定义主要包括以下几个方面:

(1)以动态图dygraph 的guard函数指定运行训练的机器资源,表明在with作用域下的程序均执行在本机的CPU|GPU资源上,程序会以飞桨动态图的模式实时执行。

(2)创建定义好的模型AudioCNN实例,并将模型的状态设置为训练。

(3)加载训练数据和测试数据。

(4)设置训练迭代次数,启动模型迭代训练。在迭代过程中,可以观察到模型的训练误差和训练精度。

(5)最后保存训练好的模型。

模型训练的代码具体可参考百度官网https://aistudio.baidu.com/aistudio/projectdetail/797250,模型训练完成后,通过以下代码来保存模型,以备测试或校验的程序调用。

fluid.save_dygraph(optimizer.state_dict(), 'final_model')

然后就可以利用模型来测试数字语音的识别效果了。

3.3 利用训练好的模型来识别语音

通过前面的任务1已经获取了英文数字的语音特征,并在任务2中对构建的神经网络模型进行了训练,下面就利用保存的模型对语音特征数据完成分类工作,将分类结果进行合并,从而最终完成对语音的识别任务。根据任务目标,按照以下步骤和操作,完成任务3。

任务目标:

利用训练好的CNN模型,对语音特征数据进行分类识别,得到语音文件audio.wav的识别结果。

完成步骤:

(1)配置模型识别的机器资源

(2)加载模型参数给模型实例

(3)将提取的特征样本输入模型,得到识别结果

1、配置模型识别的机器资源

从前面的模型定义和训练来看,我们训练好最后的模型所花销的时间相对还是很短的,主要原因是我们所使用的AudioCNN卷积神经网络比较简单。

但现实生活中,我们可能会遇到更复杂的机器学习、深度学习任务,需要运算速度更高的硬件(GPU、TPU),甚至同时使用多个机器共同训练一个任务(多卡训练和多机训练)。

但本案例是在普通的电脑上训练和预测,所以通过以下语句进行模型运行的资源配置。

with fluid.dygraph.guard(place=fluid.CPUPlace()):

2、加载模型参数给模型实例

首先要构造一个模型实例model,然后将前面训练好的模型final_model参数加载到模型实例中。

加载完毕后,还需将模型的状态调整为校验状态eval,是因为模型在训练过程中要同时支持正向计算和反向传导梯度,此时的模型比较臃肿,而校验eval后的模型只需支持正向计算,此时模型的实现简单且性能较高。

对应的代码如下。

1	model = AudioCNN()
2	params_dict, _ = load_dygraph('data/final_model')
3	model.set_dict(params_dict)
4	model.eval()

代码行1是构建神经网络类AudioCNN的一个实例model,代码行2是加载目录data下训练好的模型final_model,代码行3给模型model加载参数,代码行4完成对模型的校验,模型只用于预测。

3、将提取的特征样本输入模型,得到识别结果

在任务一中我们提取出英文数字音频的语音特征features,下面就基于该特征值,利用训练好的模型进行语音识别,实现的代码如下。

1	features =to_variable(features)
2	out = model(features)
3	result = ' '.join([str(num) for num in np.argmax(out.numpy(),1).tolist()])
4	print('语音数字的识别结果是:',result)

代码行1将多维的矩阵转换成Paddle支持的张量Tensor类型,代码行2将特征数据features作为模型的输入来预测识别结果。

由于模型的输出out仍是一个张量类型,故在代码行3中对其进行numpy转换,变成一个二维数组,然后按行求各行中的最大值的下标,因为下标值与预测的数字值是一一对应的,故最后的拼接结果result实际就是识别的数字,识别的结果如图所示。

可以看到,CNN模型准确识别出语音文件audio.wav的内容,说明卷积神经网络的确可用于语音的识别,能获得较好的识别效果。

更多精彩内容请持续关注本站!

相关文章:

  • USB2.0主机设备检测过程以及信号分析
  • 【算法业务】互联网风控业务中的拒绝推断场景算法应用分享(涉及半监督算法、异常检测、变分自编码、样本权重自适应调整、迁移学习等)
  • 2024年项目经理不能错过的开源项目管理系统大盘点:全面指南
  • 使用 Docker 部署 RStudio 的终极教程
  • 智算中心动环监控:构建高效、安全的数字基础设施@卓振思众
  • 51单片机-红外遥控器(NEC标准)-实验(红外遥控及调速电机)
  • Techub专访顾荣辉教授:解密CertiK的安全战略路线
  • 如何搭建适合自己的数据中台?六步法
  • 以串口接口为例介绍关于BSP底层架构开发的迭代过程
  • 足球预测模型理论:足球数据分析——XGBoost算法实战
  • Navicat数据库管理工具实现Excel、CSV文件导入到MySQL数据库
  • C#中NModbus4中常用的方法
  • 设计模式之装饰模式(Decorator)
  • 解决macOS安装redis以后不支持远程链接的问题
  • 如何注册和使用Disney+?Disney+会员账号可以合租?Disney+会员账号订阅购买使用教程
  • classpath对获取配置文件的影响
  • co模块的前端实现
  • ES6简单总结(搭配简单的讲解和小案例)
  • Laravel 中的一个后期静态绑定
  • python学习笔记 - ThreadLocal
  • Vim 折腾记
  • Vue.js 移动端适配之 vw 解决方案
  • 基于Vue2全家桶的移动端AppDEMO实现
  • 排序算法学习笔记
  • 前端面试题总结
  • 软件开发学习的5大技巧,你知道吗?
  • 三分钟教你同步 Visual Studio Code 设置
  • 项目实战-Api的解决方案
  • 源码之下无秘密 ── 做最好的 Netty 源码分析教程
  • RDS-Mysql 物理备份恢复到本地数据库上
  • UI设计初学者应该如何入门?
  • ## 临床数据 两两比较 加显著性boxplot加显著性
  • #LLM入门|Prompt#1.8_聊天机器人_Chatbot
  • $.proxy和$.extend
  • (+4)2.2UML建模图
  • (2)STL算法之元素计数
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (java)关于Thread的挂起和恢复
  • (vue)el-cascader级联选择器按勾选的顺序传值,摆脱层级约束
  • (安卓)跳转应用市场APP详情页的方式
  • (七)glDrawArry绘制
  • (强烈推荐)移动端音视频从零到上手(下)
  • (三)终结任务
  • (一)Neo4j下载安装以及初次使用
  • (转载)Linux网络编程入门
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .DFS.
  • .NET COER+CONSUL微服务项目在CENTOS环境下的部署实践
  • .NET MVC第五章、模型绑定获取表单数据
  • .net redis定时_一场由fork引发的超时,让我们重新探讨了Redis的抖动问题
  • .net 流——流的类型体系简单介绍
  • .NET 使用 JustAssembly 比较两个不同版本程序集的 API 变化
  • .NET/C# 使用反射注册事件
  • .Net程序猿乐Android发展---(10)框架布局FrameLayout
  • @vueup/vue-quill使用quill-better-table报moduleClass is not a constructor