第三章 人工智能和机器学习

如果将语谱图看作一张图片,就相当于把语音识别的问题变成图片分类问题。这样利用网络上大量的语料库,我们就可以训练一个机器学习模型,构建自己的语音识别体系。

本章我们将尝试利用自己录入的语音数据来完成一个简单的短语识别程序,不过在开始具体的内容之前,先来了解以下人工智能于机器学习,以及分类器的训练于评估。

3.1 人工智能

3.1.1 什么是人工智能?

人工智能这个词实际上是一个概括性术语,是指研究利用计算机模拟人的某些思维过程和智能行为的学科,涵盖从高级算法到应用机器人的所有内容。1956年8月,在美国韩诺斯小镇宁静的达特茅斯学院中,约翰麦卡锡等科学家聚在一起,讨论用机器来模仿人类学习以及其他方面智能的问题。这次会议足足开了两个月的时间,虽然大家没有达成普遍的共识,但却提出了"人工智能"这一术语,标志着"人工智能"这门新兴学科的正式诞生。

谈到人工智能,可能大家印象最深的还是2016年3月AlphaGo以4比1的总比分击败围棋世界冠军职业九段棋手李世石的场景,这标志着人工智能树立了一个新的里程碑。而前一个里程碑应该是1997年5月11日"深蓝"击败国际象棋大师卡斯帕罗夫。当时还有很多人说人工智能无法在围棋上击败人类职业的围棋冠军,因为围棋的变化太多,计算机完成不了这个数量级的计算。虽然在1997年到2016年,计算机技术依照摩尔定律突飞猛进的发展,但这并不是新里程碑出现的主要原因。AlphaGo之所以能够击败人类职业九段的围棋选手,主要是因为机器学习技术的发展。

3.1.2 什么是机器学习?

机器学习从字面上简单理解就是计算机自己学习。"深蓝"的时代采用一套称为"专家系统"的技术,这种技术回把绝大多数的可能性都存在计算机中,遇到问题的时候,计算机会搜索所有的可能性,然后选择一个最优的路线。这种技术的核心是要预先想好所有可能出现的问题以及对应的解决方案,所以当年的主要工作就是组织专家给出对用问题的解决办法,然后把这些回答按照权重组织在一起形成"专家系统"。我们现在知道这种技术有很多局限性。一方面,在复杂的应用场景下建立完善的问题库是一个非常昂贵且耗时的过程;另一方面,很多基于自然输入的应用,比如语音识别和图像识别,很难以人工方式定义具体的规则。因此现在的人工智能普遍采用机器学习的技术,这种技术于"专家系统"最大的区别就是不再告诉计算机可能出现的所有问日以及问题的解决办法了,而是设定一个元组,然后给计算机大量的数据,让计算机自己取学习如何做出决策,由于这个过程是计算机自己学习,所有称为机器学习。可以说机器学习是实线人工智能的一种训练算法的模型,这种算法使得计算机能偶学习如何做出决策。

在"专家系统"中,我们知道计算机如何工作的。还是以国际象棋为例,对应计算机的工作流程就是检索所有的棋谱,然后选择一个获胜概率最高的走法。这个过程如果没有计算机,换个普通人也能完成,知识每走一步花的是按要多一些而已,计算机的优势知识速度快。而对于机器学习来说,计算机学习完毕之后我们并不知道其对应的思考过程,既这个过程是人无论花多少时间都完成不了的。AlphaGo学习的时候还是学的棋谱。研发团队知识让它自由随意的在棋盘上下棋,然后进行自我博弈。最后的结果是在AlphaGo Zero面前,AlphaGo完全不是对手,战绩是100:0。

3.2 人工神经网络

3.2.1 什么是人工神经网络?

机器学习是目前人工智能的主要研究方向,是使计算机具有智能的根本途径。机器学习飞速发展的主要原因是科学家开始尝试模拟人类大脑的工作形式。人类的思维功能定位在大脑皮层,大脑皮层含有约上千亿神经元,每个神经元又通过神经突触于数十上百个其他神经元相连,形成一个高度复杂,高度灵活的动态网络。通过研究人脑神经网络的结构,功能及其工作机制,科学家在计算机中实线了一个人工神经网络(ANN),这是生物神经网络在某种简化意义下的技术复现,作为一门学科,人工神经网络的主要任务是根据生物神经网络的原理和实际应用的需要,利用代码建造实用的技术上实线出来用以解决实际问题。

