Metadata-Version: 2.3
Name: fasr-vad-fsmn
Version: 0.5.8
Summary: fsmn vad model for fasr
Author: osc
Author-email: osc <790990241@qq.com>
Requires-Dist: fasr
Requires-Dist: funasr-onnx
Requires-Dist: numpy>=1.24
Requires-Dist: onnxruntime>=1.16,<1.24
Requires-Python: >=3.10, <3.13
Description-Content-Type: text/markdown

# fasr-vad-fsmn

英文文档地址: [README_EN.md](README_EN.md)

FSMN 语音活动检测插件。离线 `fsmn` 模型通过 `funasr_onnx` 完成特征处理和
ONNX 推理；插件也提供 `fsmn_online` 用于流式 VAD。

## 安装

```bash
pip install fasr-vad-fsmn
```

## 注册模型

| 注册名 | 类 | 适用场景 |
|---|---|---|
| `fsmn` | `FSMNVad` | 离线 VAD，把完整音频切成语音片段 |
| `fsmn_online` | `FSMNVadOnline` | 流式 VAD，边接收音频边输出语音块 |

## 流水线使用

`add_pipe()` 中除 `component`、`model`、`batch_size` 等流水线参数外，其它
关键字参数会传给 detector 的模型。FSMN 参数可以直接写在 detector pipe 上：

```python
from fasr import AudioPipeline

pipeline = (
    AudioPipeline()
    .add_pipe(
        "detector",
        model="fsmn",
        max_end_silence_time=600,
        speech_noise_thres=0.55,
        num_threads=4,
    )
    .add_pipe("recognizer", model="paraformer")
    .add_pipe("sentencizer", model="ct_transformer")
)
```

常见配置可以这样选：

| 目标 | 写法 | 效果 |
|---|---|---|
| 少切碎句子 | `max_end_silence_time=1000` | 句中短暂停顿不容易切开 |
| 降低结束延迟 | `max_end_silence_time=300` | 更快结束片段，但句子可能更碎 |
| 噪声环境 | `speech_noise_thres=0.7` | 噪声误检更少，但轻声可能漏掉 |
| 轻声或远场 | `speech_noise_thres=0.45` | 更容易保留弱语音，但噪声更容易进入片段 |
| 提高 CPU 吞吐 | `num_threads=4` 或 `num_threads=8` | 更多 CPU 并行，CPU 占用也更高 |
| 使用 GPU | `device_id=0` | 使用第 0 张 GPU，需要安装 `onnxruntime-gpu` |

## Confection 配置

fasr 配置文件使用 Confection 的 TOML 风格，不是 YAML。

只配置 VAD 模型：

```toml
[vad_model]
@vad_models = "fsmn"
max_end_silence_time = 600
speech_noise_thres = 0.55
num_threads = 4
```

放在流水线里时，模型参数写在
`pipeline.pipes.detector.component.model` 下：

```toml
[pipeline]
@pipelines = "AudioPipeline.v1"
pipe_order = ["detector"]

[pipeline.pipes]

[pipeline.pipes.detector]
@pipes = "thread_pipe"
batch_size = 4
batch_timeout = 0.1

[pipeline.pipes.detector.component]
@components = "detector"
num_threads = 2
max_segment_duration = 30.0

[pipeline.pipes.detector.component.model]
@vad_models = "fsmn"
max_end_silence_time = 600
speech_noise_thres = 0.55
num_threads = 4
```

## 单独使用模型

模型实例化时会自动下载并加载权重。

```python
from fasr.config import registry
from fasr.data import AudioSpan, Waveform

model = registry.vad_models.get("fsmn")(
    max_end_silence_time=600,
    speech_noise_thres=0.55,
)

audio = AudioSpan(waveform=Waveform.from_file("example.wav"), start_ms=0)
segments = model.detect(audio)
for segment in segments:
    print(f"{segment.start_ms}ms - {segment.end_ms}ms")
```

使用本地权重目录：

