The README still listed the settings UI as "todo" and its quick start told users to download models into the working directory; phase 3 still described the caption window's close button as "quit" and used the wrong binary name. Bring the docs up to date and fill the gaps: a GUI guide (first run, settings tabs, tray, download, verify), a full CLI option reference marking the test-only flags, a troubleshooting page, the model registry's size/sha256 fields plus a licence/size table, the RTF measurement caveat (llama-cli 0.19 vs the in-process 0.56), and a note that the streaming-ONNX backend has its own code path. phase0/phase1 experiment docs are marked as historical. 文档与现状对齐:README 的 Phase 4 从「待做」改为完成、快速开始不再让人把模型下到当前 目录;phase3 的 ✕ 说明改为「隐藏到托盘」、用法改用 live-caption;新增 GUI/CLI/排错三份 文档;asr-backends 补上注册表的 size/sha256 字段与模型许可/体积表;phase0 补上 RTF 口径 说明(llama-cli 的 0.19 与程序内的 0.56);phase2 补上「流式 ONNX 走另一条分支」的说明。
111 lines
6.3 KiB
Markdown
111 lines
6.3 KiB
Markdown
# Phase 0 验证报告
|
||
|
||
结论:**方案成立**。系统播放音频可采集、Qwen3-ASR 可在这套系统库上运行、CPU 实时性有充足余量。可以进入实现阶段。
|
||
|
||
验证日期:2026-10-12 设备:i5-13420H / 15GB / Intel UHD(无独显)/ Deepin 25 / X11
|
||
|
||
---
|
||
|
||
## 1. 验证结论一览
|
||
|
||
| # | 假设 | 结论 | 证据 |
|
||
|---|---|---|---|
|
||
| 1 | 系统播放的声音可采集 | ✅ | 默认 sink 的 `.monitor` 源录到真实音频(mean −29.6dB / max −6.7dB)|
|
||
| 2 | Qwen3-ASR 能在本机跑 | ✅ | 主模型 arch `qwen3vl` ← `libllama` 的 `llama_model_qwen3vl`;mmproj `clip`+`qwen3a` ← `libmtmd` 的 `clip_graph_qwen3a` |
|
||
| 3 | 端到端链路可用 | ✅ | 播放 → monitor 采集 → 16k 单声道 → 转写,文本正确 |
|
||
| 4 | 中文可用 + 语言自动检测 | ✅ | `language Chinese<asr_text>不排除购房者可以在互联网上下单。` |
|
||
| 5 | CPU 实时性够用 | ✅ | 纯推理 RTF ≈ **0.19**;2s 音频约 0.3s |
|
||
| 6 | 纯 C++、无 Python | ✅ | 全程 llama.cpp C/C++ 库 |
|
||
|
||
## 2. 关键实测数据
|
||
|
||
环境:`-t 8`(i5-13420H 8 核),模型 `Qwen3-ASR-0.6B-Q8_0` + `mmproj-...-Q8_0`。
|
||
|
||
| 项目 | 结果 |
|
||
|---|---|
|
||
| 模型加载(一次性) | ≈ 4.6 s |
|
||
| 纯推理 RTF | ≈ 0.19(约 3.8× 实时)|
|
||
| 62.6s 音频总耗时 | 16.48 s(含加载)|
|
||
| 单块 2s 音频 | 墙钟 ≈ 4.9 s − 加载 4.6 s ⇒ 计算 ≈ **0.3 s** |
|
||
| 英文准确率 | 与 LibriSpeech 标准答案逐词一致 |
|
||
| 中文准确率 | 与 AISHELL-1 标准答案一致(仅多了标点)|
|
||
|
||
> 流式含义:模型常驻内存时,处理 2 秒窗口约 0.3 s,滑动窗口 + 提交策略下端到端延迟可做到 **~1 s 级**,与 Chrome 实时字幕同量级。
|
||
|
||
> **口径提示**:本页的 RTF ≈ 0.19 是 **`llama-cli` 纯生成**(`-t 8`)的数字。
|
||
> 程序内走 `libmtmd` 音频编码的实现,实测 RTF ≈ **0.56**(单线程,见
|
||
> [asr-backends.md](asr-backends.md#实测对比同一批音频1-线程));两个口径都远低于 1.0,
|
||
> 但引用数字时要注意区分。另外流式 ONNX 后端的 CPU 占用比它低约 35 倍。
|
||
|
||
### 2.1 0.6B vs 1.7B 实测对比
|
||
|
||
均为 Q8_0 主模型 + Q8_0 mmproj,`-t 8`。
|
||
|
||
| 指标 | 0.6B | 1.7B |
|
||
|---|---|---|
|
||
| 加载耗时 | 4.6 s | 6.2 s |
|
||
| 纯推理 RTF | **0.19**(≈3.8× 实时)| **0.385**(≈2.6× 实时)|
|
||
| 62.6s 音频墙钟 | 16.5 s | 30.2 s |
|
||
| 单块 2s 计算量 | ≈0.3 s | ≈0.77 s |
|
||
| 内存(主+mmproj) | ≈0.97 GB | ≈2.42 GB |
|
||
| 中文 | ✅ 正确 | ✅ 正确 |
|
||
| 英文 | `flour-fatted sauce` ✅ | `flour-fattened sauce` ❌ |
|
||
|
||
**结论**:
|
||
- 两个尺寸在本机都**能实时**,1.7B 余量更小(2.6× 实时)。
|
||
- **1.7B 在这段英文上反而不如 0.6B**(`flour-fatted` → `flour-fattened`)。单样本不能定论,但足以说明默认应选 0.6B,1.7B 作为可选并加性能/内存提示。
|
||
- 若某台机器连 0.6B 都吃力,可自行用 `llama-quantize` 从官方 Q8_0/bf16 转 Q4_K_M(注意:**不能直接用社区量化**,架构标记不兼容)。
|
||
|
||
## 3. 转写输出格式(接入时必须清洗)
|
||
|
||
原始输出形如:
|
||
|
||
```
|
||
language English<asr_text>He hoped there would be stew for dinner...
|
||
language Chinese<asr_text>不排除购房者可以在互联网上下单。
|
||
```
|
||
|
||
解析规则:`language <LANG><asr_text><正文>`。`<LANG>` 直接喂给 UI 左上角的语言标签,正文才算字幕。注意 `<LANG>` 在中文时是 `Chinese`,需做 `中文` 一类的显示映射。
|
||
|
||
## 4. 兼容性风险(重要)
|
||
|
||
Qwen3-ASR 的 GGUF **架构标记正在变动**,各家不一致:
|
||
|
||
| 来源 | `general.architecture` | 发行版 b9951 |
|
||
|---|---|---|
|
||
| **ggml-org/Qwen3-ASR-0.6B / 1.7B**(官方转换) | `qwen3vl` | ✅ 可加载 |
|
||
| cstr/qwen3-asr-0.6b-q4_k | `qwen3asr` | ❌ `unknown model architecture` |
|
||
| handy-computer/Qwen3-ASR-0.6B-* | `qwen3_asr` | ❌ `unknown model architecture` |
|
||
|
||
**结论:模型与推理运行时必须成对锁定版本。**只使用 ggml-org 官方 GGUF,或自行用同版本的 `llama-quantize` 从官方 GGUF 转换。
|
||
|
||
Q4_K_M(590MB)这类小体积量化目前只有社区版,不兼容;`llama-quantize` 可用(在 `llama.cpp-tools` 里),需要时自行从官方 Q8_0/bf16 转换。当前 Q8_0 的 RTF 0.19 已足够,**Q4 非必需**。
|
||
|
||
## 5. 环境与工具链实测
|
||
|
||
- **音频**:PipeWire 1.6.4 + pipewire-pulse;`libpulse` 17.0 开发包齐全。用 libpulse 而非 PipeWire 原生 API → 同时兼容 PipeWire / PulseAudio。
|
||
- **llama.cpp**:系统包 `9951+dfsg-1deepin1`(`libllama0` 含 `libllama` / `libmtmd` / `libllama-common`;`libllama-dev` 含 `llama.h` / `mtmd.h` / `mtmd-helper.h`)。
|
||
- **无免密 sudo**:不能装包。但 `llama.cpp-tools` 的 deb 可直接 `dpkg-deb -x` 解包使用,无需 root。开发期靠这个。
|
||
- **CMake 集成注意**:
|
||
- `llama-config.cmake` 在非标准路径 `/usr/lib/x86_64-linux-gnu/llama/cmake-private/`(`find_package(llama)` 默认找不到)。
|
||
- 同目录有 `pkgconfig/llama.pc`,**但只列了 `-lggml -lggml-base -lllama`,缺 `-lmtmd`**,需要手动补。
|
||
- `ggml` 的 cmake config 和 `ggml.pc` 在标准位置,正常可找到。
|
||
- **网络**:只有 `hf-mirror.com` 可达(huggingface.co / github.com 不通)。下载用 **aria2c 多连接**:19 MiB/s vs 单连接 3 MiB/s。
|
||
|
||
## 6. 踩过的坑
|
||
|
||
1. **`llama-cli` 会挂住**:不给 `-st` 且不让 stdin EOF 时,生成完会回到交互读取循环。解法:`-st --simple-io </dev/null` + 外层 `timeout`。
|
||
2. **Debian 的 `llama-cli` 内部其实跑的是 server**(错误日志里出现 `srv load_model`、`llama_server exited`)。这提示:Phase 1 若不想自己驱动 libllama 的解码循环,用 `llama-server` 子进程 + 本地接口也是合理选项。
|
||
3. 下载大文件时**不要开两个 curl 并行**(互相拖累到 ~0.3MB/s)。
|
||
|
||
## 7. 对后续设计的影响
|
||
|
||
- 采集层:`libpulse` + 默认 sink 的 monitor,需订阅设备变更事件跟随默认输出。
|
||
- 推理层:`AsrBackend` 接口;先用 ggml-org 的 `qwen3vl` 版 GGUF;模型+mmproj 成对管理;输出解析要处理 `language/asr_text` 前缀。
|
||
- 延迟策略:模型常驻,2s 滑窗,每 ~0.5–1s 提交一次;目标是端到端 ~1s。
|
||
- 打包:模型体积(Q8_0 768MB + mmproj 205MB)需要下载或按需获取策略;不能默认内置进包。
|
||
|
||
## 8. 复现
|
||
|
||
见 `../../experiments/phase0/README.md`。
|