2018-09-07 09:07:22 vn9PLgZvnPs1522s82g 阅读数 1972
  • 深度学习入门及如何转型AI领域

    深度学习入门转型视频教程,该课程主要告诉开发者如何快速入门深度学习。讲师是在机器学习,深度学习神经网络领域多年开发研究经验,精通算法原理与编程实践。曾完成过多项图像识别,目标识别,语音识别的实际项目,经验丰富。关注深度学习领域各种开源项目,如TensorFlow,Caffe,Torch等。喜欢理论与实践相结合的教学风格,课程编排由浅入深,体系清晰完整。

    2654 人正在学习 去看看 CSDN讲师

640?wx_fmt=jpeg


本文来自小鱼在家首席音频科学家邓滨在LiveVideoStackCon 2018讲师热身分享,并由LiveVideoStack整理而成。邓滨认为,传统的信号处理与前沿的深度学习技术结合,才能实现准确的语音交互,缺一不可。


文 / 邓滨

整理 / LiveVideoStack

直播回放:

https://www.baijiayun.com/web/playback/index?classid=18082933304314&session_id=201808300&token=HK8TUrosMf1t681rrJ0J_R1l3G4xGeRN6oakZ-l2IE6PADGtWOcHnW7r6LCYJ0wMkavU9LZ3eZYKp0fXMnVKLQ


大家好,今天与大家分享的是新潮AI硬件中的传统语音信号处理技术。


主要内容分为以下四个部分:


1、智能硬件语音交互的现实障碍

2、什么是语音前处理

3、信号处理 & 深度学习

4、语音前处理的变革演进


1、 智能硬件语音交互的现实障碍


640?wx_fmt=png


上图是美国著名科幻电影《钢铁侠》中的几个场景,可以说这部电影全面展现了未来先进人机语音交互的强大魅力。在电影中,主角托尼·斯塔克拥有一套名叫“贾维斯”的虚拟智能管家,无论是在家中还是户外,抑或是身披战甲时托尼都可随意与其对话并发号施令,而这位虚拟管家的回复之自然如同一位真实存在的伙伴,不仅对命令的理解准确无误,还能对托尼的一些比较无厘头的笑话做出与真人类似的回应,这种强大的交互能力让每一位看过此片的观众都期待能够在现实中也拥有一位这样的虚拟智能管家。实际上依赖当前的科技水平,在真实生活场景中实现如此自然的对话,仍是一件非常困难的事情。本次分享不会涉及太多有关深度学习、神经网络、知识图谱的技术范畴,也不会过多讨论诸如ASR、IOP等有关自然语言理解能力的技术,而是主要关注语音信号的拾取优化,能否进一步提升未来自然语音交互的识别能力。


以《钢铁侠》电影中的场景为例,在实际应用中,人机语音交互面临着诸多复杂的场景:


风噪、机械振动噪声:以钢铁侠战衣飞行为代表的应用场景,战衣飞行的速度越快,其产生的风噪与机械部件摩擦振动的噪声就越严重。


枪林弹雨的爆炸声:以钢铁侠作战为代表的特殊场景,战斗时周围环境中的爆炸声会对拾音系统产生严重干扰。


远场问题:以托尼的豪宅为代表的生活场景,如何保证托尼在宽敞大客厅中任何一个角落向虚拟管家下达的指令都能被准确拾取。


混响问题:以“钢铁侠战衣”的密闭空间为代表的应用场景,此场景中声音会产生反弹折射从而造成混响干扰声音拾取。


回声问题


如果以现实生活场景为例,用户与一个人工智能硬件设备进行人机对话会面临什么样的影响呢?


640?wx_fmt=png


上图展示的是一个包括客厅、书房、阳台、各种家具在内的非常典型的普通家庭场景,其中存在多种能够为语音交互带来干扰的环境因素。例如来自厨房的包括水流声、油烟机噪声、炒菜洗碗杂声在内的各种噪声;客厅中的人交谈说话、儿童游戏打闹的噪声;还有因远场和房间角落造成的混响,房间中的家用电器如空调、风扇、吸尘器、电视、音响等等发出的强烈噪声,窗外传来的包括汽车声、风声、雨声雷声在内的户外噪声等等。即使我们实现了在理想环境中智能语音交互的强大性能,一旦在实际应用中涉及到如远场噪声、回声等问题,人机交互的性能就会急剧下降。


为了进一步验证以上环境因素对智能语音识别系统的影响,我们使用智能音响进行了测试。


640?wx_fmt=png


上图是我们使用世界上最著名的智能音箱之一 Amazon Echo 测试在不同噪声场景下唤醒性能波动的结果,测试方法如下:我们使用一百次100%可用的测试用例(在安静环境中距离设备非常近的条件下播放一百次唤醒指令并确保Echo唤醒成功率为100%。则视此测试用例是可用的),并分别测试了添加七种不同类型噪声:安静、轻音乐、激烈歌曲、新闻联播、雷雨声、客厅综合噪声、厨房综合噪声;同时把声源与Echo之间的距离控制在1m与3.5m两个距离量,进行唤醒测试并统计其唤醒成功率。通过测试可以发现,在安静的环境中,距离Echo 1m时唤醒成功率可保持91%左右,3.5m时则下降到72%;而在后续各种不同噪声环境中,Echo的唤醒性能急剧下降。实验结果基本验证了之前的推测:真实生活场景中的各种环境条件,的确会对人机交互识别造成不利影响。除了Amazon Echo,我们还测试了Google Home以及国内的一些智能助手。除了以上环境变量之外,我们还选择了回声、远场、混响、不同角度等干扰场景,得到的性能曲线都是类似的。


综上所述,生活中的种种干扰因素一定会对人机语音交互的性能造成很大的不利影响,而某些干扰因素就目前技术而言,是无法从根本上解决的。如果将近场、无噪声、无回声、无混响等理想环境下的语音识别作为天花板,那么不同厂商探索的在干扰环境下的高性能语音识别方案,则是致力于如何在恶劣环境下更接近这层天花板。


2、 什么是语音前处理


接下来介绍的技术是语音前处理。这种技术从何而来?因何而生的?其意义是什么?


2.1 原理


640?wx_fmt=png


我们所谓的人机语音交互实际上是一种仿生模拟,上图第一条路径表示的是人类通过生理器官进行拾音的过程。人耳的生理构造包括耳廓、耳道、鼓膜等,外界的声波传播至耳朵,耳廓收集声波后通过耳道将其传播至鼓膜并引起鼓膜振动,鼓膜振动使声音信号通过听觉神经传递至大脑,并由大脑对接收到的声音进行辨别。这里需要强调的是,人的生理器官具有多种处理能力,例如人的耳廓与耳道具备滤波器的功能,而鼓膜与听觉神经则负责将信号放大,从而易于在声音中提炼有效信息;接下来的高级神经与大脑则具备了声纹识别、自然语言理解等语音识别的功能,最终经过大脑分捡出的有效信息则指导人类根据语言理解驱动正常的行为。


第二条路径表示的是机器进行声音拾取的过程,首先需要用于声音拾取的麦克风,在这里麦克风拾取的是模拟信号,系统需通过信号处理对模拟信号进行模数转换,从而获得声音的数字信号;与人类听觉系统类似,接下来通过数字信号领域的一系列放大、降噪、回声一致等处理,声音的清晰度与信噪比会得到显著提升,最终这些声学数字信号会被传输至机器的大脑,如深度学习或自然语言理解系统从而被转换成机器可以理解的指令。与人类的听觉系统不同,这里的麦克风明显不具备人耳的耳廓、耳道等特性,无法对声音信号进行有效的前期处理,只能最大限度地实现不失真拾音。因此我们需要在麦克风拾取原始声音的基础上进行相应的优化也就是语音“前”处理,才能得到有利于机器学习理解辨识并作出正确反馈的声学信号。


