306KB!低延迟VAD,轻量高效,流式输入+延时实测

大模型微服务容器

picture.image

猴哥的第 188 期分享,欢迎追看

前面分享了,给小智 AI 接入 ASR:

低延迟小智AI服务端搭建-ASR篇

低延迟小智AI服务端搭建-ASR篇(续):CPU可跑

延迟是关键,为了抛弃对 GPU 的依赖,接入了火山引擎的流式语音识别

小智AI接入火山引擎ASR:双向流式+负载均衡

ASR 部分的流程图如下:

picture.image

其中,VAD 之前采用的模型来自 FunASR。

最近在把 小智AI服务端 拆成各个独立的微服务,封装成 Docker 镜像,目标是所有微服务可以在 CPU 上跑起来。

不过这个 VAD 实现需要依赖 torch,打包后的镜像体积来到了 1.59G。

急需寻找 VAD 的平替方案!

今日分享:一款轻量高效的 VAD 方案 -- TEN-VAD,并给出对比实测,给有类似需求的朋友一点点参考!

1.TEN-VAD 简介

项目地址:https://github.com/TEN-framework/ten-vad

TEN-VAD 是一个低延迟,高准确率 语音活动检测模型,来看官方效果图:

picture.image

有哪些亮点?

1. 跨平台兼容:

TEN VAD 开源了 Linux(.so)、Windows(.dll)、macOS & iOS(.framework)、Android(.so)、Web(.wasm)所需的二进制文件及示例代码,开箱即用。

picture.image

2. 轻量级:

Linux 平台下的动态库链接,低至 306KB:

picture.image

  1. TEN-VAD 使用

本文将基于 Linux 平台进行实测。

2.1 工作原理

官方提供了动态链接库 - libten\_vad.so,它是由编译型语言编写,并编译成机器码的二进制文件。

而 Python 中,可以通过 ctypes 模块,调用 C/C++ 编写的动态库:

  
from ctypes import CDLL  
self.vad\_library = CDLL("ckpts/libten\_vad.so")  # 加载动态库  

调用过程如下:

  
Python 代码 → ctypes → libten\_vad.so → 执行 C/C++ 代码 → 返回结果  

从而实现:用简单的 Python 语言,充分利用 C/C++ 的性能优势。

注意 :系统中需安装libc++1

  
sudo apt update  
sudo apt install libc++1  

2.2 实现逻辑

官方提供了 Python 调用的示例代码,位于include/ten\_vad.py

无需任何复杂依赖,只要环境中有 numpy 即可跑起来!

核心功能函数如下:

  
def process(self, audio\_data: np.ndarray):  
        input\_pointer = self.get\_input\_data(audio\_data)  
        self.vad\_library.ten\_vad\_process(  
            self.vad\_handler,  
            input\_pointer,  
            c\_size\_t(self.hop\_size),  
            POINTER(c\_float)(self.out\_probability),  
            POINTER(c\_int32)(self.out\_flags),  
        )  
        return self.out\_probability.value, self.out\_flags.value  

输入是 np.int16 类型的 PCM 音频格式,长度等于 hop\_size(默认256个采样点)。

注意 :输入必须是 16kHz 采样的音频数据,因此 256 采样点对应 16ms 的音频。

输出是语音概率和标志位,用于判断每个小段音频是否包含语音活动。

2.3 流式输入

问题来了 :如何用它实时检测流式输入音频中的语音活动?

要实现哪些功能呢?

  1. 语音段检测
  • 将输入的长音频分割成小块(每块 hop_size 个采样点)
  • 逐块检测是否包含语音活动
  • 记录语音段的开始和结束时间
  1. 连续处理与缓存
  • 支持流式处理(通过 truncated 参数控制)
  • 维护 vad_cache 缓存,保存历史检测结果
  • 处理跨批次的语音段连接

