# 显卡加速的若干问题

CapsWriter-Offline 支持多种 ASR 引擎：

| 引擎名 | 准确性 | 速度 | 格式 | 调用方式 | 显卡加速 |
|------|-------|------|------|---------|---------|
| Paraformer | ★★★☆☆ | ★★★★★ | ONNX | sherpa_onnx | ❌ |
| SenseVoice-Small | ★★★☆☆ | ★★★★★ | ONNX | 自定义引擎 | ✅ |
| Fun-ASR-Nano | ★★★★☆ | ★★★★☆ | ONNX + GGUF | 自定义引擎 | ✅ |
| Qwen3-ASR | ★★★★★ | ★★★☆☆ | ONNX + GGUF | 自定义引擎 | ✅ |


Paraformer 通过 sherpa_onnx 调用，不支持显卡加速，且需要外挂标点符号模型，不建议使用，仅作纪念性保留。

性能差的电脑，建议用 SenseVoice-Small；没有独显的电脑可以尝试用 Fun-ASR-Nano 和 Qwen3-ASR，如果延迟可以接受就用；有独显的电脑直接上最顶级的 Qwen3-ASR，准确率夯爆。


---

## 一、加速概览

所有的模型原本都是 PyTorch 格式，这种格式在推理时速度较慢，为更好的推理，他们被转为了 ONNX 格式。

Fun-ASR-Nano 与 Qwen3-ASR 的 LLM Decoder 部分，作者发现用 LLama.cpp 能够实现更快的速度、更低的延迟、更少的显存占用，因此将这部分转为了 GGUF 格式，用  LLama.cpp 推理。

| 组件 | 后端 | 运行方式 |
|------|---------|------|
| ONNX 组件 | ONNX Runtime | CPU / DirectML  |
| GGUF 组件 | llama.cpp | CPU / Vulkan |

---

## 二、ONNX 组件加速

ONNX 组件可以通过设置 Provider 配置使用 CPU 或 DirectML 显卡加速。

RTX5050 开启 DML 加速时，对于30秒内的音频，SenseVoice-Small 的识别延迟不到 80ms。

有朋友实测他的 AMD 集显、AMD 独显在打开 DirectML 加速后，反而可能导致变慢，为了让这部份用户开箱可用，`DML` 加速默认是关的，需手动修改打开。

### Provider 如何配置

编辑 [config_server.py](../config_server.py)，找到你使用的引擎配置类，修改 `onnx_provider`：

```python
FunASRNanoGGUFArgs(
    onnx_provider='DML',        # ← 改为 DML，即可用 DirectML 显卡加速
    llm_use_gpu=True,           # GGUF 部分是否用 GPU，默认 True
    dml_pad_to=30,              # DML 专用优化参数
)

SenseVoiceArgs(
    onnx_provider='DML',        # ← 改为 DML，即可用 DirectML 显卡加速
    dml_pad_to=30,
)
```


### dml_pad_to 参数

DirectML 有一个特性：每次 ONNX 模型输入形状变化时，都会重新编译着色器，导致约200ms的固定延迟开销。

为此引入了 `dml_pad_to` 参数：将短音频统一填充到指定时长（秒），使 ONNX 输入形状固定。默认 `30` 秒，通常不需要修改，只会在 DML 开启时起作用。

### CUDA 加速

CUDA 可以实现比 DML 快 50% 的加速效果，但是打包 CUDA 支持需要几百兆大小，而且需要用户安装 CUDA 驱动和 cuDNN，打包起来不划算。从源码运行的朋友，如果配置了 CUDA 环境，可以 `pip install onnxruntime-gpu` 并将 Provider 改为 `CUDA`，即可启用 CUDA 加速。


---

## 三、GGUF 组件加速

对于使用 llama.cpp 解码器的引擎（**Fun-ASR-Nano**、**Qwen-ASR**、**ForceAligner**），GGUF 模型默认启用 GPU 加速：

```python
llm_use_gpu = True       # 将 GGUF 层全部卸载到 GPU
```

打包里的 LLama.cpp 的显卡加速由 Vulkan 后端实现。

