360网站收录提交入口,云南省建设测量员注册网站,如何用腾讯云建设自己网站,阿里云模板做网站流程在yolo v5训练的模型#xff0c;转onnx#xff0c;再转rknn后#xff0c;测试发现#xff1a;
rknn模型#xff0c;量化与非量化#xff0c;相较于pytorch模型#xff0c;测试精度都有降低onnx模型#xff0c;相较于pytorch模型#xff0c;测试精度也有降低#xff…在yolo v5训练的模型转onnx再转rknn后测试发现
rknn模型量化与非量化相较于pytorch模型测试精度都有降低onnx模型相较于pytorch模型测试精度也有降低且与rknn模型的精度更接近
于是根据这种测试情况rknn模型的上游就是onnx。onnx这里发现不对劲肯定是这步就出现了问题。于是就查pytorch转onnx阶段就存在转化的精度降低了。
本篇就是记录这样一个过程也请各位针对本文的问题给一些建议毕竟目前是发现了问题同时还存在一些问题在。
一、pytorch转onnxtorch.onnx.export
yolo v5 export.py: def export_onnx()中添加下面代码检查转储的onnx模型与pytorch模型的输出结果是否一致。代码如下
torch.onnx.export(model.cpu() if dynamic else model, # --dynamic only compatible with cpuim.cpu() if dynamic else im,f,verboseFalse,opset_versionopset,export_paramsTrue, # 将训练好的权重保存到模型文件中do_constant_foldingTrue, # 执行常数折叠进行优化input_names[images],output_namesoutput_names,dynamic_axes{image: {0: batch_size}, # variable length axesoutput: {0: batch_size},}
)# Checks
model_onnx onnx.load(f) # load onnx model
onnx.checker.check_model(model_onnx) # check onnx modelimport onnxruntime
import numpy as np
print(onnxruntime run start, f)
sess onnxruntime.InferenceSession(best.onnx)
print(sess run start)
output sess.run([output0], {images: im.detach().numpy()})[0]
print(pytorch model inference start)pytorch_result model(im)[0].detach().numpy()
print( allclose start)
print(output:, output)
print(pytorch_result:, pytorch_result)
assert np.allclose(output, pytorch_result), the output is different between pytorch and onnx !!!对其中的输出结果进行了打印将差异性比较明显的地方进行了标记如下所示 也可以直接使用我下面这个版本在转完onnx后进行评测转好的onnx和pt文件之间的差异性。如下
参考pytorch官方(OPTIONAL) EXPORTING A MODEL FROM PYTORCH TO ONNX AND RUNNING IT USING ONNX RUNTIME
import os
import platform
import sys
import warnings
from pathlib import Path
import torchFILE Path(__file__).resolve()
ROOT FILE.parents[0] # YOLOv5 root directory
if str(ROOT) not in sys.path:sys.path.append(str(ROOT)) # add ROOT to PATH
if platform.system() ! Windows:ROOT Path(os.path.relpath(ROOT, Path.cwd())) # relativefrom models.experimental import attempt_load
from models.yolo import ClassificationModel, Detect, DetectionModel, SegmentationModel
from utils.dataloaders import LoadImages
from utils.general import (LOGGER, Profile, check_dataset, check_img_size, check_requirements, check_version,check_yaml, colorstr, file_size, get_default_args, print_args, url2file, yaml_save)
from utils.torch_utils import select_device, smart_inference_modeimport numpy as np
def cosine_distance(arr1, arr2):# flatten the arrays to shape (16128, 7)arr1_flat arr1.reshape(-1, 7)arr2_flat arr2.reshape(-1, 7)# calculate the cosine distancecosine_distance np.dot(arr1_flat.T, arr2_flat) / (np.linalg.norm(arr1_flat) * np.linalg.norm(arr2_flat))return cosine_distance.mean()def check_onnx(model, im):import onnxruntimeimport numpy as npprint(onnxruntime run start)sess onnxruntime.InferenceSession(best.onnx)print(sess run start)output sess.run([output0], {images: im.detach().numpy()})[0]print(pytorch model inference start)with torch.no_grad():pytorch_result model(im)[0].detach().numpy()print( allclose start)print(output:, output, output.shape)print(pytorch_result:, pytorch_result, pytorch_result.shape)cosine_dis cosine_distance(output, pytorch_result)print(cosine_dis:, cosine_dis)# 判断小数点后几位4是否相等不相等就报错# np.testing.assert_almost_equal(pytorch_result, output, decimal4)# compare ONNX Runtime and PyTorch resultsnp.testing.assert_allclose(pytorch_result, output, rtol1e-03, atol1e-05)# assert np.allclose(output, pytorch_result), the output is different between pytorch and onnx !!!import cv2
from utils.augmentations import letterbox
def preprocess(img, device):img cv2.resize(img, (512, 512))img img.transpose((2, 0, 1))[::-1]img np.ascontiguousarray(img)img torch.from_numpy(img).to(device)img img.float()img / 255if len(img.shape) 3:img img[None]return img
def main(weightsROOT / weights/best.pt, # weights pathimgsz(512, 512), # image (height, width)batch_size1, # batch sizedevicecpu, # cuda device, i.e. 0 or 0,1,2,3 or cpuinplaceFalse, # set YOLOv5 Detect() inplaceTruedynamicFalse, # ONNX/TF/TensorRT: dynamic axes):# Load PyTorch modeldevice select_device(device)model attempt_load(weights, devicedevice, inplaceTrue, fuseTrue) # load FP32 model# Checksimgsz * 2 if len(imgsz) 1 else 1 # expand# Inputgs int(max(model.stride)) # grid size (max stride)imgsz [check_img_size(x, gs) for x in imgsz] # verify img_size are gs-multiplesim torch.zeros(batch_size, 3, *imgsz).to(device) # image size(1,3,320,192) BCHW iDetection# im cv2.imread(rF:\tmp\yolov5_multiDR\data\0000005_20200929_M_063Y16640.jpeg)# im preprocess(im, device)print(im.shape)# Update modelmodel.eval()for k, m in model.named_modules():if isinstance(m, Detect):m.inplace inplacem.dynamic dynamicm.export Truewarnings.filterwarnings(actionignore, categorytorch.jit.TracerWarning) # suppress TracerWarningcheck_onnx(model, im)if __name__ __main__:main()测试1图像是一个全0的数组一致性检查如下
Mismatched elements: 76 / 112896 (0.0673%)
Max absolute difference: 0.00053406
Max relative difference: 2.2101output: [[[ 3.1054 3.965 8.9553 ... 6.8545e-07 0.36458 0.53113][ 9.0205 2.5498 13.39 ... 6.2585e-07 0.18449 0.70698][ 20.786 2.2233 13.489 ... 2.3842e-06 0.033101 0.95657]...[ 419.42 493.04 106.14 ... 8.4937e-06 0.24135 0.60916][ 485.68 500.22 46.923 ... 1.1176e-05 0.33573 0.48875][ 488.37 503.87 68.881 ... 5.9605e-08 0.00030029 0.99639]]] (1, 16128, 7)
pytorch_result: [[[ 3.1054 3.965 8.9553 ... 7.0523e-07 0.36458 0.53113][ 9.0205 2.5498 13.39 ... 6.0181e-07 0.18449 0.70698][ 20.786 2.2233 13.489 ... 2.4172e-06 0.033101 0.95657]...[ 419.42 493.04 106.14 ... 8.5151e-06 0.24135 0.60916][ 485.68 500.22 46.923 ... 1.1174e-05 0.33573 0.48875][ 488.37 503.87 68.881 ... 9.3094e-08 0.0003003 0.99639]]] (1, 16128, 7)
cosine_dis: 0.04229331测试2图像是加载的本地图像一致性检查如下
Mismatched elements: 158 / 112896 (0.14%)
Max absolute difference: 0.0016251
Max relative difference: 1.2584output: [[[ 3.0569 2.4338 10.758 ... 2.0862e-07 0.16333 0.78551][ 11.028 2.0251 13.407 ... 3.5763e-07 0.090503 0.88087][ 19.447 1.8957 13.431 ... 6.8545e-07 0.047358 0.95029]...[ 418.66 487.8 80.157 ... 1.4573e-05 0.65453 0.23448][ 472.99 491.78 79.313 ... 1.3232e-05 0.79356 0.15061][ 496.41 488.49 44.447 ... 2.6256e-05 0.89966 0.08772]]] (1, 16128, 7)
pytorch_result: [[[ 3.0569 2.4338 10.758 ... 2.5371e-07 0.16333 0.78551][ 11.028 2.0251 13.407 ... 3.3069e-07 0.090503 0.88087][ 19.447 1.8957 13.431 ... 6.6051e-07 0.047358 0.95029]...[ 418.66 487.8 80.157 ... 1.4618e-05 0.65453 0.23448][ 472.99 491.78 79.313 ... 1.3215e-05 0.79356 0.15061][ 496.41 488.49 44.447 ... 2.6262e-05 0.89966 0.08772]]] (1, 16128, 7)
cosine_dis: 0.04071107发现输出结果中差异的数据点还是挺多的那么就说明在模型中有些部分的参数是有差异的这才导致相同的输入在最后的输出结果中存在差异。
但是在一定的误差内结果是一致的。比如我验证了小数点后3位都是一样的但是到第4位的时候就开始出现了差异性。
那么如何降低甚至没有这种差异该怎么办呢不知道你们有没有这方面的知识储备或经验欢迎评论区给出指导感谢。
二、新的pytorch转onnxtorch.onnx.dynamo_export
在参考pytorch官方关于torch.onnx.export的模型转换相关文档中(OPTIONAL) EXPORTING A MODEL FROM PYTORCH TO ONNX AND RUNNING IT USING ONNX RUNTIME 上述案例是pytorch官方给出评测pytorch和onnx转出模型在相同输入的情况下输出结果一致性对比的评测代码。对比这里
testing.assert_allclose(actual, desired, rtol1e-07, atol0, equal_nanTrue, err_msg, verboseTrue)其中
rtol相对tolerance容忍度公差容许偏差atol绝对tolerance要求 actual 的 desired 值的差别不超过 atol rtol * abs(desired)否则弹出错误提示
可以看出这是在误差允许的范围内进行的评测。只要满足一定的误差要求还是满足的。并且在本测试案例中也确实通过了上述设定值的误差要求。
但是峰回路转有个提示如下 于是就转到torch.onnx.dynamo_export链接点击这里直达EXPORT A PYTORCH MODEL TO ONNX
同样的流程导出模型然后进行一致性评价发现官方竟然没有采用允许误差的评测而是下面这样 输出完全一致这是一个大好消息。至此开始验证
2.1、验证结果
与此同时发现yolo v5更新到了v7.0.0的版本于是就想着把yolo 进行升级同时将pytorch版本也更新到最新的2.1.0这样就可以采用torch.onnx.dynamo_export 进行转onnx模型的操作尝试了。
当一起就绪后采用下面的代码转出onnx模型的时候却出现了错误提示。
export_output torch.onnx.dynamo_export(model.cpu() if dynamic else model,im.cpu() if dynamic else im)
export_output.save(my_image_classifier.onnx)2.2、转出失败 给出失败的的提示torch.onnx.OnnxExporterError转出onnx模型失败产生了一个SARIF的文件。然后介绍了什么是SARIF文件可以通过VS Code SARIF也可以 SARIF web查看。最后说吧这个错误报告给pytorch的GitHub的issue地方。
产生了一个名为report_dynamo_export.sarif是文件打开文件记录的信息如下
{runs:[{tool:{driver:{name:torch.onnx.dynamo_export,contents:[localizedData,nonLocalizedData],language:en-US,rules:[],version:2.1.0cu118}},language:en-US,newlineSequences:[\r\n,\n],results:[]}],version:2.1.0,schemaUri:https://docs.oasis-open.org/sarif/sarif/v2.1.0/cs01/schemas/sarif-schema-2.1.0.json
}这更像是一个运行环境收集的一个记录文件。在我对全网进行搜索时候发现了类似的报错提示但并没有解决办法。不知道是不是因为这个函数还在内测阶段并没有很好的适配。
如果你也遇到了同样的问题欢迎给评论指导问题出在了哪里如何解决这个问题。感谢
三、总结
原本想着验证最终转rknn的模型与原始pytorch模型是否一致的问题最后发现在转onnx阶段这种差异性就已经存在了。并且发现rknn的测试结果与onnx模型的测试结果更加的贴近。无论是量化后的rknn还是未量化的均存在这个问题。
同时发现量化后的rknn模型在config阶段改变量化的方式确实会提升模型的性能且几乎接近于未量化的模型版本。
原本以为采用pytorch新的转出onnx的模型函数可以解决这个问题。但是发现还是内测版本不知道问题是出在了哪里还需要大神帮助暂时未跑通。
最后如果你也遇到了同样的问题欢迎给评论指导问题出在了哪里如何解决这个问题。感谢