人工智能包含机器学习,机器学习包含人工神经网络。

神经网络算法最早来源于神经生理学家W.McCulloch和数理逻辑学家W.Pitts联合发表的一篇论文,他们对人类神经运行规律提出了一个猜想,并尝试给出一个建模来模拟人类神经元的运行规律。人工神经网络一开始由于求解问题的不稳定以及范围有限被抛弃。后来由于GPU反战带来的计算能力的提升,人工神经网络获得了爆发式的发展。

下面我们通过一些分析来理解和描述人工神经网络。首先,人工神经网络是一个统计模型,是数据集S与概率P的对应关系,P是S的近似分布。也就是说,通过P能够产生一组与S非常相似的结果。这里P并不是一个单独的函数,人工神经网络由大量节点(或称神经元)之间相互连接构成,每个节点都嗲表一种特定的函数,称为激励寒素。每两个节点间的连接都代表一个对于通过该连接信号的加权值,称之为权重,而P就是由所有这些激励函数以及节点之间的权重构成,相当于人工神经网络的记忆。人工神经网络的输出则依网络的连接方式,权重和激励函数的不同而不同。而网络自身通常都是对自然界某种算法或者函数的逼近,也可能是对一种逻辑策略的表达。

3.2.2 人工神经网路的结构

人工神经网络的结构如下如所示:

简单理解人工神经网络由三个不同的层:输入层,中间层(或者称为隐藏层)和输出层。

(1)输入层定义了人工神经网络输入节点的数量。比如我们希望创建一个人工神经网络来根据给定的动物属性判断属于那种动物,这里属性分别为体重,长度,食草还是食肉,生活在水中还是陆地上,会不会飞。如果采用这五种属性,则输入层的节点数量就是5个。

(2)输出层的定义与输入层类似,是人工神经网络输出节点的数量。还是比如要创建一个根据给定的懂得购物属性判断属于那种动物的人工神经网络,若确定分类的动物为狗,老鹰,海豚,则处处层的节点就是3个。如果输入数据不属于这些类别的范畴,网络将返回与这三个动物最相似的类别。

(3)中间层包含处理信息的节点。中间层可以由很多个,但通常大多数问题只需要一个中间层。要确定中间层的节点数,由很多经验性方法,但没有严格的准则。在实际应用中,经常会根据经验设置不同的节点数量来测试人工神经网络,最后选择一个最适合的方式。

创建人工神经网络的一般规则如下:

(1)中间层的节点数量应介于输入层和输出层节点数量之间。根据经验,如果输入层节点数量与输出层节点数量相差很大,则中间层的节点数量最好与输出层的节点数量相近。

(2)同一层的节点之间不连接。第N层的每个节点都与第N-1层的所有节点连接,第N-1层神经元的输出就是第N层神经元的输入。每个节点的连接都有一个权值。

(3)对于相对较小的输入层,中间层的节点数量最好是输入层和输出层节点数量之和的三分之二,或者小于输入层节点数量的两倍。

这里要注意一个被称为"过拟合"的现象。过拟合是指为了得到对应的结果而使待分类训练数据信息过度严格。避免过拟合是分类器设计的一个核心任务。通常采用增大数据量和测试样本集的方法对分类器性能进行评价,当然,这样需要更长的训练时间。

3.3 监督式学习与非监督学习

机器学习既然称为"学习",必然有一个利用数据训练和学习的过程。机器学习大体上可分为监督式学习和非监督式学习。简单理解监督式学习就是由人来监督机器学习发过程,而非监督式学习就是指人尽量不参与机器学习的过程。

3.3.1 监督式学习

监督式学习使用的数据都是由输入和预期输出标记的。当我们使用监督式学习训练人工智能时,需要提供一个输入并告诉它预期的输出结果。如果产生的输出结果时错误的,就需要重新调整自己的计算。这个过程将在数据集上不断迭代的完成,知道不再出错。

监督式学习问题通常分为两类,分类与回归,分别对用定性输出与定量输出。它们的区别在于,分类的目标变量时标称型的,而回归的目标变量是连续的。当输出是离散的时候,学习任务就是分类任务。当输出是连续的时候,学习任务就是回归任务。

