YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

Qwen3-ASR Runtime Library for RK3576/RK3588

v1.3.0 — Merged Encoder, Token Rollback, 代码重构 (engine.py -56%)

基于 RKNN 编码器 (NPU) + RKLLM 解码器 (NPU) 的 Qwen3-ASR 语音识别运行库。

目录结构

qwen3asr_rknn/
├── python/                    # Python 运行库
│   ├── qwen3asr/             # 核心库 (v1.3.0)
│   │   ├── __init__.py       # 包入口
│   │   ├── engine.py         # 主引擎 (文件转录, 组件加载)
│   │   ├── stream.py         # 流式识别会话 (StreamSession)
│   │   ├── encoder.py        # RKNN 编码器 (merged/split 自动检测)
│   │   ├── decoder.py        # RKLLM 解码器 (ctypes EMBED 模式)
│   │   ├── mel.py            # Mel 频谱提取 (Whisper 兼容)
│   │   ├── vad.py            # Silero VAD 封装
│   │   ├── config.py         # 配置常量和默认参数
│   │   └── utils.py          # 音频加载、ITN、文本处理
│   ├── transcribe.py         # 文件转录 CLI
│   └── mic_stream.py         # 麦克风实时识别 CLI
├── scripts/                   # 辅助脚本
│   ├── test_vad_stream.py    # VAD 流式识别测试
│   ├── bench_encoder.py      # 编码器性能测试
│   └── onnx2rknn_*.py        # 模型转换脚本
├── models/                    # 模型文件 (部署时需要)
│   ├── encoder/rk3576/       # Split 编码器 (FE+BE, 旧方案)
│   ├── qwen3_asr_encoder_merged.fp16.{N}s.rk3576.rknn
│   │                         # ▲ Merged 编码器 (推荐, 快 1.4-1.8x)
│   ├── rkllm/                # RKLLM 解码器
│   ├── embd/                 # Embedding 表
│   ├── vad/                  # Silero VAD 模型
│   ├── mel_filters.npy       # Mel 滤波器
│   └── tokenizer/            # Tokenizer
├── lib/                       # RKLLM 运行库 (librkllmrt.so)
├── audio/                     # 测试音频
├── _transfer/                 # 模型转换/测试工具
└── docs/                      # 本文档

快速开始

1. 部署到新机器

# 复制整个 qwen3asr_rknn/ 目录到目标机器
scp -r qwen3asr_rknn/ user@target:/path/to/

# 确保依赖已安装
pip install numpy librosa soundfile tokenizers
# 可选: pip install pydub (支持更多音频格式)

2. 文件转录

cd /path/to/qwen3asr_rknn/python

# 基本用法
python transcribe.py --audio /path/to/audio.wav

# 指定语言和上下文
python transcribe.py --audio audio.wav --language Chinese --context "新闻节目"

# 英文识别
python transcribe.py --audio english.wav --language English

# 自动检测语言
python transcribe.py --audio audio.wav --language auto

# 更多参数
python transcribe.py --audio audio.wav \
    --chunk-size 20 \
    --memory-num 3 \
    --cpus 4 \
    --max-new-tokens 300 \
    --start 10 --duration 60

3. 麦克风实时识别

# 查看可用设备
python mic_stream.py --list-devices

# 开始实时识别 (默认 USB 麦克风)
python mic_stream.py

# 自定义参数
python mic_stream.py --device plughw:2,0 --chunk-size 10 --language Chinese

# 限制时长
python mic_stream.py --max-seconds 60

4. Python API 调用

from qwen3asr import Qwen3ASREngine

# 初始化引擎
engine = Qwen3ASREngine(
    model_dir="/path/to/models",
    platform="rk3576",
    encoder_sizes=[2, 3, 4],  # 只加载需要的尺寸 (加快启动)
    enabled_cpus=2,            # 2 = A72 大核
    repeat_penalty=1.15,       # W4A16 推荐 >1.0
    compact_suffix=True,       # 精简提示词, 省 ~120ms/chunk
)

