语音识别引擎Wenet系列四:进阶话题:Cache

语音之家 2021-09-15 15:43:46
加精

第一章节可参考

● 第1节: 端到端语音识别基础

  CTC目标函数

  Attention-based Encoder Decoder

  联合建模

  神经网络类型

  流式语音识别

● 第2节: Wenet中的神经网络设计与实现

  Subsampling网络

  Encoder Block

  模型定义

  创建模型

  前向计算

  其他接口

  模型入口 ASRModel

  Encoder网络

  Attention based Decoder网络

  CTC Loss

  Attention based Decoder Loss

  网络的完整结构

● 第3节: 进阶话题:Mask

  Subsampling中的mask

  Conformer Block中的Conv的mask

  MultiHeadedAttention Module的Mask实现

  Chunk-based mask

  处理Padding对Loss的影响

  处理模型输入Padding

  问题1:Batch Padding

  问题2: 自回归

  问题3: Chunk-Based Model

  Encoder中的mask

  Decoder中的mask

本文讲解第四章

● 第4节: 进阶话题:Cache

  Runtime流式解码

  Python流式解码

  BaseEncoder.forward_chunk()分析

  offset

  subsampling内部

  subsampling_cache

  elayers_output_cache

  conformer_cnn_cache

进阶话题:Cache

标准的forward是整个序列进行计算,但是在流式推断时,需要chunk级别的forward,因此需要引入cache的概念,即当前chunk的进行前向计算时,需要拿到上次前向的一些结果作为输入。

什么是cache?

对于流式推断,输入是一个个chunk的到来,对第i个chunk,当计算第k层网络的输出时,由于网络结构存在对左侧上下文的依赖,需要依赖第k-1层网络里在i之前的一些chunks的输出。如果对于当前到来chunk,将其和依赖的chunk序列(比如10层self-attention层,每层依赖左侧4个chunk,则累积起来需要依赖左侧40个chunk)拼起来作为网络输入进行前向,其计算量会比较大。对于那些已经计算过的chunk,可以将那些在计算下一个chunk的输出时需要的中间量保存下来,从而减少重复计算。这种方式就叫cache。

另外,wenet的网络在设计时,对于因果卷积和self-attention的左侧上下文都使用有限长度,因此无论序列多长,每次cache的大小是不变的(不增长)。

仅仅encoder部分涉及chunk计算时的cache。

● 对于CTC decoder,由于是线性层,不需要cache。

● 对于AED decoder,是在计算完整个序列的encoder输出后进行rescoring,不涉及chunk。

 

Runtime流式解码

asr_model.py中的forward_encoder_chunk()通过jit导出,用于C++ runtime,其内部使用了encoder.py中的forward_chunk()函数。

Python流式解码

如果设置simulate_streaming为True,则会模拟runtime流时解码的过程,将数据分成chunk,依次进行前向计算。该方法的结果,和送入整个序列通过mask进行流式模拟的结果应该是一致的。

forward_chunk_by_chunk()的内部也是使用的forward_chunk()函数。

 

BaseEncoder.forward_chunk()分析

xs是当前的chunk输入,由于对于单个chunk的前向计算,需要之前的chunk的计算得到的信息,因此这里需要传入相关的三个cache信息。

● subsampling_cache:torch.Tensorsubsampling的输出的cache。即第一个conformer block的输入。

● elayers_output_cache:List[torch.Tensor]第1个到最后1个conformer block的输出的cache。也就是第2个conformer block的输入和CTC层的输入。

● conformer_cnn_cache:List[torch.Tensor]conformer block里的conv层的左侧依赖的输入cache。

cache的大小

● subsampling_cache和elayers_output_cache的大小 由self-attention是对左侧的依赖长度required_cache_size决定。decoding_chunk_size是解码帧级别的chunk大小, num_decoding_left_chunks是self-attention依赖的左侧chunk数。

● conformer_cnn_cache的大小和required_cache_size无关,由casual网络的左侧上下文lorder决定。

函数返回了四个值,包括当前chunk输入对应的输出,更新后的三个cache。

该函数的整个计算过程请参考下图

offset

当按chunk进行输入时,不能直接得到chunk在序列中的位置,需要传入offset给出该chunk在整个序列里的偏移,用于计算positional encoding。

subsampling内部

subsampling内部的计算虽然存在冗余,但是不进行cache。一个是其实现比较复杂,另一个原因是subsampling的计算量占比不大。

subsampling_cache