监督式学习中分类任务的最典型例子就是让计算机来识别圆,矩形和三角形。在训练的时候我们会给计算机提供很多带有标记的图片数据,这些标记表示图片的圆形,矩形,还是三角形。这些数据被认为是一个训练数据集,要等到计算机能偶以可接收的塑速率成功的对图像进行分类之后,训练过程才算结束。而回归任务的最典型例子就是预测,比如预测北京的房价,每套房源是一个样本,样本数据中会包含每个样本的特征,比如房屋面积,建筑年代等,房价就是目标变量,通过拟合房价的曲线预测房价,预测值越接近真实值越好。

3.3.2 非监督式学习

非监督式学习式利用既不分类也不标记的信息进行机器学习,并且允许算法在没有指导的情况下对这些信息进行操作。当使用非监督式学习训练机器时,可以让人工智能对数据进行逻辑分类。这里机器的任务时根据相似性和差异性对未排序的信息进行分组,而不需要事先对数据进行处理。

如果利用非监督式学习让计算机识别圆形,矩形和三角形,那么计算机可以根据图形的边数,两条边之间的夹角等特征将相似的对象分到同一个组以完成分类,这个过程交做聚类分析。聚类分析式提取某一类特征的众所周知的方法。根据数据的特征和关键元素,我们将数据分未未定义的组(集群)。

在聚类分析的过程中,我们将根据大量数据发现一组相似的特征和属性,而不是根据事先明确的特征对数据进行分类。作为被收集的结果,它可以式圆形组或三角形组,再或者是矩形组。但是,人类不可能理解计算机用于分组的特征。聚集这个组的原因可能不是人类对圆形,矩形,三角形的理解。

这种可以从大量数据中找出特征和关键元素的非监督式学习,也可以用于商业领域的趋势分析和未来预测。例如,如果对购买某物品的人进行聚类分析,则可以将某物品作为推荐物品呈现给购买类似物品的人,最近,购物网站通过都有这种人工智能内容推荐的功能。

还有另一种机器学习方法,称为强化学习。像非监督式学习一样,强化学习也没有正确答案的标记。这种方式通过反复试错来推进学习。就像一个人学习如何骑自行车一样,不是简单的知道正确的答案,而是通过反复练习以获取正确的骑行方式。在强化学习的情况下,会通过成功时给予的"奖励"告诉计算机当时的方法是成功的,并使其成为学习的目标。这样的话,计算机会自动的学习以提高成功率。

3.4 scikit-learn模块

scikit-learn模块简称sklearn,是机器学习领域中最知名的Python模块之一。scikit-learn模块主要是用Python编写的,并且广泛使用Numpy模块进行高性能的线性代数和数组运算,具有机器学习所需的回归i,分类,聚类等算法。sklean的官网(scikit-learn: machine learning in Python --- scikit-learn 0.16.1 documentation)有很多机器学习的例子,是学习sklean最好的平台。

3.4.1 sklean模块的安装

sklean模块也是由第三方提供的,因此使用之前需要先安装。在Windows系统中打开cmd命令行工具,然后再其中输入

python 复制代码
pip install scikit-learn

3.4.2 简单的人工神经网络

MLPClassifiershi sklearn模块中的一个监督学习算法,下面我们就利用这个算法搭建并应用一个简单的人工神经网络。

MLPClassifier算法的初始化函数形式如下:

python 复制代码
MLPClassifier(solver='sgd',activation='relu',alpha=le-4,hidden_layer_sizes=(50,50),random_state=1,max_iter=10,learning_rate_init=.1)

solver为权重优化器,可选项由lbfgs,sgd和adam,默认为adam。lbfgs是quasi-Newton方法的优化器,sgd是随机梯度下降优化器,adam是机遇随机梯度优化器。注意,adam在相对较大的数据集上效果比较好(几千个样本或者更多),而对小数据集来说,'lbfgs'收敛更快,效果也更好。

activation为中间层的激活函数,可选项由identity(既f(x)=x),logistic(既f(x)=1/(1+exp(-x))),tanh(既f(x)=tanh(x))和relu(既f(x)=max(0,x)),默认为relu。

alpha为正则化项参数,浮点小数数据类型,可选,默认为0.0001。