# --- 文件转录 ---
result = engine.transcribe(
    audio="audio.wav",
    language="Chinese",
    chunk_size=4.0,            # 4s chunk, 配合 merged encoder 最佳
    memory_num=2,
    rollback_tokens=2,         # Token 回退防止边界错误
)
print(result["text"])
print(f"RTF: {result['stats']['rtf']:.3f}")

# --- 流式识别 ---
stream = engine.create_stream(
    language="Chinese",
    chunk_size=4.0,
    memory_num=2,
    rollback_tokens=2,
)

# 喂入音频数据 (16kHz mono float32)
import numpy as np
pcm = np.zeros(16000 * 4, dtype=np.float32)  # 4秒
result = stream.feed_audio(pcm)
print(result["text"])  # 中间结果

final = stream.finish()
print(final["text"])

# --- 带 VAD 的流式识别 ---
from qwen3asr import SileroVAD
vad = SileroVAD("/path/to/models/vad/silero_vad.onnx")
stream = engine.create_stream(language="Chinese", vad=vad)
# VAD 自动过滤静音, 仅在检测到语音时触发 ASR

engine.close()

参数说明

引擎初始化参数 (Qwen3ASREngine.__init__)

参数 类型 默认值 说明
model_dir str 必填 模型根目录
platform str "rk3576" 平台:rk3576 或 rk3588
encoder_sizes list None 加载的编码器尺寸列表,如 [2,3,4];None=全部加载
encoder_quant str "fp16" 编码器量化:fp16 或 int8 (int8 质量差,不推荐)
decoder_quant str "w4a16_g128" 解码器量化类型
enabled_cpus int 2 RKLLM CPU 核心数 (2=A72 大核)
max_context_len int 4096 KV 缓存最大上下文长度
max_new_tokens int 500 每次生成最大 token 数
top_k int 1 Top-K 采样 (1=贪心, 推荐用于 ASR)
top_p float 1.0 核采样阈值
temperature float 1.0 采样温度
repeat_penalty float 1.15 重复惩罚 (W4A16 推荐 >1.0)
frequency_penalty float 0.0 频率惩罚
presence_penalty float 0.0 存在惩罚
embed_flash int 1 Flash Embedding 模式
compact_suffix bool True 精简后缀提示词,节省 ~120ms/chunk
decoder_callback Callable None 流式回调 callback(text, is_finish)

转录参数

transcribe() — 文件/数组一次性转录

参数 类型 默认值 说明
audio str/ndarray 必填 音频文件路径或 16kHz float32 数组
language str "Chinese" 语言:Chinese/English/auto 等
context str "" 上下文描述 (提升准确率)
chunk_size float 30.0 音频块大小 (秒, 自动裁剪到编码器容量)
memory_num int 2 滑动窗口块数 (保留最近 N 块 embedding)
rollback_tokens int 5 前缀回退 token 数 (减少边界抖动)
max_new_tokens int 500 每块最大生成 token 数
start_second float 0.0 起始偏移 (秒)
duration float None 持续时间 (秒, None=全部)
max_chunks int None 最大处理块数
apply_itn_flag bool True 是否应用逆文本归一化

create_stream() — 创建流式会话

参数 类型 默认值 说明
language str "Chinese" 语言提示
context str "" 上下文描述
chunk_size float 4.0 每块秒数 (流式推荐 2-5s)
memory_num int 2 滑动窗口大小 (≥2)
unfixed_chunks int 0 前 N 块不使用前缀文本
rollback_tokens int 2 前缀回退 token 数
max_new_tokens int 128 每块最大 token 数
on_text Callable None 文本回调 on_text(full_text)
vad SileroVAD None VAD 实例,自动过滤静音

注意: transcribe()create_stream() 的默认参数不同。 transcribe() 使用大 chunk (30s) 和较多回退 (rb=5) 适合离线; create_stream() 使用小 chunk (4s) 和少量回退 (rb=2) 适合实时。

支持的语言

