GLM-ASR
模型介绍
GLM-ASR-Nano-2512 是一款鲁棒的开源语音识别模型,参数量为 1.5B。
该模型专为应对真实世界的复杂场景而设计,在多项基准测试中超越 OpenAI Whisper V3,同时保持紧凑的模型规模。
核心能力包括:
卓越的方言支持
除标准普通话和英语外,模型针对粤语及其他方言进行了深度优化,有效填补了方言语音识别领域的空白。低音量语音鲁棒性
专门针对“低语/轻声”场景进行训练,能够捕捉并准确转录传统模型难以识别的极低音量音频。SOTA 性能
在同类开源模型中实现最低平均错误率 (4.10),在中文基准测试(Wenet Meeting、Aishell-1 等)中展现出显著优势。
https://github.com/zai-org/GLM-ASR/tree/main
基准测试
我们将 GLM-ASR-Nano 与主流开源和闭源模型进行了对比评测。结果表明,GLM-ASR-Nano (1.5B) 表现优异,尤其在复杂声学环境下优势明显。

说明:
- Wenet Meeting 反映了包含噪声和语音重叠的真实会议场景。
- Aishell-1 是标准普通话基准测试集。
模型下载
- ModelScope: https://www.modelscope.cn/models/ZhipuAI/GLM-ASR-Nano-2512/summary
- HuggingFace: https://huggingface.co/zai-org/GLM-ASR-Nano-2512
推理
GLM-ASR-Nano-2512 可通过 transformers 库轻松集成。
我们将支持 transformers 5.x 以及 vLLM、SGLang 等推理框架。
环境依赖
pip install -r requirements.txt
sudo apt install ffmpeg示例代码
python inference.py --checkpoint_dir zai-org/GLM-ASR-Nano-2512 --audio examples/example_en.wav # 英文
python inference.py --checkpoint_dir zai-org/GLM-ASR-Nano-2512 --audio examples/example_zh.wav # 中文对于上述两段示例音频,模型能够生成准确的转录结果:
be careful not to allow fabric to become too hot which can cause shrinkage or in extreme cases scorch
我还能再搞一个,就算是非常小的声音也能识别准确🔥 只有 1.5B 参数,却在中文、方言(尤其是粤语)、甚至“窃窃私语”的低音量场景下,全面超越了 Whisper V3!
GLM-ASR-Nano-2512 特点
💥 核心能力:专治各种“听不清”
🗣️ 方言之王(尤其是粤语): 除标准普通话和英语外,模型针对粤语及其他方言进行了深度优化。对于做港剧字幕组、粤语客服质检的小伙伴来说,有效填补了方言识别领域的空白。
🤫 低音量语音鲁棒性: 它专门针对 “低语/轻声”场景进行训练,能够捕捉并准确转录传统模型难以识别的极低音量音频。以后开会偷偷录音(误),也不怕听不清了。
🏆 SOTA 性能: 在同类开源模型中实现了最低平均错误率 (4.10),在 Wenet Meeting、Aishell-1 等中文基准测试中展现出显著优势。
🌍 多语言支持: 支持 17 种语言(WER ≤ 20%),包括日、英、法、德、俄、西等主流语言,甚至连加泰罗尼亚语、立陶宛语这种小语种都支持。
5分钟本地部署
光说不练假把式。趁着周五下班前,咱们用 Python 把它跑起来!
1. 准备工作
首先,你需要安装 ffmpeg,它是处理音频的核心工具。
- Conda 用户(推荐):
conda install "ffmpeg" -c conda-forge - Ubuntu/Debian:
sudo apt install ffmpeg - Windows: 下载 release 包并配置环境变量。
- 接下来,安装 Python 依赖(注意版本要求):
pip install torch>=2.9.1 torchaudio>=2.9.1 torchcodec>=0.9.0 transformers==4.51.32. 模型下载
为了演示方便,我已经手动将模型下载到了本地目录:zai-org/GLM-ASR-Nano-2512。 大家可以从上面的 ModelScope 或 HuggingFace 地址下载。
目录结构:

