首页 > 其他分享 >Retinaface ONNX 如何正确导出

Retinaface ONNX 如何正确导出

时间:2022-09-05 16:45:38浏览次数:107  
标签:Retinaface return int ONNX size 导出 shape out view

Retinaface 是一个人脸检测器,人脸检测天生存在强先验知识,比如近场人脸识别,人脸较大,监控视角下人脸识别通常人脸较小,两者天生对输入的分辨率有个假设,如果人脸很大,不需要大的分辨率,提升速度。人脸小,希望提高 Recall 那么需要大的分辨率。Retinaface 在不同分辨率下怎么做这件事情。怎么通过 这个仓库的方案解决该问题。

https://github.com/biubug6/Pytorch_Retinaface

直接执行 convert_to_onnx.py

python  convert_to_onnx.py

报错:找不到 './weights/mobilenetV1X0.25_pretrain.tar'

该权重是在 ImageNet 下预训练的模型,ImageNet 的预训练模型喜欢 tar 结尾。

解决:打开 data/config.py

# 修改为 False
'pretrain': False,

然后执行:

python  convert_to_onnx.py

又报错:找不到 './weights/mobilenet0.25_Final.pth'

解决:去github 仓库下载该模型,建个weights 文件夹,放到里面。

然后执行:

python  convert_to_onnx.py

成功!

使用 Netron 观察 onnx 模型,

老版本与老版本区别:

1. 使用的上采样为 upsample, 并且又警告提示

2. 有很多的 shape 引用(主要是输出头那里),产生了 gather 等节点

3. 输出有三个,借鉴 yolov5 做法,三个拼接为一个,后处理代码会简化。

问题1解决方案:

drawing

观察到: 点击输出节点 output0 : opset =9(我的是 opset = 13)。opset=13会输出多个如下警告(opset_version = 11 可以解决该问题):

WARNING: The shape inference of prim::Constant type is missing, so it may result in wrong shape inference for the exported graph. Please consider adding it in symbolic function.

原则1:

使用 opset_version = 11 ,不要低于 11

问题1解决:一般我们需要 opset=11 或者更高版本。convert_to_onnx.py:

torch_out = torch.onnx._export(net, inputs, output_onnx, export_params=True, verbose=False,
                               input_names=input_names, output_names=output_names,
                               opset_version = 11 )

opset=11或更高 影响 upsample,会将其变为 resize。opset_version = 11解决了上面的警告。

但是还是有 shape 引用。点击 resize 节点:

drawing

观察到 scales 是空的,使用的是 sizes。引用了上面 sizes 的大小,所以引用sizes 就需要引用上一级的 shape 来计算 sizes 得到结果。

原则2:

对于 nn.upsample 或 nn.functional.interpolate 函数,使用 scale_factor 指定倍率,而不是使用 size 参数指定大小。

解决:models/net.py:

# up3 = F.interpolate(output3, size=[output2.size(2), output2.size(3)], mode="nearest")
up3 = F.interpolate(output3, scale_factor=2, mode="nearest")

# up2 = F.interpolate(output2, size=[output1.size(2), output1.size(3)], mode="nearest")
up2 = F.interpolate(output2, scale_factor=2, mode="nearest")

再次导出。

然后观察到,与 yolov5 一样,使用 scales :1,1,2,2。shape 引用也被干掉。

drawing

节点如下:

drawing

问题2 解决方案

观察到:

drawing

原则3:

对于任何用到 shape、size返回值的参数时,例如: tensor.view(tensor.size(0), -1) 这类操作,避免直接使用 tensor.size 的返回值,而是加上 int 转换,tensor.view(int(tensor.size(0)), -1)

修改代码: models/retinaface.py 主要是修改三个 head, 如下:

	# return out.view(out.shape[0], -1, 2)
	return out.view(int(out.shape[0]), -1, 2)
	
	# return out.view(out.shape[0], -1, 4)
    return out.view(int(out.shape[0]), -1, 4)
	
	# return out.view(out.shape[0], -1, 10)
	return out.view(int(out.shape[0]), -1, 10)

结果:

drawing

点击 reshape 节点,发现:

drawing

原则4:

对于 reshape、view 操作时, -1 放到 batch 维度。其他维度可以计算得到。batch 维度禁止指定大于 -1 的明确数字。

	# [1, 40, 40, 4] -> [-1, ?, 2]
	# ? = 40 * 40 * 2 与 与 yolov5 中 3 * 80 * 80 是一样的,2 这里指的是 anchor 的数量为2。
	# print(f"**************{out.shape}")
	# return out.view(out.shape[0], -1, 2)
	# return out.view(int(out.shape[0]), -1, 2)
	return out.view(-1,  int(out.shape[1] * out.shape[2] * 2), 2)
	
	# return out.view(int(out.shape[0]), -1, 4)
	return out.view(-1,  int(out.shape[1] * out.shape[2] * 2), 4)
	
	# return out.view(int(out.shape[0]), -1, 10)
	return out.view(-1,  int(out.shape[1] * out.shape[2] * 2), 10)