2.2 意义


640?wx_fmt=png


为什么需要语音“前”处理?上图表示一个比较典型的语音信号处理过程:首先,我们将麦克风拾取声音信号的过程称为“听到”,此过程的作用是将声音信息由声波形式转换成数字信号形式;随后声音信息被传输至“语音信号处理”模块,此语音数字信号处理模块的功能是“听清”,也就是对接收到的声音信号进行清晰化处理;经过清晰化处理之后的声音信号会被继续传输至文字信息识别系统,我们将文字信息识别系统中的处理过程称为“听懂”——从“听到”、“听清”到“听懂”的整体流程就是机器模拟人听觉生理活动的过程。在“听懂”部分,系统首先会对信号中的声学特征进行提取,随后根据之前整个深度学习系统经过大量标准语言训练训练得到的声学模型与语音模型进行匹配与解码,最终得到一个较为准确的文字识别结果。如果在“听到”阶段没有清晰拾得目标音频,麦克风拾取到的信号中就会包含我们上文介绍到的各种恶劣环境影响因子例如混响声音、外界噪声、回声、远场声音、衰减声音等等,倘若不处理这些混有噪音的声音信号而是直接将其送到文字识别系统就难以根据之前的标准语言训练得到的声学模型对目标声音进行识别与匹配,识别效果一定会大打折扣。因而我们必须在其中添加一个“听清”的过程,在语音识别之前加入语音信号处理模块,通常我们会把这部分流程我们称为“语音前处理”。


3、 信号处理VS深度学习


接下来我将会讲述信号处理与深度学习的关系。可以说这两者中的前者算是传统学科,后者算是前沿学科。首先需要提出以下几个问题:深度学习+大数据能否解决所有的语音干扰问题?深度学习时代的前端数字信号处理技术是否已经过时?深度学习是数字信号处理的终结吗?仅针对干扰的模型训练能够有效识别并去除干扰吗?之前我参与了有关深度学习时代信号处理没有意义的讨论,对此观点的结论是否定的。


为什么深度学习不可能代替信号处理?我们在现实生活中面临以下几大问题:


第一大问题是噪声问题。噪声分为平稳噪声与非平稳噪声,平稳噪声指的是特性相对平稳,以日常生活中的一些如白噪声、驾驶汽车匀速行驶时发动机的声音、风噪等频率特性、时变特性比较平稳的理想噪声为例;而非平稳噪声则与之相反,比较典型的例子是人说话声、KTV音乐等等。


第二大问题是回声问题,例如一个智能音箱正在播放歌曲,此时音响上的麦克风也正在工作并处于随时等待被主人唤醒的待命状态。这时,用户会希望与智能音箱进行语音交互时麦克风不会混淆拾取到的自己发出的指令声与音响喇叭放出的音乐声,此时对于用户发出的语音指令来说此音箱喇叭发出的声音就被称为“回声”;在实践中音响必须滤除此回声并保留来自用户有效的指令声才能对用户的指令做出正确反应。也许有些人会认为这与噪声类似,实际上二者并不一样,处理方法也不尽相同。


第三大问题是远场问题。用户距离智能音响比较近时可获得较为准确的语音识别体验;而一旦用户距离智能音响较远,其语音交互的性能就会急剧下降并影响用户使用智能音箱的良好体验。


第四大问题是混响问题。当将此设备摆放在墙角或较为空旷的房间时,用户发出的有效指令声经过此房间的墙壁折射反弹多次后被设备的麦克风拾取,麦克风会收到混合在一起的多个不同时间延迟下的指令声音,这种混响多次的指令也会为语音识别带来巨大干扰。


第五大问题是声音定位。围绕在此设备周围360度空间内的任何方位都有可能成为用户指令的声源位置,声音定位的目的就是瞄准用户指令声源所在的角度并进行波束集中,有效提高声音拾取的准确性。


那么这些问题可以用深度学习来有效解决吗?


640?wx_fmt=png


平稳噪声:可以解决


方法是针对一个干扰模型进行大量训练。例如在训练最初时向语音识别系统输入大量加噪的语料,这里的“加噪”是指加入明确希望去除的噪声类型如风噪、汽车噪声等。将此噪声提前模拟并加入训练后得到的识别系统可准确识别此噪声的声学特性,这样就可得到能够识别并处理真正含有此噪声语料的语音识别系统,增强它的鲁棒性,更有效地去除平稳噪声对有效语音的影响。


非平稳噪声:部分解决


即使绝大多数非平稳噪声无法被捕捉特性,但仍然存在少量非平稳噪声可被捕捉到特性,我们可以通过深度学习训练解决这部分非平稳噪声的干扰问题。


混响问题:部分解决


如果我们确定了某房间的混响模型,例如这间房间的空旷程度、长宽高、墙壁的材质、设备在房间中摆放的位置等,那么声音在此房间中传递、反弹再传递到设备的时长、混响效果与混响模型就是确定的,就能将其结合深度学习从而解决混响问题;如果这些场景发生了改变,那么相对应的混响模型就需要进行改变。


综上所述,深度学习可以解决平稳噪声问题与部分非平稳噪声和混响问题,但是丰富其语料模型从而达到良好训练效果的工作量很大;而通过深度学习并不能妥善解决并不具备恒定特性的远场、回声与声源定位问题,我们无法从这三者中提取有价值的模型特征的。语音识别问题归根结底是信噪比问题,我们可以把所有的干扰都视为影响原始语音信号信噪比的噪声,当信噪比不佳时系统无法从声音中提取有效信号的声音模型,语音识别就无法成功。


4、 语音前处理的变革演进


讲完了语音信号处理的前世,接下来我们谈一谈语音信号处理的今生。想必大家听完之前的分享,心中可能会产生一个疑问:我们知道语音信号处理是一个有着近百年历史的传统技术,那么传统的语音信号处理技术能否直接完美地运用于人机语音交互呢?


640?wx_fmt=png


我们熟知的语音信号处理主要被应用于通信系统,而通信系统的设备处于一个较为可控的应用场景中,例如从最早的座机、固定电话到现在的移动电话,而移动电话也是从模拟信号发展到到数字电话时代,整体主要服务于包括军用步话机在内的通信场景。我们以手机为例,手机有四种通讯模式:手持、免提、插线耳机以及蓝牙耳机。对于语音信号处理来说,经过业界几十年的探索,这几种模式的发展都比较成熟,大家已经摸索出了应对这几种通讯模式较为典型的语音算法,例如免提模式下如何降噪,手持模式下可用手机多个麦克风进行降噪等。


业界应对这些传统方式都有比较成熟的方案,但是面对现在以智能音箱为例的新型人工智能硬件设备来说,其与手机的结构和应用场景完全不同,手机主要用于近场通讯,但智能音箱主要运用在中远距离通讯,且智能音箱上喇叭的功率与其播放的声音强度比手机高很多;使用距离较远就存在我之前提到的远场声音问题,与此同时麦克风所能识别到用户的指令音量也会更小而回声却会更恶劣;由于智能音箱摆放位置的多样性,其需要面临的混响环境也会更加复杂;即使智能音箱具备多个麦克风,但由于其是作为一个远场设备,我们无法使用副麦进行降噪处理。有信号处理经验的同学可能对此会比较了解,副麦降噪依赖于手持模式下主麦在用户嘴边而副麦在手机背面,只有当主麦副麦之间拾音差异在6dB以上才能实现副麦降噪,那么对于远场设备来说副麦降噪并无理论基础。


