Zipformer
1 概述¶
1.1 背景介绍¶
Zipformer 是k2-fsa/icefall生态主推的新一代语音识别编码器(ASR),兼顾高效建模与低延迟流式推理,具有速度快、显存占用低、精度高等特点。icefall完整实现了流式/非流式、RNNT-T架构下的全套训练、推理流程。
详情可参考官方说明
https://github.com/k2-fsa/icefall/blob/master/README.md
该示例采用流式推理+RNNT-T的架构进行部署,模型下载地址如下: - kws_librispeech
注意:该模型是基于librispeech数据集训练的,如有其他需求可从icefall官网下载其他模型进行转换。
1.2 使用说明¶
Linux SDK-alkaid中默认带了已经预先转换好的离线模型及板端示例, 相关文件路径如下:
-
板端示例程序路径
Linux_SDK/sdk/verify/opendla/source/asr/zipformer -
板端离线模型路径
Linux_SDK/project/board/${chip}/dla_file/ipu_open_models/asr/zipformer_encoder.img Linux_SDK/project/board/${chip}/dla_file/ipu_open_models/asr/zipformer_decoder.img Linux_SDK/project/board/${chip}/dla_file/ipu_open_models/asr/zipformer_joiner.img -
板端测试音频路径
Linux_SDK/sdk/verify/opendla/source/resource/zipformer/1188-133604-0000.wav -
板端测试字典路径
Linux_SDK/sdk/verify/opendla/source/resource/zipformer/tokens.txt Linux_SDK/sdk/verify/opendla/source/resource/zipformer/tokenizer_config.json Linux_SDK/sdk/verify/opendla/source/resource/zipformer/preprocessor_config.json
如果用户不需要转换模型可直接跳转至第3章节。
2 模型转换¶
2.1 onnx模型转换¶
-
python环境搭建
$conda create -n zipformer python==3.11 $conda activate zipformer $git clone https://github.com/k2-fsa/icefall.git注意: 这里提供的python环境搭建, 仅作为参考示例, 具体搭建过程请参考官方源码运行教程:
https://k2-fsa.github.io/icefall/installation/index.html -
模型导出
-
安装依赖库
$pip install onnx -i https://pypi.tuna.tsinghua.edu.cn/simple -
下载的模型会包含
- pretrianed.pt
- data/lang_bpe_500/tokens.txt
-
运行icefall自带的模型转换脚本, 确保icefall环境配置正确。
$cd icefall/egs/librispeech/ASR/ $export PYTHONPATH=$PYTHONPATH:$(pwd)/../../../ $python ./zipformer/export-onnx-streaming-new.py \ --exp-dir icefall-asr-librispeech-streaming-zipformer-2023-05-17/exp \ --tokens icefall-asr-librispeech-streaming-zipformer-2023-05-17/data/lang_bpe_500/tokens.txt \ --use-averaged-model 0 \ --epoch 30 \ --avg 1 \ --chunk-size 16 \ --left-context-frames 128 \ --decoder-dim 512 \ --joiner-dim 512 \ --num-encoder-layers 2,2,3,4,3,2 \ --feedforward-dim 512,768,1024,1536,1024,768 \ --encoder-dim 192,256,384,512,384,256 \ --encoder-unmasked-dim 192,192,256,256,256,192 \ --causal 1
其中,
exp即为从官网上下载的模型文件夹, 可自行命名。模型转换成功后, 输出的log信息中会打印:Export decoder to path/decoder-epoch-99-avg-1-chunk-16-left-128.onnxExport encoder to path/encoder-epoch-99-avg-1-chunk-16-left-128.onnxExport jointer to path/jointer-epoch-99-avg-1-chunk-16-left-128.onnx此时已经可以转换出onnx, 但是还无法部署到到我们的平台, 需要对某些算子进行修改。
-
-
模型修改
模型转换代码中已提供代码修改的patch,可直接运行修改,运行命令如下:
$cp 0001-modify-export-onnx-streaming.py-for-fixed-inference.patch ./ $git am 0001-modify-export-onnx-streaming.py-for-fixed-inference.patch修改完成后, 再执行模型导出步骤, 即可生成可以部署的zipformer.onnx模型。 - encoder_optimized-epoch-30-avg-1-chunk-16-left-128.onnx - decoder-epoch-30-avg-1-chunk-16-left-128.onnx - joiner-epoch-30-avg-1-chunk-16-left-128.onnx
2.2 离线模型转换¶
2.2.1 offline模型转换流程¶
注意:1)OpenDLAModel对应的是压缩包image-dev_model_convert.tar解压之后的smodel文件。2)与其他算法不同的是,该算法不需要进入docker即可转换。
-
拷贝onnx模型到转换代码目录
$cp path/encoder_optimized-epoch-30-avg-1-chunk-16-left-128.onnx OpenDLAModel/asr/zipformer/onnx $cp path/decoder-epoch-30-avg-1-chunk-16-left-128.onnx OpenDLAModel/asr/zipformer/onnx $cp path/joiner-epoch-30-avg-1-chunk-16-left-128.onnx OpenDLAModel/asr/zipformer/onnx -
转换命令
#进入到OpenDLAModel目录 $cd /work/SGS_XXX/OpenDLAModel $bash convert.sh -a asr/zipformer -c config/asr_zipformer.cfg -p SGS_IPU_Toolchain(绝对路径) -s false -
最终生成的模型地址
output/${chip}_${时间}/zipformer_encoder.img output/${chip}_${时间}/zipformer_decoder.img output/${chip}_${时间}/zipformer_joiner.img
2.2.2 预&后处理说明¶
-
预处理
该模型的输入为fbank特征,fbank的提取流程为:对16kHz原始音频依次进行预加重、分帧(帧长25ms、帧移10ms)、加汉明窗、FFT计算幅度谱,再通过80维Mel滤波器组并取对数,得到80维对数梅尔滤波器组特征,作为encoder的输入。
-
后处理
该模型有多种后处理(解码方式),这里介绍两种:prefix_beam_search或者greedy search
-
greedy search(贪心解码)
每一步直接选取 logit 最大值对应的 token 作为输出,路径唯一、速度快、计算量小。
-
Prefix Beam Search(前缀束搜索)
- 维护多个候选序列(前缀),每个时间步对所有候选扩展 token,按累计概率保留 top-N(beam size,对应 -n 参数)条路径。
- 对相同前缀的分数做合并,避免重复路径,最后输出累计分数最高的序列。
这种解码方式准确率更高、更鲁棒;代价是计算和显存开销更大,速度更慢。
-
2.2.3 关键脚本参数解析¶
-
encoder_config.ini
[INPUT_CONFIG] inputs=x,encoder_states_0,encoder_states_1,encoder_states_2,encoder_states_3,encoder_states_4,encoder_states_5,embed_states,processed_lens; input_formats=RAWDATA_F32_NHWC,RAWDATA_F32_NHWC,RAWDATA_F32_NHWC,RAWDATA_F32_NHWC,RAWDATA_F32_NHWC,RAWDATA_F32_NHWC,RAWDATA_F32_NHWC,RAWDATA_F32_NHWC,RAWDATA_S16_NHWC; quantizations=TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE; [OUTPUT_CONFIG] outputs=encoder_out,new_encoder_states_0,new_encoder_states_1,new_encoder_states_2,new_encoder_states_3,new_encoder_states_4,new_encoder_states_5,new_embed_states,new_processed_lens; dequantizations=TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,TRUE; [OPTIMIZE_CONFIG] optimize_layernorm_precision=TRUE; [CONV_CONFIG] input_format=ALL_FP16; # int16量化时, 如果是mhera之后的chip,都是ALL_FP16 -
decoder_config.ini
[INPUT_CONFIG] inputs=y; input_formats=RAWDATA_S16_NHWC; quantizations=TRUE; [OUTPUT_CONFIG] outputs=decoder_out; dequantizations=TRUE; [OPTIMIZE_CONFIG] optimize_layernorm_precision=TRUE; [CONV_CONFIG] input_format=ALL_FP16; # int16量化时, 如果是mhera之后的chip,都是ALL_FP16;否则,填ALL_INT16 -
joiner_config.ini
[INPUT_CONFIG] inputs=encoder_out,decoder_out; input_formats=RAWDATA_F32_NHWC,RAWDATA_F32_NHWC; quantizations=TRUE,TRUE; [OUTPUT_CONFIG] outputs=logit; dequantizations=TRUE; [OPTIMIZE_CONFIG] optimize_layernorm_precision=TRUE; [CONV_CONFIG] input_format=ALL_FP16; # int16量化时, 如果是mhera之后的chip,都是ALL_FP16
2.3 模型仿真¶
-
获取float/fixed/offline模型输出
$bash convert.sh -a asr/zipformer -c config/asr_zipformer.cfg -p SGS_IPU_Toolchain(绝对路径) -s true执行上述命令后,根据输入的参数,会对
float、fixed、offline进行推理,可在代码中添加打印获取模型输出tensor。 -
模型精度对比
python asr/zipformer/sim_onnx_zipformer.py \ --encoder output/${chip}_${时间}/zipformer_decoder.img \ --decoder output/${chip}_${时间}/zipformer_decoder.img \ --joiner output/${chip}_${时间}/zipformer_joiner \ --tokens asr/zipformer/tokens.txt \ --wav asr/zipformer/test_wavs/1089-134686-0001.wav \ --sample-rate 16000 \ --feature-dim 80 \ --optimized执行上述命令后,会输出onnx模型的推理结果,可在中间添加打印,获取模型的输出tensor。
3 板端部署¶
3.1 程序编译¶
示例程序编译之前需要先根据板子(nand/nor/emmc, ddr型号等)选择deconfig进行sdk整包编译, 具体可以参考alkaid sdk sigdoc《开发环境搭建》文档。
-
编译板端zipformer示例。
$cd sdk/verify/opendla $make clean && make source/asr/zipformer -j8 -
最终生成的可执行文件地址
sdk/verify/opendla/out/${AARCH}/app/prog_asr_zipformer
3.2 运行文件¶
运行程序时, 需要先将以下几个文件拷贝到板端
- prog_asr_zipformer
- 1188-133604-0000.wav
- tokens.txt
- tokenizer_config.json
- preprocessor_config.json
- zipformer_decoder.img
- zipformer_encoder.img
- zipformer_joiner.img
3.3 运行说明¶
-
Usage:
./prog_asr_zipformer -d model -w wav -b use_beam_search -n beam_size(执行文件使用命令) -
Required Input:
- d:模型路径
- e:encoder 模型名称
- D:decoder 模型名称
- j:joiner 模型名称
- w:音频路径
- b:是否使用prefix_beam_search
- n: 使用的beam数量
-
Typical Output:
./prog_asr_zipformer -d models/zipformer/ -e zipformer_encoder.img -D zipformer_decoder.img -j zipformer_joiner.img -w models/zipformer/1188-133604-0000.wav -b true -n 5 Using models - encoder: zipformer_encoder.img, decoder: zipformer_decoder.img, jointer: zipformer_joiner.img load dict from models/zipformer/tokens.txt Loading Zipformer model from: models/zipformer/ init zipformer init decoder init encoder init jointer Model loaded successfully. Opened file: models/zipformer/1188-133604-0000.wav feats shape = [85680] zipformer response is : YOU WILL FIND ME CONTINUALLY SPEAKING OF FOUR MEN TITIAN HOBINE TURNER AND TINKORAT IN ALMOST THE SAME TERMS