subsampling的输出的cache。即第一个conformer block的输入。

elayers_output_cache

第1个到最后1个conformer block的输出的cache。也就是第2个conformer block的输入和CTC层的输入。

注意,此处的xs不是当前的chunk,而是当前chunk+cache输入,所以其长度不是chunk_size, 而是chunk_size + required_cache_size。

layer()对应着wenet/transformer/encoder_layer.py中的ConformerEncoderLayer.forward()。下面是其具体过程。

注意,self-attention之前的一些前向计算其实仍然存在冗余,如果对attention层的输入进行cache,而不是对conformer block层的输入cache,可以进一步降低计算量。

conformer_cnn_cache

conformer block里的conv层的左侧依赖的输入cache。

conformer_cnn_cache大小为lorder,即因果卷积左侧依赖。

本文来源:语音之家

...全文
3874 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复
源码直接下载地址: https://pan.quark.cn/s/a4b39357ea24 ### Home Bus 协议概述 Home Bus协议,亦被称为家庭总线协议,是由日本研发的一种专门应用于家庭自动化领域的通信标准。该协议在商用空调及其他家用电器的远程操控方面具备广泛的应用范围。借助Home Bus协议,设备之间能够达成高效的通信,使用户能够更加便利地监管家庭中的各类智能设备。 ### ECHONET协议及其背景 Home Bus协议与ECHONET协议存在紧密的联系,实际上,ECHONET代表了一种更为具体的技术规范,其目的在于为家庭自动化领域构建一个开放且统一的通信标准。ECHONET由ECHONET财团负责维护与支持,该组织致力于推动该协议的进步与标准化进程。ECHONET协议的应用范围不仅限于家庭环境,还包括了楼宇自动化以及工业自动化等多个领域。 #### ECHONET的历史版本及修订记录 - **Version 1.0**:发布于2000年3月18日,同年7月对联盟成员公开,最终于同年对公众发布。 - **Version 1.01**:在2001年5月23日,向联盟成员发布,主要进行了补充和勘误工作。 - **Version 2.00**:2001年8月7日,针对联盟成员发布。此版本中将电源线A和电源线B两种方式合并为单一电源线方式(基于电源线A),并对相关描述进行了调整。 - **Version 2.01**:2001年11月9日,进行了一些必要的修正,包括排版错误的修正、术语的标准化等。 - **Version 2.10**:经历预览版和草案阶段后,于2002年3月7日正式对联盟成员开放。此次更新主要涉及第3部分关于状态转换的描述修改。 -...
源码直接下载地址: https://pan.quark.cn/s/a4b39357ea24 依据所提供的文档材料,可以归纳出以下核心知识点: 1. **TM1668控制器**:TM1668属于一种专为驱动LED显示屏设计的专用驱动集成电路,其特别适用于驱动数码管,能够达成多路LED的驱动与控制,从而提升了显示的效率。 2. **程序简化与时序控制**:程序完成了对TM1668芯片的操作,其功能已经达到最简化程度,且时序设置正确无误。在编程过程中,确保时序的准确性至关重要,因为它直接关联到设备能否正常运作。 3. **寄存器操作**:在编程实践中,运用了 uchar、int 等数据类型来表示数据及控制位。uchar或许是一种8位无符号字符类型,用于存储数据信息。同时,还涉及到对特定位的操作,比如 & 、 >> 等,这些操作用于设定或检测数据位的状态。 4. **硬件控制位**:在代码中,设定了用于控制TM1668的硬件控制位,涵盖 STB(片选信号)、CLK(时钟信号)以及 DIO(数据输入输出信号)。这些控制位的作用在于向TM1668发送指令与数据信息。 5. **数码管显示控制**:借助一系列的 send_data 函数调用,向TM1668发送控制指令与数据,以此来调控数码管的显示状态。例如,设定显示位、挑选显示地址、将数据传输至特定的数码管显示单元等。 6. **定时器中断**:在程序设计中,应用了定时器中断(INT0_timer)来周期性地执行任务。通过设定定时器的初始值(TH0和TL0),定时器在倒计时完成后会触发中断,使得程序能够以固定的频率更新数码管的显示内容。 7. **中断服务程序**:设定了一个中断服务程序,在定时器中断发生时被调用。在中断服务程序...

235

社区成员

发帖
与我相关
我的任务
社区描述
助力AI语音开发者的社区
语音识别人工智能自然语言处理 企业社区 北京·昌平区
社区管理员
  • 语音之家
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