除了以上新型智能音箱人机对话与传统通讯工具手机电话之间的明显差异,人脑对语言的理解与机器之间也存在不小差异。传统的通信是人与人之间的交流,而语音识别则是人与机器之间的交流,二者本质上存在很大差别。任何的信号处理过程都会破坏语音信号声学特性,也许人能够成功识别这种破坏后的信息但机器却无法处理。因而我们需要在传统通信的语音信号处理基础上进行改进和创新,特别优化匹配语音识别的特性要求,从而让人工智能硬件既能听清楚也能讲明白,这也是所有人工智能硬件厂家核心科技之所在。


总结来说,就是从前端的信号处理与后端的识别两个层面进行系统性的综合优化,才能实现我们期待的与人工智能自然交流的美好愿景。


Q&A


Q:前端使用哪些去噪算法?


A:通常降噪有以下几类方法:


1)滤波器降噪:一种较为典型的方案,主要通过如维纳滤波这样的自适应滤波对声音进行降噪。


2)主副麦降噪:主要运用于手机等手持模式上,使用位于手机下方的主麦克风与手机背面的副麦克风进行降噪。


当用户使用手持模式拨打电话时主麦靠在嘴边而副麦朝向外界,当外界环境充斥噪声时主麦玉副麦都会收到有效语音与噪声的混合声音,但对比两个麦克风,主麦收到用户的有效语音信号更强而副麦收到外界的噪声更强,使用谱减法将主麦收到的声音减去副麦的噪声,留下的就是有效信号;再放大有效信号即可得到清晰的语音。而智能硬件无法使用副麦降噪,如果使用单麦那么我们可借助滤波与噪声估计,用估计出噪声的频谱与此噪声对比,并使用普减法从原始信号中消除噪声频谱。在这里需要强调的是我们的降噪处理最终的接收对象是谁。如果是给机器则不能破坏原始语音的声学特征,需要把降噪控制在一定的程度内。


Q:远场单通道降噪对于收益率有何影响?


A:两年前我们的小鱼在家产品就使用了单麦克风并实现降噪与语音信号放大、回声抑制、远场增强等一系列功能,提升十分明显。我们曾使用讯飞的语音识别引擎与标准接口进行对比实验,在没有添加任何其他处理算法的情况下使用讯飞识别引擎测试近场拾音,其准确率可达到100%,一旦将距离增加到1m~3m的远场,识别率会大幅度降低至50%~10%;而如果加上远场单通道语音增强算法,可将3m时10%的准确率提升至70%左右,收益十分明显。单麦算法的使用需要结合不同场景,如果现在绝大多数智能音箱为了比拼识别准确率都用麦克风阵列,在成本上则会带来很大压力,单麦算法在小型设备或低成本设备的应用前景十分广阔。


Q:智能音箱的扬声器音量是否不能过大,否则会造成强非线性影响AEC?


A:是的,这涉及到硬件的选型问题。我们知道较昂贵的扬声器其声音特性也会更出色,主要体现在线性优秀、底噪更低、失真更小、信噪比更高等。但由于受到产品的限制我们往往无法选择性能如此优秀的扬声器,因而扬声器的播放响度控制在不失真的范围内。如果一味地追求声音大而使播放出的声音信号被麦克风吸收使得频谱失真或造成非常强的非线性,那么从算法层面上来说很难解决由此带来的影响。我认为应该尽可能调试好扬声器的声学参数或从硬件选型进行控制从而达到一个音量与音质的平衡。



640?wx_fmt=jpeg

2019-05-28 22:30:40 david_tym 阅读数 796
  • 深度学习入门及如何转型AI领域

    深度学习入门转型视频教程,该课程主要告诉开发者如何快速入门深度学习。讲师是在机器学习,深度学习神经网络领域多年开发研究经验,精通算法原理与编程实践。曾完成过多项图像识别,目标识别,语音识别的实际项目,经验丰富。关注深度学习领域各种开源项目,如TensorFlow,Caffe,Torch等。喜欢理论与实践相结合的教学风格,课程编排由浅入深,体系清晰完整。

    2654 人正在学习 去看看 CSDN讲师

上篇博客(语音识别传统方法(GMM+HMM+NGRAM)概述)说到我们team要做语音识别相关的项目,而我们公司的芯片是用在终端上的,即我们要做终端上的语音识别。由于目前终端(如手机)上的CPU还不足够强劲,不能让语音识别的各种算法跑在终端上,尤其现在语音识别都是基于深度学习来做了,更加不能跑在终端上,所以目前主流的语音识别方案是声音采集和前处理在终端上做,语音识别算法则放在服务器(即云端)上跑。虽然这种方案有泄漏隐私(把终端上的语音数据发给服务器)和没有网络不能使用等缺点,但也是不得已而为之的,相信在不久的将来等终端上的CPU足够强劲了会把语音识别的所有实现都放在终端上的。

 

是不是意味着终端上做不了语音识别相关的算法了?其实也不是,语音唤醒功能是需要在终端上实现的。语音唤醒是指设定一个唤醒词,如Siri的“Hi Siri”,只有用户说了唤醒词后终端上的语音识别功能才会处于工作状态,否则处于休眠状态。这样做主要是为了降功耗,增加续航时间。目前很多终端都是靠电池供电的,对功耗很敏感,是不允许让语音识别功能一直处于工作状态的。为此我就对语音唤醒技术做了一番调研。依旧是看各种文档和博客,然后进行梳理和总结,形成PPT,给组内同学介绍。在此我也把PPT贴出来,给有需要或感兴趣的朋友看看,有什么不正确的也请指正。我的PPT中的一些图是用的文档或他人博客里的,谢谢这些原作者。以下就是我的关于语音唤醒技术的PPT。

 

 

2018-07-27 09:49:50 haoyutiangang 阅读数 935
  • 深度学习入门及如何转型AI领域

    深度学习入门转型视频教程,该课程主要告诉开发者如何快速入门深度学习。讲师是在机器学习,深度学习神经网络领域多年开发研究经验,精通算法原理与编程实践。曾完成过多项图像识别,目标识别,语音识别的实际项目,经验丰富。关注深度学习领域各种开源项目,如TensorFlow,Caffe,Torch等。喜欢理论与实践相结合的教学风格,课程编排由浅入深,体系清晰完整。

    2654 人正在学习 去看看 CSDN讲师

Part 2: 触发字检测

关键词语音唤醒

触发字检测

欢迎来到这个专业课程的最终编程任务!

在本周的视频中,你了解了如何将深度学习应用于语音识别。在本作业中,您将构建一个语音数据集并实现触发字检测算法(有时也称为关键字检测或唤醒检测)。触发字检测技术,可以让亚马逊Alexa,Google Home,Apple Siri和百度DuerOS等设备在听到某个词语时进行唤醒。

本练习中,我们的触发词将是“Activate”。每当它听到你说“Activate”时,它就会发出“chiming”声音。在此作业结束时,您将能够录制自己正在讲话的片段,并在算法检测到您说出“chiming”时让算法触发一次钟声。

完成作业后,也许你还可以扩展到笔记本电脑上运行,这样每当你说“chiming”它启动你最喜欢的应用程序,或打开你家的网络连接灯,或触发一些其他事件。

image

本作业中,你将学到

  • 构建一个语音识别项目
  • 合成和处理音频记录以创建训练/开发测试集
  • 训练触发字检测模型并进行预测

导包

import numpy as np
from pydub import AudioSegment
import random
import sys
import io
import os
import glob
import IPython
from td_utils import *
%matplotlib inline

1 数据合成:创建语音数据集

