【方言语音识别与翻译实战】:吴语/粤语/川渝方言评测
方言语音识别与转写实践:基于 Qwen3-ASR 的吴语/粤语/川渝方言评测
中文方言语音识别(ASR,Automatic Speech Recognition)与方言转普通话翻译(AST,Automatic Speech Translation)是语音技术落地的重要场景。我国方言体系复杂,吴语、粤语、川渝方言是使用人口多、产业落地需求旺盛的三大方言区。
本文基于 WenetSpeech 系列开源方言数据集,采用 Qwen3-ASR-1.7B 作为语音识别底座,搭配 Qwen3-8B-AWQ 大语言模型构建「ASR 识别 + 文本翻译」的级联 AST 方案,完成了吴语、粤语、川渝方言三个方向的数据处理、模型部署与效果评测,为方言语音技术落地提供可复现的实践参考。
1. 数据集介绍
本次实验采用 ASLP-lab 开源的 WenetSpeech 系列方言数据集,该系列是目前规模较大、标注质量较高的开源中文方言语料,覆盖吴语、粤语、川渝方言等多个方言,包含训练集与专门的评测集,分别在 ModelScope(国内推荐)与 HuggingFace 平台托管。
1.1 训练数据集
以下为大规模训练数据集,适合用于模型微调,国内用户推荐通过 ModelScope 下载,HuggingFace 地址在境内无法正常访问。
- 吴语数据集:https://www.modelscope.cn/datasets/ASLP-lab/WenetSpeech-Wu
- 粤语数据集:https://www.modelscope.cn/datasets/ASLP-lab/WenetSpeech-Yue
- 川渝方言数据集:https://www.modelscope.cn/datasets/ASLP-lab/WSChuan-Train
注:ModelScope 数据集页面需登录后查看完整数据与下载入口,也可通过 ModelScope Python SDK 一键下载:
pip install modelscope
modelscope download --dataset ASLP-lab/WenetSpeech-Wu --local_dir ./WenetSpeech-Wu
1.2 评测数据集
以下为官方整理的标准测试集,用于模型效果基准测试,每个方言均包含长短音频,覆盖不同难度场景。
吴语基准测试集
- ModelScope 地址:https://www.modelscope.cn/datasets/ASLP-lab/WenetSpeech-Wu-Bench
- HuggingFace 地址:https://huggingface.co/datasets/ASLP-lab/WenetSpeech-Wu-Bench
- 特点:同时包含 ASR(吴语文本标注)与 AST(普通话翻译标注)双任务标注,支持语音识别与语音翻译两类评测。
粤语 ASR 测试集
- ModelScope 地址:https://www.modelscope.cn/datasets/ASLP-lab/WSYue-ASR-eval
- HuggingFace 地址:https://huggingface.co/datasets/ASLP-lab/WSYue-ASR-eval
- 特点:仅含粤语 ASR 标注,分为长音频(10–30s)和短音频(0–10s)两个子集。
川渝方言评测集
- ModelScope 地址:https://www.modelscope.cn/datasets/ASLP-lab/WSChuan-Eval
- HuggingFace 地址:https://huggingface.co/datasets/ASLP-lab/WSC-Eval
- 特点:仅含川渝方言 ASR 标注,同样分为长、短音频两个子集。
2. 数据处理
三个评测集采用了不同的数据组织格式,下文分别说明读取与处理方法,并针对吴语双任务数据集构造 AST 评测专用数据集。
WenetSpeech-Wu-Bench
WenetSpeech-Wu-Bench 采用 Parquet 格式存储,压缩率高、读取效率好,同时兼容 ASR 和 AST 两类任务。
基础读取
import pyarrow.parquet as pq
# 读取完整表,asr或ast任务
table = pq.read_table("WenetSpeech-Wu-Bench/understanding/asr.parquet")
# table = pq.read_table("WenetSpeech-Wu-Bench/understanding/ast.parquet")
print ("表结构:", table.schema)
# 按需转 pandas DataFrame
df = table.to_pandas()
# 基础统计
print(df.shape)
print(df.head())
输出结果

