2. 模型格式转换基础
任务目标
将预训练的 wav2vec2 语音模型从 PyTorch 格式转换为 ONNX 格式,并验证转换前后模型输出的一致性。本案例以 facebook/wav2vec2-base 为例,完成从 PyTorch 到 ONNX 的完整转换闭环。
环境依赖
torch≥ 2.0transformers≥ 4.30onnx≥ 1.14onnxruntime≥ 1.16numpy
安装命令:pip install torch transformers onnx onnxruntime numpy
核心实现
以下代码完成模型加载、ONNX 导出及输出一致性验证。导出时固定 input_values 维度为 [1, 16000](1 秒音频),并使用 opset=14 保证算子兼容性。
import torch
import numpy as np
import onnx
import onnxruntime as ort
from transformers import Wav2Vec2Processor, Wav2Vec2Model
# 1. 加载模型与处理器
model_id = "facebook/wav2vec2-base"
processor = Wav2Vec2Processor.from_pretrained(model_id)
model = Wav2Vec2Model.from_pretrained(model_id)
model.eval()
# 2. 构造示例输入(1秒随机音频)
sample_rate = 16000
dummy_input = torch.randn(1, sample_rate, dtype=torch.float32)
# 3. 导出为 ONNX
onnx_path = "wav2vec2_base.onnx"
with torch.no_grad():
torch.onnx.export(
model,
dummy_input,
onnx_path,
input_names=["input_values"],
output_names=["last_hidden_state", "extract_features"],
dynamic_axes={
"input_values": {1: "sequence_length"},
"last_hidden_state": {1: "sequence_length"},
"extract_features": {1: "sequence_length"},
},
opset_version=14,
)
# 4. 验证 ONNX 模型结构完整性
onnx_model = onnx.load(onnx_path)
onnx.checker.check_model(onnx_model)
print(f"ONNX 模型结构验证通过,节点数: {len(onnx_model.graph.node)}")
# 5. 使用 ONNX Runtime 推理并与 PyTorch 输出对比
ort_session = ort.InferenceSession(onnx_path, providers=["CPUExecutionProvider"])
# 使用同一输入进行推理
test_input = torch.randn(1, sample_rate, dtype=torch.float32).numpy()
with torch.no_grad():
torch_outputs = model(torch.from_numpy(test_input))
torch_last_hidden = torch_outputs.last_hidden_state.numpy()
torch_extract = torch_outputs.extract_features.numpy()
ort_outputs = ort_session.run(
output_names=["last_hidden_state", "extract_features"],
input_feed={"input_values": test_input},
)
ort_last_hidden, ort_extract = ort_outputs
# 6. 计算最大误差
max_diff_last_hidden = np.max(np.abs(torch_last_hidden - ort_last_hidden))
max_diff_extract = np.max(np.abs(torch_extract - ort_extract))
print(f"last_hidden_state 最大误差: {max_diff_last_hidden:.6e}")
print(f"extract_features 最大误差: {max_diff_extract:.6e}")
# 7. 一致性判定(阈值设为 1e-4)
threshold = 1e-4
if max_diff_last_hidden < threshold and max_diff_extract < threshold:
print("✅ 转换验证通过:PyTorch 与 ONNX 输出一致")
else:
print("❌ 转换验证失败:输出差异超过阈值")
运行方式
- 将上述代码保存为
convert_wav2vec2.py。 - 在终端执行:
python convert_wav2vec2.py。 - 首次运行会自动下载模型权重(约 350 MB),需保持网络连接。
验证方法与判定标准
- 结构验证:
onnx.checker.check_model通过且无异常抛出,说明 ONNX 文件结构合法。 - 数值一致性:比较 PyTorch 与 ONNX Runtime 对同一随机输入的两个输出张量
last_hidden_state和extract_features的最大误差。 - 通过条件:两组输出的最大误差均小于
1e-4,即认为转换后模型输出一致。
预期输出示例
ONNX 模型结构验证通过,节点数: 284
last_hidden_state 最大误差: 2.384186e-06
extract_features 最大误差: 1.907349e-06
✅ 转换验证通过:PyTorch 与 ONNX 输出一致
注:以上数值为基于代码逻辑的确定性预期示例,实际误差可能因随机输入不同而略有浮动,但应保持在 1e-5 量级以内。
常见问题
- 导出时提示不支持算子:尝试将
opset_version提升至 15 或 16,或升级transformers到最新版本。 - 动态序列长度导致推理失败:本案例已配置
dynamic_axes,ONNX Runtime 支持变长输入;若遇问题,可固定输入长度(去掉dynamic_axes)重新导出。 - 内存不足:将
sample_rate从 16000 减小至 8000(0.5 秒音频),或使用facebook/wav2vec2-tiny-random等更小模型测试流程。