# Paraformer-large训练微调指南:自定义数据集适配步骤详解
## 1. 引言:为什么需要训练自己的语音识别模型?
你用过现成的语音转文字工具吗?效果还不错,对吧?但有没有遇到过这种情况:你的音频里全是专业术语,比如“卷积神经网络”、“反向传播算法”,结果模型给你转成了“卷鸡神经王落”、“反像传播算法”,让人哭笑不得。
或者,你的业务场景很特殊,比如医疗问诊录音、法律庭审记录、地方方言访谈,通用的语音识别模型根本听不懂那些专业词汇和特殊口音。这时候,你就需要一个能“听懂你说话”的专属模型。
这就是我们今天要聊的——如何用Paraformer-large这个强大的语音识别模型,训练一个属于你自己的版本。别担心,听起来很高大上,其实跟着步骤走,一点都不难。我会用最直白的话,带你从零开始,搞定整个训练流程。
## 2. 准备工作:训练环境与数据
### 2.1 你需要准备什么?
在开始动手之前,我们先看看需要哪些“食材”:
1. **一个能跑起来的GPU环境**:训练模型就像炒菜,需要一口好锅。建议使用带GPU的云服务器,比如我们用的这个镜像,已经预装好了所有环境。
2. **你的专属语音数据集**:这是最重要的“食材”。没有数据,巧妇也难为无米之炊。
3. **一点点耐心**:训练需要时间,可能几个小时,也可能一两天,取决于数据量和你的GPU。
### 2.2 理解你的数据集
你的数据应该长什么样?理想情况下,它包含两个部分:
- **音频文件**:`.wav`格式最常见,确保是16kHz采样率(模型要求的)。如果你的音频是其他格式(如.mp3, .m4a),需要先转换。
- **对应的文本标注**:就是音频里说了什么话,一个字一个字地写下来。
**数据格式示例**:
假设你有一个音频文件叫 `meeting_001.wav`,里面说的是“本周五下午三点开项目评审会”。
那么,你需要一个对应的文本文件(比如叫 `meeting_001.txt`),里面就写这一句话:“本周五下午三点开项目评审会”。
**数据量要多少?**
对于微调(Fine-tuning)来说,不像从零训练需要海量数据。一般来说:
- **如果想提升特定领域的词汇识别率**(比如法律、医疗):准备5-20小时该领域的清晰录音,效果就会有明显提升。
- **如果想适应某种特定口音或发音习惯**:可能需要更多一些,比如20-50小时,让模型充分学习这种语音模式。
- **重要原则**:质量比数量更重要。10小时清晰的、标注准确的音频,远胜过100小时嘈杂的、标注错误的数据。
## 3. 第一步:整理和准备你的数据集
这是最基础,也最关键的一步。数据整理得好,训练就成功了一半。
### 3.1 数据清洗与格式转换
首先,把收集到的音频文件集中到一个文件夹里,比如叫 `my_custom_audio`。
**步骤1:统一音频格式**
打开终端,进入你的工作目录。我们可以用 `ffmpeg`(镜像里已经装好了)来批量转换音频格式和采样率。
```bash
# 假设你的原始音频在 raw_audio 文件夹,格式杂乱
mkdir -p my_custom_audio
# 使用一个循环,将 raw_audio 下的所有音频文件转为 16k Hz 的单声道 wav 文件
for file in raw_audio/*.{mp3,m4a,wav,flac}; do
if [ -f "$file" ]; then
filename=$(basename "$file" .${file##*.})
ffmpeg -i "$file" -ar 16000 -ac 1 "my_custom_audio/${filename}.wav" -y
echo "已转换: $file"
fi
done
```
**步骤2:整理文本标注**
为每一个 `.wav` 文件创建对应的 `.txt` 文本文件。**确保文件名严格对应**。
例如:
- `my_custom_audio/meeting_001.wav`
- `my_custom_audio/meeting_001.txt`
文本文件的内容就是纯文字,不要有任何其他信息(如时间戳、说话人ID等,除非你后续需要更复杂的处理)。
### 3.2 创建训练所需的清单文件
模型训练时,需要一个“清单”来告诉它:哪个音频文件对应哪个文本。这个清单通常是一个 `.tsv`(制表符分隔)文件。
我们来手动创建一个。首先,列出所有音频文件的信息:
```bash
cd /root/workspace
mkdir -p data_custom
cd data_custom
# 创建一个文件,列出所有wav文件的路径和大小(字节数)
find /root/workspace/my_custom_audio -name "*.wav" | while read wav_path; do
wav_size=$(stat -c%s "$wav_path")
echo -e "${wav_path}\t${wav_size}" >> wav.scp
done
```
然后,创建另一个文件,建立从音频文件ID到文本内容的映射:
```bash
# 创建 text.txt 文件,格式:音频ID 对应文本
# 假设你的音频文件ID就是去掉后缀的文件名
find /root/workspace/my_custom_audio -name "*.wav" | while read wav_path; do
audio_id=$(basename "$wav_path" .wav)
text_path="${wav_path%.wav}.txt"
if [ -f "$text_path" ]; then
text_content=$(cat "$text_path")
# 这里可以做一些简单的文本清洗,比如去除多余空格、换行符
text_content=$(echo "$text_content" | tr -d '\n' | sed 's/ */ /g')
echo -e "${audio_id}\t${text_content}" >> text.txt
else
echo "警告: 找不到 $text_path 的对应文本文件"
fi
done
```
现在,你的 `data_custom` 文件夹里应该有了 `wav.scp` 和 `text.txt` 两个关键文件。你可以用 `head` 命令查看一下内容:
```bash
head -5 wav.scp
head -5 text.txt
```
## 4. 第二步:配置训练任务
Paraformer-large 基于 FunASR 框架,训练配置主要通过一个 YAML 文件来完成。别被吓到,我们一步步来。
### 4.1 准备配置文件
在 `/root/workspace` 下创建一个新的配置文件,比如叫 `finetune_paraformer.yaml`。
```yaml
# finetune_paraformer.yaml
# 基础配置
task: asr
task_name: asr
model: paraformer
model_conf:
ctc_weight: 0.3
lsm_weight: 0.1
length_normalized_loss: false
# 数据集路径配置
dataset: aishell
dataset_conf:
data_path: /root/workspace/data_custom/ # 指向我们刚刚准备的数据目录
# 你的数据清单文件,我们等下会生成
train_set: train
dev_set: dev
# 数据增强配置(可选,用于让小数据集效果更好)
speed_perturb: true
spec_aug: true
spec_aug_conf:
num_t_mask: 2
num_f_mask: 2
max_t: 50
max_f: 10
# 模型结构配置(基于Paraformer-large)
encoder: sanm
encoder_conf:
attention_heads: 8
linear_units: 2048
num_blocks: 24
dropout_rate: 0.1
positional_dropout_rate: 0.1
attention_dropout_rate: 0.1
input_layer: conv2d
normalize_before: true
decoder: sanm
decoder_conf:
attention_heads: 8
linear_units: 2048
num_blocks: 6
dropout_rate: 0.1
positional_dropout_rate: 0.1
self_attention_dropout_rate: 0.1
src_attention_dropout_rate: 0.1
# 训练参数(关键!微调时学习率要调小)
optim: adam
optim_conf:
lr: 0.0005 # 微调学习率,比从头训练小很多
scheduler: warmuplr
scheduler_conf:
warmup_steps: 25000
batch_type: folded
batch_size: 16
accum_grad: 2
max_epoch: 20 # 微调不需要太多轮次
patience: 5
log_interval: 100
```
**重点解释几个参数**:
- `data_path`:一定要改成你存放 `data_custom` 的绝对路径。
- `lr: 0.0005`:**学习率**,这是微调最重要的参数之一。因为我们是在一个已经训练好的大模型(Paraformer-large)基础上调整,所以步子要小一点,学习率设得比从头训练低(通常是十分之一到百分之一),否则容易“学歪了”,把模型原本好的能力也破坏了。
- `max_epoch: 20`:**训练轮数**。微调时,模型收敛很快,一般10-20轮就足够了。你可以观察损失值(loss),如果连续几轮都不再下降,就可以提前停止了。
- `batch_size` 和 `accum_grad`:根据你的GPU内存来调整。如果训练时出现“内存不足(OOM)”错误,就减小 `batch_size` 或增大 `accum_grad`。
### 4.2 划分训练集和验证集
我们不能把所有数据都用来训练,需要留出一部分作为“验证集”,用来在训练过程中检查模型学得怎么样,防止它“死记硬背”(过拟合)。
一个简单的做法是,按大约 9:1 的比例随机划分数据。我们可以写个Python小脚本来完成:
```python
# /root/workspace/split_data.py
import os
import random
data_dir = "/root/workspace/data_custom"
wav_scp_path = os.path.join(data_dir, "wav.scp")
text_path = os.path.join(data_dir, "text.txt")
# 读取数据
wav_lines = []
with open(wav_scp_path, 'r', encoding='utf-8') as f:
wav_lines = f.readlines()
text_dict = {}
with open(text_path, 'r', encoding='utf-8') as f:
for line in f:
parts = line.strip().split('\t')
if len(parts) == 2:
text_dict[parts[0]] = parts[1]
# 获取所有有效的音频ID
audio_ids = []
for line in wav_lines:
parts = line.strip().split('\t')
if len(parts) == 2:
wav_path = parts[0]
audio_id = os.path.splitext(os.path.basename(wav_path))[0]
if audio_id in text_dict: # 确保有对应的文本
audio_ids.append(audio_id)
# 随机打乱并划分 (90% 训练, 10% 验证)
random.shuffle(audio_ids)
split_idx = int(len(audio_ids) * 0.9)
train_ids = audio_ids[:split_idx]
dev_ids = audio_ids[split_idx:]
print(f"总样本数: {len(audio_ids)}")
print(f"训练集: {len(train_ids)}")
print(f"验证集: {len(dev_ids)}")
# 写入Kaldi格式的文件(FunASR所需)
def write_kaldi_file(ids, wav_lines, text_dict, set_name):
with open(os.path.join(data_dir, f"wav.{set_name}.scp"), 'w', encoding='utf-8') as f_wav:
with open(os.path.join(data_dir, f"text.{set_name}"), 'w', encoding='utf-8') as f_text:
for aid in ids:
# 写wav.scp
for line in wav_lines:
if aid in line: # 简单匹配,根据实际情况调整
f_wav.write(line)
break
# 写text
if aid in text_dict:
f_text.write(f"{aid}\t{text_dict[aid]}\n")
write_kaldi_file(train_ids, wav_lines, text_dict, "train")
write_kaldi_file(dev_ids, wav_lines, text_dict, "dev")
print("数据划分完成!")
```
运行这个脚本:
```bash
cd /root/workspace
python split_data.py
```
执行后,在 `data_custom` 文件夹里,你应该能看到新生成的 `wav.train.scp`, `text.train`, `wav.dev.scp`, `text.dev` 这四个文件。这样,数据准备就全部完成了。
## 5. 第三步:开始模型训练
万事俱备,只欠东风。现在可以启动训练了。
### 5.1 下载预训练模型
FunASR 训练脚本通常支持从ModelScope(魔搭社区)自动下载预训练模型。但为了更稳定,我们可以先手动下载好 Paraformer-large 的预训练权重。
```bash
cd /root/workspace
# 使用 modelscope 库下载
python -c "from modelscope import snapshot_download; model_dir = snapshot_download('iic/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch', revision='v2.0.4'); print(f'模型已下载至: {model_dir}')"
```
下载完成后,记下模型存放的路径,稍后需要在训练命令中引用。
### 5.2 启动训练任务
我们使用 FunASR 提供的 `asr_train.py` 脚本进行训练。打开终端,执行以下命令:
```bash
cd /root/workspace
# 激活conda环境(如果镜像已自动激活可省略)
source /opt/miniconda3/bin/activate torch25
# 开始训练
python -m funasr.bin.asr_train \
--config-path /root/workspace/ \
--config-name finetune_paraformer.yaml \
--init_param /root/.cache/modelscope/hub/iic/speech_paraformer-large-vad-punc_asr_nat-zh-cn-16k-common-vocab8404-pytorch/model.pth \ # 这里替换成你实际下载的路径
--output_dir /root/workspace/exp/custom_paraformer_finetune \
--num_workers 4 \
--log_interval 100 \
--seed 777
```
**命令参数解释**:
- `--config-path` 和 `--config-name`: 指定我们刚才写的配置文件。
- `--init_param`: **这是关键!** 指定预训练模型的路径。这告诉程序:“不要从零开始,在这个已经很强的模型基础上继续学习。”
- `--output_dir`: 训练过程中所有的日志、中间模型、最终模型都会保存在这个目录。
- `--num_workers`: 数据加载的进程数,根据你的CPU核心数调整,可以加快数据读取速度。
- `--seed`: 随机种子,固定它可以让每次训练结果可复现。
敲下回车,训练就开始了!屏幕上会滚动显示训练日志,包括当前是第几轮(epoch)、第几个批次(batch)、损失值(loss)等。
### 5.3 监控训练过程
训练开始后,别干等着。我们需要观察几个关键指标,判断模型学得好不好:
1. **看损失(Loss)**:这是最直接的指标。正常情况下,训练损失(train loss)和验证损失(val loss)都应该随着训练轮数增加而稳步下降。如果验证损失不降反升,说明模型可能过拟合了。
2. **看识别率**:FunASR日志里通常会输出字符错误率(CER)。这个值越低越好。关注验证集上的CER,它是模型在新数据上表现的真实反映。
训练完成后,在 `--output_dir` 指定的目录下(比如 `/root/workspace/exp/custom_paraformer_finetune`),你会找到:
- `valid.acc.ave.pth`: 通常这是在验证集上平均效果最好的模型,是我们最终要用的。
- `model.yaml`: 模型的配置文件。
- `train.log`: 完整的训练日志。
## 6. 第四步:测试与使用你的微调模型
模型训练好了,怎么用它呢?和之前使用原始模型几乎一样,只需要把模型路径换成我们自己的。
### 6.1 修改Gradio应用代码
还记得我们镜像里自带的那个漂亮的Web界面吗?我们只需要修改一两行代码,让它加载我们刚训练好的模型。
打开或创建 `app_finetuned.py`:
```python
# app_finetuned.py
import gradio as gr
from funasr import AutoModel
import os
# 关键修改在这里!
# 不再从魔搭社区加载,而是加载我们本地训练好的模型
finetuned_model_dir = "/root/workspace/exp/custom_paraformer_finetune" # 你的训练输出目录
best_model_file = "valid.acc.ave.pth" # 最佳模型文件名
model = AutoModel(
model=finetuned_model_dir, # 指定模型目录
model_file=best_model_file, # 指定模型文件
device="cuda:0" if torch.cuda.is_available() else "cpu"
)
def asr_process(audio_path):
if audio_path is None:
return "请先上传音频文件"
res = model.generate(
input=audio_path,
batch_size_s=300,
)
if len(res) > 0:
return res[0]['text']
else:
return "识别失败,请检查音频格式"
with gr.Blocks(title="我的专属Paraformer语音识别") as demo:
gr.Markdown("# 🎤 我的专属语音识别模型")
gr.Markdown("这是用我自己的数据微调过的模型,识别我的专业领域内容更准确!")
with gr.Row():
with gr.Column():
audio_input = gr.Audio(type="filepath", label="上传音频或直接录音")
submit_btn = gr.Button("开始转写", variant="primary")
with gr.Column():
text_output = gr.Textbox(label="识别结果", lines=15)
submit_btn.click(fn=asr_process, inputs=audio_input, outputs=text_output)
demo.launch(server_name="0.0.0.0", server_port=6006)
```
### 6.2 启动服务并测试
保存文件后,启动新的服务:
```bash
cd /root/workspace
python app_finetuned.py
```
同样,通过SSH隧道将服务器的6006端口映射到本地,然后在浏览器打开 `http://127.0.0.1:6006`。
现在,上传一段你训练数据领域内的新音频(但确保这段音频**没有**出现在之前的训练集里!),听听转写结果。你会发现,对于那些专业术语、特定口音,识别准确率应该比原始模型高出一大截!
## 7. 总结与进阶建议
恭喜你!走到这一步,你已经成功拥有了一个为你量身定制的语音识别模型。我们来回顾一下整个过程,并看看还有什么可以优化的。
### 7.1 关键步骤回顾
1. **准备数据**:收集高质量的音频和文本对,统一格式,整理成模型需要的清单文件。
2. **划分数据集**:分出训练集和验证集,这是评估模型好坏、防止过拟合的关键。
3. **配置训练**:编写YAML配置文件,**核心是调小学习率**,并正确指向你的数据和预训练模型。
4. **启动训练**:使用 `asr_train.py` 脚本,耐心等待训练完成,并观察损失和错误率。
5. **部署使用**:修改应用代码,加载你自己的模型文件,享受更精准的识别服务。
### 7.2 遇到问题怎么办?
- **训练损失不下降**:检查学习率是否合适,数据标注是否有大量错误,或者数据量是否实在太少。
- **验证损失上升(过拟合)**:这是微调常见问题。可以尝试:进一步减小学习率、增加数据增强的强度、提前停止训练(减少 `max_epoch`)、或者在配置文件中加入 `weight_decay` 参数进行正则化。
- **显存不足(OOM)**:减小 `batch_size`,或者增大 `accum_grad`(梯度累积步数)。
- **识别结果没改善**:确保你的测试音频确实是训练数据所覆盖的领域。用完全无关的音频测试,效果可能和原模型差不多。
### 7.3 下一步可以做什么?
你的专属模型已经跑起来了,但技术的探索永无止境:
- **持续迭代**:收集模型识别错误的案例,修正标注,加入到训练数据中,重新训练。这样模型会越来越聪明。
- **尝试更多模型**:Paraformer很强,但也不是唯一选择。FunASR框架里还有Conformer、UniASR等模型架构,针对流式、非自回归等不同场景有优化,你可以根据需求尝试。
- **集成更多功能**:我们这个微调主要针对识别核心能力。你还可以在Pipeline中集成更强大的VAD(语音端点检测)来精准切分长语音,或者集成更好的标点恢复模型,让转写结果更易读。
训练自己的AI模型,就像教一个聪明的小孩。一开始它可能听不懂你的“行话”,但只要你耐心地、用正确的数据去教它,它就能成为你业务中不可或缺的得力助手。希望这份指南能帮你迈出这坚实的第一步。
---
> **获取更多AI镜像**
>
> 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。