首先为触发字检测算法构建一个数据集。 理想情况下,语音数据集尽可能接近您希望运行的应用程序。 在这种情况下,您希望在工作环境(图书馆,家庭,办公室,开放空间等)中检测到“activate”一词。 因此,您需要在不同的背景声音中混合使用正面词语(“activate”)和负面词语(除activate以外的随机词)。 我们来看看如何创建这样一个数据集。

1.1 聆听数据

你的朋友正在帮助你完成这个项目,并且他们已经去过遍布该地区的图书馆,咖啡馆,餐馆,家庭和办公室,以记录背景噪音,以及人们说正面/负面词汇的片段的片段。 这个数据集包括以各种口音说话的人。

在raw_data目录中,您可以找到正面单词,负面单词和背景噪音的原始音频文件的子集。 您将使用这些音频文件合成数据集来训练模型。 “activate”目录包含说“activate”的人的正面例子。 “negatives”目录包含说除“activate”以外的随机单词的反面例子。 每个音频记录有一个词。 “backgrounds”目录包含步同环境下的背景噪音的10s的剪辑。

聆听样例数据

IPython.display.Audio("./raw_data/activates/1.wav")
IPython.display.Audio("./raw_data/negatives/4.wav")
IPython.display.Audio("./raw_data/backgrounds/1.wav")

你将使用这三种类型的音频数据创建标签数据集。

1.2 从录音到声谱图

什么是录音? 麦克风随着时间的推移记录气压的微小变化,正是这些气压的微小变化让你的耳朵感觉到了声音。 你可以想象一个录音是一个长长的数字列表,用于测量麦克风检测到的微小气压变化。 我们将使用以44100赫兹采样的音频。 这意味着麦克风每秒给我们44100个数字。 因此,10秒音频剪辑由441000个数字(= 10×44100)表示。

从这个音频的原始数据表示中找出是否包含“activate”这个词是相当困难的。 为了帮助你的序列模型更容易学习检测触发字,我们将计算音频的谱图。 频谱图告诉我们一段时间内音频片段中存在多少不同的频率。

(如果你曾经学习过信号处理或傅里叶变换上的课程,频谱的计算时通过在原始音频信号上滑动窗口计算的,并使用傅立叶变换计算每个窗口中最活跃的频率。 如果你不理解前面的句子,也不用担心。)

让我们看一个例子:

IPython.display.Audio("audio_examples/example_train.wav")
x = graph_spectrogram("audio_examples/example_train.wav")

image

上面的图表表示每个频率(y轴)在各个时间步(x轴)上的活动情况。

image

上图是音频记录的频谱图,其中颜色显示的是不同时间点音频不同频率的程度。 绿色方块意味着音频片段中的某个频率更加活跃(声音更响亮); 蓝色方块表示较少的活动频率。

输出谱图的维度取决于谱图软件的超参数和输入的长度。 在本文中,我们将使用10秒音频剪辑作为我们培训示例的“标准长度”。 频谱图的时间步数将为5511.稍后你会看到频谱图作为输入X给带网络中,因此Tx = 5511。

_, data = wavfile.read("audio_examples/example_train.wav")
print("Time steps in audio recording before spectrogram", data[:,0].shape)
print("Time steps in input after spectrogram", x.shape)

# Time steps in audio recording before spectrogram (441000,)
# Time steps in input after spectrogram (101, 5511)

现在你可以定义:

Tx = 5511 # The number of time steps input to the model from the spectrogram
n_freq = 101 # Number of frequencies input to the model at each time step of the spectrogram

注意: 即使10秒作为我们默认的训练示例长度,也可以将10秒的时间离散为不同的数值。 你已经看过441000(原始音频)和5511(频谱图)。 在前一种情况下,每个时间步代表10/441000≈0.000023秒。 在第二种情况下,每个时间步代表10/5511≈0.0018秒。

对于10s的音频,关键的值有:

  • 441000(原始音频)
  • 5511=Tx(频谱图输出,也是神经网络输入的维度)
  • 10000(由pydub模块用于合成的音频)
  • 1375=Ty(即将构建的GRU的输出时间步的数量)

注意: 每一个样本恰好10秒的时间,被不同类型进行离散化。这些都是超参数,可以更改(除了441000,这是麦克风的功能)。 这里选择了语音系统标准范围内的值。

比如Ty = 1375意味着对于模型的输出,我们将10秒离散成1375个时间间隔(每个长度为10 /1375≈0.0072秒),并尝试预测这些时间间隔是否最近有人说过“activate”。

又如上面的10000这个数字,将10秒剪辑离散化为10/10000 = 0.001秒的间隔。 0.001秒也被称为1毫秒 所以当我们说按照1ms间隔进行离散化时,这意味着正在使用10,000步。

Ty = 1375 # The number of time steps in the output of our model

1.3 生成一个训练示例

由于语音数据很难获取和标记,因此您将使用正向、反向和背景的音频剪辑合成训练数据。 记录大量10秒的随机“activates”音频剪辑是很慢的。 相反,记录大量正向和反向词汇,并单独记录背景噪音(或从免费在线渠道下载背景噪音)更容易。

为了合成一个训练样本,你需要:

  • 随机选择一个10秒的背景音频剪辑
  • 随机将0-4个正向音频片段插入此10秒剪辑中
  • 随机将0-2个反向音频片段插入此10秒剪辑中

因为您已将“activates”一词合成到背景剪辑中,所以您确切知道10秒剪辑中何时出现“activates”。 稍后您会看到,这样也更容易生成标签y⟨t⟩。

您将使用pydub软件包来处理音频。 Pydub将原始音频文件转换为Pydub数据结构列表(这里了解细节并不重要)。 Pydub使用1ms作为离散化间隔(1ms是1毫秒= 1/1000秒),这就是为什么10秒剪辑总是使用10,000步表示的原因。

# Load audio segments using pydub 
activates, negatives, backgrounds = load_raw_audio()

print("background len: " + str(len(backgrounds[0])))    # Should be 10,000, since it is a 10 sec clip
print("activate[0] len: " + str(len(activates[0])))     # Maybe around 1000, since an "activate" audio clip is usually around 1 sec (but varies a lot)
print("activate[1] len: " + str(len(activates[1])))     # Different "activate" clips can have different lengths 

# background len: 10000
# activate[0] len: 916
# activate[1] len: 1579

在背景上覆盖正面/负面的词语

给定一个10秒的背景剪辑和一个短的音频剪辑(正面或负面的单词),您需要能够将单词的短片段“添加”或“插入”背景。 为确保插入到背景上的音频片段不重叠,需要跟踪以前插入的音频片段的时间。 您将在背景中插入多个正面/负面单词剪辑,并且不希望插入有重叠。

为了清楚起见,当您在咖啡厅噪音的10秒剪辑中插入1秒“activate”时,最终会出现10秒的剪辑,听起来像某人在咖啡厅中说“activate”。你不会以11秒的剪辑结束。 稍后你会看到pydub如何让你做到这一点。

在插入的同时创建标签

回想一下,标签y⟨t⟩表示某人是否刚说完“activate”。给定一个背景剪辑,我们可以初始化所有t的y⟨t⟩= 0,因为该剪辑不包含任何“activate”。

当你插入或覆盖“activate”剪辑时,您还将更新yt的标签,以便输出的50个步骤具有目标标签1.您将训练GRU以检测某人何时说完“激活”。 例如,假设合成的“activate”剪辑在10秒音频中的5秒处结束 - 恰好在剪辑的中途。 回想一下Ty = 1375,所以时间步长687 = int(1375 * 0.5)对应于5秒进入音频的时刻。 所以,你会设置y688= 1。 此外,如果GRU在短时间内在任何时间内检测到“activate”,那么在此时刻之后,您会非常满意,所以我们实际上将标签yt的50个连续值设置为1.具体来说,我们有y688=y689==y737=1

