fix: respect explicit VAD silence threshold

This commit is contained in:
游雁
2026-06-11 15:16:24 +00:00
parent b78e636170
commit ef46055056
5 changed files with 94 additions and 2 deletions
+8
View File
@@ -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
+7
View File
@@ -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 推理引擎架构
+7
View File
@@ -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 推理引擎架构
+4 -2
View File
@@ -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)
+68
View File
@@ -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()