信号为E时,如何让语音识别脱“网”而出? (3)

汇编版本的neon代码编写与维护成本高,但速度比c版本更快。秉着精益求精的态度,我们实现了汇编代码:

void vector_product_neon(const char * start_a, const char * start_b, int & result, const int cnt) { int res = 0; asm volatile( "vmov.s32 q2, #0" "\n\t" "lsr %[cnt], %[cnt], #4" "\n\t" ".charloop:" "vld1.s8 {d0}, [%[vec1]]!" "\n\t" "vld1.s8 {d1}, [%[vec2]]!" "\n\t" "vmull.s8 q1, d0, d1" "\n\t" "vld1.s8 {d0}, [%[vec1]]!" "\n\t" "vld1.s8 {d1}, [%[vec2]]!" "\n\t" "vmlal.s8 q1, d0, d1" "\n\t" "vaddw.s16 q2, q2, d2" "\n\t" "vaddw.s16 q2, q2, d3" "\n\t" "subs %[cnt], %[cnt], #1" "\n\t" "bne .charloop" "\n\t" "vadd.s32 d4, d4, d5" "\n\t" "vmov.s32 r4, d4[0]" "\n\t" "add %[sum], r4" "\n\t" "vmov.s32 r4, d4[1]" "\n\t" "add %[sum], r4" "\n\t" : [sum]"+r"(res) : [vec1]"r"(start_a), [vec2]"r"(start_b), [cnt]"r"(cnt) : "r4", "cc", "memory" ); result = res; }

2.奇异值分解优化声学模型运算量

为了降低乘加运算的次数,我们决定利用奇异值分解来对DNN进行重构,通过裁剪掉最小的奇异值及其相对应的特征向量,来达到减少乘加运算数量的目标。奇异值分解将任意矩阵Wm×n(不失一般性,假设m≤n)分解成3个矩阵相乘:Wm×n =Um×mΣm×mVm×n。

其中:Σm×m 为对角矩阵,即Σm×m =diag(σ1,σ2,…,σm),它的对角元素即为Wm×n的奇异值;Um×m 为单位正交矩阵,其列向量为与奇异值对应的特征向量;Vm×n中的行向量是互相单位正交的,也是与奇异值对应的特征向量。

下图是我们以DNN模型其中一层网络作为例子,阐述我们在重构DNN中的模型转化,其中原始DNN模型为图中上方子图(a),新重构DNN模型在下方子图(b)所示:

img

a:原始DNN模型的一层结构

img

(b)新DNN模型的两层对应结构

利用SVD对声学模型计算量优化大致分为3个步骤

(1)训练初始DNN神经网络;

(2)对权重矩阵进行奇异值分解;

(3)对重构后的DNN模型重新训练。

通过基于SVD的模型压缩方法,我们可以在稍微降低模型性能的前提下,将声学模型计算量减少30%。

3.哈夫曼优化语言模型内存

一般地,n-gram语言模型可以用一张有向图存储便于介绍存储空间以及快速查询,这张图上的边要存储词汇信息。我们知道以汉语为例,不同词语的出现频率相差极大,如果所有词汇的label id都用int类型存储,那空间的利用率较为低下。

以“我”“要”“吃饭”为例,假设语言模型的词汇频率:我>要>吃饭,那么我们可以构建图3的哈夫曼树,则四个字使用的编号码分别为:我(0),要(10),吃饭(110)

img

二叉哈夫曼

img

十六叉哈夫曼树

然而,采用图4的二叉树数据结构,一次只能处理1bit效率较低,也不便于工程实现。所以在工程实现的时候,我们按4bits编码为单位,对词汇进行分类存储处理。

我们使用一棵16叉树的哈夫曼树结构,每层树节点的编号总量是上一层的16倍。树中的所有编号为0的子节点用于储存词汇,越高频的词汇储存于深度越低的节点位置。

通过哈夫曼优化,我们的引擎最终成功降低了25%的内存占用,同时引擎是资源文件也得到50%左右的优化。

04

识别性能的优化

1.基于TDNN优化声学模型

近几年,TDNN(Time-Delay Neural Network,延时神经网络)【5】的拓扑结构被应用于语音识别。事实上,该结构于1989年被提出,随着近几年技术的发展,重新进入了大家的视线。

img

DNN结构

DNN的拓扑网络仅针对单一特征时刻点建模。

img

TDNN结构

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyxddy.html