这是合成训练数据的另一个原因:上面描述的生成这些标签y⟨t⟩比较简单;相反,如果在麦克风上录制了10秒的音频,那么听到该音频并且在“activate”完成时手动标记是非常耗时的。

下面是一张插图,展示了插入“activate”,“innocent”,“activate”,“baby” 的剪辑的标签y⟨t⟩。请注意,正面标签“1”仅与正面字词相关。

image

要实现训练集合成过程,您将使用以下辅助函数。 所有这些功能将使用1ms离散化间隔,所以10秒的音频总是被离散化为10,000步。

  1. get_random_time_segment(segment_ms) 从背景音频中获取随机时间片段
  2. is_overlapping(segment_time, existing_segments) 检查时间片是否与另一个时间片重叠
  3. insert_audio_clip(background, audio_clip, existing_times) 使用 get_random_time_segment 和 is_overlapping 在背景音频的随机时间处插入一个音频时间片
  4. insert_ones(y, segment_end_ms) 在”activate”之后插入1到标签向量 y 中

get_random_time_segment(segment_ms) 方法返回一个可以插入segment_ms的随机时间片。

阅读如下代码理解在做什么。

def get_random_time_segment(segment_ms):
    """
    Gets a random time segment of duration segment_ms in a 10,000 ms audio clip.

    Arguments:
    segment_ms -- the duration of the audio clip in ms ("ms" stands for "milliseconds")

    Returns:
    segment_time -- a tuple of (segment_start, segment_end) in ms
    """

    segment_start = np.random.randint(low=0, high=10000-segment_ms)   # Make sure segment doesn't run past the 10sec background 
    segment_end = segment_start + segment_ms - 1

    return (segment_start, segment_end)

接下来,假设您在(1000,1800)和(3400,4500)处插入了音频剪辑。 即,第一段从步骤1000开始,并在步骤1800结束。
现在,如果考虑在(3000,3600)处插入新的音频剪辑,它是否与先前插入的段之一重叠? 在这种情况下,(3000,3600)和(3400,4500)重叠,所以不能在这里插入剪辑。

这个函数的目的是:(100,200)和(200,250)是重叠的,因为它们在时间步200重叠。但是,(100,199)和(200,250)是不重叠的。

练习:实现 is_overlapping(segment_time, existing_segments)

检查新的时间片是否与之前的任意时间片有重叠。这需要两步:
1. 创建”false”标签,稍后如果有重叠则置为”true”
2. 浏览之前插入时间片的开始和结束时间,比较与新时间片是否有重叠,如果有则将标签置为”true”。

for ....:
        if ... <= ... and ... >= ...:
            ...

提示:如果新的时间片在上一个时间片结束之前开始,或者在下一个时间片开始之后结束,都是有重叠。

# GRADED FUNCTION: is_overlapping

def is_overlapping(segment_time, previous_segments):
    """
    Checks if the time of a segment overlaps with the times of existing segments.

    Arguments:
    segment_time -- a tuple of (segment_start, segment_end) for the new segment
    previous_segments -- a list of tuples of (segment_start, segment_end) for the existing segments

    Returns:
    True if the time segment overlaps with any of the existing segments, False otherwise
    """

    segment_start, segment_end = segment_time

    ### START CODE HERE ### (≈ 4 line)
    # Step 1: Initialize overlap as a "False" flag. (≈ 1 line)
    overlap = False

    # Step 2: loop over the previous_segments start and end times.
    # Compare start/end times and set the flag to True if there is an overlap (≈ 3 lines)
    for previous_start, previous_end in previous_segments:
        if segment_start <= previous_end and segment_end >= previous_start:
            overlap = True
    ### END CODE HERE ###

    return overlap

####################################################

overlap1 = is_overlapping((950, 1430), [(2000, 2550), (260, 949)])
overlap2 = is_overlapping((2305, 2950), [(824, 1532), (1900, 2305), (3424, 3656)])
print("Overlap 1 = ", overlap1)
print("Overlap 2 = ", overlap2)

Overlap 1 =  False
Overlap 2 =  True

期待的输出

key value
Overlap 1 False
Overlap 2 True

现在,我们随机将一个新的音频片段插入到10秒的背景中,但要确保任何新插入的片段都不会与之前的片段重叠。

练习:实现 insert_audio_clip()

将一个新的音频片段插入到10秒的背景中,你需要完成4步:

  1. 以毫秒为单位获取随机时间段。
  2. 确保时间段与前面的任何时间段都不重叠;如果重叠,则返回步骤1并选择新的时间段。
  3. 将新时间段添加到现有时间段列表中,以跟踪插入的所有时间段。
  4. 使用pydub将音频剪辑覆盖在背景上(我们已经为你实现了这个方法)。
# GRADED FUNCTION: insert_audio_clip

def insert_audio_clip(background, audio_clip, previous_segments):
    """
    Insert a new audio segment over the background noise at a random time step, ensuring that the 
    audio segment does not overlap with existing segments.

    Arguments:
    background -- a 10 second background audio recording.  
    audio_clip -- the audio clip to be inserted/overlaid. 
    previous_segments -- times where audio segments have already been placed

    Returns:
    new_background -- the updated background audio
    """

    # Get the duration of the audio clip in ms
    segment_ms = len(audio_clip)

    ### START CODE HERE ### 
    # Step 1: Use one of the helper functions to pick a random time segment onto which to insert 
    # the new audio clip. (≈ 1 line)
    segment_time = get_random_time_segment(segment_ms)

    # Step 2: Check if the new segment_time overlaps with one of the previous_segments. If so, keep 
    # picking new segment_time at random until it doesn't overlap. (≈ 2 lines)
    while is_overlapping(segment_time, previous_segments):
        segment_time = get_random_time_segment(segment_ms)

    # Step 3: Add the new segment_time to the list of previous_segments (≈ 1 line)
    previous_segments.append(segment_time)
    ### END CODE HERE ###

    # Step 4: Superpose audio segment and background
    new_background = background.overlay(audio_clip, position = segment_time[0])

    return new_background, segment_time

#######################################################

np.random.seed(5)
audio_clip, segment_time = insert_audio_clip(backgrounds[0], activates[0], [(3790, 4400)])
audio_clip.export("insert_test.wav", format="wav")
print("Segment Time: ", segment_time)
IPython.display.Audio("insert_test.wav")

# Segment Time:  (2254, 3169)

期待的输出

key value
Segment Time (2254, 3169)
# Expected audio
IPython.display.Audio("audio_examples/insert_reference.wav")

最后,假设你刚刚插入一个“activate”,实现代码来更新标签yt。在下面的代码中,y是一个(1,1375)维向量,因为Ty = 1375。

如果“activate”在时间步骤t结束,则设置yt+1=y<t+2>=y<t+50>个连续值,但是Ty = 1375,注意 y<t+m> 不能越界。

练习:实现 insert_ones()

你可以使用for循环。
(如果你是python的slice操作的专家,也可以使用切片来将其向量化)。
如果一个段在segment_end_ms处结束(使用10000步离散化),将其转换为输出y的索引(使用1375步离散化),我们将使用这个公式:

segment_end_y = int(segment_end_ms * Ty / 10000.0)

代码

# GRADED FUNCTION: insert_ones