以下给出笔者的实现,供大家参考:

  
    def generate(self, input: np.ndarray, truncated=False):  
        '''process audio data trunks'''  
        if truncated:  
            self.last\_pos = 0  
            self.vad\_cache = []  
        num\_frames = input.shape[0] // self.hop\_size  
        speech\_segments = []  
        current\_segment\_start = None  
        for i in range(num\_frames):  
            audio\_data\_trunk = input[i * self.hop\_size: (i + 1) * self.hop\_size]  
            \_, out\_flag = self.process(audio\_data\_trunk)  
            # 计算当前chunk的时间戳(毫秒)  
            current\_time\_ms = self.last\_pos + i * self.hop\_size // 16  # 采样率为16kHz  
            if out\_flag == 1 and current\_segment\_start is None:  
                # 如果检测到语音且当前没有记录起始位置,则记录起始位置  
                current\_segment\_start = current\_time\_ms  
            if out\_flag == 0 and current\_segment\_start is not None:  
                # 如果检测到非语音且之前有语音段,则结束当前段  
                speech\_segments.append([current\_segment\_start, current\_time\_ms])  
                current\_segment\_start = None  
        # 处理最后一段语音(如果结束时仍在语音中)  
        if current\_segment\_start is not None:  
            speech\_segments.append([current\_segment\_start, -1])  
        # 处理vad\_cache  
        if len(self.vad\_cache) > 0 and self.vad\_cache[-1][1] == -1:  
            if len(speech\_segments) == 0:  
                self.vad\_cache[-1][1] = self.last\_pos  
            else:  
                self.vad\_cache[-1][1] = speech\_segments[0][1]  
                speech\_segments = speech\_segments[1:]  
        self.vad\_cache.extend(speech\_segments)  
        self.last\_pos += num\_frames * self.hop\_size // 16  
        return self.vad\_cache  

2.4. 延时实测

输入为 240ms 的音频片段,延时实测效果如下:

  • 方案一:FunASR 中的 VAD模型:
  
Time cost: 0.16324639320373535s []   
Time cost: 0.007938146591186523s [[0, -1]]   
Time cost: 0.007047176361083984s []   
Time cost: 0.006856679916381836s []   
Time cost: 0.006888389587402344s [[-1, 930], [930, -1]]  

  • 方案二:TEN-VAD 模型:
  
Time cost: 0.004173994064331055s [[208, -1]]   
Time cost: 0.003608226776123047s [[240, -1]]   
Time cost: 0.004375457763671875s [[480, 656]]   
Time cost: 0.0036001205444335938s []   
Time cost: 0.004243135452270508s [[1040, -1]]   

可以发现,对于 240ms 的音频输入,延时稳定在 3-4ms,只有方案一的一半。

由于抛弃了对 torch 的依赖,整个 ASR 镜像的体积也降到了 342MB

  
REPOSITORY                IMAGE ID          SIZE  
espbot-asr-worker       af4487d1b92c       1.59GB  
espbot-asr-worker-ten   6960580c9785       342MB  

  1. 接入小智AI

由于 VAD 部分的延时几乎可忽略,整个处理过程的延时基本等于设置的静音时长

picture.image

而 ASR 这里采用流式识别,延时也几乎可忽略,因此整个方案的延时约等于0。

写在最后

本文分享了一款轻量高效的 VAD 方案 -- TEN-VAD,并给出了对比实测。

如果对你有帮助,欢迎点赞收藏 备用。

👇 关注猴哥,快速入门AI工具

picture.image

# AI 工具:

本地部署大模型?看这篇就够了,Ollama 部署和实战

盘点9家免费且靠谱的AI大模型 API,统一封装,任性调用!

免费GPU算力本地跑DeepSeek R1,无惧官方服务繁忙!

# AI应用** :**

弃坑 Coze,我把 Dify 接入了个人微信,AI小助理太强了

我把「FLUX」接入了「小爱」,微信直接出图,告别一切绘画软件!

202K 下载!最强开源OCR:本地部署,邀你围观体验

阿里开源TTS CosyVoice 再升级!语音克隆玩出新花样,支持流式输出

借 WeChatFerry 东风,我把微信机器人复活了!

成本不到50的AI对话机器人,如何自建服务端?自定义角色+语音克隆

0
0
0
0
关于作者

文章

0

获赞

0

收藏

0

相关资源
大规模高性能计算集群优化实践
随着机器学习的发展,数据量和训练模型都有越来越大的趋势,这对基础设施有了更高的要求,包括硬件、网络架构等。本次分享主要介绍火山引擎支撑大规模高性能计算集群的架构和优化实践。
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论