离线语音识别库有whisper、kaldi、pocketshpinx等,在了解这些库的时候,发现了所谓“下一代Kaldi”的sherpa。从文档和模型名称看,它是一个很新的离线语音识别库,支持中英双语识别,文件和实时语音识别。我加了sherpa的交流群,提了一个issue后工作人员马上更新了代码,看来至少目前的支持也很不错。而sherpa-ncnn使用ncnn替代pytorch,“ncnn是一个为手机端极致优化的高性能神经网络前向计算框架”,更适合在小型的嵌入式平台上运行。
这里我分别用我的树莓派3B+和一台小型Windows服务器测试下sherpa-ncnn的文件识别性能,记录下供后续参考。
树莓派3B+的结果
安装过程不表,按照官方教程即可,注意选择Embedded Linux (arm)章节。
测试文件就使用sherpa-ncnn自带的wav文件,单通道采样率16000,选其中最长的一个(17s),具体信息如下:
pi@raspberrypi:~/sherpa-ncnn $ soxi sherpa-ncnn-conv-emformer-transducer-2022-12-06/test_wavs/4.wav
Input File : 'sherpa-ncnn-conv-emformer-transducer-2022-12-06/test_wavs/4.wav'
Channels : 1
Sample Rate : 16000
Precision : 16-bit
Duration : 00:00:17.64 = 282240 samples ~ 1323 CDDA sectors
File Size : 565k
Bit Rate : 256k
Sample Encoding: 16-bit Signed Integer PCM
sherpa提供了3种预训练的模型,分别为zipformer、LSTM和conv-enformer。测试音频是一段英语教学音频,所以这里都使用双语模型。
以zipformer小模型为例:
pi@raspberrypi:~/sherpa-ncnn $ build-arm-linux-gnueabihf/bin/sherpa-ncnn
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/tokens.txt
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/encoder_jit_trace-pnnx.ncnn.param
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/encoder_jit_trace-pnnx.ncnn.bin
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/decoder_jit_trace-pnnx.ncnn.param
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/decoder_jit_trace-pnnx.ncnn.bin
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/joiner_jit_trace-pnnx.ncnn.param
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/joiner_jit_trace-pnnx.ncnn.bin
./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/test_wavs/4.wav
2 greedy_search
Disable fp16 for Zipformer encoder
Don't Use GPU. has_gpu: 0, config.use_vulkan_compute: 1
ModelConfig(encoder_param="./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/encoder_jit_trace-pnnx.ncnn.param", encoder_bin="./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/encoder_jit_trace-pnnx.ncnn.bin", decoder_param="./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/decoder_jit_trace-pnnx.ncnn.param", decoder_bin="./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/decoder_jit_trace-pnnx.ncnn.bin", joiner_param="./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/joiner_jit_trace-pnnx.ncnn.param", joiner_bin="./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/joiner_jit_trace-pnnx.ncnn.bin", tokens="./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/tokens.txt", encoder num_threads=2, decoder num_threads=2, joiner num_threads=2)
DecoderConfig(method="greedy_search", num_active_paths=4, enable_endpoint=False, endpoint_config=EndpointConfig(rule1=EndpointRule(must_contain_nonsilence=False, min_trailing_silence=2.4, min_utterance_length=0), rule2=EndpointRule(must_contain_nonsilence=True, min_trailing_silence=1.4, min_utterance_length=0), rule3=EndpointRule(must_contain_nonsilence=False, min_trailing_silence=0, min_utterance_length=20)))
wav filename: ./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/test_wavs/4.wav
wav duration (s): 17.64
Started!
Done!
Recognition result for ./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/test_wavs/4.wav
嗯 ON TIME比较准时 IN TIME是及时叫他总是准时教他的作业那用一般现在时是没有什么感情色彩的陈述一个事实下一句话为什么要用现在进行时它的意思并不是说说他现在正在教他的
Elapsed seconds: 10.790 s
Real time factor (RTF): 17.640 / 10.790 = 0.612
结果中输出了运行参数,音频文件信息,以及识别结果。以上结果为2个线程,识别17s的文件用了10.79s,RTF=0.612。改用4线程:
Recognition result for ./sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16/test_wavs/4.wav
嗯 ON TIME比较准时 IN TIME是及时叫他总是准时教他的作业那用一般现在时是没有什么感情色彩的陈述一个事实下一句话为什么要用现在进行时它的意思并不是说说他现在正在教他的
Elapsed seconds: 8.930 s
Real time factor (RTF): 17.640 / 8.930 = 0.506
速度比2线程稍快,RTF=0.506。所有已发布的预训练双语模型的结果如下,其中CPU占用率为观察的大致值:
Windows主机的结果
测试用的Windows主机是一台做黑群晖的小型服务器,CPU是AMD 3000G,内存16GB, 可用内存14GB,操作系统是Windows 10 企业版 LTSM,划了4GB给VMWARE。
安装和编译sherpa-ncnn需要MSVC环境,同样跟着官网教程走,环境正确的话就没有问题。
各双语模型结果如下:
由于平台性能的提升,在识别速度方面大大改善。
结论
测试音频可能是取自一段课堂录音,老师的语速较快,其实际内容应该是:
“嗯,ON TIME叫准时,IN TIME是及时交。他总是准时交他的作业。那用一般现在时是没有什么感情色彩的,陈述一个事实。下一句话为什么要用现在进行时,它的意思并不是说,说他现在正在交他的。”
根据测试结果,识别结果与模型的关联度较强,与平台性能没有什么关系。
整体识别率都不错。其中有3个错字都是同音字,确实不容易识别。只有lstm-small的第二个jiao字正确,但也是因为它把后面的“他”误识别为“谈”,误打误撞组了词的关系,因此并不能说它的识别率更好。仅从这一小段的测试结果来看,大规模的模型效果好于小规模的模型,这是符合直觉的。所有模型在停顿上都一样,可能是因为原文后半段的语速较快,在这方面没有分出优劣。
而在识别速度方面,小规模的模型速度比大规模的更快,这也是符合直觉的。但是lstm-small在树莓派3B+上的优势没有在Windows主机上的显著。在树莓派3B+上,更多的线程可以略微提高识别速度,但收益不够明显。而在Windows主机上,更多的线程未必能提高速度,可能是因为在更高性能的平台上,少量线程已经能使RTF达到较低水平的缘故,与平台类型应该没有什么关联。
综上,我最终的选择是将Windows主机上的sherpa-ncnn打包成服务,由树莓派采集的语音通过局域网服务识别。模型方面,5秒以下的语音,用conv-emformer;5~10秒的语音用zipformer;超过10秒的语音就用lstm-small。这样可以最大程度平衡识别速度和质量。鉴于sherpa-ncnn的很多模型在树莓派3B+上的RTF比较大,有些甚至超过了语音本身的时长,只有zipformer-small-96还可以用一下。这个可以作为局域网方案的本地FAILSAFE。
注
- zipformer-small-96模型指的是:A faster model of sherpa-ncnn-streaming-zipformer-small-bilingual-zh-en-2023-02-16。
- 所有测试没有遍历多少次,并不是严谨的测试,仅供参考。