From ef4605505664038ee4420055055da29367623e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B8=B8=E9=9B=81?= Date: Thu, 11 Jun 2026 15:16:24 +0000 Subject: [PATCH] fix: respect explicit VAD silence threshold --- docs/vllm_guide.md | 8 +++ docs/vllm_guide_zh.md | 7 +++ docs/vllm_guide_zh_v2.md | 7 +++ funasr/models/fsmn_vad_streaming/model.py | 6 +- tests/test_fsmn_vad_dynamic_silence.py | 68 +++++++++++++++++++++++ 5 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 tests/test_fsmn_vad_dynamic_silence.py diff --git a/docs/vllm_guide.md b/docs/vllm_guide.md index f180ea7c3..d6729640e 100644 --- a/docs/vllm_guide.md +++ b/docs/vllm_guide.md @@ -45,6 +45,14 @@ cd /path/to/FunASR && pip install -e . **Hardware**: GPU ≥ 8 GB VRAM, CUDA ≥ 11.8. 16 GB+ recommended. +Install a PyTorch/torchaudio/vLLM combination that matches your NVIDIA driver and +CUDA runtime. Do not blindly keep the newest wheel if it was built for a newer +CUDA runtime than your driver supports; PyTorch can fail during CUDA +initialization with `The NVIDIA driver on your system is too old` before FunASR +starts. If that happens, reinstall compatible PyTorch, torchaudio, and vLLM +wheels for the CUDA version reported by `nvidia-smi`, or update the NVIDIA +driver first. + --- ## 2. vLLM Engine Architecture diff --git a/docs/vllm_guide_zh.md b/docs/vllm_guide_zh.md index bce42db5e..81e44c314 100644 --- a/docs/vllm_guide_zh.md +++ b/docs/vllm_guide_zh.md @@ -44,6 +44,13 @@ cd /path/to/FunASR && pip install -e . **硬件**:GPU ≥ 8GB VRAM,CUDA ≥ 11.8。推荐 16GB+。 +请根据 NVIDIA 驱动和 `nvidia-smi` 显示的 CUDA 版本选择匹配的 +PyTorch/torchaudio/vLLM 组合,不要无条件保留 pip 拉到的最新 wheel。若 +vLLM 或 PyTorch wheel 依赖的 CUDA runtime 高于当前驱动支持范围,可能在 +FunASR 启动前就报 `The NVIDIA driver on your system is too old`。遇到该错误时, +优先重装与当前驱动/CUDA 匹配的 PyTorch、torchaudio、vLLM wheel,或先升级 +NVIDIA 驱动。 + --- ## 2. vLLM 推理引擎架构 diff --git a/docs/vllm_guide_zh_v2.md b/docs/vllm_guide_zh_v2.md index 80a00c8d3..0e4a6ea2b 100644 --- a/docs/vllm_guide_zh_v2.md +++ b/docs/vllm_guide_zh_v2.md @@ -45,6 +45,13 @@ cd /path/to/FunASR && pip install -e . **硬件**:GPU ≥ 8GB VRAM,CUDA ≥ 11.8。推荐 16GB+。 +请根据 NVIDIA 驱动和 `nvidia-smi` 显示的 CUDA 版本选择匹配的 +PyTorch/torchaudio/vLLM 组合,不要无条件保留 pip 拉到的最新 wheel。若 +vLLM 或 PyTorch wheel 依赖的 CUDA runtime 高于当前驱动支持范围,可能在 +FunASR 启动前就报 `The NVIDIA driver on your system is too old`。遇到该错误时, +优先重装与当前驱动/CUDA 匹配的 PyTorch、torchaudio、vLLM wheel,或先升级 +NVIDIA 驱动。 + --- ## 2. vLLM 推理引擎架构 diff --git a/funasr/models/fsmn_vad_streaming/model.py b/funasr/models/fsmn_vad_streaming/model.py index 9874affd5..ae5f43aaa 100644 --- a/funasr/models/fsmn_vad_streaming/model.py +++ b/funasr/models/fsmn_vad_streaming/model.py @@ -938,8 +938,10 @@ class FsmnVADStreaming(nn.Module): n = int(len(audio_sample) // chunk_stride_samples + int(_is_final)) m = int(len(audio_sample) % chunk_stride_samples * (1 - int(_is_final))) segments = [] - # Dynamic silence threshold - dynamic_silence = kwargs.get("dynamic_silence", True) + # Keep explicit fixed-threshold requests from being overwritten by the dynamic schedule. + dynamic_silence = kwargs.get( + "dynamic_silence", kwargs.get("max_end_silence_time") is None + ) silence_schedule = kwargs.get("silence_schedule", DEFAULT_SILENCE_SCHEDULE) speech_to_sil_ms = self.vad_opts.speech_to_sil_time_thres accumulated_ms = cache.get("_dynamic_accumulated_ms", 0) diff --git a/tests/test_fsmn_vad_dynamic_silence.py b/tests/test_fsmn_vad_dynamic_silence.py new file mode 100644 index 000000000..f396614f9 --- /dev/null +++ b/tests/test_fsmn_vad_dynamic_silence.py @@ -0,0 +1,68 @@ +import unittest +from types import SimpleNamespace +from unittest.mock import patch + +import torch + +from funasr.models.fsmn_vad_streaming import model as vad_model + + +class TestFsmnVadDynamicSilence(unittest.TestCase): + def _run_inference(self, **kwargs): + vad = vad_model.FsmnVADStreaming.__new__(vad_model.FsmnVADStreaming) + vad.vad_opts = SimpleNamespace(speech_to_sil_time_thres=100) + vad.forward = lambda **batch: [] + + cache = { + "frontend": {}, + "prev_samples": torch.empty(0), + "encoder": {}, + "stats": SimpleNamespace( + vad_state_machine=vad_model.VadStateMachine.kVadInStateInSpeechSegment, + max_end_sil_frame_cnt_thresh=200, + speech_noise_thres=0.6, + ), + } + frontend = SimpleNamespace(fs=16000, frame_shift=10, lfr_n=1) + + def fake_extract_fbank(*args, **kwargs): + cache["frontend"]["waveforms"] = torch.zeros(1, 16000) + return torch.zeros(1, 1, 80), torch.tensor([100]) + + with ( + patch.object( + vad_model, + "load_audio_text_image_video", + return_value=[torch.zeros(16000)], + ), + patch.object(vad_model, "extract_fbank", side_effect=fake_extract_fbank), + ): + vad_model.FsmnVADStreaming.inference( + vad, + torch.zeros(16000), + frontend=frontend, + cache=cache, + key=["utt"], + chunk_size=1000, + is_final=False, + device="cpu", + **kwargs, + ) + + return cache + + def test_explicit_max_end_silence_time_keeps_fixed_threshold_by_default(self): + cache = self._run_inference(max_end_silence_time=300) + + self.assertEqual(cache["stats"].max_end_sil_frame_cnt_thresh, 200) + self.assertNotIn("_dynamic_accumulated_ms", cache) + + def test_explicit_dynamic_silence_still_enables_schedule(self): + cache = self._run_inference(max_end_silence_time=300, dynamic_silence=True) + + self.assertEqual(cache["stats"].max_end_sil_frame_cnt_thresh, 1900) + self.assertEqual(cache["_dynamic_accumulated_ms"], 1000) + + +if __name__ == "__main__": + unittest.main()