飞桨paddlespeech语音唤醒推理C浮点实现

上篇(飞桨paddlespeech 语音唤醒初探)初探了paddlespeech下的语音唤醒方案,通过调试也搞清楚了里面的细节。因为是python 下的,不能直接部署,要想在嵌入式上部署需要有C下的推理实现,于是我就在C下把这个方案的部署实现了。需要说明的是目前完成的是浮点实现,真正部署时要用的是定点实现,后面要做的是从浮点到定点的转换。浮点实现也做了两个版本。一是跟python下的实现完全一致的版本,做这个版本的目的是方便与python版本的结果比较,确保每个模块的实现完全正确。二是将模型中的卷积层和对应的batchNormal(BN)层合并为一个卷积层的版本,将卷积层和对应的BN层合并为一个卷积层一是可以减少参数的个数,二是可以减少运算量(BN里有求方差等运算)。做定点化时也是要基于这个版本来做的。下面就讲讲我是怎么做C下的实现的。

语音唤醒的推理过程如下图所示:

从上图可以看出主要分两步,一是做特征提取,二是做模型推理。将提取出来的特征值作为模型的输入,推理后得到模型的输出,从而给出是否是关键词的结果。

1,  特征提取

特征提取的步骤如下图所示:

做这一步时主要基于两份开源的代码: FFT 和 MFCC。Fbank是MFCC的一部分,因此需要对代码进行裁剪。做时从分帧开始到得到特征值,每一步处理都要跟python下的保持完全一致,如分帧时用的是什么窗,用的是能量谱还是对数谱等。调试时基于一个具体的WAV文件来调。每一步执行后python下有一个输出,在C下也有一个输出,要确保这两个输出在误差允许范围内保持一致,否则就是C的实现有问题。经过调试后特征提取部分就完成了,python下的结果和C下的结果保持小数点后面前四位相同,误差还是非常小的。

2,  模型推理

模型推理可以分为如下几个步骤:在Python下获取模型参数并保存进文件给C实现用,跟python完全一致的浮点实现,将卷积层和对应的BN层合并为一个卷积层的浮点实现。

2.1 模型参数获取

在paddlespeech下先用API获取每层的参数,代码大致如下:

然后将每层的参数按事先规定的格式保存在一个文件里,供C实现去解析参数。我用的参数保存格式如下:

即参数一层一层的放。在每一层里,先是层名,然后是weight参数的个数和bias参数的个数,最后是weight和bias具体的参数值。在C中就根据这个规则去解析从而得到每一层的参数。

2.2 跟python推理完全一致的浮点实现

模型的框图如下:

主要有PreProcess/DTCNStack等模块。先实现模型用到的神经网络里的基本单元,有depthwise_conv1d/pointwise_conv1d/relu/batch_normal/sigmoid等。再将这些基本单元组成pre_process模块来调试。依旧是用调试特征提取时的方法来调,确保每一步的输出跟python下的在误差允许范围内保持一致。PreProcess模块调好后再来调DTCNStack等模块,最终形成一个完整的推理实现。下图给出了我调试时用的wav的最终每帧的在python下和C下的后验概率(有多个值,限于长度,这里只截取了部分),可以看出python下和C下的结果是保持一致的。

2.3将卷积层和对应的BN层合并为一个卷积层的浮点实现

为了减少参数个数和运算量,可以将将卷积层和对应的BN层合并为一个卷积层。具体原理如下:

对于C实现来说,只要把banch_normal()函数去掉就可以了。但是在保存参数时卷积层的参数要根据上面的公式做个换算,同时把BN层的去掉。下图是做最后linear以及后验概率运算时有没有BN层的结果(有多个值,限于长度,这里只截取了部分)。