构造 AST 联合评测集
由于 ASR 文件仅含吴语标注、AST 文件仅含普通话标注,且两个子集存在重叠音频,因此我们可以通过音频 ID 关联两份标注,构造「方言语料 + 吴语转写 + 普通话翻译」的完整三元组,用于后续 COMET 翻译质量评测。
该数据集的价值在于:既可以验证「ASR + 翻译」级联方案的端到端效果,也可以作为 AST 模型的标准评测集。
import pandas as pd
def main():
# 读取两个parquet文件
df_asr = pd.read_parquet("WenetSpeech-Wu-Bench/understanding/asr.parquet")
df_ast = pd.read_parquet("WenetSpeech-Wu-Bench/understanding/ast.parquet")
# 校验必要字段
required_cols = {"task", "utt_id", "audio", "label"}
for name, df in [("asr", df_asr), ("ast", df_ast)]:
missing = required_cols - set(df.columns)
if missing:
raise ValueError(f"{name}.parquet 缺少字段: {missing}")
df_join = pd.merge(
df_ast,
df_asr[["audio", "label", "utt_id"]],
on="audio",
how="inner",
suffixes=("_ast", "_asr")
)
df_new = pd.DataFrame({
"task": df_join["task"],
"utt_id": df_join["utt_id_ast"],
"audio": df_join["audio"],
"label_asr": df_join["label_asr"], # ASR识别文本作为源文本
"label_ast": df_join["label_ast"], # AST翻译参考标签
})
print(f"asr数据集总条数: {len(df_asr)}")
print(f"ast数据集总条数: {len(df_ast)}")
print(f"完全匹配条数: {len(df_new)}")
# 输出新parquet
output_path = "comet_eval_dataset.parquet"
df_new.to_parquet(output_path, index=False)
print(f"已保存交集数据集到 {output_path}")
if __name__ == "__main__":
main()
运行结果

