前面的文章(飞桨paddlespeech语音唤醒推理C浮点实现)讲了飞桨paddlespeech语音唤醒推理的C浮点实现。但是嵌入式设备通常CPU频率低和memory小,在嵌入式设备上要想流畅的运行语音唤醒功能,通常用的是定点实现。于是我就在浮点实现(把卷积层和相应的batchNormal层合并成一个卷积层)的基础上做了定点实现。需要说明的是目前完成的是16bit的定点实现,后面会在此基础上做8bit的定点实现。

做定点实现主要包括两部分工作,一是模型参数的量化和定Q格式等,二是基于Q格式的定点实现。关于模型参数的量化,我曾写过相关的文章(深度学习中神经网络模型的量化),有兴趣的可以去看看。我用的是对称量化,这里简述一下这部分的工作。

1,  在python下根据paddlepaddle提供的API(named_parameters)得到模型每层的参数(weight & bias),同时看每层的weight和bias的绝对值的最大值,从而确定参数的Q格式,再以这个Q格式对weight 和bias做量化。

2,  在python下得到测试集里非常多个文件每层的输入和输出的绝对值的最大值,从而确定每层的输入和输出的Q格式。

至于代码的定点化,主要包括如下几点:

1,  卷积层的定点化

主要是做好乘累加以及输出的移位和防饱和处理。在文章(深度学习中神经网络模型的量化)里有详细描述,这里就不细讲了。

2,  sigmoid的定点化

调研了一下,sigmoid的定点化主要用查表法来实现。Sigmoid(x)在x<=-8时近似为0,在x>=8时近似为1,因此做表时在[-8,8)之间就可以了。 若表中有256个值,则表中x的间隔是16/256 = 0.0625。表中第一个值对应的是x=-8时sigmoid的值,第二个值对应的是x=-7.9375(-8 + 0.0635 = -7.9375)时sigmoid的值,以此类推。Sigmoid输出的取值范围是(0,1),因此用的Q格式是Q0.15。例如当x=0时,sigmoid(0) = 0.5,表示成Q0.15格式是0x4000。当x在[-8,8)范围内每隔0.0625的256个sigmoid值都算出来并换算成Q0.15格式,就得到表中的256个值了。

具体实现时参考率CMSIS_5的代码,如下图:

做表时把前128个值(x < 0时的)与后128个值(x>=0时的)做了位置上的互换。主要是因为处理时先对x定点化后的16位输入值做右移8位处理,就变成了8位的值,再变成unsigned char(U8)用于做表的索引。 U8(0) = 0, U8(127) = 127, 但U8(-128) = 128, U8(-127) = 129, ……, U8(-1) = 255。所以表中的位置前后部分就互换了。再看sigmoid层的输入与sigmoid函数的输入的关系。 假设sigmoid函数输入的16位定点值为0x1869,右移8位后为0x18,即为24。表中第24个代表的是x=1.5(24 * 0.0675 = 1.5)时的sigmoid值。我的sigmoid层的输入Q格式是Q7.8, 1.5用Q7.8表示就是0x0180, 而函数中要求的是0x18XX,所以需要把层的输入的值做左移4位处理。由于sigmoid函数只对[-8,8)内的值做处理,因此首先需要对层的输入值做[-8,8)的限幅处理。上面两步的代码如下图:

调sigmoid_q15()时把int_width设成3,就表示输入范围是[-8,8)。 由于输入的x值不一定正好落在表中的那些点上,如x = 0.0325就落在点0.0和点0.0625之间。 为了使sigmoid的输出值更准确,函数中用线性插值法求那些不落在点上的sigmoid值。我在文章(基于sinc的音频重采样(二):实现)中讲过线性插值法,有兴趣的可以去看看。要想sigmoid的输出值更准确,还可以扩大表里值的个数,比如变成512个值,代价是多用些memory。

3,  确定好评估的指标

