前面的文章(飞桨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. CS144 计算机网络 Lab0:Networking Warmup

    前言 本科期间修读了<计算机网络>课程,但是课上布置的作业比较简单,只是分析了一下 Wireshark 抓包的结构,没有动手实现过协议.所以最近在哔哩大学在线学习了斯坦福大学的 CS144 ...

  2. 省市县树形结构打印-.netCore控制台程序

    using CityJson;using Dapper;using Newtonsoft.Json;{ using (var db = DbHelper.Db()) { //数据格式 //code_p ...

  3. Webpack5构建性能优化:构建耗时从150s到60s再到10s

    作者:京东科技 牛志伟 近期对Webpack5构建性能进行了优化,构建耗时从150s到60s再到10s,下面详细讲解下优化过程. 优化前现状 1.历史项目基于Vue3 + Webpack5技术栈,其中 ...

  4. 2020-10-21:go中channel的send流程是什么?

    福哥答案2020-10-21: ***[评论](https://user.qzone.qq.com/3182319461/blog/1603234689)

  5. 2022-07-22:以下go语言代码输出什么?A:1;B:1.5;C:编译错误;D:1.49。 package main import “fmt“ func main() { var i

    2022-07-22:以下go语言代码输出什么?A:1:B:1.5:C:编译错误:D:1.49. package main import "fmt" func main() { v ...

  6. golang技术栈常见网址

    go所有,包含goadmin golang标准库文档 golang修养之路 Golang Profiling: 关于 pprof go问题 go语言设计与实现 go.mod解析 proto3 prot ...

  7. 2021-10-20:分数到小数。给定两个整数,分别表示分数的分子numerator和分母denominator,以字符串形式返回小数。如果小数部分为循环小数,则将循环的部分括在括号内。输入: num

    2021-10-20:分数到小数.给定两个整数,分别表示分数的分子numerator和分母denominator,以字符串形式返回小数.如果小数部分为循环小数,则将循环的部分括在括号内.输入: num ...

  8. Selenium - 元素等待(2) - 显式等待/EC等待

    Selenium - 元素等待 显式等待 显式等待是一种灵活的等待方式,需要声明等待的结束条件,当满足条件时会自动结束等待: 需要引入WebDriverWait包以及exception_conditi ...

  9. 汇总低效的SQL语句

    背景 SQL专家云像"摄像头"一样,对环境.参数配置.服务器性能指标.活动会话.慢语句.磁盘空间.数据库文件.索引.作业.日志等几十个运行指标进行不同频率的实时采集,保存到SQL专 ...

  10. OSPF路由控制

    实验拓扑 实验需求 公司A使用OSPF路由协议实现公司设备全网互通,后来公司A扩张兼并了公司B,要求将公司B采用的IS-IS路由协议与公司A的OSPF协议互相引入,使得相应部门可以实现互通. Rout ...