DNN计算在移动端的实现技巧

阿凡达2018-08-21 13:36

2011年,微软雷德蒙研究院将DNNDeep Neural Networks)技术成功应用于英文连续语音识别,获得了相对33%的识别性能提升,识别结果变得可以被大多数人接受,开启了语音识别新潮流。近年来,在智能手表场景中,语音被认为是最佳交互方式,如Ticwatch已使用中文语音交互来操控手表、打电话以及查询信息等。这将带来语音识别请求量的爆发式增长。

然而,由于DNN计算中的矩阵维度通常达到512或以上,并涉及多个高维矩阵-矩阵相乘、矩阵-向量相乘,其模型尺寸有数十兆,计算量很大。常规的解决方案是移动端只负责发送语音和接收识别结果,在后端提供数百台服务器来部署语音识别服务,并利用昂贵的GPU显卡来加速DNN计算,需要耗费大量财力物力。

因此,无需服务器和网络的移动端离线语音识别成为更经济的方式。但是移动端计算性能、存储空间均有限,DNN的实现成为瓶颈之一。本文将从DNN计算和模型存储两方面介绍DNN在移动端的实现技巧,并结合iOSAndroid的平台特性分别给出参考解决方案。

一、DNN计算

        在语音识别中,DNN主要用作声学模型中观察概率的建模,典型的结构如图1所示。

1  使用DNN作为声学模型

        图1中,使用DNN作为声学模型中观察概率的建模方式,DNN在其中所起的作用是将观察到的声学特征(如MFCC特征序列构成的输入矩阵)映射到HMM框架中的观察概率,其中DNN模型结构中M层各自的参数矩阵,维度通常达到512及以上。在逐层计算过程中,主要是矩阵-矩阵相乘运算:Y = WX + B,其中W为参数矩阵,X为输入矩阵,B为偏置向量,Y为输出矩阵,并用于下一层的输入。

        因此,DNN计算过程其实是矩阵运算。DNN优化问题转化为如何在移动端加速矩阵运算的问题。此外,在语音识别中DNN中每个参数通常采用单精度浮点表示,模型文件较大。

二、矩阵运算性能分析及常见解决方案

1、性能瓶颈

        矩阵运算,若采用常规的3for循环计算方式,将涉及反复读取一段内存(一行或一列)到寄存器的操作,然后再进行浮点运算(一行乘以一列并求和)。众所周知,将数据从内存加载到寄存器的耗时,比从寄存器直接访问数据的耗时要大的多。且内存加载和存储指令的耗时比浮点运算更加昂贵,计算过程的大部分时间处于等待从内存中获取或返回新数据的状态。而这也正是矩阵运算的性能瓶颈所在。

2、移动端常见方案(定点化+neon

        移动端的DNN计算,目前常见的方案是利用定点化(32bit float转为8bit signed char)和NEONSIMDARM架构下的实现)指令集来实现优化加速[2]。但这种方式仅仅是加速了浮点运算,对耗时巨大的内存访问并没有加速。此外,定点化的精度损失也较大。

3、改进方案(矩阵分块+neon

        类似OpenBLASATLAS这种PC或服务器端开源矩阵运算库,最主要的优化是利用矩阵分块增加数据访问局部性,尽可能减少cache miss次数,并利用SIMD(单指令多数据流)并行加速来进一步减少浮点运算耗时。但这些开源库直接移植到移动端,费时费力。针对DNN计算中的矩阵相乘,可以利用该思想,结合ARMNEON指令集来实现这种方案,并根据ARML1 cache大小来优化macromicro核的设计。

        下图是矩阵-向量运算,减少内存操作次数的伪代码示例。

矩阵-向量运算减少内存操作次数的实现

        图2中左侧为常规计算方式,右侧每次加载4个元素,虽然总的浮点计算次数(flops)相同,但可减少(2/3)mn次内存操作(memops)。

        类似,矩阵-矩阵相乘运算原理的示意图如下图3所示,通过将矩阵分块,可显著降低内存操作次数[1]

矩阵-矩阵相乘中的矩阵分块示意图

4、性能对比

        在项目开发中,详细对比了上述两种方案以及传统的3for循环方案的矩阵相乘运算耗时。下表是在iPhone 4S真机上,模拟测试两个矩阵相乘的耗时对比。

矩阵相乘的方案性能对比

      方案

矩阵尺寸

3for循环

(秒)

定点化+neon

(秒)

矩阵分块+neon

(秒)

512*512

3.10

0.81

0.25

1024*1024

23.34

5.95

1.92

        由表1可见,采用矩阵分块+neon方案,比定点化+neon加速约3倍,比3for循环加速约12倍。

 

三、DNN计算在移动端的实现方案

        移动端主要是iOSAndroid平台下的实现,需根据平台特性来挑选实现方案。

1iOS

        iOS自带的硬件加速框架vDSP,在底层实现了矩阵-矩阵、矩阵-向量相乘运算,其基本原理也是采用矩阵分块及NEON加速方案,但在底层进行了深度定制,无需重新实现。具体使用方式可参考vDSP开发手册。表2是在iPhone 4S上利用vDSP的测试结果。

2  vDSP性能对比

      方案

矩阵尺寸

矩阵分块+neon

(秒)

vDSP

4S,秒)

512*512

0.25

0.07

1024*1024

1.92

0.59

        由表2可见,在iOS平台下,采用vDSP框架更可取。

2Android

        Android端尚无类似iOSvDSP加速框架,采用定点化+neon指令集,或者矩阵分区+neon指令集来实现。需要针对具体Android平台的寄存器大小等硬件性能来设计MacroMicro核的参数[1]

3、模型压缩

        由于矩阵相乘中,浮点运算耗时占比较小,可直接采用浮点运算,避免定点化带来的精度损失。在语音识别项目中,训练所获得的DNN模型,可进一步采用半精度浮点来压缩模型[4],经测试对识别准确率几乎无影响,可应用于离线语音识别的模型压缩中[3]。单精度浮点、半精度浮点对比如表3所示。

单精度VS半精度

 

 


bit

结构(符号位+指数位+尾数位)

取值范围

精度

单精度float

32

1+8+23

-3.40E+38~+3.40E+38

6~7位有效数字

半精度float

16

1+5+10

-65504~65504

3~4位有效数字

        利用半精度浮点,可将DNN模型压缩为原来的一半大小。

 

四、总结

        本文主要介绍了DNN计算在移动端的实现技巧,重点分析了矩阵-矩阵相乘运算中的性能瓶颈,并结合平台特性给出移动端的实现方案。本文所实现的改进方案已成功应用于Android端离线语音识别项目中,识别速度比文献中常见的DNN加速方案提高约3倍。此外,可进一步利用半精度浮点来压缩DNN模型,精度比定点化更高,对语音识别性能的不良影响几乎可以忽略。欢迎感兴趣的同事一起交流学习。

 

参考资料

[1] BLIS: A Framework for Rapidly Instantiating BLAS Functionality.  2015.

[2] Speeding up Deep Neural Networks for Speech Recognition on ARM Cortex-A Series Processors.  2014.

[3] Accurate and Compact Large Vocabulary Speech Recognition on Mobile Devices.  2013.

[4] https://en.wikipedia.org/wiki/Half-precision_floating-point_format.


网易云新用户大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者胡光龙授权发布。