def insert_ones(y, segment_end_ms):
    """
    Update the label vector y. The labels of the 50 output steps strictly after the end of the segment 
    should be set to 1. By strictly we mean that the label of segment_end_y should be 0 while, the
    50 followinf labels should be ones.


    Arguments:
    y -- numpy array of shape (1, Ty), the labels of the training example
    segment_end_ms -- the end time of the segment in ms

    Returns:
    y -- updated labels
    """

    # duration of the background (in terms of spectrogram time-steps)
    segment_end_y = int(segment_end_ms * Ty / 10000.0)

    # Add 1 to the correct index in the background label (y)
    ### START CODE HERE ### (≈ 3 lines)
    for i in range(segment_end_y+1, segment_end_y+51):
        if i < Ty:
            y[0, i] = 1.0
    ### END CODE HERE ###

    return y

####################################################

arr1 = insert_ones(np.zeros((1, Ty)), 9700)
plt.plot(insert_ones(arr1, 4251)[0,:])
print("sanity checks:", arr1[0][1333], arr1[0][634], arr1[0][635])

# sanity checks: 0.0 1.0 0.0

image

最后,你可以使用insert_audio_clip 和 insert_ones 创建一个新的训练样本。

练习:实现 create_training_example()
  1. 将标签向量y初始化为零值的(1,Ty)numpy数组
  2. 将已存在时间片集合初始化为空列表。
  3. 随机选择0至4个“activate”音频剪辑,并将其插入10秒剪辑,记着将标签插入标签向量y中的正确位置
  4. 随机选择0到2个负面音频片段,并将它们插入10秒片段。
# GRADED FUNCTION: create_training_example

def create_training_example(background, activates, negatives):
    """
    Creates a training example with a given background, activates, and negatives.

    Arguments:
    background -- a 10 second background audio recording
    activates -- a list of audio segments of the word "activate"
    negatives -- a list of audio segments of random words that are not "activate"

    Returns:
    x -- the spectrogram of the training example
    y -- the label at each time step of the spectrogram
    """

    # Set the random seed
    np.random.seed(18)

    # Make background quieter
    background = background - 20

    ### START CODE HERE ###
    # Step 1: Initialize y (label vector) of zeros (≈ 1 line)
    y = np.zeros((1, Ty))

    # Step 2: Initialize segment times as empty list (≈ 1 line)
    previous_segments = []
    ### END CODE HERE ###

    # Select 0-4 random "activate" audio clips from the entire list of "activates" recordings
    number_of_activates = np.random.randint(0, 5)
    random_indices = np.random.randint(len(activates), size=number_of_activates)
    random_activates = [activates[i] for i in random_indices]

    ### START CODE HERE ### (≈ 3 lines)
    # Step 3: Loop over randomly selected "activate" clips and insert in background
    for random_activate in random_activates:
        # Insert the audio clip on the background
        background, segment_time = insert_audio_clip(background, random_activate, previous_segments)
        # Retrieve segment_start and segment_end from segment_time
        segment_start, segment_end = segment_time
        # Insert labels in "y"
        y = insert_ones(y, segment_end)
    ### END CODE HERE ###

    # Select 0-2 random negatives audio recordings from the entire list of "negatives" recordings
    number_of_negatives = np.random.randint(0, 3)
    random_indices = np.random.randint(len(negatives), size=number_of_negatives)
    random_negatives = [negatives[i] for i in random_indices]

    ### START CODE HERE ### (≈ 2 lines)
    # Step 4: Loop over randomly selected negative clips and insert in background
    for random_negative in random_negatives:
        # Insert the audio clip on the background 
        background, _ = background, segment_time = insert_audio_clip(background, random_negative, previous_segments)
    ### END CODE HERE ###

    # Standardize the volume of the audio clip 
    background = match_target_amplitude(background, -20.0)

    # Export new training example 
    file_handle = background.export("train" + ".wav", format="wav")
    print("File (train.wav) was saved in your directory.")

    # Get and plot spectrogram of the new recording (background with superposition of positive and negatives)
    x = graph_spectrogram("train.wav")

    return x, y

######################################################

x, y = create_training_example(backgrounds[0], activates, negatives)

# File (train.wav) was saved in your directory.

image

现在你可以听一下你创建的新样本,和上面的频谱比较一下。

IPython.display.Audio("train.wav")

期待的输出

IPython.display.Audio("audio_examples/train_reference.wav")

最后,你可以将生成的训练样本的相关标签绘制成图。

plt.plot(y[0])

image

1.4 全部训练集

你现在已经实现了生成单个训练样本所需的代码。 我们将使用这个过程来生成一个大的训练集。 为了节省时间,我们已经生成了一组训练示例。

# Load preprocessed training examples
X = np.load("./XY_train/X.npy")
Y = np.load("./XY_train/Y.npy")

1.5 开发测试集

为了测试我们的模型,我们记录了25个样本的开发集。 虽然我们的训练数据是合成的,但我们希望创建一个与实际输入相同分布的开发集。 因此,我们记录了人们说“activate”和其他随机单词的25个10秒钟音频剪辑,并手工进行标记。 这遵循在课程3中描述的原则,我们应该创建一个尽可能与测试集分布相似的开发集; 这就是为什么我们的开发测试集使用真实而不是合成音频。

# Load preprocessed dev set examples
X_dev = np.load("./XY_dev/X_dev.npy")
Y_dev = np.load("./XY_dev/Y_dev.npy")

2 模型

现在建立好了数据集,让我们写一个训练触发字检测的模型吧。

该模型将使用一维卷积层,GRU层和密集层。 让我们加载可以在Keras中使用这些层的包。 这可能需要一分钟时间。

from keras.callbacks import ModelCheckpoint
from keras.models import Model, load_model, Sequential
from keras.layers import Dense, Activation, Dropout, Input, Masking, TimeDistributed, LSTM, Conv1D
from keras.layers import GRU, Bidirectional, BatchNormalization, Reshape
from keras.optimizers import Adam

# Using TensorFlow backend.

2.1 构建模型

下面是将要使用的模型结构。 花点时间看看模型,看看它是否有意义。

image

该模型的一个关键步骤是1维卷积步骤(靠近图的底部)。 它输入5511步频谱,并输出一个1375步输出,然后再进行多层处理得到最终的Ty = 1375步输出。 该层的作用类似于您在课程4中看到的提取低级特征的2D卷积,然后可能会生成较小维度的输出。

从计算角度而言,1-D 卷积层有助于加速模型,因为现在GRU仅处理1375个时步而不是5511个时间步。 两个GRU层从左到右读取输入序列,然后最终使用密集+sigmoid层对yt进行预测。 因为y是二进制值(0或1),所以我们在最后一层使用sigmoid输出来估计输出为1的机会,对应于刚刚说过“activate”的用户。

注意: 我们使用单向RNN而不是双向RNN。 这对于触发字检测非常重要,因为我们希望能够在它说出后立即检测触发字。 如果我们使用双向RNN,我们必须等待整个10秒的音频被记录下来,然后才能确定音频片段的第一秒是否有“activate”。

通过以下四步来实现模型:

  1. 卷积层
  2. 第一个GRU层

    X = GRU(units = 128, return_sequences = True)(X)
    • 设置return_sequences=True确保所有GRU的隐藏状态都被传送到下一层。
    • 记住这一层后面紧跟着Dropout和BatchNorm。
  3. 第二个GRU层
    • 与第一个GRU层类似,只是有一个额外的dropout层
  4. 创建时间分布的dense层

    X = TimeDistributed(Dense(1, activation = "sigmoid"))(X)
    • 这将创建一个dense层,后跟一个sigmoid,以便用于dense层的参数对于每个时间步都是相同的。[See documentation.]
练习:实现 model()
# GRADED FUNCTION: model

