欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~
一般没有网络时,语音识别是这样的
▽

而同等环境下,嵌入式语音识别,是这样的
▽
不仅可以帮您边说边识、出口成章,有个性化名字的时候也难不倒它。
这就是嵌入式语音识别的魅力。
本文将从微信智聆的嵌入式语音识别引擎的实现和优化,
介绍嵌入式语音识别的技术选型。
01
语音识别,大体是这么来的
语音识别,能让机器“听懂”人类的语音,把说话内容识别为对应文本。
开始于上世纪50年代
从最初的小词量孤立识别系统
到如今的大词量连续识别系统
语音识别系统的发展,性能得到显著的提升,主要得利于以下几个方面:
大数据时代的到来
深度神经网络在语音识别中的应用
GPU硬件的发展
因此,语音识别逐步走向实用化和产品化

语音输入法,语音智能助手,语音车载交互系统……
可以说,语音识别是人类征服人工智能的前沿阵地,是目前机器翻译、自然语言理解、人机交互等的奠基石。
然而,性能的提升基于服务端CPU/GPU高计算能力和大内存,没有网络的时候将无法享受语音识别的便利。
为了解决这个问题,微信智聆针对嵌入式语音识别进行研发。嵌入式语音识别,也称为嵌入式LVCSR(或离线LVCSR,Large Vocabulary Continuous Speech Recognition),指全程运行在手机端的语音识别,而不依赖于服务端强大的计算能力。
在一些网络不稳的特殊场景(车载、境外等等),嵌入式语音识别可“曲线救国”。
那么,实现一个嵌入式语音识别,存在哪些难点呢?

语音识别的基本流程
主流的语音识别算法当中,包括声学和语言两大模型。声学模型得利于近十年深度学习的发展,从GMM(高斯模型)到DNN(深度神经网络),再从DNN到LSTM RNN(循环神经网络),识别率不断提升的同时,计算量也不断地飞涨。而语言模型常用的n-gram算法,阶数越高性能越好,常用的模型多达数十G的内存。
所以综合起来,嵌入式语音识别有以下几个难点:
\1. 深度学习运算复杂,仅仅对模型进行裁剪性能损失大,需寻找挽回性能的方法;
\2. 裁剪模型不可避免,在模型训练环节如何避免小模型训练易陷入局部最优的问题;
\3. 如何计算的更快,满足嵌入式的CPU环境;
\4. 如何组织语言模型存储,能在有限的内存下存储更多的语言信息。
本文将以语音识别的技术原理出发,浅谈微信智聆嵌入式的实现技术。
内容将分为四个部分:
\1. 回顾语音识别的基本概念;
\2. 简单介绍在速度和内存优化上我们做的部分工作,侧重于工程应用实现;
\3. 说一说为了更好的性能我们做了哪些事,侧重于算法研究介绍;
\4. 我们进行实验对比,最后我们进行总结。
02
语音识别的各个组件