我在文章(深度学习中神经网络模型的量化)中对评估指标有所描述。这里我选用的是欧氏距离(Euclidean Distance)。具体调试时浮点实现和定点实现并行运行。即算出的浮点的fbank值作为浮点实现模型的输入,将浮点的Fbank值根据定标转换成定点值作为定点实现模型的输入,然后每层的浮点实现和定点实现并行运行。浮点实现得到的结果是浮点值,定点实现得到的结果是定点值,再根据输出的Q格式转换成浮点值。最后再用欧氏距离对输出结果进行评估。下图给出了某一depthwise卷积层的实现代码。先做浮点的卷积层运算,结果保存在fbankFloat里,然后做定点的卷积层运算,结果保存在fbankFix里,再根据输出的Q格式将fbankFix转换成浮点值,最后算欧氏距离。欧氏距离越小越好。

下图给出了调试好后部分层的欧氏距离的值,都是很小的(图中0/1/2等表示卷积层ID)。

4,如何调试

模型定点化调试时要从第一层到最后一层一层一层的调试,只有当上一层的欧氏距离达标后再去调下一层。具体到调试某一层时,通过log找到那些浮点值与定点转浮点后的值差值较大的值,再到浮点实现和定点实现里打印出输入和运算后的具体值,分析具体原因。有可能是定点实现里移位防饱和等没做好,也有可能是参数量化没作对,还有可能是输入和输出的Q格式没定好导致误差偏大等。在定输入和输出的Q格式时,是根据绝对值的最大值来的。如果发现精度不够,有可能需要调整输入或输出的Q格式(小数位要多一位,依据是看超出定标最大值出现的次数,次数占比较小就可以)。

调试时是用一个音频文件去调。等模型调试完成后要在一个大的数据集上对定点实现做全面的评估,看唤醒率和误唤醒率的变化。我做完定点实现后在一个有两万五千多音频文件的数据集上做评估,跟浮点实现比,唤醒率下降了0.2%,误唤醒率上升了0.3%。说明定点化后性能没有出现明显的下降。

飞桨paddlespeech语音唤醒推理C定点实现的更多相关文章

  1. 飞桨paddlespeech语音唤醒推理C实现

    上篇(飞桨paddlespeech 语音唤醒初探)初探了paddlespeech下的语音唤醒方案,通过调试也搞清楚了里面的细节.因为是python 下的,不能直接部署,要想在嵌入式上部署需要有C下的推 ...

  2. 讯飞语音唤醒SDK集成流程

    唤醒功能,顾名思义,通过语音,唤醒服务,做我们想做的事情. 效果图(开启应用后说讯飞语音或者讯飞语点唤醒) 源码下载 地址:http://download.csdn.net/detail/q48788 ...

  3. android 开发 讯飞语音唤醒功能

    场景:进入程序后处于语音唤醒状态,当说到某个关键词的时候打开某个子界面(如:语音识别界面) 技术要点: 1. // 设置唤醒一直保持,直到调用stopListening,传入0则完成一次唤醒后,会话立 ...

  4. 【百度飞桨】手写数字识别模型部署Paddle Inference

    从完成一个简单的『手写数字识别任务』开始,快速了解飞桨框架 API 的使用方法. 模型开发 『手写数字识别』是深度学习里的 Hello World 任务,用于对 0 ~ 9 的十类数字进行分类,即输入 ...

  5. 我做的百度飞桨PaddleOCR .NET调用库

    我做的百度飞桨PaddleOCR .NET调用库 .NET Conf 2021中国我做了一次<.NET玩转计算机视觉OpenCV>的分享,其中提到了一个效果特别好的OCR识别引擎--百度飞 ...

  6. 提速1000倍,预测延迟少于1ms,百度飞桨发布基于ERNIE的语义理解开发套件

    提速1000倍,预测延迟少于1ms,百度飞桨发布基于ERNIE的语义理解开发套件 11月5日,在『WAVE Summit+』2019 深度学习开发者秋季峰会上,百度对外发布基于 ERNIE 的语义理解 ...

  7. 树莓派4B安装 百度飞桨paddlelite 做视频检测 (一、环境安装)

    前言: 当前准备重新在树莓派4B8G 上面搭载训练模型进行识别检测,训练采用了百度飞桨的PaddleX再也不用为训练部署环境各种报错发愁了,推荐大家使用. 关于在树莓派4B上面paddlelite的文 ...

  8. 百度飞桨数据处理 API 数据格式 HWC CHW 和 PIL 图像处理之间的关系

    使用百度飞桨 API 例如:Resize Normalize,处理数据的时候. Resize:如果输入的图像是 PIL 读取的图像这个数据格式是 HWC ,Resize 就需要 HWC 格式的数据. ...

  9. Ubuntu 百度飞桨和 CUDA 的安装

    Ubuntu 百度飞桨 和 CUDA 的安装 1.简介 本文主要是 Ubuntu 百度飞桨 和 CUDA 的安装 系统:Ubuntu 20.04 百度飞桨:2.2 为例 2.百度飞桨安装 访问百度飞桨 ...

  10. 【一】ERNIE:飞桨开源开发套件,入门学习,看看行业顶尖持续学习语义理解框架,如何取得世界多个实战的SOTA效果?

    ​ 参考文章: 深度剖析知识增强语义表示模型--ERNIE_财神Childe的博客-CSDN博客_ernie模型 ERNIE_ERNIE开源开发套件_飞桨 https://github.com/Pad ...

