第一章節可參考
● 第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,即因果卷積左側依賴。
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!