Open xiaoyewww opened 3 weeks ago
@Zheng-Bicheng 大佬,具体做的时候有以下几个问题:
@xiaoyewww
添加对半精度 Paddle 模型的支持,这个具体行为是指将paddle fp16模型转化成onnx fp16的模型吗?还是将paddle fp32模型转化成onnx fp16模型就好,我看这个原生是支持的,只是过程中会将数值截断成fp16,是具体对这个地方修改吗?
Paddle2ONNX 目前支持 FP16 模型的方式类似把 FP32 格式的 Paddle 模型转换为 FP32 的ONNX模型,然后再把 FP32 的 ONNX 转为 FP16 的 ONNX 模型。这次的任务是直接转换 FP16 格式的 Paddle 模型。
对算子的FP16支持具体是怎么做呢?在每个op里面做一下数值的fp32到fp16的转换?
基本上可以按照以下步骤进行:
FP16的Resnet模型可以通过类似以下方式来实现
import paddle
from paddlenlp.transformers import UIEX # 从模型代码中导入模型
model = UIEX.from_pretrained("uie-x-base") # 实例化模型
model.to(dtype="float16") # 加载预训练模型参数
model.eval() # 将模型设置为评估状态
input_spec = [
paddle.static.InputSpec(shape=[None, None], dtype="int64", name="input_ids"),
paddle.static.InputSpec(shape=[None, None], dtype="int64", name="token_type_ids"),
paddle.static.InputSpec(shape=[None, None], dtype="int64", name="position_ids"),
paddle.static.InputSpec(shape=[None, None], dtype="int64", name="attention_mask"),
paddle.static.InputSpec(shape=[None, None, 4], dtype="int64", name="bbox"),
paddle.static.InputSpec(shape=[None, 3, 224, 224], dtype="float16", name="image"),
] # # 定义输入数据
print("Exporting ONNX model to %s" % "./uiex_fp16.onnx")
paddle.onnx.export(model, "./uiex_fp16", input_spec=input_spec) # ONNX模型导出
print("ONNX model exported.")
FP16的Resnet模型可以通过类似以下方式来实现
import paddle from paddlenlp.transformers import UIEX # 从模型代码中导入模型 model = UIEX.from_pretrained("uie-x-base") # 实例化模型 model.to(dtype="float16") # 加载预训练模型参数 model.eval() # 将模型设置为评估状态 input_spec = [ paddle.static.InputSpec(shape=[None, None], dtype="int64", name="input_ids"), paddle.static.InputSpec(shape=[None, None], dtype="int64", name="token_type_ids"), paddle.static.InputSpec(shape=[None, None], dtype="int64", name="position_ids"), paddle.static.InputSpec(shape=[None, None], dtype="int64", name="attention_mask"), paddle.static.InputSpec(shape=[None, None, 4], dtype="int64", name="bbox"), paddle.static.InputSpec(shape=[None, 3, 224, 224], dtype="float16", name="image"), ] # # 定义输入数据 print("Exporting ONNX model to %s" % "./uiex_fp16.onnx") paddle.onnx.export(model, "./uiex_fp16", input_spec=input_spec) # ONNX模型导出 print("ONNX model exported.")
这里我看了一下PaddleClas相关的代码,Resnet看上去好像没有from_pretrained这种调用方式,所以我直接通过下载模型及其权重来转换了。
@xiaoyewww
添加对半精度 Paddle 模型的支持,这个具体行为是指将paddle fp16模型转化成onnx fp16的模型吗?还是将paddle fp32模型转化成onnx fp16模型就好,我看这个原生是支持的,只是过程中会将数值截断成fp16,是具体对这个地方修改吗?
Paddle2ONNX 目前支持 FP16 模型的方式类似把 FP32 格式的 Paddle 模型转换为 FP32 的ONNX模型,然后再把 FP32 的 ONNX 转为 FP16 的 ONNX 模型。这次的任务是直接转换 FP16 格式的 Paddle 模型。
对算子的FP16支持具体是怎么做呢?在每个op里面做一下数值的fp32到fp16的转换?
基本上可以按照以下步骤进行:
- 1 升级基本转换机制:paddle2onnx/parser/parser.cc 需要对 FP16 格式的 Paddle 模型做适配,否则会直接报错退出
- 2 升级算子:paddle2onnx/mapper/nn/batch_norm.cc 中的算子,需要新增 GetMinOpset 函数,在函数中需要判断当前是否是FP16算子,是的话需要升级 opset,并添加针对性的实现
针对第二点,请问一下具体是什么呢?比如batch_norm算子是对相关float的参数做处理?
另外用paddle原生直接对resnet的模型做半精度推理,是不支持的吗,报了下面的错:
Traceback (most recent call last):
File "/wuzp/Paddle2ONNX/tests/test_resnet_fp16.py", line 57, in <module>
paddle_output = model(paddle_input)
File "/root/miniconda3/envs/paddle_onnx/lib/python3.9/site-packages/paddle/nn/layer/layers.py", line 1429, in __call__
return self.forward(*inputs, **kwargs)
File "/root/miniconda3/envs/paddle_onnx/lib/python3.9/site-packages/paddle/jit/translated_layer.py", line 1477, in __i_m_p_l__
return _run_dygraph(self, input, program_holder)
File "/root/miniconda3/envs/paddle_onnx/lib/python3.9/site-packages/paddle/jit/translated_layer.py", line 1004, in _run_dygraph
_legacy_C_ops.run_program(
ValueError: (InvalidArgument) Scale input should be of float type
[Hint: Expected bn_param_type == framework::TransToProtoVarType( ctx.Input<phi::DenseTensor>("Scale")->dtype()), but received bn_param_type:5 != framework::TransToProtoVarType( ctx.Input<phi::DenseTensor>("Scale")->dtype()):4.] (at ../paddle/fluid/operators/batch_norm_op.cc:198)
[operator < batch_norm > error] [operator < run_program > error]
这里我看了一下PaddleClas相关的代码,Resnet看上去好像没有from_pretrained这种调用方式,所以我直接通过下载模型及其权重来转换了。
没问题的
另外用paddle原生直接对resnet的模型做半精度推理,是不支持的吗
要用GPU推理我记得,这个最好是去Paddle的Issues提一下
另外用paddle原生直接对resnet的模型做半精度推理,是不支持的吗
要用GPU推理我记得,这个最好是去Paddle的Issues提一下
我这里已经用的是gpu进行推理,我去issue上问一下
比如batch_norm算子是对相关float的参数做处理?
比如 layer_norm.cc#L35 这里会强转FP16为FP32,需要针对性添加支持
比如batch_norm算子是对相关float的参数做处理?
比如 layer_norm.cc#L35 这里会强转FP16为FP32,需要针对性添加支持
resnet中没有layernorm,所以我对matmul修改了一下,麻烦看一下这样修改是否正确,没问题的话我剩下相关的layer都这样处理。
另外像batchnorm这些层该怎么升级op处理呢?这里说实话有点看不懂,这里有相关的dtype constraints,第一行看上去float,float16这些都支持,后面又说限制float,这里具体怎么处理呢?
比如batch_norm算子是对相关float的参数做处理?
比如 layer_norm.cc#L35 这里会强转FP16为FP32,需要针对性添加支持
resnet中没有layernorm,所以我对matmul修改了一下,麻烦看一下这样修改是否正确,没问题的话我剩下相关的layer都这样处理。
另外像batchnorm这些层该怎么升级op处理呢?这里说实话有点看不懂,这里有相关的dtype constraints,第一行看上去float,float16这些都支持,后面又说限制float,这里具体怎么处理呢?
我只是举了个例子,可以按实际情况来处理,例如如果实际没有这个算子就不需要升级
@xiaoyewww 这个有些问题,以你这里适配的matmul为例子:
@Zheng-Bicheng 大佬,我修改layer_norm这个算子的时候遇到点问题,onnx上不是最低只支持opset17吗,怎么p2o上有opset7的支持呢? https://onnx.ai/onnx/operators/onnx__LayerNormalization.html#layernormalization-17
另外,这个误差范围多少合适呢,我目前比较的是fp32下的推理结果:
Mismatched elements: 35 / 1000 (3.5%)
Max absolute difference: 0.00010923
Max relative difference: 0.01125892
x: array([[3.214033e-05, 2.723171e-04, 3.689834e-04, 3.431249e-04,
5.028006e-04, 3.669124e-04, 9.550410e-04, 1.896740e-04,
8.601158e-05, 1.495139e-04, 5.724585e-04, 1.789319e-03,...
y: array([[3.2008e-05, 2.7180e-04, 3.6883e-04, 3.4189e-04, 5.0068e-04,
3.6669e-04, 9.5177e-04, 1.8966e-04, 8.5950e-05, 1.4973e-04,
5.7554e-04, 1.8015e-03, 7.2336e-04, 1.2159e-03, 5.3692e-04,...
@xiaoyewww 这个有些问题,以你这里适配的matmul为例子:
- 1 先打开 ONNX Matmul OP 查看一下算子的相关信息
- 2 可以看到Mutmul在 opset为9的情况下是不支持fp16的,因此需要添加matmul对opset13的支持
抱歉才看到,这里我看不是支持的吗,opset13支持的是BF16?
@xiaoyewww 这个有些问题,以你这里适配的matmul为例子:
- 1 先打开 ONNX Matmul OP 查看一下算子的相关信息
- 2 可以看到Mutmul在 opset为9的情况下是不支持fp16的,因此需要添加matmul对opset13的支持
抱歉才看到,这里我看不是支持的吗,opset13支持的是BF16?
这里看错了,确实是支持FP16的,没有问题
@Zheng-Bicheng 大佬,我修改layer_norm这个算子的时候遇到点问题,onnx上不是最低只支持opset17吗,怎么p2o上有opset7的支持呢? https://onnx.ai/onnx/operators/onnx__LayerNormalization.html#layernormalization-17
Opset7的支持是把这个算子拆分成很多个其他算子来做的
@Zheng-Bicheng 修改好了,麻烦再review一下,目前有这么几个问题麻烦确认一下:
numpy 这两天更新到了2.0.0,我这边目前onnxruntime==1.18.0不支持2.0.0,所以这里做了一下限制 numpy <= 2.0.0,麻烦看一下有没有必要
关于onnx的问题,您能帮忙在 README 中也做对应的修改吗?
numpy 这两天更新到了2.0.0,我这边目前onnxruntime==1.18.0不支持2.0.0,所以这里做了一下限制 numpy <= 2.0.0,麻烦看一下有没有必要
关于onnx的问题,您能帮忙在 README 中也做对应的修改吗?
已修改
大佬,数据类型列表这块是不是改成储存支持的数据类型好一点?我看你这漏了不少数据类型啊。
郑师傅,我这里这样理解的:
比如对pool这个算子,因为没有int8的测例,但又因为这是onnx支持的,所以我第一反应是这个算子是不需要cast的,所以没放在列表里
@Zheng-Bicheng 已按要求修改,麻烦再review一下
Details: support model convert from fp32 to fp16