1. 背景
在众多的开源模型中基本上没有可以准确识别藏语的语音识别模型,无论是国外开源的Whisper,还是国内阿里开源的Qwen3-ASR,均无法识别藏语,这个你们可以自行测试。如果我们需要本地化私有化部署一个可以识别藏语的语音识别项目,那么就需要使用大量的藏语数据集来训练模型。这里记录一位客户找到我训练藏语语音识别模型的过程,供你们参考学习。
首先我使用基于FunASR这个依赖使用Paraformer和SenseVoiceSmall都训练过,但是效果不理想,后面客户要求使用Qwen3-ASR来训练藏语语音识别模型,下面主要记录基于阿里开源的Qwen3-ASR-1.7B这个大模型来训练藏语语音识别模型的过程。
2. 数据集的准备
首先需要准备数据集,这里客户提供了10多个小时的藏语数据集,这些数据均是客户自己安排人员采集制作的。数据集要符合一定的格式要求,需要整理为jsonl格式文件,分为两个jsonl文件,一个是train.jsonl文件,这是训练集,还有一个是验证集val.jsonl。格式可以参考下面这样的:
{"audio": "/data/corpus/2026-08-11/converted/1000.wav", "text": "language Tibetan<asr text>རང་ཉིད་ངལ་རྩོལ་གྲལ་རིམ་གྱི་བསམ་བློ་བཡིན་རློམ་བྱེད་བཞིན་དུ།"}
其中这个audio是指音频所在的绝对路径,然后这个text是音频对应的文字内容,当然前面还添加了语种标识language Tibetan<asr text>,如果不想要语种标识,可以不添加这个,可以直接写音频对应的文字内容即可。

这里由于先做的paraformer训练,我这里编写了一个python脚本直接把paraformer_train.jsonl这样的数据转为这个Qwen3-ASR训练用的数据,下面是这个脚本代码。
# !/usr/bin/env python
# _*_ coding utf-8 _*_
# @Time: 2026/8/24 14:51
# @Author: Luke Ewin
# @Blog: https://blog.lukeewin.top
# 转换 paraformer 的训练的 jsonl 格式为符合 Qwen3-ASR 训练的格式
import json
import sys
def convert_jsonl(input_file, output_file):
"""
将原始JSONL转换为目标格式:
- 原 'source' -> 新 'audio'
- 原 'target' -> 新 'text',并在最前面添加 "language Tibetan<asr text>"
"""
with open(input_file, 'r', encoding='utf-8') as fin, \
open(output_file, 'w', encoding='utf-8') as fout:
for line in fin:
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
except json.JSONDecodeError as e:
print(f"跳过无效JSON行: {e}", file=sys.stderr)
continue
# 提取所需字段
audio_path = data.get('source')
target_text = data.get('target')
# 如果缺少必要字段,跳过该行(也可选择报错)
if audio_path is None or target_text is None:
print("跳过缺少 'source' 或 'target' 的行", file=sys.stderr)
continue
# 构建新记录
new_record = {
"audio": audio_path,
"text": f"language Tibetan<asr text>{target_text}"
}
# 写入输出文件
fout.write(json.dumps(new_record, ensure_ascii=False) + '\n')
if __name__ == "__main__":
# 使用方法:python script.py input.jsonl output.jsonl
if len(sys.argv) != 3:
print("用法: python convert.py <输入文件.jsonl> <输出文件.jsonl>", file=sys.stderr)
sys.exit(1)
input_file = sys.argv[1]
output_file = sys.argv[2]
convert_jsonl(input_file, output_file)
print(f"转换完成,结果已保存至 {output_file}")
3. 搭建训练环境
上面准备好了数据集,就可以开始搭建训练的Python环境了,这里使用uv,当然你也可以使用其它的,比如conda。
如何安装uv这里就不说了,比较简单,网上也可以很容易找到安装的文档。
安装好uv之后,就可以使用下面的命令创建一个python运行环境了。
uv venv --python 3.12
这里使用的python版本指定为3.12版本,其它的版本不知道是否可以。
激活环境:
source .venv/bin/activate
激活之后,就可以安装对应的python依赖了。
uv pip install -e .
这里是通过源码方式安装的qwen-asr依赖,此外,训练还需安装datasets依赖。
uv pip install datasets
需要主要的是一定要安装上这个cuda版本的torch,你执行上面两条安装命令的时候默认会给你安装上这个torch,可以检查一下,是否安装对了。
import torch
torch.cuda.is_available()
如果返回的是True就说明可以使用cuda。
系统安装的CUDA版本是13.2,如果使用的是5090显卡,需要安装的CUDA版本大于等于12.8。这里尽量选择安装最新版本的CUDA和显卡驱动。