Chinese, English, Cantonese, Arabic, German, French, Spanish, Portuguese, Indonesian, Italian, Korean, Russian, Thai, Vietnamese, Japanese, Turkish, Hindi, Malay, Dutch, Swedish, Danish, Finnish, Polish, Czech, Filipino, Persian, Greek, Romanian, Hungarian, Macedonian

技术架构

编码器 (Encoder)

支持两种部署模式,自动检测:

Merged 模式 (推荐, v1.3+)

将 Frontend + Backend 合并为单个 RKNN 模型,减少一次 NPU 调用开销。

  • 模型: qwen3_asr_encoder_merged.fp16.{N}s.rk3576.rknn (369-371MB)
  • 输入: input_features(1, 128, T_mel) + attention_mask(1, 1, T_down, T_down)
  • 输出: audio_embeds(1, T_down, 1024) 浮点 embedding
  • 性能: 比 Split 模式快 1.4-1.8x (详见性能章节)

Split 模式 (传统)

Frontend 和 Backend 分开推理:

  • Frontend: encoder_fe.fp16.{N}s.rk3576.rknn (~22MB)
  • Backend: encoder_be.fp16.{N}s.rk3576.rknn (~350MB)
  • 流程: Mel 频谱 → Frontend (NPU) → Backend (NPU) → embedding

共同特性

  • 输入: 16kHz PCM → 128-bin Mel 频谱
  • Token 计算: ceil(T_mel / 8) + 1 (3层CNN子采样), 每秒 ~13 tokens
  • 多尺寸: 加载 2s/3s/4s/5s 等多种尺寸,运行时按音频长度自动选择最近尺寸
  • INT8: 质量严重下降,不可用

解码器 (Decoder)

  • 模型: Qwen3 (标准, 非 VL) 导出的 RKLLM
  • 推荐量化: W4A16_G128 (GRQ), 精度与 W8A8 相当但更快
  • 输入: EMBED 模式 - [前缀embedding | 音频embedding | 后缀embedding]
  • 关键设置:
    • rkllm_set_chat_template(handle, "", "", "") - 禁用内置模板
    • role = "" - 空角色
    • embed_flash = 1 - Flash Embedding
    • compact_suffix = True - 精简后缀,省约 10 tokens / 120ms
  • 采样: 默认贪心 (top_k=1) + repeat_penalty=1.15

Prompt 模板

标准模式:

<|im_start|>system
You are a helpful assistant. {context}<|im_end|>
<|im_start|>user
<|audio_start|>{AUDIO_EMBEDDING}<|audio_end|>
数字用0123456789,语音转录:<|im_end|>
<|im_start|>assistant
language {Language}<asr_text>{prefix_text}

精简模式 (compact_suffix=True):

<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
<|audio_start|>{AUDIO_EMBEDDING}<|audio_end|><|im_end|>
<|im_start|>assistant
<asr_text>{prefix_text}

流式识别策略 (StreamSession)

  1. 音频按 chunk_size 秒分块
  2. 每块独立编码 (NPU, 自动选择最近编码器尺寸)
  3. 保留最近 memory_num 块的 embedding (滑动窗口)
  4. 旧块文本作为前缀传入 LLM (_decode_with_window() 统一核心)
  5. 前缀文本回退 rollback_tokens 个 token (减少边界错误)
  6. 可选 VAD 门控 (_feed_with_vad()), 仅在检测到语音时触发 ASR

Token Rollback

解决分块边界处的文本错误 (如 "九百六。十七期" → "九百六十七期"):

  • rollback_tokens=0: 无回退
  • rollback_tokens=2-3: 推荐, 平衡准确率与重复推理开销
  • rollback_tokens=5: transcribe() 默认, 适合离线批量

工作原理: 提交前缀文本时截掉最后 N 个 token, 让 LLM 在下一块重新生成这部分, 从而消除边界伪影。

性能参考 (RK3576, 锁频后)

锁频配置(推荐)

锁定 CPU/NPU/DDR 频率可显著提升性能稳定性 (~27% 提升):