从上两图看出将卷积层和BN层合并为一层对最终结果的影响是非常小的,但是省掉了2.5K的参数以及原先BN层要做的运算量。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
实现自然推理系统需要涉及很多知识,包括语言分析、逻辑规则、证明策略等等。这是一个庞大的项目,需要很长时间和精力才能完成。在这里,我只能给你一个大致的框架和思路。 首先,需要定义一些数据结构和函数来表示和处理命题和证明过程。 定义数据结构: ``` // 表示命题的结构体 typedef struct _Proposition { char* formula; // 命题公式 struct _Proposition* next; // 下一个命题 } Proposition; // 表示证明规则的枚举类型 typedef enum { AXIOM, HYPOTHESIS, AND_INTRO, AND_ELIM, OR_INTRO, OR_ELIM, NOT_INTRO, NOT_ELIM, IMPLY_INTRO, IMPLY_ELIM, EQUIV_INTRO, EQUIV_ELIM } Rule; // 表示证明步骤的结构体 typedef struct _ProofStep { Proposition* proposition; // 命题 Rule rule; // 证明规则 struct _ProofStep* prev; // 前一个证明步骤 struct _ProofStep* next; // 后一个证明步骤 } ProofStep; ``` 定义函数: ``` // 创建一个命题 Proposition* createProposition(char* formula); // 销毁一个命题 void destroyProposition(Proposition* prop); // 创建一个证明步骤 ProofStep* createProofStep(Proposition* proposition, Rule rule, ProofStep* prev, ProofStep* next); // 销毁一个证明步骤 void destroyProofStep(ProofStep* step); // 插入一个证明步骤 void insertProofStep(ProofStep* step, ProofStep* before); // 删除一个证明步骤 void deleteProofStep(ProofStep* step); ``` 接下来,需要实现这些函数。 首先是创建和销毁命题的函数: ``` Proposition* createProposition(char* formula) { Proposition* prop = (Proposition*)malloc(sizeof(Proposition)); prop->formula = formula; prop->next = NULL; return prop; } void destroyProposition(Proposition* prop) { if (prop == NULL) { return; } destroyProposition(prop->next); free(prop); } ``` 接下来是创建和销毁证明步骤的函数: ``` ProofStep* createProofStep(Proposition* proposition, Rule rule, ProofStep* prev, ProofStep* next) { ProofStep* step = (ProofStep*)malloc(sizeof(ProofStep)); step->proposition = proposition; step->rule = rule; step->prev = prev; step->next = next; return step; } void destroyProofStep(ProofStep* step) { if (step == NULL) { return; } destroyProposition(step->proposition); destroyProofStep(step->prev); destroyProofStep(step->next); free(step); } ``` 然后是插入和删除证明步骤的函数: ``` void insertProofStep(ProofStep* step, ProofStep* before) { step->prev = before->prev; step->next = before; before->prev->next = step; before->prev = step; } void deleteProofStep(ProofStep* step) { step->prev->next = step->next; step->next->prev = step->prev; destroyProofStep(step); } ``` 接下来就是实现证明策略的部分。证明策略是推理系统的核心,它包括了一系列的推理规则和推理步骤。 下面是一些常见的证明规则: - 假言引入:如果前提是“如果A,那么B”,且已经证明了A,则可以得出B。 - 假言消去:如果已经证明了“A”,且已经证明了“如果A,那么B”,则可以得出B。 - 合取引入:如果已经证明了A和B,则可以得出“A且B”。 - 合取消去:如果已经证明了“A且B”,则可以得出A和B。 - 析取引入:如果已经证明了A,则可以得出“A或B”。 - 析取消去:如果前提是“A或B”,且已经证明了A,那么可以得出结论。同理,如果前提是“A或B”,且已经证明了B,那么也可以得出结论。 在实现证明策略时,需要考虑到各种不同的情况和推理规则的适用条件。这需要涉及到语言分析和逻辑推理的知识,需要进行深入的研究和设计。 最后,需要实现一个主函数,用来调用各种函数进行推理过程的演示。这个主函数需要读入用户输入的命题和证明步骤,并进行相应的处理和推导。 以上只是一个大致的框架和思路,实现自然推理系统需要涉及到很多细节和复杂的设计。如果你有兴趣和时间,可以进一步深入研究和实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值