def model(input_shape):
    """
    Function creating the model's graph in Keras.

    Argument:
    input_shape -- shape of the model's input data (using Keras conventions)

    Returns:
    model -- Keras model instance
    """

    X_input = Input(shape = input_shape)

    ### START CODE HERE ###

    # Step 1: CONV layer (≈4 lines)
    X = Conv1D(196, 15, strides=4)(X_input)                               # CONV1D
    X = BatchNormalization()(X)                                # Batch normalization
    X = Activation('relu')(X)                               # ReLu activation
    X = Dropout(0.8)(X)                                 # dropout (use 0.8)

    # Step 2: First GRU Layer (≈4 lines)
    X = GRU(units = 128, return_sequences = True)(X)                                 # GRU (use 128 units and return the sequences)
    X = Dropout(0.8)(X)                                 # dropout (use 0.8)
    X = BatchNormalization()(X)                                 # Batch normalization

    # Step 3: Second GRU Layer (≈4 lines)
    X = GRU(units = 128, return_sequences = True)(X)         # GRU (use 128 units and return the sequences)
    X = Dropout(0.8)(X)                                 # dropout (use 0.8)
    X = BatchNormalization()(X)                                 # Batch normalization
    X = Dropout(0.8)(X)                                 # dropout (use 0.8)

    # Step 4: Time-distributed dense layer (≈1 line)
    X = TimeDistributed(Dense(1, activation = "sigmoid"))(X) # time distributed  (sigmoid)

    ### END CODE HERE ###

    model = Model(inputs = X_input, outputs = X)

    return model  

#################################################

model = model(input_shape = (Tx, n_freq))

打印总结概况

model.summary()

# _________________________________________________________________
# Layer (type)                 Output Shape              Param #   
# =================================================================
# input_1 (InputLayer)         (None, 5511, 101)         0         
# _________________________________________________________________
# conv1d_1 (Conv1D)            (None, 1375, 196)         297136    
# _________________________________________________________________
# batch_normalization_1 (Batch (None, 1375, 196)         784       
# _________________________________________________________________
# activation_1 (Activation)    (None, 1375, 196)         0         
# _________________________________________________________________
# dropout_1 (Dropout)          (None, 1375, 196)         0         
# _________________________________________________________________
# gru_1 (GRU)                  (None, 1375, 128)         124800    
# _________________________________________________________________
# dropout_2 (Dropout)          (None, 1375, 128)         0         
# _________________________________________________________________
# batch_normalization_2 (Batch (None, 1375, 128)         512       
# _________________________________________________________________
# gru_2 (GRU)                  (None, 1375, 128)         98688     
# _________________________________________________________________
# dropout_3 (Dropout)          (None, 1375, 128)         0         
# _________________________________________________________________
# batch_normalization_3 (Batch (None, 1375, 128)         512       
# _________________________________________________________________
# dropout_4 (Dropout)          (None, 1375, 128)         0         
# _________________________________________________________________
# time_distributed_1 (TimeDist (None, 1375, 1)           129       
# =================================================================
# Total params: 522,561
# Trainable params: 521,657
# Non-trainable params: 904
# _________________________________________________________________

期待的输出

key value
Total params 522,561
Trainable params 521,657
Non-trainable params 904

网络的输入是(无,5511,101),输出是(无,1375,1)。Conv1D将频谱图中5511步减少到1375步。

2.2 适应模型

触发字检测需要很长时间来训练。 为了节省时间,我们已经使用上面构建的模型结构在GPU上训练了约3小时的模型,并使用大约4000个样本进行了训练。 让我们加载这个模型。

model = load_model('./models/tr_model.h5')

您可以使用Adam优化器和二元交叉熵损失进一步训练模型,如下所示。
执行速度很快,因为我们只训练一个epoch,并且只有26个样本的小训练集。

opt = Adam(lr=0.0001, beta_1=0.9, beta_2=0.999, decay=0.01)
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=["accuracy"])

下面适应模型

model.fit(X, Y, batch_size = 5, epochs=1)

# Epoch 1/1
# 26/26 [==============================] - 29s - loss: 0.0728 - acc: 0.9806

2.3 测试你的模型

最后,我们看看模型在开发测试集上表现如何。

loss, acc = model.evaluate(X_dev, Y_dev)
print("Dev set accuracy = ", acc)

# 25/25 [==============================] - 4s
# Dev set accuracy =  0.944989085197

看起来很不错! 然而,对于这项任务来说,准确性并不是一个很好的指标,因为标签严重倾斜到0,所以只输出0的神经网络的准确性会略高于90%。 我们可以定义更多有用的指标,如F1分数或Precision / Recall。 但是,这里我们不要烦恼,只是凭经验去看模型是如何工作的。

3 做预测

现在您已经构建了触发字检测的工作模型,让我们用它来进行预测。 此代码段通过网络运行音频(保存在wav文件中)。

def detect_triggerword(filename):
    plt.subplot(2, 1, 1)

    x = graph_spectrogram(filename)
    # the spectogram outputs (freqs, Tx) and we want (Tx, freqs) to input into the model
    x  = x.swapaxes(0,1)
    x = np.expand_dims(x, axis=0)
    predictions = model.predict(x)

    plt.subplot(2, 1, 2)
    plt.plot(predictions[0,:,0])
    plt.ylabel('probability')
    plt.show()
    return predictions

计算出在每个输出步骤检测到“activate”这个词的概率,当概率超过某个阈值时,你就可以触发“chiming”声音。
此外,在“activate”之后,对于连续的许多值,yt可能接近1,但我们只想要一次铃声。
所以我们每75个输出步骤最多插入一次“chiming”声音。
这将有助于防止我们为单个“chiming”实例插入两个“chiming”声音。
(这起到类似于计算机视觉非最大抑制的作用。)

chime_file = "audio_examples/chime.wav"
def chime_on_activate(filename, predictions, threshold):
    audio_clip = AudioSegment.from_wav(filename)
    chime = AudioSegment.from_wav(chime_file)
    Ty = predictions.shape[1]
    # Step 1: Initialize the number of consecutive output steps to 0
    consecutive_timesteps = 0
    # Step 2: Loop over the output steps in the y
    for i in range(Ty):
        # Step 3: Increment consecutive output steps
        consecutive_timesteps += 1
        # Step 4: If prediction is higher than the threshold and more than 75 consecutive output steps have passed
        if predictions[0,i,0] > threshold and consecutive_timesteps > 75:
            # Step 5: Superpose audio and background using pydub
            audio_clip = audio_clip.overlay(chime, position = ((i / Ty) * audio_clip.duration_seconds)*1000)
            # Step 6: Reset consecutive output steps to 0
            consecutive_timesteps = 0

    audio_clip.export("chime_output.wav", format='wav')

3.3 在开发测试集上进行测试

让我们来看看我们的模型在开发集中的两个看不见的音频片段上表现如何。 让我们先听两个开发者设定的剪辑。

IPython.display.Audio("./raw_data/dev/1.wav")
IPython.display.Audio("./raw_data/dev/1.wav")

现在让我们在这些音频剪辑上运行模型,看看它是否在“activate”之后添加了“chiming”声音!

filename = "./raw_data/dev/1.wav"
prediction = detect_triggerword(filename)
chime_on_activate(filename, prediction, 0.5)
IPython.display.Audio("./chime_output.wav")
filename  = "./raw_data/dev/2.wav"
prediction = detect_triggerword(filename)
chime_on_activate(filename, prediction, 0.5)
IPython.display.Audio("./chime_output.wav")

谨记

  • 数据合成是为语音问题创建大型训练集的有效方式,特别是触发词检测。
  • 在将音频数据传送到RNN,GRU或LSTM之前,使用频谱图和可选的1D conv层是一个常见的预处理步骤。
  • 可以使用端到端的深度学习方法来构建非常有效的触发字检测系统。