# 锁定 CPU 大核 (需 root)
echo userspace > /sys/devices/system/cpu/cpufreq/policy4/scaling_governor
echo 2208000 > /sys/devices/system/cpu/cpufreq/policy4/scaling_setspeed
echo 2208000 > /sys/devices/system/cpu/cpufreq/policy6/scaling_setspeed

# 锁定 NPU
echo userspace > /sys/class/devfreq/fdab0000.npu/governor
echo 1000000000 > /sys/class/devfreq/fdab0000.npu/userspace/set_freq

# 锁定 DDR
echo userspace > /sys/class/devfreq/dmc/governor
echo 2736000000 > /sys/class/devfreq/dmc/userspace/set_freq

# 查看 NPU 负载
cat /sys/kernel/debug/rknpu/load

实测性能 (W4A16_G128, memory=2, 锁频)

Merged Encoder (推荐)

Chunk 编码 (ms) vs Split 加速 RTF (60s 音频) 适用场景
2s ~302 1.79x ~0.55 低延迟实时
3s ~364 1.55x ~0.56 折中
4s ~499 1.38x ~0.57 流式推荐
5s ~643 1.20x ~0.58 质量优先

Split Encoder (传统)

Chunk FE (ms) BE (ms) 总编码 (ms) RTF
2s ~60 ~480 ~540 ~0.70
3s ~60 ~505 ~565 ~0.68
4s ~60 ~630 ~690 ~0.66
5s ~60 ~710 ~770 ~0.65

锁频 vs 未锁频

指标 锁频前 锁频后 提升
首 chunk 延迟 ~2.4s ~1.8s ~25%
后续 chunk 延迟 ~1.8s ~1.4s ~22%
RTF (60s 音频) 0.78 0.57 27%

硬件限制

  • 最低延迟: ~1.0s (merged encoder) / ~1.3s (split encoder)
  • Python/ctypes 开销: 4% (20ms),可忽略
  • INT8 encoder: 质量严重下降,不可用
  • 内存: W4A16 decoder ~1GB, 单个 merged encoder ~370MB

部署检查清单

  • 编码器模型: merged (encoder_merged.fp16.*.rknn) 或 split (encoder_fe/be)
  • 解码器模型: decoder_qwen3.w4a16_g128.{platform}.rkllm
  • 辅助文件: mel_filters.npz, embed_tokens.npy, tokenizer.json
  • 运行库: librkllmrt.solib/ 目录
  • Python 依赖: numpy, librosa, soundfile, tokenizers
  • RKNN runtime: ≥ 2.3.2 (rknnlite)
  • 锁频: CPU 2208MHz, NPU 1000MHz, DDR 2736MHz (推荐)
  • 麦克风: arecord -l (实时场景)

故障排除

EMBED 模式只输出 1-3 个 token

  • 确认使用 decoder_qwen3.*.rkllm (model_type=qwen3, 非 qwen3_vl)
  • 确认调用了 rkllm_set_chat_template(h, "", "", "")
  • 确认 role = "" (空字符串)

编码器加载失败

  • 检查 RKNN runtime 版本 ≥ 2.3.2
  • 检查 NPU 驱动版本 ≥ 0.9.8
  • 确认模型与平台匹配 (rk3576 vs rk3588)
  • Merged 模型文件名须含 merged 关键字

内存不足

  • W4A16 decoder 约需 1GB
  • 单个 merged encoder 约 370MB
  • encoder_sizes=[4] 只加载单个尺寸可节省内存
  • 减少 max_context_len 可降低 KV 缓存内存

Token Rollback 不生效

  • 确认 rollback_tokens ≥ 1
  • 首块无前缀,回退仅对第 2 块开始生效
  • unfixed_chunks > 0 会延迟前缀使用

流式结果有重复文字

  • 增大 repeat_penalty (推荐 1.15-1.3)
  • 检查 memory_num ≥ 2
  • 适当增大 rollback_tokens (2-3)
Downloads last month
110
GGUF
Model size
0.8B params
Architecture
qwen3vl
Hardware compatibility
Log In to add your hardware

4-bit

Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support