点击 reshape,看到:

drawing

问题3 解决方案

定义顺序:xywh,negative, positive, landmark(10)

	if self.phase == 'train':
		output = (bbox_regressions, classifications, ldm_regressions)
	else:
		output = (bbox_regressions, F.softmax(classifications, dim=-1), ldm_regressions)
	return output

推理时候多加一个 F.softmax(classifications, dim=-1), 因为训练时候使用的是 layers/modules/multibox_loss.py:

loss_c = F.cross_entropy(conf_p, targets_weighted, reduction='sum') # F.Cross_entropy(input, target)函数中包含了softmax 和 log 的操作,即网络计算送入的input参数不需要进行这两个操作。

因此推理时候,需要额外加 F.softmax。一般我们原则是尽量把操作放到onnx 中,让onnx 来优化运算。但是,softmax 可以被优化,减少计算量,参考:https://blog.csdn.net/hymn1993/article/details/124093421

所以,我们去掉 softmax,选择在 C++ 代码中进行优化加快推理速度。

models/retinaface.py:

	return torch.cat((bbox_regressions, classifications, ldm_regressions), dim = -1)
	# if self.phase == 'train':
	#     output = (bbox_regressions, classifications, ldm_regressions)
	# else:
	#     output = (bbox_regressions, F.softmax(classifications, dim=-1), ldm_regressions)
	# return output
drawing

自此, Retinaface 的模型导出就全部完成了。至于 C++ 推理部分和如何设置动态宽高推理,有时间我会更新。

标签:Retinaface,return,int,ONNX,size,导出,shape,out,view
From: https://www.cnblogs.com/odesey/p/16657935.html

相关文章

  • 文件导出ZIP压缩
    文件导出ZIP压缩 @OverridepublicStringdownloadallfiles(HttpServletRequestrequest,StringlsbpId,StringbsTitle){ JwtUserObjectjwtUserObject=JwtUtil.g......
  • 导出模板设置其中某一列下拉选
    导出模板设置其中某一列下拉选 *设置下拉选 */ for(inti=0;i<headers.length;i++){ Stringheader=headers[i]; if(header.equals("电站简称")){ Str......
  • vue纯前端导入导出excel
    vue纯前端导入导出excel我们有时会遇到在前端实现导入/导出excel的需求这里直接推荐两个现成的vue导入导出excel的库,他们是基于xlsx封装的https://www.npmjs.com/packa......
  • Oracle数据库导入、导出dmp文件
    1、数据库导出dmp文件exphdrg/[email protected]:1521/orclfile=D:\hdrg.dmp说明:exp用户名/密码@数据库名file=E:\file.dmptables=(要导出的表名称,以逗号隔开)2、o......
  • navicat连接远程数据库,mysql workbench导出数据表
    navicat连接远程数据库: mysqlworkbench导出数据表: ......
  • Java实现Excel导入导出操作详解
    前言本次封装是基于POI的二次开发,最终使用只需要调用一个工具类中的方法,就能满足业务中绝大部门的导入和导出需求。1.功能测试1.1测试准备在做测试前,我们需要將【2......
  • markdown preview enhanced插件导出为.html文件
      不知不觉,vscode和Markdown文档的配合使用已经用了很久了,但对于没有使用过Markdown的小伙伴,想要给他快速的分享你的Markdown笔记,却是一个问题。解决方案  使用vscod......
  • 【Word】如何批量导出ppt中的备注
    【Word】如何批量导出ppt中的备注文件|导出|创建讲义|备注在幻灯片旁在word中删除左边两列,复制剩下的表格|粘贴-只保留文本......
  • Python导出微信公众号所有文章
    前言公司周年庆,行政的同事想让我帮个忙,把微信公众号的文章都导在一个文档里面,方便统计和检索。在网上找了一圈,大部分工具处于不可用状态,或者需要收费,于是花了一个多小时......
  • 如何以 Arduino 可播放格式导出黑白 Open Frameworks 动画
    如何以Arduino可播放格式导出黑白OpenFrameworks动画如何将使用OpenFrameworks创建的动画导出为可在运行Arduino的微控制器上存储和播放的格式OpenFrameworks......