在上一篇博客《大模型之二十八-语音识别Whisper进阶》中我们留了一个尾巴,就是在流式场景以及如何提升推理速度。
流式场景
流式场景分两种,一种是伪流式一种是真流式,伪流式就是bilibili或者YouTub,终端用户在观看视频的时候,是从服务器或者CDN节点下载视频,其会缓存一些数据,对于真流式场景就是抖音直播这些场景,但是双向视频通讯的会议场景对延迟要求更为苛刻。
在视频会议场景,所有传输都没法类似制作好的视频事先缓存,因网络拥塞、数据传输路径的长度、服务器处理时间会导致通讯延迟,延迟是指数据从视频会议的一端源头传到另一端所需的时间,通常以毫秒(ms)为单位。在实时通信中,尤其是在视频会议中,较低的延迟是保证流畅通信的重要因素。
延迟对通话体验的影响:
延迟 | 影响 |
---|---|
低于 150 ms | 良好的,用户通常不会感觉到明显的延迟,类似面对面的交流。 |
150 ms 到 400 ms | 大多数情况仍可接受,在快速互动的对话中轻微不自然 |
400 ms 到 500 ms | 对话流畅性可能受影响,表现为更频繁地进行确认,以确保信息传达 |
超过 500 ms | 较大影响,用户可能会感到沟通困难,需要等待对方回应,这会打断对话的连贯性。 |
超过 800 ms | 不可接受,严重影响沟通效率和用户满意度。在这种延迟下,进行流畅的对话几乎是不可能的 |
通话场景下延迟是最为苛刻的,比YouTub视频平台要求严苛的多,虽然YouTub在ASR以及字幕翻译的时候会采用用户首次触发的机制启动字幕(当上传时未配置字幕时,将启用ASR服务)以减少服务器和存储开销,并在之后会类似上传的字幕一样存储字幕,在该视频的后续字幕请求的时候,直接下发字幕而非再次启用ASR服务。
但是本质上识别的过程和视频会议类似,这里衍生出两个问题1.如何加速原始模型的的推理速度(原始模型的输入窗长是30s),2.如何在流式场景使用?
原始模型加速
模型推理加速的核心思想是更加高效的使用运算和存储资源,对于大规模部署应用场景,目前底层一般是c/c++,服务端上层是c++/java/go之类的,所以这里以c/c++为例,不论是Whisper.cpp还是faster-whisper底层的核心都是c/c++。
对一个13分钟的音频,faster-whisper加速情况如下:
faster-whisper是基于CTranslate2库的,如果是考虑代码复用和模型支持的种类可以考虑faster-whisper,因为比较类似,这里以更纯粹的Whisper.cpp说明。
Whisper.cpp的结构如下:
- The core tensor operations are implemented in C (ggml.h / ggml.c)
- The transformer model and the high-level C-style API are implemented in C++ (whisper.h / whisper.cpp)
- Sample usage is demonstrated in main.cpp
- Sample real-time audio transcription from the microphone is demonstrated in stream.cpp
- Various other examples are available in the examples folder
因为神经网络主要是矩阵运算,ggml是利用硬件高效实现矩阵运算的具体实现,其他的都是封装和使用。
GGML特点如下:
Written in C
16-bit float support
Integer quantization support (4-bit, 5-bit, 8-bit, etc.)
Automatic differentiation
ADAM and L-BFGS optimizers
Optimized for Apple Silicon
On x86 architectures utilizes AVX / AVX2 intrinsics
On ppc64 architectures utilizes VSX intrinsics
No third-party dependencies
Zero memory allocations during runtime
还有一类的优化是从模型侧入手的,比如whisper-medusa,其在原有模型的基础上,增加了10个Medusa Head,以增加自回归模型的并行输出能力。
Steam流式
因为实时性要求,对于视频会议识别长度(输入长度)一般都在500ms左右,也就是1~3个字左右,但是如果仅仅输入500ms左右时长的音频,比如“办理登记”和“办理登机”非常接近,但是如果送入的仅仅就是500ms这么短的音频,就很可能导致识别错误,如果能够增加上下文,比如收入的是:“他到飞机场,办理…"这时,识别的准确性会高很多,这就是滑动窗口。
- 有效识别长度:如上面对于视频会议中选择的500ms,YouTub可以选择3~5秒这个长度可以根据实际需求和模型性能进行调整。
- 输入长度: 一般ASR系统输入长度为5至30秒的音频,对于Whisper可以选择30秒。
以1秒有效识别长度,15秒输入长度为例,针对视频会议是先攒段时间,如3秒钟(太短了就算识别也是没有意义的),其中一段是:20秒-35秒,识别的包括了第35秒的音频,然后下一段是21秒~36秒,识别的结果包括了36秒,这被称为滑动窗口的重叠(这里重叠长度是14秒),这意味着他们最终输出的文本绝大多数是重复的。
输出长度和去重策略
由于滑动窗口的重叠,相邻的窗口可能会生成重复的字幕内容。因此,需要一种机制来识别和合并重复的输出,以提供清晰连贯的字幕。
- 去重逻辑:
- 时间戳对比:每个字幕片段都应该与时间戳关联。通过比较当前字幕片段的时间戳与前一片段的时间戳,可以判断是否存在重复。
- 文本对比:对于时间戳相近的字幕片段,可以进行文本内容的对比,确定是否有重复或部分重复。部分重复的片段可以通过字符串操作进行合并处理。
- 输出更新:
- 每次生成新的字幕片段后,都应该对现有的输出进行更新,这可能涉及添加新片段、删除旧片段或合并重复片段。
- 更新策略应确保字幕的流畅性和准确性,避免因重复或过时的信息造成观众的困扰。
stream
./stream -m ./models/ggml-base.en.bin -t 8 --step 500 --length 5000
比如这里的选择的有效识别长度是500ms,而识别的输入长度是5秒钟,当然,也可以使用VAD方法减少网络传输的复杂,节省服务端资源。
至此,基本上我们将ASR的开源最强多语言Whisper模型fine-tune,服务端加速、实时/伪实时场景都涵盖,另外一些针对问题规模,诸如数据量和模型size选择,服务端并发、业务场景参数调优等等这些和解决问题息息相关,需要实践的积累。
欢迎关注、点赞、收藏,以及时收到推送,接下来,我将分享和语音(音乐在后面)生成的,TTS(Text to speech)以及VC(voice clone),这个应用场景包括解说配音(影视解说就那几个比较有名的配音)、有声书、对话机器人、机器情感伴侣、俱身机器人等场景应用非常广泛。