语音识别“黑盒”
语音识别从输入录音输出文字,黑盒子处理经过特征提取、声学模型、发音词典、语言模型等流程,笔者认为可以把语音识别比作一台计算机。
特征提取相当于是路由器,作为领头羊给后续环节提供源源不断的数据来源。
声学模型相当于语音识别的心脏——CPU,他将最直接影响着识别的准确性能。
语言模型相当于语音识别的硬盘,大量的词汇组合信息存储于此。
发音词典相当于内存条,能有效组织声学模型与语言模型的关系。
除此之外,语音识别包含一个解码器,他如同计算机的操作系统,有效地组织着各个环节。
接下来,我们基于每个“部件”简介其基本概念,以便后续介绍如何在这些“部件”上对嵌入式ASR工作的展开。
1.特征提取
音识别特征提取包括预加重、分帧、加窗、FFT(Fast Fourier Transform)等一系列流程,常用的特征有PLP、MFCC、FBANK等等。一般来说,语音识别把一秒语音分成100段(之间有互相重叠),而特征提取能把每段语音数据转化为一个向量(常见的有39维MFCC特征)。
为了关联上下文信息,特征作为声学模型的输入时,常将相邻帧拼凑一起。比如以39维特征为例,前后各取5帧信息,那么总共有11帧,输入的向量维度为11*39=429。一般地,语音识别的性能与取帧宽度是正相关的。
作为语音识别的路由器,特征提取环节的运算量并不大。然而其作为声学模型拓扑结构的输入,间接影响着深度学习的运算量,是我们在嵌入式ASR中要考虑的问题。
2.帧率抖动
5s统计一次直播流视频帧率,1min计算一次帧率方差,方差过大,视为推流帧率抖动.
3.声学模型(acoustic model)
声学模型作为语音识别的CPU,其重要性不言自喻。
一般地,它占据着语音识别大部分的运算开销,直接影响着语音识别系统的性能。传统语音识别系统普遍基于GMM-HMM的声学模型,其中GMM对语音声学特征的分布进行建模,HMM则用于对语音信号的时序性进行建模。
2006年深度学习兴起以后,深度神经网络(DNN,Deep Neural Networks)被应用于声学模型。
近十多年,声学模型的上深度学习的发展一路高歌,各种CNN、RNN、TDNN的拓扑结构如雨后春笋一一冒出,关于深度学习在声学模型的更多介绍见文。
对于嵌入式LVCSR来说,选择合适的DNN拓扑结构,并用合理的优化在手机实现结构的运算,是声学模型在其的核心诉求。
4.语言模型(language model)
语言模型,NLP从业者相对更为熟悉。在语音识别里,语言模型用来评估一个句子(即图2的词语序列)出现的概率高低。
在语言模型的实现算法中,最常见的为n-gram模型(n-gram models),利用当前词前面的n个词来计算其概率,是一个上下文有关模型。几年来,神经语言模型(Neural language models)使用词汇Embedding来预测,也得到广泛的发展与应用。
在嵌入式ASR中,由于计算资源要留予声学模型,所以语言模型采用的依旧是n-gram的思想。那么在有限的内存中,如何最大化存储语言模型,是嵌入式ASR要解决的问题。
5.发音词典
发音词典,是语音识别的内存条。内存能将硬盘的数据读入,并使用cpu进行运算。同样的,发音词典,能将语言模型的词条序列转化为音素序列,并用声学模型进行分数评估运算。
发音词典是连接声学模型和语言模型的桥梁,他的大小直接影响声学模型和语言模型的发挥空间。
在嵌入式ASR中,发音词典的大小,与语言模型的规模互相共鸣,所以要解决的问题可以与语言模型归为一谈。
6.解码器
解码器,估计这个词的来自英文decoder的直译,笔者认为更恰当的名字应称为识别器。之所以叫解码器,还有另外一个比较形象的原因。以16bit语音数据为例,计算机的存储是一堆我们看不懂的short类型数字,如同密码一般。语音识别能破解这些密码,将明文展示在我们面前。
所以通俗来讲,解码器就是将语音识别各个流程串联的代码工程。一般云端采用与WFST(带权优有限状态自动机)搭档的静态解码器,可以更方便地综合处理语音识别的各个环节。而嵌入式为了节省语言模型的内存开支,采用特定的动态解码器。
03
开始优化这些组件——速度和内存优化
为了优化这些“部件”占用的时间与内存,我们做了一系列工作:
neon计算优化,奇异值分解优化,哈夫曼编码优化。
1.neon优化声学模型计算
neon的计算优化,已是广大工程师们的老生常谈,机器学习相关的T族们更是耳熟能详。在嵌入式ASR引擎中,我们对核心高频运算的函数进行了neon优化,采用了汇编语言进行编写,最终有效提高了25%的计算速度。
接下来,本文现以实现char类型向量乘的介绍优化的实现,分三版本来介绍:
A. 优化前的朴素版
B. neon c版
C. neon汇编版
首先,我们将要实现的函数是:
/** * 实现两个char类型向量乘 * start_a: 向量A * start_b: 向量B * cnt:向量元素个数 * result:向量乘返回存储变量 */ void vector_product_neon(const char * start_a, const char * start_b, int & result, const int cnt);A. 优化前朴素版
void vector_product_neon(const char * start_a, const char * start_b, int & result, const int cnt) { int res = 0; for(int j = 0; j < cnt; j++) { res += int(*start_a) * int(*start_b); start_a++; start_b++; } result = res; }B. neon c版
Neon寄存器能实现128位空间的并行运算,对于char类型的向量乘而言,两两相乘的结果在short类型范围内,故可8个为一组实现。以下代码,8个元素一组,一次循环处理两组。在我们的深度学习运算中,隐层的向量长度保证为16倍数,实现代码如下:
void vector_product_neon(const char * start_a, const char * start_b, int & result, const i
