本文旨在介绍说明yolov5自带的分类如何导出动态的batch的onnx。其中输出两种形式:
形式(1):导出带softmax映射到概率的
形式(2):导出不带softmax的,这个也是官方默认的方式
一、动态导出
我们先看下如何得到我们想要的仅有动态batch的导出,在export.py中修改代码如下:
导出的onnx可视化如下:
注:官方直接导出,命令行使用simplify也可以得到上述结果
二、获取带softmax的onnx
原始官方导出是不带softmax概率映射的,因此想要获得带softmax的onnx,可以有两种做法:
(1)修改源码
一开始我打算从这个地方进行源码修改,发现没找到forward函数,因此很明显,这里还是继承的BaseModel类的forward。那么我就去看看BaseModel类的forward函数:
然后我们运行命令:
python export_cls.py --weights yolov5s-cls.pt --include onnx --dynamic
导出的onnx可视化如下:
(2)修改onnx文件
# 插入 Softmax 节点到模型输出之前
代码如下:
import torch
import onnx
import onnx.helper
import onnx.utils
import numpy as np
output_path = "yolov5s-cls.onnx"
# 加载 ONNX 模型
model = onnx.load(output_path)
# 获取模型输出名称
output_name = model.graph.output[0].name
# 创建 Softmax 节点
softmax_node = onnx.helper.make_node(name='Softmax',
op_type="Softmax",
inputs=[output_name],
outputs=['output_softmax'])
# 插入 Softmax 节点到模型输出之前
#model.graph.node.extend([softmax_node])
model.graph.node.append(softmax_node)
model.graph.output[0].name = 'output_softmax'
# 保存修改后的模型
onnx.checker.check_model(model)
onnx.save(model, output_path)
#注意原生的是output,现在不可以设置softmax输出为同名,否则会出错。
#要想使用output这个名称,可以先修改原生的onnx网络图的名字为其他名字,再修改设置为
原来的是:
修改后:
三、不带softmax的onnx在trt中的后处理
(1)CPU方式
std::vector<float> cls_softmax(float* prob, int n)
{
std::vector<float> res;
float sum = 0.0f;
float t;
for (int i = 0; i < n; i++) {
t = expf(prob[i]);
res.push_back(t);
sum += t;
}
for (int i = 0; i < n; i++) {
res[i] /= sum;
}
return res;
}
//做softmax概率映射
std::vector<float> softmax_res = cls_softmax(parray, output_num_cls);
(2)GPU方式