WSYue-ASR-eval
粤语评测集采用经典的 Praat TextGrid 标注格式,音频为 16kHz 单声道 WAV 格式,分为 Long(长音频,370 条,10–30s)和 Short(短音频,7060 条,0–10s)两个目录。长音频场景更贴近真实对话场景,因此本次以长音频子集作为测试对象。
标注解析与音频读取
TextGrid 文件包含分段的时间戳与文本标注,我们通过正则提取「文本」层的所有有效标注,拼接为完整的句子级标注。
import re
import csv
import wave
from pathlib import Path
def parse_textgrid(file_path: Path):
"""
解析TextGrid文件,提取【文本】tier下所有非空text
返回: list[dict], 每个元素 {"xmin":float, "xmax":float, "text":str}
"""
with open(file_path, "r", encoding="utf-8") as f:
content = f.read()
# 定位到 name = "文本" 这个tier块
pattern = re.compile(
r'item \[\d+\]:\s*?class = "IntervalTier"\s*?name = "文本"\s*?'
r'xmin = ([0-9.]+)\s*?xmax = ([0-9.]+)\s*?intervals: size = \d+\s*?(.*?)(?=item \[\d+\]:|$)',
re.DOTALL
)
match = pattern.search(content)
if not match:
return []
intervals_block = match.group(3)
# 解析每一个intervals [n] 块
interval_pat = re.compile(
r'intervals \[\d+\]:\s*?'
r'xmin = ([0-9.]+)\s*?'
r'xmax = ([0-9.]+)\s*?'
r'text = "(.*?)"',
re.DOTALL
)
results = []
for m in interval_pat.finditer(intervals_block):
xmin = float(m.group(1))
xmax = float(m.group(2))
text = m.group(3).strip()
if text: # 只保留非空文本
results.append({
"xmin": xmin,
"xmax": xmax,
"text": text
})
return results
def get_audio_from_file(file_path):
with wave.open(str(file_path), "rb") as wav_file:
frames = wav_file.readframes(wav_file.getnframes())
data = bytes(frames)
return data
def main(input_dir):
input_dir = Path(input_dir)
tg_dir = input_dir / "TextGrid"
wav_dir = input_dir / "wav"
csv_fields = ["utt_id", "asr_gt_text"]
with open("yue_long_gt.csv", "w", encoding="utf-8", newline="") as csv_f:
csv_writer = csv.DictWriter(csv_f, fieldnames=csv_fields)
csv_writer.writeheader()
wav_files = sorted(wav_dir.glob("*.wav"))
for idx, wav_file in enumerate(wav_files):
base_name = wav_file.stem # 不带后缀文件名
tg_file = tg_dir / f"{base_name}.TextGrid"
if not tg_file.exists():
print(f"警告:找不到对应TextGrid文件 {tg_file}, 跳过")
continue
text_items = parse_textgrid(tg_file)
asr_gt_text = "".join([item["text"] for item in text_items])
csv_writer.writerow({
"utt_id": base_name,
"asr_gt_text": asr_gt_text
})
if __name__ == "__main__":
main("WSYue-ASR-eval/Long")
WSChuan-Eval
川渝方言评测集采用 WenetSpeech 原生的 Kaldi 风格格式:text文件存储「音频 ID + 标注文本」,wav目录存放对应音频文件,同样分为长音频(322 条)和短音频(8051 条)两个子集。本次同样选取长音频进行测试。
标注解析与音频读取
import os
import wave
from pathlib import Path
def get_audio_from_file(file_path):
with wave.open(str(file_path), "rb") as wav_file:
frames = wav_file.readframes(wav_file.getnframes())
data = bytes(frames)
return data
def main(input_dir):
input_dir = Path(input_dir)
all_data = []
with open(os.path.join(input_dir, "text"), "r", encoding="utf8") as fin:
for line in fin.readlines():
data = line.strip().split()
all_data.append(
{
"utt_id": data[0],
"gt_text": " ".join(data[1:]),
}
)
for data in all_data:
utt_id = data["utt_id"]
asr_gt_text = data["gt_text"]
audio_bytes = get_audio_from_file(os.path.join(input_dir, "wav", f"{utt_id}.wav"))
# 后续可批量写入评测文件
if __name__ == "__main__":
main("WSChuan-Eval/WS-Chuan-ASR-Eval/open-source/long")
3. ASR 和 AST 任务测试
本次实验采用「语音识别 + 文本翻译」的两级级联方案实现方言 AST:
- 第一级:使用 Qwen3-ASR-1.7B 将方言语音识别为对应方言的书面文本
- 第二级:使用 Qwen3-8B-AWQ 大模型将方言文本翻译为标准普通话
该方案的优势是无需训练专属 AST 模型,复用成熟的 ASR 与 LLM 能力,落地成本低、迭代灵活。
3.1 ASR(Qwen3-ASR)
模型选型说明
本次选用 Qwen3-ASR-1.7B 作为识别底座,核心原因如下:
- 方言覆盖广:官方支持 22 种中文方言,包括吴语、粤语、四川话等本次测试的所有方言,无需额外微调即可开箱即用
- 精度领先:根据官方基准测试,该模型在 WenetSpeech 系列方言数据集上的识别精度显著优于 Whisper-large-v3 等主流开源模型
- 部署友好:支持 transformers 与 vLLM 双后端,原生支持长音频、流式推理,搭配 FlashAttention 可大幅降低显存占用
模型地址:https://www.modelscope.cn/models/Qwen/Qwen3-ASR-1.7B
推理实现
import torch
from qwen_asr import Qwen3ASRModel
import numpy as np
import wave
class Qwen3ASR:
def __init__(self, model_name, device_id=0):
self.model = Qwen3ASRModel.from_pretrained(
model_name,
dtype=torch.bfloat16,
device_map=f"cuda:{device_id}",
attn_implementation="flash_attention_2",
max_inference_batch_size=1,
max_new_tokens=1024, # 长音频需设置足够大的生成token数
)
def single_transcribe(self, audio_bytes):
# 将WAV字节流转为模型要求的numpy数组 + 采样率格式
np_wav = np.frombuffer(audio_bytes, np.int16).flatten()
results = self.model.transcribe(
audio=(np_wav, 16000),
language=None, # 不指定语言,测试模型自动方言识别能力
)
return results[0]
if __name__ == "__main__":
model = Qwen3ASR("Qwen/Qwen3-ASR-1.7B", device_id=0)
with wave.open("WSYue-ASR-eval/Long/wav/0000000831.wav", "rb") as wav_file:
frames = wav_file.readframes(wav_file.getnframes())
data = bytes(frames)
result = model.single_transcribe(data)
print("识别语言:", result.language)
print("识别文本:", result.text)
运行结果

