GFPGANv1.3的.pth转ONNX遇类型错误,求解决方法及流程讲解
运行环境
- Windows 10
- Python 3.10.0
- torch 2.1.2
- gfpgan 1.3.8
- onnx 1.14.0
- onnxruntime 1.15.0
转换代码
import torch import torch.onnx import onnx import onnxruntime from gfpgan.archs.gfpganv1_clean_arch import GFPGANv1Clean device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') onnx_path = "models/GFPGANv1.3.onnx" gfpgan_path = "models/GFPGANv1.3.pth" torch_model = GFPGANv1Clean( out_size=512, num_style_feat=512, channel_multiplier=2, decoder_load_path=None, fix_decoder=False, num_mlp=8, input_is_latent=True, different_w=True, narrow=1, sft_half=True) # 加载预训练模型权重 loadnet = torch.load(gfpgan_path) # 用预训练权重初始化模型 torch_model.load_state_dict(loadnet, strict=False) torch_model.to(device) # 设置模型为评估模式 torch_model.eval() # 模型输入 inputs = torch.ones((1, 3, 512, 512)).to(device) # 导出模型为ONNX格式 torch.onnx.export(torch_model, # 要导出的模型 inputs, # 模型输入(多输入用元组) onnx_path, # 模型保存路径 export_params=True, # 将训练好的参数权重存入模型文件 verbose=False, do_constant_folding=True, # 是否执行常量折叠优化 input_names=['input'], # 模型输入名称 output_names=['output'], # 模型输出名称 opset_version=12 # 导出使用的ONNX版本 ) # 验证ONNX模型 onnx_model = onnx.load("models/GFPGANv1.3.onnx") onnx.checker.check_model(onnx_model)
导出阶段错误
D:\roop\.venv\lib\site-packages\torchvision\transforms\functional_tensor.py:5: UserWarning: The torchvision.transforms.functional_tensor module is deprecated in 0.15 and will be **removed in 0.17**. Please don't rely on it. You probably just need to use APIs in torchvision.transforms.functional or in torchvision.transforms.v2.functional. warnings.warn( D:\roop\.venv\lib\site-packages\gfpgan\archs\gfpganv1_clean_arch.py:314: TracerWarning: 将张量转换为Python布尔值可能会导致追踪结果不正确。我们无法记录Python值的数据流,因此该值未来会被视为常量。这意味着追踪结果可能无法推广到其他输入! if return_rgb: D:\roop\.venv\lib\site-packages\gfpgan\archs\gfpganv1_clean_arch.py:62: TracerWarning: 将张量转换为Python布尔值可能会导致追踪结果不正确。我们无法记录Python值的数据流,因此该值未来会被视为常量。这意味着追踪结果可能无法推广到其他输入! if randomize_noise: D:\roop\.venv\lib\site-packages\gfpgan\archs\gfpganv1_clean_arch.py:102: TracerWarning: 将张量转换为Python整数可能会导致追踪结果不正确。我们无法记录Python值的数据流,因此该值未来会被视为常量。这意味着追踪结果可能无法推广到其他输入! out_same, out_sft = torch.split(out, int (out.size(1) // 2), dim=1) D:\roop\.venv\lib\site-packages\gfpgan\archs\gfpganv1_clean_arch.py:114: TracerWarning: 将张量转换为Python布尔值可能会导致追踪结果不正确。我们无法记录Python值的数据流,因此该值未来会被视为常量。这意味着追踪结果可能无法推广到其他输入! if return_latents: D:\roop\.venv\lib\site-packages\torch\onnx\utils.py:1686: UserWarning: 导出的ONNX模型未通过ONNX形状推理。该模型无法被ONNX Runtime执行。如果这并非预期且您认为存在bug,请在https://github.com/pytorch/pytorch/issues提交问题。 严格ONNX形状推理报告的错误:[ShapeInferenceError] (op_type:Conv, node name: /stylegan_decoder/to_rgb1/modulated_conv/Conv): W has inconsistent type tensor(float) (Triggered internally at ..\torch\csrc\jit\serialization\export.cpp:1421.) _C._check_onnx_proto(proto)
问题描述
我成功生成了GFPGANv1.3.onnx模型,但不确定这些错误的影响。刚接触模型开发与训练,推测最初的数据类型警告是由于gfpgan 1.3.8(最后更新于2022年9月16日)与torch 2.1.2(2023年12月15日)之间存在版本不兼容问题。
当我尝试用以下代码创建ONNX Runtime会话时:
# 使用ONNX Runtime的Python API计算输出 ort_session = onnxruntime.InferenceSession("models/GFPGANv1.3.onnx", providers=["CPUExecutionProvider"])
再次遇到了导出阶段提示的错误:
Traceback (most recent call last): File "D:\roop\convert.py", line 56, in <module> ort_session = onnxruntime.InferenceSession("models/GFPGANv1.3.onnx", providers=["CPUExecutionProvider"]) File "D:\roop\.venv\lib\site-packages\onnxruntime\capi\onnxruntime_inference_collection.py", line 383, in __init__ self._create_inference_session(providers, provider_options, disabled_optimizers) File "D:\roop\.venv\lib\site-packages\onnxruntime\capi\onnxruntime_inference_collection.py", line 424, in _create_inference_session sess = C.InferenceSession(session_options, self._model_path, True, self._read_config_from_model) onnxruntime.capi.onnxruntime_pybind11_state.Fail: [ONNXRuntimeError] : 1 : FAIL : Load model from models/GFPGANv1.3.onnx failed:Type Error: Type parameter (T) of Optype (Conv) bound to different types (tensor(double) and tensor(float) in node (/stylegan_decoder/to_rgb1/modulated_conv/Conv).
我希望有人能指出这些错误的解决方案,更重要的是讲解整个模型转换流程。之前我以为转换过程很简单,用外部脚本就能完成,但现在发现并非如此。
解决方案与流程讲解
错误原因分析
- 版本不兼容:GFPGAN 1.3.8是2022年的版本,而PyTorch 2.1.2是2023年底的版本,两者的API和追踪逻辑存在差异,导致导出时出现类型不匹配问题。
- 张量类型不统一:导出的ONNX模型中,Conv节点的权重(W)是float类型,但输入可能被解析为double类型,导致ONNX Runtime加载失败。
- TorchScript追踪警告:代码中存在将张量转为Python布尔/整数的操作,破坏了TorchScript的追踪流程,导致导出的模型无法适配动态输入。
具体解决方案
1. 统一数据类型
在导出模型前,确保模型和输入都使用float32类型,避免混合double和float:
# 修改输入张量的类型 inputs = torch.ones((1, 3, 512, 512)).to(device).float() # 强制模型参数转为float32 torch_model = torch_model.float()
2. 调整PyTorch版本
降级PyTorch到与GFPGAN 1.3.8兼容的版本,比如PyTorch 1.12.x或1.13.x,这能减少版本差异带来的API不兼容问题。
3. 修复GFPGAN代码中的追踪问题
修改gfpganv1_clean_arch.py中的相关代码,避免将张量转为Python原生类型:
- 对于
if return_rgb:这类判断,确保return_rgb是模型初始化时的固定参数(而非张量),或者使用torch.where替代Python条件判断。 - 对于
int(out.size(1) // 2),改为使用张量操作:
split_size = out.size(1) // 2 out_same, out_sft = torch.split(out, split_size, dim=1)
(去掉int转换,让TorchScript能追踪到这个值的数据流)
4. 调整ONNX导出参数
导出时指定do_constant_folding=False,避免常量折叠导致的类型错误;同时提升opset版本到14或更高,更好地兼容新版PyTorch的算子:
torch.onnx.export(torch_model, inputs, onnx_path, export_params=True, verbose=False, do_constant_folding=False, input_names=['input'], output_names=['output'], opset_version=14, dynamic_axes={'input': {0: 'batch_size'}, 'output': {0: 'batch_size'}}) # 如果需要动态批量
模型转换完整流程
1. 环境准备
- 确认模型依赖的框架版本兼容性,优先选择官方推荐的版本组合(比如GFPGAN 1.3.8推荐PyTorch 1.10+)。
- 安装必要库:
torch、onnx、onnxruntime、gfpgan。
2. 模型加载与初始化
- 从官方渠道下载预训练权重(.pth文件)。
- 导入模型结构类,初始化模型并加载权重,设置为
eval()模式(关闭dropout、batchnorm的训练行为)。
3. 输入准备
- 创建与模型输入尺寸、类型匹配的张量,确保设备(CPU/GPU)与模型一致。
- 如果需要动态输入,提前规划好动态维度(比如batch_size)。
4. ONNX导出
- 使用
torch.onnx.export()导出模型,指定输入输出名称、opset版本、是否保存参数等。 - 导出后用
onnx.checker.check_model()验证模型结构合法性。
5. 模型验证
- 用ONNX Runtime加载模型,对比PyTorch模型和ONNX模型的输出结果,确保误差在可接受范围内。
- 如果加载失败,检查错误日志中的类型、形状不匹配问题,针对性调整导出参数或模型代码。
内容的提问来源于stack exchange,提问作者Prashant
相关产品推荐
相关产品推荐