hidden_layer_sizes为中间层的大小,元组形式,例如,hidden_layer_sizes=(50,50),表示由两层中间层,第一层中间层由50个神经元,第二层也有50个神经元。

random_state为随机数生成器的状态或种子,可选,默认为None。

max_iter为最大迭代次数,可选,默认200。

learning_rate_init为学习率,用于权重跟小滚,只有当solver为sgd时使用

应用MLPClassifier算法的代码如下:

python 复制代码
 from sklearn.neural_network import MLPClassifier
    x=[[0,0],[1,1],[-2,2],[-1,-2],[2,-1],[-3,-3],[3,2]]
    y=[1,1,2,3,4,3,1]
    clf=MLPClassifier(solver='lbfgs', alpha=1e-5,
                      hidden_layer_sizes=(5,5), random_state=1)
    # 训练
    clf.fit(x,y)

    x1=[[2,3],[-1,2]]
    #预测
    preY1=clf.predict(x1)
    print(preY1)
    print(clf.predict_proba(x1))

人工神经网络的应用步骤大致来说分为三步:

(1)设置学习模型

(2)创建训练数据并进行训练

(3)预测(或识别)

基于这三个步骤,在上面代码的开头,当我们导入MLPClassifier并设置了训练的数据之后,就创建了一个人工神经网络,对应代码为

python 复制代码
clf=MLPClassifier(solver='lbfgs', alpha=1e-5,
                      hidden_layer_sizes=(5,5), random_state=1)

这里权重优化器选择的是lbfgs,另外人工神经网络中间层由两层,两层各由5个神经元。

第二步是进行训练,对应代码为

python 复制代码
 # 训练
    clf.fit(x,y)

由于MLPClassifier是监督式学习算法,所以方法中提供的两个参数是识别的数据余正确答案。这里要识别的是一个包含两个数据的列表,如果将这两个数据看成平面坐标的话,我们可以将正确答案看成坐标所在的象限,既

1,1,2,3,4,3,1

最后一步是进行预测(或识别),需要使用对象的方法predict(),对应代码为:

python 复制代码
 #预测
    preY1=clf.predict(x1)
    print(preY1)

预测的时候需要提供进行预测的数据,每个数据应该都是由两个数据组成的。

最后这段代码通过输出显示预测的结果,同时还通过

python 复制代码
print(clf.predict_proba(x1))

输出预测结果的准确率。

当我们运行程序时,会在PyCharm的控制台中输出如下内容:

1 2

\[9.99988686e-01 1.21846437e-06 3.07665494e-07 9.78742706e-06

2.52684380e-24 1.00000000e+00 4.97139735e-14 4.12132122e-31\]

这意味着第一个数据(由两个数据组成)的预测结果为1,我们可以理解为在第一象限;而第二个数据(由两个数据组成)的预测结果为2,我们可以理解为在第二象限。

之后的输出为预测结果的准确率,对于第一个数据来说,结果为1的概率为9.99988686e-01,结果为2的概率为1.21846437e-06,结果为3的概率为3.07665494e-07,结果为4的概率为9.78742706e-06。第二个数据的准确率类似。

这知识一个简单的例子,没有实际意义,但可以测试人工神经网络是否能够正常运行。如果我们希望增加训练的数据或是增加预测的数据,直接更改代码中里列表的数据即可,不过要注意x中元素的个数要余y中元素的个数一致,这里我们再添加一组训练数据和两个要识别的数据,示例代码如下:

python 复制代码
from sklearn.neural_network import MLPClassifier
    x=[[0,0],[1,1],[-2,2],[-1,-2],[2,-1],[-3,-3],[3,2],[1,-1]]
    y=[1,1,2,3,4,3,1,4]
    clf=MLPClassifier(solver='lbfgs', alpha=1e-5,
                      hidden_layer_sizes=(5,5), random_state=1)
    # 训练
    clf.fit(x,y)

    index=0
    for w in clf.coefs_:
        index+=1
        print("第{}层网络层".format(index))
        print("权重矩阵:",w.shape)
        print("系数矩阵:",w)

    print(clf.classes_)
    print(clf.loss_)
    print(clf.intercepts_)
    print(clf.n_iter_)

    x1=[[2,3],[-1,2],[3,-1],[0,2]]
    #预测
    preY1=clf.predict(x1)
    print(preY1)
    print(clf.predict_proba(x1))