随机推荐

  1. 3385. 【NOIP2013模拟】黑魔法师之门

    3385. [NOIP2013模拟]黑魔法师之门 题目大意: 做法: 代码: 题目大意: 给你一个无向无权图,每次询问加入一条边问你图中每个点的度数大于零且都是偶数的子图的个数对1000000009取 ...

  2. JUC同步工具CountDownLatch

    CountDownLatch:允许一条或多条线程等待其它线程中的一组操作完成后再继续执行. 在探究CountDownLatch之前,我们知道Thread的join也有类似功能,先看thread的joi ...

  3. ERROR: libfdk_aac not found和ERROR: libmp3lame &gt;= 3.98.3 not dound

    ERROR: libfdk_aac not found和ERROR: libmp3lame >= 3.98.3 not dound 编译ffmepg时出现这两个错误或者有时候需要x264编码的时 ...

  4. TypeScript 引用资源文件后提示找不到的异常处理

    在tsx中引用图片,在文件文本编辑器中提示错误引用: typescript无法识别非代码文件(js是可以的).如果需要在ts中识别此文件资源,可以先声明文件类型. 新建一个ts文件,比如global. ...

  5. 深度学习-08(PaddlePaddle文本分类)

    深度学习-08(PaddlePaddle文本分类) 文章目录 深度学习-08(PaddlePaddle文本分类) NLP概述 NLP基本概念 什么是NLP NLP的主要任务 传统NLP方法 传统NLP ...

  6. [MAUI]模仿iOS多任务切换卡片滑动的交互实现

    @ 目录 原理 创建布局 创建分布函数 创建动效 创建绑定数据 细节调整 首张卡片的处理 为卡片添加裁剪 跳转到最后一张卡片 项目地址 看了上一篇博文的评论,大家对MAUI还是比较感兴趣的,非常感谢大 ...

  7. CF1808E Minibuses on Venus 智商毁灭记

    都要考省选了大脑还在这里下线 场上看到这道题很快推出了 \(k\) 为奇数的搞法,发现可以直接做到 \(O(k\log n)\),一阵狂喜然后肝起了 E3,结果 E1 都没过. 事实上这道题可以直接做 ...

  8. Python网络爬虫原理及实践

    作者:京东物流 田禹 1 网络爬虫 网络爬虫:是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本. 网络爬虫相关技术和框架繁多,针对场景的不同可以选择不同的网络爬虫技术. 2 Scrapy框架( ...

  9. 2021-05-13:数组中所有数都异或起来的结果,叫做异或和。给定一个数组arr,返回arr的最大子数组异或和。

    2021-05-13:数组中所有数都异或起来的结果,叫做异或和.给定一个数组arr,返回arr的最大子数组异或和. 前缀树.一个数,用二进制表示,0走左边分支,1走右边分支. 时间复杂度:O(N). ...

  10. 2021-12-25:给定一个只由0和1组成的字符串S,假设下标从1开始,规定i位置的字符价值V[i]计算方式如下

    2021-12-25:给定一个只由0和1组成的字符串S,假设下标从1开始,规定i位置的字符价值V[i]计算方式如下 : 1 i == 1时,V[i] = 1: 2 i > 1时,如果S[i] ! ...