配置说明:
- 使用 bf16 精度推理,在保证精度的同时降低显存占用
- 启用 FlashAttention-2 加速,长音频场景显存收益更明显
language=None测试模型零样本方言识别能力,实际生产中可指定语言进一步提升精度
3.2 AST(Qwen3-ASR + Qwen3)
在 ASR 识别出方言文本的基础上,通过 Qwen3-8B-AWQ 大模型完成方言到普通话的文本翻译。
模型选型说明
选用 Qwen3-8B-AWQ 的原因:
- 量化效率高:AWQ 4bit 量化后精度损失极小,显存占用仅为原版的 1/4 左右,单张消费级显卡即可部署
- 翻译能力强:Qwen3 原生支持上百种语言与方言,具备优秀的中文内翻译能力
- 部署生态完善:完美兼容 vLLM 推理框架,支持高并发批量调用,适合批量评测
模型地址:https://www.modelscope.cn/models/Qwen/Qwen3-8B-AWQ
3.2.1 vLLM 启动服务
通过 vLLM 部署为 OpenAI 兼容接口,便于批量调用与后续工程化落地。
vllm serve Qwen3-8B-AWQ --port 1234 --gpu-memory-utilization 0.4 --max-model-len 4096 --quantization awq
3.2.2 调用服务
翻译任务属于确定性文本生成,因此关闭思考模式以提升推理速度与输出稳定性。根据官方最佳实践,非思考模式使用 Temperature=0.7、TopP=0.8、TopK=20、MinP=0 的采样参数。
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:1234/v1", api_key="default")
prompt_template = """你是方言转普通话翻译专家,支持方言文本翻译。
规则:
1.输入是方言口语书面转写文本,输出标准现代汉语普通话;
2.保留原句语义、语气,不要随意增删内容;
3.方言代词、助词替换成普通话对应词汇;
4.只输出翻译后的句子,不要额外解释,不要输出思考过程。
方言文本:{text}
普通话输出:"""
def dialect_to_mandarin(text: str):
resp = client.chat.completions.create(
model="Qwen3-8B-AWQ",
messages=[{"role":"user","content":prompt_template.format(text=text)}],
temperature=0.7,
top_p=0.8,
max_tokens=256,
# vLLM扩展参数放到extra_body
extra_body={
"chat_template_kwargs": {
"enable_thinking": False
},
"top_k": 20,
"min_p": 0.0
}
)
return resp.choices[0].message.content.strip()
if __name__ == "__main__":
print(dialect_to_mandarin("阿拉现在可以请理工大的老教授带了伊拉的孙子孙女"))
Prompt 设计思路:
- 明确定义角色与任务边界,避免模型输出无关内容
- 约束输出格式,仅返回翻译结果,便于批量自动化评测
- 明确翻译规则,保证方言口语特征正确转换为普通话书面表达
3.3 评价指标
3.3.1 ASR 任务 ——CER(字错误率)
中文语音识别通用**字错误率(Character Error Rate, CER)**作为核心指标,计算识别结果与标注文本之间的字符级编辑距离(替换、插入、删除操作数之和)与参考文本总字符数的比值,数值越低代表识别精度越高。
使用jiwer库进行计算:
import jiwer
# reference: 参考标注文本,hypothesis: 模型识别结果
score = jiwer.cer(reference, hypothesis)
print(f"CER: {score:.4f}")
说明:中文场景优先使用 CER 而非 WER(词错误率),因为中文分词标准不统一,CER 不受分词影响,结果更稳定可比。
3.3.2 AST 任务
语音翻译任务采用两类主流指标进行评价:统计指标 BLEU 与语义指标 COMET。
BLEU
BLEU 是基于 n-gram 重合度的经典翻译评价指标,计算速度快、计算逻辑简单,适合快速横向对比。中文评测需指定tokenize="zh"以启用中文分词。
import sacrebleu
# hypotheses: 模型翻译结果列表,references: 参考译文列表
bleu_result = sacrebleu.corpus_bleu(hypotheses, [references], tokenize="zh")
print(f"BLEU: {bleu_result.score:.2f}")
COMET
COMET 是基于预训练语言模型的语义化翻译评价指标,更贴合人类主观判断,分为两种范式,环境安装可参考我的另一篇博客【机器翻译评价——COMET环境安装(GPU版本)】:
- 有参考(wmt22-comet-da):需要源文本、机器译文、人工参考译文三者,评价精度最高
- 无参考(wmt22-cometkiwi-da):仅需源文本与机器译文,适合缺少人工标注的场景
wmt22-comet-da(有参考)
from comet import load_from_checkpoint
import torch
comet_inputs = []
comet_inputs.append({
"src": src,
"mt": translation,
"ref": tgt
})
comet_model = load_from_checkpoint("wmt22-comet-da/checkpoints/model.ckpt")
if torch.cuda.is_available():
comet_model = comet_model.cuda()
outputs = comet_model.predict(comet_inputs, batch_size=8)
scores = outputs.scores
avg_comet = sum(scores)/len(scores)
wmt22-cometkiwi-da(无参考)
from comet import load_from_checkpoint
import torch
comet_inputs = []
comet_inputs.append({
"src": src,
"mt": translation,
})
comet_model = load_from_checkpoint("wmt22-cometkiwi-da/checkpoints/model.ckpt")
if torch.cuda.is_available():
comet_model = comet_model.cuda()
outputs = comet_model.predict(comet_inputs, batch_size=8)
scores = outputs.scores
avg_comet = sum(scores)/len(scores)
3.4 评测结果
3.4.1 ASR 识别效果
本次测试均采用长音频子集,不指定语言、让模型自动识别方言,最终字错误率如下:
| 方言 | CER |
|---|---|
| 吴语 | 0.2331 |
| 粤语 | 0.2199 |
| 川渝方言 | 0.1062 |
结果分析:
- 川渝方言识别精度最优,CER 仅 10.62%,原因是川渝方言属于西南官话,与普通话语音体系差异较小,模型零样本识别难度低。
- 吴语与粤语 CER 相对较高,符合预期 —— 吴语、粤语与普通话发音、词汇差异大,属于汉语方言中差异度最高的层级。
- 整体来看,Qwen3-ASR 在三款方言上均达到可用水平,无需微调即可支撑基础方言转写场景。
3.4.2 AST 翻译效果
BLEU 指标
| 方言 | BLEU |
|---|---|
| 吴语 | 47.50 |
有参考(wmt22-comet-da)
| 方言 | COMET |
|---|---|
| 吴语 | 0.7345 |
无参考(wmt22-cometkiwi-da)
| 方言 | COMET |
|---|---|
| 粤语 | 0.5467 |
结果分析:
- 吴语有参考 COMET 得分 0.7345,说明级联方案的翻译整体语义准确性较好,能够完成基本的方言转普通话需求。
- 粤语无参考 COMET 得分偏低,主要受两方面影响:一是粤语 ASR 识别误差会传递到翻译阶段,形成误差累积;二是无参考 COMET 模型本身对中文方言的适配度有限。
- 级联方案的核心瓶颈在于 ASR 识别精度 —— 方言识别错误越多,后续翻译的偏差越大,优化 ASR 方言识别能力是提升 AST 效果的关键。
总结
核心结论
- Qwen3-ASR 方言能力突出:在吴语、粤语、川渝方言三款主流方言上,零样本即可达到可用的识别精度,其中川渝方言 CER 低至 10.62%,是目前开源 ASR 中方言能力第一梯队的模型。
- 级联 AST 方案落地性强:「ASR 识别 + 大模型翻译」的方案无需专门训练端到端 AST 模型,依托通用大模型即可快速实现方言转普通话能力,适合快速落地与小成本试点。
- 方言差异是核心影响因素:方言与普通话的语音、词汇差异越大,ASR 识别难度越高,进而影响最终 AST 效果;西南官话类方言落地门槛最低,吴语、粤语等差异大的方言建议针对性微调优化。
踩坑与注意事项
- 数据集下载:HuggingFace 数据集地址在国内无法正常访问,国内用户请优先使用 ModelScope 平台或 SDK 下载。
- 环境依赖:qwen-asr包建议在 Python 3.12 环境中安装,FlashAttention 需匹配 CUDA 版本,低内存机器编译时可设置MAX_JOBS限制并发数。
- 显存配置:Qwen3-ASR-1.7B(bf16)约占 5-6GB 显存,Qwen3-8B-AWQ 约占 9-10GB 显存。
- 长音频参数:处理长音频时务必调大max_new_tokens,否则会出现识别结果截断的问题。
- vLLM 部署:AWQ 量化模型必须添加–quantization awq参数,否则会出现加载错误;建议使用 vLLM 0.8.5 及以上版本以兼容 Qwen3 系列模型。
更多推荐


所有评论(0)