这次我们还输出显示了当前MLPClassifier算法的部分属性,再次运行程序时,再控制台显示如下内容:

第1层网络层

权重矩阵: (2, 5)

系数矩阵: \[ 0.86645505 -3.98126018 -2.8992557 -1.00677431 -2.18071012

-1.60223691 -2.97928158 3.07169059 -1.50494201 0.40756373\]

第2层网络层

权重矩阵: (5, 5)

系数矩阵: \[-1.12724208 2.43462481 -1.09008979 -0.77459746 -0.55581412

-0.84346303 2.73571365 -1.12539402 -0.82130537 1.03829626

0.25589098 0.24811313 -1.08592943 -0.51111393 2.98379991

-1.1704702 2.30631399 -0.81417608 -0.45292752 1.85466385

-0.09639785 0.74392358 0.21953578 -0.74570641 1.81977114\]

第3层网络层

权重矩阵: (5, 4)

系数矩阵: \[ 2.52058093 -0.45970025 -1.09704778 -1.06520098

-0.91156535 -3.04534729 0.81666782 1.57351416

-0.43137177 -0.06859841 -0.32342471 -0.1807975

0.30895555 -0.43039635 -0.20332878 -0.4289019

-1.97562968 2.54829826 0.63395959 -1.90406556\]

1 2 3 4

0.00011112132791645494

array(\[ 0.15192676, -0.49283078, -0.1797305 , -0.03353104, -0.14239677\]), array(\[ 2.43783225, 0.03967731, -1.05473376, -1.57565246, 0.2439457 \]), array(\[ 4.42040974, -0.52889056, -3.26611559, 0.45102454\])

17

2 2 4 2

\[5.04905790e-13 9.99999999e-01 1.22560560e-09 1.28941416e-18

1.93812840e-51 1.00000000e+00 2.47754522e-22 2.29933560e-54

1.74499086e-10 1.71156158e-22 7.73967922e-06 9.99992260e-01

1.66879351e-29 1.00000000e+00 1.27386082e-15 1.60390720e-34\]

这里第一层网络时指输入层与第一层中间层形成的网络,大小为(2,5),之后的系数矩阵就是第一层网络中输入层的第一个神经元与第一层中间层的5个神经元的权重系数,以及第一层网络中输入层的第二个神经元与第一层中间层的5个神经元的权重系数。

之后第二层网络和第三层网络的内容与第一层网络类似。显示了每一层神经网络的权重矩阵之后,还输出了每个输出的类标签,这里就是1,2,3,4还有当前损失值和偏差向量,以及迭代次数17.

最后输出预测数据的结果以及准确率,注意这里变成了4个结果。

3.4.3 简单的短语识别

基于MLPClassifier算法我们可以实现一个本地简单的短语识别程序。

这里要实现的功能是通过程序识别我们说的是"早上好","下午好"还是"晚上好"。实现这以目标的方法是先创建一个人工神经网络并设置学习模型,然后用一系列已分类的语音数据进行训练,最后进行短语的识别。

创建人工神经网络的内容之前已经介绍过了,这里不再赘述,本示例最关键且优先级最高的工作是创建训练数据集。如果我们希望通过程序识别不同人的声音,那么首先需要让不同的人录制短语的音频。这个准备工作我们通过程序来生成训练数据。对于训练用的音频要求如下:

(1)单声道

(2)采样频率11025

(3)音频时长2秒

基于上述要求完成代码如下:

python 复制代码
import pyaudio
import wave
#一次读取数据流的数据量,避免一次性的数据量太大
CHUNK=1024
#采样精度
FORMAT = pyaudio.paInt16
#声道数
CHANNELS=1
#采样频率
RATE=11025
# 录音时长,单位秒
RECORD_SECONDS=2