恭喜你完成了最后的作业!

感谢你一直坚持到最后以及为学习深度学习所付出的所有努力。 我们希望你喜欢这门课程!

4 试验你自己的例子!(可选)

录制10秒的音频片段,说出“activate”和其他随机单词,然后将其上传到Coursera中心作为myaudio.wav。 确保将音频上传为wav文件。 如果您的音频以不同的格式(例如mp3)录制,则可以在线找到用于将其转换为wav的免费软件。 如果您的录音时间不是10秒钟,下面的代码会根据需要进行修剪或填充,使其达到10秒。

# Preprocess the audio to the correct format
def preprocess_audio(filename):
    # Trim or pad audio segment to 10000ms
    padding = AudioSegment.silent(duration=10000)
    segment = AudioSegment.from_wav(filename)[:10000]
    segment = padding.overlay(segment)
    # Set frame rate to 44100
    segment = segment.set_frame_rate(44100)
    # Export as wav
    segment.export(filename, format='wav')

一旦将音频文件上传到Coursera,请将文件路径放在下面的变量中。

your_filename = "audio_examples/my_audio.wav"
preprocess_audio(your_filename)
IPython.display.Audio(your_filename) # listen to the audio you uploaded 

最后,使用模型来预测在10秒音频片段中何时有”activate”并触发“chiming”声音。 如果没有正确添加“chiming”声音,请尝试调整chime_threshold。

chime_threshold = 0.5
prediction = detect_triggerword(your_filename)
chime_on_activate(your_filename, prediction, chime_threshold)
IPython.display.Audio("./chime_output.wav")
2019-04-20 17:16:17 zhinengxuexi 阅读数 79
  • 深度学习入门及如何转型AI领域

    深度学习入门转型视频教程,该课程主要告诉开发者如何快速入门深度学习。讲师是在机器学习,深度学习神经网络领域多年开发研究经验,精通算法原理与编程实践。曾完成过多项图像识别,目标识别,语音识别的实际项目,经验丰富。关注深度学习领域各种开源项目,如TensorFlow,Caffe,Torch等。喜欢理论与实践相结合的教学风格,课程编排由浅入深,体系清晰完整。

    2654 人正在学习 去看看 CSDN讲师

智能语音的应用从初期的手机助手形态(语音拨号、语音导航、语音搜索、语音听写等),发展到今天软硬一体的远讲降噪、语音唤醒、声纹识别、语用计算、流式交互等等。

从当前的语音识别技术发展看来,基础理论和技术框架已经基本成熟,目前主要是基于深度神经网络的识别架构,再加上大规模的真实数据训练。目前在手机端的近讲语音识别错误率可以做到3%以内,在电话语音识别错误率可以做到6%以内,基本上接近或超过人工识别的水平。语义理解和知识图谱等认知技术,目前还没有形成通用的技术框架,主要是针对具体垂直领域进行优化,这部分有待突破性进展。

目前语音交互技术面临最大的挑战还是来自产业应用层面:

首先是针对专业领域的优化,比如在医疗领域,通常专用词汇比较多,让我们普通人去听的时候可能都写不下来,只有经过专业训练的医生和护士才能准确记录;影视节目查询、商品搜索、路径导航等方面也同样需要做针对性的优化。

其次是相对复杂的口音和噪声环境,包括全国各地的口音和方言、远讲、噪声、混响等,都是比较复杂的。声音传播能量是随距离平方成反比关系的,传播距离增加一倍能量就衰减到四分之一,在五米外采集的语音能量,和在一米采集能量相比就相差25倍,但噪声并没有因为距离而降低,加上距离远之后,房间会出现多次反射和叠加,还会形成混响效果,信噪比会下降很多,都会对识别效果造成影响,这些是需要麦克风阵列结合语音声学模型去解决的问题。

第三是低功耗、低成本、高可靠的问题,智能家电需要满足绿色环保标准,需要确保24小时误唤醒低于1次,尽量不出现误操作,要实现大规模量产出货,还要降低整体方案的成本。面向物联网的智能语音交互方案,如果功耗成本下不来就不能普及,智能手表、手环等依赖电池的穿戴设备,功耗和成本问题就更加严重。

最后是语音交互设计问题,这是语音技术产品化的重中之重,现在的物联网设备,大到汽车、空调、机器人,小到玩具、穿戴设备等,有大有小、有带屏幕和不带屏幕、涉及不同的应用领域,交互方式差异非常大,需要针对性优化语义理解和知识图谱。

语音交互是未来物联网的重要交互手段,这是我们为什么把物联网列为语音技术落地主战场的原因。有了智能语音交互基础之后,我们还要做好精准和个性化的内容和服务,这才是用户真正想要的。

改变用户的使用方式

在智能语音最早进入市场时,用户会觉得比较新奇,当时用户是需要对着话筒,在近讲和安静情况下比较配合才能使用(最初还需要用户先念一段话来训练模型),所以大家觉得语音识别和人工智能技术不靠谱。

最近这几年,随着深度学习技术和大数据的发展,智能语音技术的进步已经超出了很多用户的想象,用户可以无需预先训练,在真实应用场景下实现相对自然的语音交互。现阶段用户对语音交互的接受度在逐步提升,随着语音应用和服务的日臻完善,让用户会逐渐形成习惯,越来越接受这种交互方式,机器则可以通过后台数据的不断快速迭代提高精度,用户就越来越喜欢用。

人工智能、大数据、云计算和物联网的未来发展值得重视,均为前沿产业,多智时代专注于人工智能和大数据的入门和科谱,在此为你推荐几篇优质好文:
这才是人们需要的AI语音助手
http://www.duozhishidai.com/article-12812-1.html
AI语音对话,什么时候能够摆脱智障?
http://www.duozhishidai.com/article-7553-1.html
智能语音技术革命的前世与今生
http://www.duozhishidai.com/article-2416-1.html


多智时代-人工智能大数据学习入门网站|人工智能、大数据、物联网云计算的学习交流网站

多智时代-人工智能大数据学习入门网站|人工智能、大数据、云计算、物联网的学习服务的好平台
  
2016-03-30 16:26:03 happytofly 阅读数 1245
  • 深度学习入门及如何转型AI领域

    深度学习入门转型视频教程,该课程主要告诉开发者如何快速入门深度学习。讲师是在机器学习,深度学习神经网络领域多年开发研究经验,精通算法原理与编程实践。曾完成过多项图像识别,目标识别,语音识别的实际项目,经验丰富。关注深度学习领域各种开源项目,如TensorFlow,Caffe,Torch等。喜欢理论与实践相结合的教学风格,课程编排由浅入深,体系清晰完整。

    2654 人正在学习 去看看 CSDN讲师

环形五麦克风阵列360°全平面拾音角度,远场拾音距离可达5米。

功能特性包括:

  • 二维空间拾音
  • 抗噪能力增强
  • 远距拾取音频
  • 支持连续唤醒
  • 支持回声消除
  • 支持语音打断

噪声、混响、干扰和回声是声学信号处理需要解决的问题。讯飞采用声源定位技术,利用麦克风阵列用基于TDOA(Time Difference Of Arrival,到达时间差)计算声源距离阵列的角度和距离,实现对目标声源的跟踪。再通过波束形成技术,即在期望方向上有效地形成一个波束,仅拾取波束的信号,从而达到同时提取声源和抑制噪声的目的。

图片描述

图片描述

原文:http://www.pieeco.com/zb/keda.html?from=groupmessage&isappinstalled=0

Wake Up AI

阅读数 40

没有更多推荐了,返回首页