4. 开始训练
经过上面的步骤,环境和数据集都做好了,就可以开始训练了,这里为了访问编写一个shell脚本,执行这个脚本就可以开始训练了。
#!/usr/bin/env bash
set -e
export CUDA_VISIBLE_DEVICES=0
MODEL_PATH="/opt/asr/Qwen3/models/Qwen3-ASR-1.7B"
TRAIN_FILE="/opt/asr/Qwen3/finetuning/data/train.jsonl"
EVAL_FILE="/opt/asr/Qwen3/finetuning/data/val.jsonl"
OUTPUT_DIR="/opt/asr/Qwen3/output"
torchrun --nproc_per_node=1 qwen3_asr_sft.py \
--model_path ${MODEL_PATH} \
--train_file ${TRAIN_FILE} \
--eval_file ${EVAL_FILE} \
--output_dir ${OUTPUT_DIR} \
--batch_size 2 \
--grad_acc 4 \
--lr 2e-5 \
--epochs 10 \
--log_steps 10 \
--save_strategy steps \
--save_steps 200 \
--save_total_limit 5 \
--num_workers 32 \
--pin_memory 1 \
--persistent_workers 1 \
--prefetch_factor 2
需要根据自己的硬件条件修改上面的数值,比如服务器有一张显卡,那么就指定CUDA_VISIBLE_DEVICES=0,如果有多张,就可以使用CUDA_VISIBLE_DEVICES=0,1,这种方式添加多张显卡。还有这个batch_size的值一定要是2的n次方,这个n可以是非负整数。然后这个num_workers的值最大填写你服务器CPU核心数,比如这里有32个核心,就最大可以填写32,这个值也尽量填写2的n次方,同样这个n可以是非负整数。
授予可执行权限。
chmod +x finetun.sh
然后执行这个脚本,开始训练,如果你的显存不够,就可以减小batch_size值。
./finetun.sh
可以看到下面日志中输出的loss值一直在减小,说明训练是有效果的。

可以看到,刚开始这个loss值很高,随着训练的进行,这个loss值会越来越小,如果这个loss值不减小,反而变大,说明这个训练参数设置的不对。
然后可以观察训练中,这个显卡的情况。

从上面可知,如果训练的数据集是10多个小时,那么至少需要一张24GB显存的显卡。如果你的数据集更大,就需要更大显存的显卡。
5. 效果检验
经过上面的训练,现在已经完成了训练,我们可以使用下面的python代码测试一下是否真的有效果。
# !/usr/bin/env python
# _*_ coding utf-8 _*_
# @Time: 2025/2/28 1:53
# @Author: Luke Ewin
# @Blog: https://blog.lukeewin.top
import torch
from qwen_asr import Qwen3ASRModel
model = Qwen3ASRModel.from_pretrained(
"/opt/asr/Qwen3/output/checkpoint-12830",
dtype=torch.bfloat16,
device_map="cuda:0",
attn_implementation="flash_attention_2",
max_inference_batch_size=32, # Batch size limit for inference. -1 means unlimited. Smaller values can help avoid OOM.
max_new_tokens=256, # Maximum number of tokens to generate. Set a larger value for long audio input.
)
results = model.transcribe(
audio=input("请输入音频路径:"),
language=None, # set "English" to force the language
)
print(results[0].language)
print(results[0].text)
这个/opt/asr/Qwen3/output/checkpoint-12830是我上面训练输出的模型权重路径,你需要修改你自己保存训练后的模型权重路径,这里最后填写绝对路径。
然后这里还需要说明一下,我这里开启了flash_attention_2,你需要提前安装好这个依赖flash-attn。我这里使用的是whl方式安装的,如果执行下面方式安装,速度会很慢,会编译很长时间,所以这里找了一个编译好的whl文件直接安装。
uv pip install flash-attn --no-build-isolation
我这里下载的这个whl文件是:
aria2c -x 16 -s 16 -c "https://github.com/mjun0812/flash-attention-prebuild-wheels/releases/download/v0.9.47/flash_attn-2.6.3+cu130torch2.13-cp312-cp312-linux_x86_64.whl"
执行上面的python代码,可以看到有输出藏文,相比训练之前来说好很多,训练之前输出的是中文。

如果要测试训练之前的效果,只需要修改上面python代码中的加载模型权重路径为训练之前的模型权重路径即可。

可以对比发现,原先模型不能识别藏语,输出的直接是中文,并且意思也不对,并不是翻译为中文输出,你可以理解为模型胡乱输出了中文来应付我们。然后经过训练之后的模型,可以看到输出了藏文,由于我看不懂藏文,这里我发送给AI大模型分析,这意思和音频对应藏文意思是差不多的。
6. 其它
如果需要训练其它少数民族语言或者方言的语音识别模型,欢迎私信咨询。
更多内容可以关注我的博客。
Q.E.D.