sampleNum=0
while True:
    cmd=input("输入r开始录音")
    if cmd=="r":
       p=pyaudio.PyAudio()
       stream=p.open(format=FORMAT,channels=CHANNELS,
            	rate=RATE,input=True,frames_per_buffer=CHUNK)
       # 录音开始
       print("录音开始......")
       frames=[]
       for i in range(0,int(RATE/CHUNK*RECORD_SECONDS)):
             data=stream.read(CHUNK)
             frames.append(data)
       #录音结束
       print("录音结束")
       stream.stop_stream()
       stream.close()
       p.terminate()

       wf=wave.open(str(sampleNum)+".wav","wb")
       wf.setnchannels(CHANNELS)
       wf.setsampwidth(p.get_sample_size(FORMAT))
       wf.setframerate(RATE)
       wf.writeframes(b''.join(frames))
       wf.close()
       sampleNum=sampleNum+1
       if sampleNum==5:
            break
     # 对应外层的if
     else:
         print("输入错误")

这段代码中我们增加了一个交互,既只有用户输入字母r才会开始录音并生成一个音频数据,而音频文件保存的位置在.py文件所在文件夹的m1文件夹下,另外这里新建了一个变量sampleNum来保存文件的编号,这个编号就是音频文件的文件名,当编号达到1000时,跳出循环终止程序(既生成1000个训练用的音频文件)。

第一次运行程序时可以找不同的人来说"早上好",生成1000个因我呢见之后程序停止运行,此时可以将所有文件放在名为morning的文件夹下。接着再运行一次程序,这次找不同的人来说"下午好",生成1000个音频文件之后程序停止运行,此时可以将所有文件放在名为afternoon的文件夹下。最后再运行一次程序,这次找不同的人来说"晚上好",同样再生成1000个音频文件之后程序停止运行,此时将所有文件放在名为night的文件夹下。这样训练数据集就建成了。

训练数据准备好之后,接下来完成训练和识别,对应的代码如下:

python 复制代码
	from sklearn.neural_network import MLPClassifier
    import python_speech_features as sf
    import pyaudio
    import wave
    import numpy
    #一次读取数据流的数据量,避免一次性的数据量太大
    CHUNK=1024
    #采样精度
    FORMAT = pyaudio.paInt16
    #声道数
    CHANNELS=1
    #采样频率
    RATE=11025
    #录音时长,单位秒
    RECORD_SECONDS=2
    #音频数据与正确答案,0为早上好,1为下午好,2为晚上好
    voice_data=[]
    voice_id=[]

    #读取"早上好"的数据并提取MFCC特征
    for i in range(0,5):
        #打开WAV文档
        f=wave.open(r"morning//"+str(i)+".wav","rb")
        params=f.getparams()
        nchannels, sampwidth, framerate, nframes =params[:4]

        #读取波形数据
        str_data=f.readframes(nframes)
        f.close()

        #将波形数据转换为数组
        wave_data=numpy.frombuffer(str_data,dtype=numpy.short)
        mfcc=sf.mfcc(wave_data,framerate)

        voice_data.append(mfcc.ravel())
        voice_id.append(0)

    # 读取"下午好"的数据并提取MFCC特征
    for i in range(0, 5):
        # 打开WAV文档
        f = wave.open(r"afternoon//" + str(i) + ".wav", "rb")
        params = f.getparams()
        nchannels, sampwidth, framerate, nframes = params[:4]

        # 读取波形数据
        str_data = f.readframes(nframes)
        f.close()

        # 将波形数据转换为数组
        wave_data = numpy.frombuffer(str_data, dtype=numpy.short)
        mfcc = sf.mfcc(wave_data, framerate)

        voice_data.append(mfcc.ravel())
        voice_id.append(1)

        # 读取"晚上好"的数据并提取MFCC特征
    for i in range(0, 5):
        # 打开WAV文档
        f = wave.open(r"night//" + str(i) + ".wav", "rb")
        params = f.getparams()
        nchannels, sampwidth, framerate, nframes = params[:4]

        # 读取波形数据
        str_data = f.readframes(nframes)
        f.close()

        # 将波形数据转换为数组
        wave_data = numpy.frombuffer(str_data, dtype=numpy.short)
        mfcc = sf.mfcc(wave_data, framerate)

        voice_data.append(mfcc.ravel())
        voice_id.append(2)

    #搭建人工神经网络
    #初始化分类器,增加最大迭代次数,原来为 5,这里修改为 100
    clf=MLPClassifier(hidden_layer_sizes=(500,50),max_iter=100)

    #训练
    clf.fit(voice_data,voice_id)

    while True:
        cmd=input("输入r开始录音并识别")
        if cmd=="r":
            p=pyaudio.PyAudio()
            stream=p.open(format=FORMAT,channels=CHANNELS,
                          rate=RATE,input=True,frames_per_buffer=CHUNK)
            #录音开始
            print("录音开始")
            frames=[]
            for i in range(0,int(RATE/CHUNK*RECORD_SECONDS)):
                data = stream.read(CHUNK)
                frames.append(data)
            #录音结束,开始识别
            print("录音结束,开始识别")
            stream.stop_stream()
            stream.close()
            p.terminate()
            wf = wave.open("mlp.wav","wb")
            wf.setnchannels(CHANNELS)
            wf.setsampwidth(p.get_sample_size(FORMAT))
            wf.setframerate(RATE)
            wf.writeframes(b''.join(frames))
            wf.close()

            f=wave.open("mlp.wav","rb")
            params=f.getparams()
            nchannels, sampwidth, framerate, nframes =params[:4]

            #读取波形数据
            str_data=f.readframes(nframes)
            f.close()

            #将波形数据转换为数组
            wave_data=numpy.frombuffer(str_data,dtype=numpy.short)

            mfcc=sf.mfcc(wave_data,framerate)
            x1=[]
            x1.append(mfcc.ravel())

            #预测
            preY1=clf.predict(x1)
            print(preY1)
            print(clf.predict_proba(x1))
        else:
            print("输入错误")

