未验证 提交 4a3eb2c5 编写于 作者: J Junxian Ye 提交者: GitHub

add support to fuse hardswish into 1 operation for ONNX (#1276)

* fix upsample support error

* add support for float type constant data loading

* support opset 11 version of clip op convertion

* support conv+clip fusion in graph_opt

* add asymmetric transformation mode support for resize op

* add hardswish fusion function support

* add hardswish support
Co-authored-by: Nyejunxian <yejunxian@dm-ai.com>
Co-authored-by: Nyejunxian <yejunxian@dmai.com>
上级 0d9b45e8
...@@ -2132,7 +2132,9 @@ static int load_resize(ir_graph_t* graph, ir_node_t* node, const onnx::NodeProto ...@@ -2132,7 +2132,9 @@ static int load_resize(ir_graph_t* graph, ir_node_t* node, const onnx::NodeProto
interp_param->width_scale = 0; interp_param->width_scale = 0;
std::string coordinate_transformation_mode = GetAttributeOrDefault<std::string>(onnx_node, "coordinate_transformation_mode", "half_pixel"); std::string coordinate_transformation_mode = GetAttributeOrDefault<std::string>(onnx_node, "coordinate_transformation_mode", "half_pixel");
TASSERT(coordinate_transformation_mode == "half_pixel" || coordinate_transformation_mode == "align_corners"); TASSERT(coordinate_transformation_mode == "half_pixel" ||
coordinate_transformation_mode == "align_corners" ||
coordinate_transformation_mode == "asymmetric");
int align_corner = (coordinate_transformation_mode == "align_corners"); int align_corner = (coordinate_transformation_mode == "align_corners");
if (onnx_node.input_size() == 1) if (onnx_node.input_size() == 1)
......
...@@ -22,7 +22,8 @@ https://github.com/ultralytics/yolov5 ...@@ -22,7 +22,8 @@ https://github.com/ultralytics/yolov5
1. Remove the focus nodes of prepare process; 1. Remove the focus nodes of prepare process;
2. Remove the YOLO detection nodes of postprocess; 2. Remove the YOLO detection nodes of postprocess;
3. Fusion the activation HardSwish node replace the Sigmoid and Mul; 3. Fusion the activation HardSwish node replace the Sigmoid and Mul;
4. Update input/output tensor. 4. Fusion add+clip+div+mul ops into one HardSwish op;
5. Update input/output tensor.
This tool is based on ONNX Framework. This tool is based on ONNX Framework.
Usage: Usage:
...@@ -34,6 +35,7 @@ Author: ...@@ -34,6 +35,7 @@ Author:
xwwang@openailab.com, initial xwwang@openailab.com, initial
hhchen@openailab.com, update hhchen@openailab.com, update
qinhj@lsec.cc.ac.cn, update qinhj@lsec.cc.ac.cn, update
yejunxian@dm-ai.com, update
""" """
import numpy as np import numpy as np
...@@ -45,14 +47,14 @@ from onnxsim import simplify ...@@ -45,14 +47,14 @@ from onnxsim import simplify
def parse_args(): def parse_args():
parser = argparse.ArgumentParser(description='YOLOv5 Optimize Tool Parameters') parser = argparse.ArgumentParser(description='YOLOv5 Optimize Tool Parameters')
parser.add_argument('--input', help='input model path', default='./yolov5s.onnx', type=str) parser.add_argument('--input', help='input model path', default='./yolov5s.onnx', type=str)
parser.add_argument('--output', help='output model path', default='./yolov5s-opt.onnx', type=str) parser.add_argument('--output', help='output model path', default='./yolov5s-opt.onnx', type=str)
parser.add_argument('--in_tensor', help='input tensor name', default='167', type=str) parser.add_argument('--in_tensor', help='input tensor name', default='167', type=str)
parser.add_argument('--out_tensor', help='output tensor names', default='381,420,459', type=str) parser.add_argument('--out_tensor', help='output tensor names', default='381,420,459', type=str)
parser.add_argument('--cut_focus', action='store_false', help='cut focus from model if true') parser.add_argument('--cut_focus', action='store_false', help='cut focus from model if true')
parser.add_argument('--verbose', action='store_true', help='show verbose info') parser.add_argument('--verbose', action='store_true', help='show verbose info')
args = parser.parse_args() args = parser.parse_args()
return args return args
...@@ -69,14 +71,14 @@ def cut_focus_output(input_node, in_name, out_name, cut_focus): ...@@ -69,14 +71,14 @@ def cut_focus_output(input_node, in_name, out_name, cut_focus):
out_name: output cut tensor value names out_name: output cut tensor value names
Returns: Returns:
new_nodes: the new node new_nodes: the new node
""" """
node_dict = {} # output node name node_dict = {} # output node name
for i in range(len(input_node)): for i in range(len(input_node)):
node_dict[input_node[i].output[0]] = i node_dict[input_node[i].output[0]] = i
if args.verbose: if args.verbose:
# (key, value): (output node[0] name, index) # (key, value): (output node[0] name, index)
print("[Verbose] node_dict:", node_dict) print("[Verbose] node_dict:", node_dict)
# cut output nodes # cut output nodes
output_pass = np.zeros((len(input_node)), dtype=np.int) output_pass = np.zeros((len(input_node)), dtype=np.int)
for i in range(len(out_name)): for i in range(len(out_name)):
...@@ -114,7 +116,7 @@ def fusion_hardswish(input_node): ...@@ -114,7 +116,7 @@ def fusion_hardswish(input_node):
input_node: the nodes of ONNX model input_node: the nodes of ONNX model
Returns: Returns:
the new node the new node
""" """
del_list = [] del_list = []
for i in range(len(input_node) - 1): for i in range(len(input_node) - 1):
if (input_node[i].op_type == 'Sigmoid' and input_node[i+1].op_type == 'Mul'): if (input_node[i].op_type == 'Sigmoid' and input_node[i+1].op_type == 'Mul'):
...@@ -127,6 +129,47 @@ def fusion_hardswish(input_node): ...@@ -127,6 +129,47 @@ def fusion_hardswish(input_node):
return input_node return input_node
def fusion_hardswish_into_1op(input_node):
"""
using hardswish replace the add+clip+div+mul
Args:
input_node: the nodes of ONNX model
Returns:
the new node
"""
new_nodes = []
new_list = []
tmp_list = []
for i in range(len(input_node)):
if input_node[i].op_type == "Add" and \
input_node[i+1].op_type == "Clip" and \
input_node[i+2].op_type == "Div" and \
input_node[i+3].op_type == "Mul":
suffix = input_node[i+3].name.split("_")[-1]
new_node = onnx.helper.make_node(
name=f"hardswish_{suffix}",
inputs=input_node[i].input[:1],
outputs=input_node[i+3].output,
op_type="Sigmoid"
)
new_node.op_type = "HardSwish"
new_nodes.append(new_node)
tmp_list.append(None)
tmp_list.append(input_node[i])
# in order to keep tapology sort order
i = 0
while i < len(tmp_list):
if tmp_list[i] == None:
new_list.append(new_nodes.pop(0))
i += 5 # skip add+clip+div+mul
else:
new_list.append(tmp_list[i])
i += 1
return new_list
def keep_or_del_elem(obj, elem_name_list, keep=False): def keep_or_del_elem(obj, elem_name_list, keep=False):
""" """
...@@ -190,6 +233,7 @@ def main(): ...@@ -190,6 +233,7 @@ def main():
# op fusion, using HardSwish replace the Sigmoid and Mul # op fusion, using HardSwish replace the Sigmoid and Mul
print("[Quant Tools Info]: Step 2, Using hardswish replace the sigmoid and mul.") print("[Quant Tools Info]: Step 2, Using hardswish replace the sigmoid and mul.")
new_nodes = fusion_hardswish(new_nodes) new_nodes = fusion_hardswish(new_nodes)
new_nodes = fusion_hardswish_into_1op(new_nodes)
# rebuild new model, set the input and outputs nodes # rebuild new model, set the input and outputs nodes
print("[Quant Tools Info]: Step 3, Rebuild onnx graph nodes.") print("[Quant Tools Info]: Step 3, Rebuild onnx graph nodes.")
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册