OpenAI 开源的 Whisper 项目号称英文语音识别能力已达到人类水平,且支持其它 98 种语言的自动语音辨识。Whisper 所提供的自动语音识与翻译任务,它们能将各种语言的语音变成文本,也能将这些文本翻译成英文。本篇文章主要的目的是为了对 Whisper 模型使用 Lora 进行微调,还支持 CTranslate2 加速推理。
一、基础环境
二、模型选型
三、安装环境
四、准备SFT数据
五、微调模型
五、合并模型
七、评估模型
八、推理预测
九、推理加速
十、Web界面部署
# 今日AI资讯看点 #
一、基础环境
二、模型选型
本次微调期望看到 Whisper 最优性能,所以我选用的版本是 openai/whisper-large-v2 。当然您使用浅尝的话可以选以下几个版本:
- openai/whisper-tiny
- openai/whisper-base
- openai/whisper-small
- openai/whisper-medium
三、安装环境
- 首先安装的是 Pytorch 的 GPU 版本,以下介绍两种安装 Pytorch 的方式,只需要选择一种即可。使用 miniconda 安装 Pytorch 环境。如已安装,请跳过。
conda install pytorch==1.13.1 torchvision==0.14.1 torchaudio==0.13.1 pytorch-cuda=11.6 -c pytorch -c nvidia
- 安装所需的依赖库
python -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
四、准备 SFT 数据
SFT 数据集是一个 jsonlines 的数据列表,也就是每一行都是一个 JSON 数据,数据格式如下。数据集下载地址:https://openslr.elda.org/resources/33/data_aishell.tgz,包括训练集和测试集。
{
"audio": {
"path": "dataset/jiaenqiu.wav"
},
"sentence": "我写了一封长长的情书,填对了地址,却选错了时间。",
"language": "Chinese",
"sentences": [
{
"start": 0,
"end": 2.38,
"text": "我写了一封长长的情书,"
},
{
"start": 2.4,
"end": 5.4,
"text": "填对了地址,却选错了时间。"
}
],
"duration": 5.4
}
注意:
- 如果不使用时间戳训练,可以不包含 sentences 字段数据。
- 如果只有一种语言的数据,可以不包含 language 字段数据。
- 如果训练空语音数据,sentences 字段为[],sentence 字段为””,language 字段可以不存在。
- 数据可以不包含标点符号,但微调后模型会损失添加符号能力。
五、微调模型
准备好数据之后,就可以开始微调模型了。训练最重要的两个参数分别是:
- –base_model 指定微调的 Whisper 模型路径。我是提前在 HuggingFace 下载,使用参数指定本地路径,同时 –local_files_only 设置为 True。
- –output_path 是训练时保存的 Lora 检查点路径。因为我们使用 Lora 微调模型。如果显存足够,最好将 –use_8bit 设置为 False,这样训练速度快很多。
其他更多的参数请查看脚本 finetune.py。
单卡训练
单卡训练命令如下,Windows 系统可以不添加 CUDA_VISIBLE_DEVICES 参数。
CUDA_VISIBLE_DEVICES=0 python finetune.py --base_model=openai/whisper-large-v2 --local_files_only=True --output_dir=output/ --train_data=dataset/train_2.json --test_data=dataset/test_2.json
输出日志如下:
{'loss': 0.9098, 'learning_rate': 0.000999046843662503, 'epoch': 0.01}
{'loss': 0.5898, 'learning_rate': 0.0009970611012927184, 'epoch': 0.01}
{'loss': 0.5583, 'learning_rate': 0.0009950753589229333, 'epoch': 0.02}
{'loss': 0.5469, 'learning_rate': 0.0009930896165531485, 'epoch': 0.02}
{'loss': 0.5959, 'learning_rate': 0.0009911038741833634, 'epoch': 0.03}
------------------------------------------------
训练数据:13,4424,测试数据:7176
===============================================================
trainable params: 81,1776 || all params: 3857,2480 || trainable%: 2.1045470760500753
===============================================================
finetune.py 部分代码
add_arg("train_data", type=str, default="dataset/train.json", help="训练数据集的路径")
add_arg("test_data", type=str, default="dataset/test.json", help="测试数据集的路径")
add_arg("base_model", type=str, default="openai/whisper-tiny", help="Whisper的基础模型")
add_arg("output_dir", type=str, default="output/", help="训练保存模型的路径")
add_arg("warmup_steps", type=int, default=50, help="训练预热步数")
add_arg("logging_steps", type=int, default=100, help="打印日志步数")
add_arg("eval_steps", type=int, default=1000, help="多少步数评估一次")
add_arg("save_steps", type=int, default=1000, help="多少步数保存模型一次")
add_arg("num_workers", type=int, default=8, help="读取数据的线程数量")
add_arg("learning_rate", type=float, default=1e-3, help="学习率大小")
add_arg("min_audio_len", type=float, default=0.5, help="最小的音频长度,单位秒")
add_arg("max_audio_len", type=float, default=30, help="最大的音频长度,单位秒")
add_arg("use_adalora", type=bool, default=True, help="是否使用AdaLora而不是Lora")
add_arg("fp16", type=bool, default=True, help="是否使用fp16训练模型")
add_arg("use_8bit", type=bool, default=False, help="是否将模型量化为8位")
add_arg("timestamps", type=bool, default=False, help="训练时是否使用时间戳数据")
add_arg("local_files_only", type=bool, default=False, help="是否只在本地加载模型,不尝试下载")
add_arg("num_train_epochs", type=int, default=3, help="训练的轮数")
add_arg("language", type=str, default="Chinese", help="设置语言,可全称也可简写,如果为None则训练的是多语言")
add_arg("task", type=str, default="transcribe", choices=['transcribe', 'translate'], help="模型的任务")
add_arg("augment_config_path", type=str, default=None, help="数据增强配置文件路径")
add_arg("resume_from_checkpoint", type=str, default=None, help="恢复训练的检查点路径")
add_arg("per_device_train_batch_size", type=int, default=8, help="训练的batch size")
add_arg("per_device_eval_batch_size", type=int, default=8, help="评估的batch size")
add_arg("gradient_accumulation_steps", type=int, default=1, help="梯度累积步数")
# 获取Whisper的数据处理器,这个包含了特征提取器、tokenizer
processor = WhisperProcessor.from_pretrained(args.base_model,
language=args.language,
task=args.task,
no_timestamps=not args.timestamps,
local_files_only=args.local_files_only)
# 读取数据
train_dataset = CustomDataset(data_list_path=args.train_data,
processor=processor,
language=args.language,
timestamps=args.timestamps,
min_duration=args.min_audio_len,
max_duration=args.max_audio_len,
augment_config_path=args.augment_config_path)
test_dataset = CustomDataset(data_list_path=args.test_data,
processor=processor,
language=args.language,
timestamps=args.timestamps,
min_duration=args.min_audio_len,
max_duration=args.max_audio_len)
print(f“训练数据:{len(train_dataset)},测试数据:{len(test_dataset)}”)
# 获取Whisper模型
model = WhisperForConditionalGeneration.from_pretrained(args.base_model,
load_in_8bit=args.use_8bit,
device_map=device_map,
local_files_only=args.local_files_only)
# 量化模型
model = prepare_model_for_kbit_training(model)
print(‘加载LoRA模块…’)
if args.resume_from_checkpoint:
print(f‘adding LoRA modules…’)
target_modules = [“k_proj”, “q_proj”, “v_proj”, “out_proj”, “fc1”, “fc2”]
print(target_modules)
config = AdaLoraConfig(init_r=12, target_r=4, beta1=0.85, beta2=0.85, tinit=200, tfinal=1000, deltaT=10,
lora_alpha=32, lora_dropout=0.1, orth_reg_weight=0.5, target_modules=target_modules)
model = get_peft_model(model, config)
output_dir = os.path.join(args.output_dir, os.path.basename(args.base_model))
# 定义训练参数
training_args =
Seq2SeqTrainingArguments(output_dir=output_dir, # 保存检查点和意志的目录
per_device_train_batch_size=args.per_device_train_batch_size, # 训练batch_size大小
per_device_eval_batch_size=args.per_device_eval_batch_size, # 评估batch_size大小
gradient_accumulation_steps=args.gradient_accumulation_steps, # 训练梯度累计步数
learning_rate=args.learning_rate, # 学习率大小
warmup_steps=args.warmup_steps, # 预热步数
num_train_epochs=args.num_train_epochs, # 微调训练轮数
save_strategy=“steps”, # 指定按照步数保存检查点
evaluation_strategy=“steps”, # 指定按照步数评估模型
load_best_model_at_end=True, # 指定是否在结束时加载最优模型
fp16=args.fp16, # 是否使用半精度训练
report_to=[“tensorboard”], # 指定使用tensorboard保存log
save_steps=args.save_steps, # 指定保存检查点的步数
eval_steps=args.eval_steps, # 指定评估模型的步数
save_total_limit=5, # 只保存最新检查点的数量
optim=‘adamw_torch’, # 指定优化方法
ddp_find_unused_parameters=False if ddp else None, # 分布式训练设置
dataloader_num_workers=args.num_workers, # 设置读取数据的线程数量
logging_steps=args.logging_steps, # 指定打印log的步数
remove_unused_columns=False, # 删除模型不需要的数据列
label_names=[“labels”]) # 与标签对应的输入字典中的键列表
# 开始训练
trainer.train(resume_from_checkpoint=args.resume_from_checkpoint)
# 保存最后的模型
trainer.save_state()
if training_args.local_rank == 0 or training_args.local_rank == -1:
model.save_pretrained(os.path.join(output_dir, “checkpoint-final”))
六、合并模型
微调完成之后会有两个模型,第一个是 Whisper 基础模型,第二个是 Lora 模型,需要把这两个模型合并之后才能之后的操作。两个参数:
- –lora_model 是训练结束后保存的 Lora 模型路径,就是检查点文件夹路径
- –output_dir 是合并后模型的保存目录
python merge_lora.py --lora_model=output/whisper-large-v2/checkpoint-best/ --output_dir=models/
七、评估模型
执行以下程序进行评估模型,最重要的两个参数分别是。
- –model_path 是合并后的模型路径,同时也支持直接使用 Whisper 原模型,例如直接指定 openai/whisper-large-v2
- –metric 是评估方法,例如:字错率 cer 和词错率 wer。
python evaluation.py --model_path=models/whisper-large-v2-finetune --metric=wer
- 提示:没有微调的模型,可能输出带有标点符号,影响准确率
知识拓展
在 LLM 评估中,CER(Character Error Rate)和 WER(Word Error Rate)是两个常用的指标,用于评估文本生成任务中的错误率。
- CER(Character Error Rate)是用于衡量生成文本中字符级别错误的指标。它计算生成文本与参考文本之间的字符差异率,表示为错误字符的数量除以参考文本的总字符数。CER 的值越低,表示生成文本与参考文本越接近。
- WER(Word Error Rate)是用于衡量生成文本中词级别错误的指标。它计算生成文本与参考文本之间的词差异率,表示为错误词的数量除以参考文本的总词数。WER 的值越低,表示生成文本与参考文本越接近。
- 中文一般用 CER 来表示字错率,原因:计算的时候谁不是按:中文的一个字符 = 英文的一个 Word。英文,因为最小单元是 Word,语音识别应该用”词错误率”(WER);中文,因为最小单元是字符,语音识别应该用“字符错误率”(CER)。
二者区别
- CER 是在字符级别上评估错误率,而 WER 是在词级别上评估错误率。
- CER 关注的是字符的插入、删除和替换错误,而 WER 关注的是词的插入、删除和替换错误。
- CER 更加细粒度,能够捕捉到字符级别的错误,而 WER 更加高层次,考虑了词级别的错误。
- CER 和 WER 能够反映生成文本与参考文本之间的差异和错误。它们是评估文本生成质量的重要指标,常用于语音识别、机器翻译等任务的性能评估,可以帮助量化系统的准确性和错误率。一般来说,较低的 CER 和 WER 值表示生成的文本更接近参考文本,表示系统性能更好。
八、推理预测
执行以下程序进行语音识别,使用 transformers 直接调用微调后的模型或 Whisper 原模型预测,只适合推理短音频,长语音还是参考 infer_ct2.py 方式。
- –audio_path 指定的是要预测的音频路径
- –model_path 指定的是合并后的模型路径,同时也支持直接使用 Whisper 原模型,例如直接指定 openai/whisper-large-v2
python infer_tfs.py --audio_path=dataset/jiaenqiu.wav --model_path=models/whisper-large-v2-finetune
python infer_ct2.py --audio_path=dataset/long.wav --model_path=models/whisper-large-v2-finetune
九、推理加速
尝试过直接使用 Whisper 模型推理是比较慢的,所以提供了推理加速。主要是使用 CTranslate2 进行加速,首先要转换模型,把合并后的模型转换为 CTranslate2 模型。
ct2-transformers-converter --model models/whisper-large-v2-finetune --output_dir models/whisper-large-v2-finetune-ct2 --copy_files tokenizer.json --quantization float16
- –model 参数指定的是合并后的模型路径,同时也支持直接使用 Whisper 原模型,例如直接指定 openai/whisper-large-v2
- –output_dir 参数指定的是转换后的 CTranslate2 模型路径
- –quantization 参数指定的是量化模型大小,不希望量化模型可直接去掉此参数
python infer_ct2.py --audio_path=dataset/jiaenqiu.wav --model_path=models/whisper-large-v2-finetune-ct2
- –audio_path 参数指定的是要预测的音频路径
- –model_path 指定的是转换后的 CTranslate2 模型 输出结果:
----------- Configuration Arguments -----------
audio_path: dataset/jiaenqiu.wav
model_path: models/whisper-large-v2-finetune-ct2
language: zh
use_gpu: True
use_int8: False
beam_size: 10
num_workers: 1
vad_filter: False
local_files_only: True
------------------------------------------------
[0.0 - 5.2]:我写了一封长长的情书,填对了地址,却选错了时间。
十、Web 界面部署
启动命令:
python infer_server.py --model_path=models/whisper-large-v2-finetune-ct2
- Web界面地址
http://127.0.0.1:5000
引用:https://github.com/yeyupiaoling
后续我会对微调前后的模型做一次全面性能测试,敬请关注➕
今日AI资讯 2023.08.10 星期四 六月廿四日
- 奇虎360智脑4.0整体能力1个月提升近15%
- 奇虎360与8家企业签署大模型战略应用合作协议
- 面向大型语言模型多维基准测试工具AgentBench
- 福布斯发布云计算100强榜单,OpenAI第一
- 旷视FaceID人身核验引入视觉大模型
- 科大讯飞与电信签署协议:展开大模型、云计算等业务合作
- 中国电信柯瑞文:正在深入研究通用大模型 下半年会看到成果
- Spotify:向更多地区推出AI DJ功能
欢迎关注,一起进步一起成长