由于MLPClassifier是监督式学习算法,所以再程序的开始定义了两个变量voice_data和voice_id,分别用来保存数据与正确答案,这里的数据是提取了MFCC特征之后的数据,程序中将这个数据以音频文件为单位i一个个加入数组当中。

训练数据集中有三类数据,所以用三个for循环来分贝读取,0对应"早上好",1对应"下午好",2对应"晚上好"。

接下来就是搭建人工神经网络并完成训练。训练完成后,则进入一个while循环进行短语识别。这里同样有一个输入的交互,既只有用户输入字母r才会开始录音并进行识别,识别的过程是先提取语音的MFCC特征,再对数据进行预测。

程序运行时的输出如下所示:

1

\[5.93627233e-11 5.46079208e-01 4.53920792e-01\]

输入r开始录音并识别r

录音开始

录音结束,开始识别

2

\[2.78178360e-17 8.76533835e-12 1.00000000e+00\]

输入r开始录音并识别r

录音开始

录音结束,开始识别

1

\[5.57214153e-02 9.44278573e-01 1.17663424e-08\]

输入r开始录音并识别

程序刚开始运行的时候,时训练的过程,所以什么也不显示。等待一段时间,模型训练完成,会显示"输入r开始录音并识别"并等待我们输入。当我们输入r后,提示开始录音,此时可以说"早上好","下午好","晚上好"中的任意一句。

提示录音结束之后,程序开始对音频进行识别,最后返回识别的结果以及识别结果的准确率。

如果我们希望获得更直观的反馈,还可以增加以下判断语句。

python 复制代码
            if preY1[0]==0:
                print("你说的是早上好")
            elif preY1[0]==1:
                print("你说的是下午好")
            elif preY1[0]==2:
                print("你说的是晚上好")

至此一个简单的短语识别的程序就完成了。大家也可以尝试添加更多的短语进行识别,比如识别不同的水果名称。

相关推荐
IT_陈寒34 分钟前
Vue这个坑我跳了两次,原来问题出在这
前端·人工智能·后端
新新技术迷1 小时前
Node给AI接口做SSE代理与鉴权
人工智能
redreamSo2 小时前
大模型是不是到顶了?瓶颈到底在哪
人工智能·openai
Oo9202 小时前
Tool Use 背后的技术逻辑
人工智能
姗姗来迟了2 小时前
Vue3封装AI流式对话组件踩坑实录
人工智能
码上天下2 小时前
用Pinia管理AI多会话状态
人工智能
用户054324329703 小时前
Next.js接大模型流式SSE实操踩坑
人工智能
Lihua奏3 小时前
# 机器学习:机器是怎么从数据里学出规则的
机器学习
Assby3 小时前
从 Function Calling 到 MCP:理解 Agent 工具调用的底层通信机制
人工智能·后端
小星AI4 小时前
Claude Code 从入门到精通,一步到位
人工智能