部分 Intel 集成显卡在 GPU 解码 GGUF 时可能出现精度溢出（识别结果乱码），只能将 `llm_use_gpu` 改为 `False` 用 CPU 运行。

部分 Nvidia 独显用户，可能由于未知的系统问题，导致无法使用 Vulkan 加载模型，此时有两种解决路径：

- 将 `llm_use_gpu` 改为 `False` 用 CPU 运行
- 弃用 Vulkan，改用 CUDA 加速。确保安装 CUDA 驱动后，前往 llama.cpp [Releases](https://github.com/ggerganov/llama.cpp/releases) 页面，找到最新版本，下载 CUDA 发行包，将其 dll 替换到 `core/server/engines/llama` 文件夹里。

部分集显用户，可能会 Vulkan 载入模型失败，或者遇到「解码有误，强制熔断」的输出，在 `config_server.py` 中有这样的注释，可尝试将对应的补丁取消注释，让补丁生效：

```python
class ServerConfig:

    ...

    # 集成显卡兼容性补丁
    # os.environ["GGML_VK_DISABLE_COOPMAT"] = "1"   # AMD集显无法加载 GGUF 模型时尝试
    # os.environ["GGML_VK_DISABLE_F16"] = "1"       # 集成显卡解码有误，强制熔断时尝试
```

### GPU 预加速功能

几乎所有独显都采用类似的电源策略：有负载任务时显存频率提升到全速（如 9000MHz），空闲时降到很低（如 405MHz）以省电。当新任务到来时，频率再提升上去——但这个提升过程有延迟（约 100~200ms），导致 ASR 这种"短突发"型负载每次都被冷启动惩罚。实测 RTX5050 Qwen3-ASR 在显存降频后冷启动转录延迟升至约 **300ms**。

为了解决这个问题，我引入了 **GPU 预加速**功能，默认关闭，可在 `config_server.py` 中配置开启：

```python
# GPU 预加速配置（有识别任务时，提前调高显存频率，降低延迟，需管理员权限运行）
gpu_boost_enabled = False                   # 总开关，默认关闭
gpu_boost_cmd = 'nvidia-smi -lmc 9000'      # GPU 预加速命令，锁定显存频率
gpu_unboost_cmd = 'nvidia-smi -rmc'         # GPU 取消预加速命令，解锁显存频率
gpu_unboost_timeout = 1                     # 空闲多少秒后取消加速
```

该功能本质上是让服务端在适当时机执行两条 Shell 命令：

| 时机 | 命令 | 作用 |
|------|------|------|
| 录音开始 | `nvidia-smi -lmc 9000` | 锁定显存频率到 9000MHz |
| 空闲超时 | `nvidia-smi -rmc` | 恢复显存到默认频率 |

默认命令针对 **NVIDIA 显卡**。我还不确定AMD 显卡应该用什么命令。

这种方式不会对显卡有任何负作用，独显在有负载时也会被动升高显存频率。我们只是在录音开始时就主动升高显存频率，在录音结束后开始识别时，直接享受高带宽、低延迟。

开启 GPU 预加速时，**必须**以管理员权限运行服务端，否则 `nvidia-smi` 的锁频命令无法执行成功。

实测 RTX5050 锁定显存频率后，短音频转录延迟可从 300ms 降至 **100ms**。

![Qwen3-ASR-短句超低延迟.png](../assets/Qwen3-ASR-短句超低延迟.png)


---

## 四、常见问题

### Q: 怎么确认 GPU 加速生效了？

查看服务端日志 `logs/server_latest.log`，会显示 provider 信息：

```
[INFO] ONNX provider: DML
[INFO] GGUF GPU offload: True
```

同时识别速度会有明显提升（尤其是长音频），查看显存也会有占用的提升。

### Q: DirectML 比 CUDA 慢吗？

通常 CUDA 比 DML 快 10-30%。但 DML 的优势在于**通用性**——AMD 和 Intel 显卡也能用，且打包体积小。

### Q: 显存占用大吗？

SenseVoice 通常占用小于 1GB；Fun-ASR-Nano 与 Qwen-ASR 整体显存占用通常 1GB ~ 2GB。