📢 获取源码
本系列所有章节的可运行代码都会同步上传至 GitHub。
欢迎关注后私信关键字:实战
获取仓库地址。
3. 硬核推理代码
这个模型的调用方式稍微有点硬核,需要手动处理音频特征。我已经帮大家把坑都踩平了,直接复制下面的代码即可运行!
import torch
import torchaudio
import soundfile as sf
from pathlib import Path
from transformers import AutoTokenizer, WhisperFeatureExtractor, AutoConfig, AutoModelForCausalLM
# -----------------------------
# 固定配置
# -----------------------------
WHISPER_FEAT_CFG = {
"chunk_length": 30,
"feature_extractor_type": "WhisperFeatureExtractor",
"feature_size": 128,
"hop_length": 160,
"n_fft": 400,
"n_samples": 480000,
"nb_max_frames": 3000,
"padding_side": "right",
"padding_value": 0.0,
"processor_class": "WhisperProcessor",
"return_attention_mask": False,
"sampling_rate": 16000,
}
def load_audio(path, target_sr=16000):
wav, sr = sf.read(path)
if wav.ndim > 1: # 多声道取第一声道
wav = wav[:, 0]
wav = torch.tensor(wav, dtype=torch.float32).unsqueeze(0)
if sr != target_sr:
wav = torchaudio.transforms.Resample(sr, target_sr)(wav)
sr = target_sr
return wav, sr
def get_audio_token_length(seconds, merge_factor=2):
# 计算音频token长度
def get_T_after_cnn(L_in, dilation=1):
for padding, kernel_size, stride in eval("[(1,3,1)] + [(1,3,2)] "):
L_out = L_in + 2 * padding - dilation * (kernel_size - 1) - 1
L_out = 1 + L_out // stride
L_in = L_out
return L_out
mel_len = int(seconds * 100)
audio_len_after_cnn = get_T_after_cnn(mel_len)
audio_token_num = (audio_len_after_cnn - merge_factor) // merge_factor + 1
return min(audio_token_num, 1500 // merge_factor)
def build_prompt(audio_path, tokenizer, feature_extractor, merge_factor):
# wav, sr = load_audio(str(audio_path))
wav, sr = torchaudio.load(str(audio_path))
wav = wav[:1, :]
if sr != feature_extractor.sampling_rate:
wav = torchaudio.transforms.Resample(sr, feature_extractor.sampling_rate)(wav)
tokens = []
tokens += tokenizer.encode("<|user|>\n")
audios, audio_offsets, audio_length = [], [], []
chunk_size = 30 * feature_extractor.sampling_rate
# 分块处理音频
for start in range(0, wav.shape[1], chunk_size):
chunk = wav[:, start:start + chunk_size]
mel = feature_extractor(
chunk.numpy(),
sampling_rate=feature_extractor.sampling_rate,
return_tensors="pt",
padding="max_length",
)["input_features"]
audios.append(mel)
seconds = chunk.shape[1] / feature_extractor.sampling_rate
num_tokens = get_audio_token_length(seconds, merge_factor)
tokens += tokenizer.encode("<|begin_of_audio|>")
audio_offsets.append(len(tokens))
tokens += [0] * num_tokens
tokens += tokenizer.encode("<|end_of_audio|>")
audio_length.append(num_tokens)
tokens += tokenizer.encode("<|user|>\nPlease transcribe this audio into text")
tokens += tokenizer.encode("<|assistant|>\n")
return {
"input_ids": torch.tensor([tokens]),
"audios": torch.cat(audios, dim=0),
"audio_offsets": [audio_offsets],
"audio_length": [audio_length],
"attention_mask": torch.ones(1, len(tokens)),
}
def run_asr(model_dir, audio_path):
print("🎤 开始识别音频:", audio_path)
device = "cuda"if torch.cuda.is_available() else"cpu"
tokenizer = AutoTokenizer.from_pretrained(model_dir)
feature_extractor = WhisperFeatureExtractor(**WHISPER_FEAT_CFG)
config = AutoConfig.from_pretrained(model_dir, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_dir, config=config, trust_remote_code=True, torch_dtype=torch.bfloat16
).to(device)
model.eval()
batch = build_prompt(audio_path, tokenizer, feature_extractor, config.merge_factor)
model_inputs = {
"inputs": batch["input_ids"].to(device),
"attention_mask": batch["attention_mask"].to(device),
"audios": batch["audios"].to(device, dtype=torch.bfloat16),
"audio_offsets": batch["audio_offsets"],
"audio_length": batch["audio_length"],
}
prompt_len = batch["input_ids"].shape[1]
with torch.inference_mode():
generated = model.generate(
**model_inputs,
max_new_tokens=128,
do_sample=False,
)
transcript_ids = generated[0, prompt_len:].cpu().tolist()
result = tokenizer.decode(transcript_ids, skip_special_tokens=True)
print("\n-------- 📝 识别结果 --------")
print(result)
print("-----------------------------\n")
return result
if __name__ == "__main__":
# 请确保模型路径正确!
model_path = "./zai-org/GLM-ASR-Nano-2512"
# run_asr(model_path, "./audio/example_en.wav")
# run_asr(model_path, "./audio/example_zh.mp3")
# 🔥 重点测试:粤语识别
run_asr(model_path, "./audio/example_yy.mp3")
最后编辑:Jeebiz 更新时间:2025-12-13 09:02