Home kaldi vs wenet:online流程设计对照
Post
Cancel

kaldi vs wenet:online流程设计对照

  ASR online实现是工程实现必不可少的一环,可以随着用户实时语音流的输入及时返回识别结果,对于用户体验感非常重要。kaldi/wenet都支持全流程的online实现,主要包括online feature extractor、online model inference、online decoding。由于wenet借鉴了kaldi的不少实现思路和代码,所以本文以kaldi为主介绍online实现的整体思路,并在差异化环节分别介绍kaldi和wenet的实现和简单原理,本文还是遵循kaldi的初衷使用“online”(而非“流式”或者“实时”)作为一种谨慎描述。

Take care

完成一个Online系统,要妥善处理几方面:

  • processing level:一般有三个level,分别为frame-level,chunk-level,utterence-level。hmm-based asr由于遵循一阶马尔可夫假设,基本可以做到frame-level。self-attention based在ASR(短时上下文依赖特性)应用中可以用chunk-level,当然utterence-level会更好。同时在最上层一般都是utterence-level综合决策,如voice activity detection,end-point detection or rescoring 。
  • offset:全局的偏移量。如kaldi decoder中num_frame_decoded_,wenet中transformer positon encoding。
  • cache:由于网络的上下文依赖,feature一般需要cache多帧,如kaldi中mfcc或者wenet中的fbank的queue实现。同时网络中间层的输出由于存在复用性,也会进行cache。decode部分同样依赖历史解码信息,在kaldi中的token保存,transformer中decoder层的自回归解码。
  • interact:不同模块之间的交互逻辑。如feature extractor和model inference模块之间的交互。model在online模式下是如何使用feature的。

对于上述细节在kaldi和wenet中再着重展开一下。

feature extraction

  wenet基本采用了kaldi中FeaturePipeline的接口和实现逻辑,但是又略有差别。

目的和差别kaldiwenet
waveform输入,kaldi中实现了resampling
操作,wenet做了简化
void AcceptWaveform(
BaseFloat sampling_rate,
constVectorBase &waveform) = 0;
void FeaturePipeline::AcceptWaveform(const
std::vector& wav);
下层访问接口,kaldi中提供了随机访问的接
口,使用NumFramesReady()信号,而
wenet严格按照顺序方式生产和消耗。同时
当模型需要的特征得不到满足时,会阻塞在
ReadOne()
void GetFrame(int32 frame,
VectorBase *feat);
bool ReadOne(std::vector* feat)
cache,kaldi中采用了简单的双端队列实
现,而wenet考虑到多线程部署问题,采
用了更为智能的BlockingQueue,但会阻
塞线程。
std::deque<Vector*> items_;BlockingQueue<std::vector> feature_queue_;
offsetfeature_.Size()num_frames_
kaldi中其他有意思的实现惰性计算,如ivector 

model structure and inference

  由于kaldi和wenet采用了完全不同的网络结构,所以该处的实现区别很大,TDNN实现相对简单,而conformer/transformer的实现复杂一些。kaldi将model inference整合成单独的模块,而wenet采用了torch jit script进行模型前向并整合到torch_asr_decoder中。

目的和差别kaldiwenet
feature输入非阻塞式,NumFramesReady()阻塞式
下层访问接口,kaldi中提供了
LogLikelihood()惰性触发网络
计算,而wenet每个chunk直
接触发网络前向计算。
BaseFloat LogLikelihood(int32 frame,
int32 index);
model_->torch_model() ->run_method(“ctc_activation”, chunk_out) .toTensor()[0];
cache,kaldi中所有的cache内部
进行统一管理(内部相对复杂的
dilated 1d-cnn cache结构),
只要满足一个chunk的特征数据
即可计算。wenet显式传入cache,
同时left context feature也需要cache。
所有cache内部管理。subsampling_cache: subsampling的输出的cache。
elayers_output_cache:所有conformer block的输出的cache。
conformer_cnn_cache: conformer block内部 causal conv层的左侧依赖的输入cache。
网络结构和上下文,网络基本没有
太多共同之处。在subsampling上
略有共同点,kaldi 实现了1d-cnn
的叠加,wenet使用2d-cnn,优化
帧率和解码计算量。kaldi为了避免
右侧依赖过长而使用了不对称的网络结构
,使右侧依赖相对较小。wenet只
依赖左侧chunk和conformer 内部
使用左侧依赖的casual cnn,使得
只有在subsampling时引入少许右侧依赖。
subsampling: dilated 1d-cnn
叠加降低计算量和跳帧解码降低帧率

一种可能配置
chunk_size =18
right_context = 9
left_context = 12
subsampling: 2d-cnn直接降低帧率且降低计算量
一种可能配置
chunk_size =16*4(wenet直接从decoder角度描述chunk_size,则实际的net chunk_size = subsampling_factor*chunk_size)
right_context = 6
left_context = num_left_chunks*chunk_size

decoder

  kaldi一般采用基于WFST结构的HCLG解码图进行解码,而wenet由于端对端网络结构的特殊性,采用了多种解码策略,比较重要的有两种:1.基于WFST结构的TLG解码图进行解码。2.基于CTC prefix beam search的direct decode和attention parallel rescoring。方法1和kaldi基本一致,而方法2和kaldi无关。同时两个decoder的含义略有不同,kaldi decoder只负责给定网络前向结果后的解码搜索。而wenet将网络前向和解码搜索整合到torch_asr_decoder中简化了流程,但是实际的解码在SearchInterface的派生类中实现,当实现为CtcWfstBeamSearch和kaldi几乎一致。   同时由于基于WFST的解码方式基本依赖左侧,因此具有天然的online特性。对于lattice-faster-online-decoder,相对去之前lattice-faster-decoder实现了更为高效的get partial result,cache也只是为了记录active_tokens_。

目的和差别kaldiwenet
score获取BaseFloat LogLikelihood(int32 frame,
int32 index)
ctc_log_probs = model_->torch_model()>run_method(“ctc_activation”, chunk_out).toTensor()[0];
实际由于复用了kaldi的LatticeFasterDecoder,所以当search函数采用kWfstBeamSearch模式时,采用了fake的decodable对象进行接口转换。
decoderlattice-faster-online-decoderlattice-faster-online-decoder
Graph结构HCLG采用CtcWfstBeamSearch时会在TLG上进行搜索。 采用CtcPrefixBeamSearch时则没有使用WFST。
search strategybeam search, max_active, min_activeCtcPrefixBeamSearch: two pass beam prune

CtcWfstBeamSearch: kaldi beam search, blank_skip_thresh skip blank frame.
outputone-best, n-best, latticeCtcWfstBeamSearch: one-best,n-best,lattice
CtcPrefixBeamSearch: one-best,n-best

reference

[1] https://github.com/kaldi-asr/kaldi

[2] https://github.com/wenet-e2e/wenet

[3] Wenet网络设计与实现4-Cache - 知乎 (zhihu.com)

This post is licensed under CC BY 4.0 by the author.

Trending Tags