```python
model.load_checkpoint("/path/to/fsmn-vad")
```

## 参数

离线 `fsmn` 只保留真正影响 `funasr_onnx` 推理的参数。`checkpoint`、
`cache_dir`、`endpoint`、`revision`、`force_download` 等通用参数由基类提供。

| 参数 | 类型 / 范围 | 默认值 | 调大时 | 调小时 | 什么时候改 |
|---|---|---|---|---|---|
| `sample_rate` | `int`，建议 `16000` | `16000` | 不建议，增加成本 | 不建议，可能损失语音细节 | 通常不要改 |
| `device_id` | `None`、`-1`、`"cpu"` 或 GPU id | `None` | 设置 GPU id 使用 GPU | `None` / `-1` / `"cpu"` 使用 CPU | 需要低延迟或高并发 |
| `num_threads` | `int >= 0` | `2` | CPU 推理可能更快，但占用更多核心 | 更省 CPU，但可能变慢 | CPU 部署调优 |
| `max_end_silence_time` | `int >= 0`，毫秒 | `500` | 更容忍停顿，片段更完整，结束更晚 | 结束更快，片段更碎 | 句子切太碎或结束太慢 |
| `speech_noise_thres` | `float`，`0.0` 到 `1.0` | `0.6` | 更严格，噪声误检少，轻声可能漏掉 | 更敏感，弱语音保留更多，噪声可能进入 | 噪声误检或轻声漏检 |

## 调参建议

| 现象 | 优先尝试 |
|---|---|
| 一句话被切成很多段 | `max_end_silence_time=1000` 或 `1200` |
| 说完后很久才结束 | `max_end_silence_time=300` 到 `500` |
| 背景噪声被当成语音 | `speech_noise_thres=0.7` 或 `0.8` |
| 轻声、远场说话被漏掉 | `speech_noise_thres=0.45` 或 `0.5` |
| CPU 占用太高 | 降低 `num_threads` |
| CPU 推理太慢 | 提高 `num_threads`，或安装 `onnxruntime-gpu` 并设置 `device_id=0` |

`fsmn_online` 使用 `device="cpu"` / `device="cuda"` 选择设备，并额外提供
`chunk_size_ms`。`chunk_size_ms` 越小越实时，但调度开销更大；越大吞吐更稳，
但输出更晚。默认 `100` ms 适合多数实时场景。

`fsmn_online` 还支持通过 `apply_turn_detection(...)` 做实时断句参数更新。
这个接口主要给 websocket 这类长连接会话使用；离线 `fsmn` 处理的是完整音频，
不需要这类运行时更新接口。

`fsmn_online` 的运行时调参重点如下：

| 参数 | 默认值 | 调大时 | 调小时 |
|---|---|---|---|
| `max_end_silence_time` / `silence_duration_ms` | `500` | 断句更保守，不容易过早切断，但最终结果延迟更高 | 断句更快，但更容易把一句话切成多段 |
| `speech_noise_thres` / `threshold` | `0.6` | 更严格，更抗噪，但可能漏掉轻声语音 | 更敏感，更容易抓到弱语音，但也更容易误触发噪声 |
| `prefix_padding_ms` | `0` | 更不容易截掉句首，但可能带入更多前置噪声 | 片段更紧，但更容易丢掉第一个音节 |

`prefix_padding_ms` 在 wrapper 层实现：检测到说话开始时，会把输出片段的起点
按设定值向前回退，并在已有缓冲音频范围内做裁剪。

## CPU / GPU

默认使用 CPU ONNX Runtime。加载模型时会打印当前使用 CPU 还是 GPU。

GPU 推理：

```bash
uv pip install onnxruntime-gpu
```

```python
model = registry.vad_models.get("fsmn")(device_id=0)
stream_model = registry.vad_models.get("fsmn_online")(device="cuda")
```

## 依赖

- `fasr`
- `funasr-onnx`
- `numpy >= 1.24`
- `onnxruntime >= 1.16, < 1.24`
- Python 3.10-3.12
