mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-29 20:14:01 +00:00
sort quantized nodes in topo logical order (#7172)
This commit is contained in:
parent
4f30341253
commit
c4ebc60870
3 changed files with 50 additions and 3 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import onnx
|
||||
import itertools
|
||||
from .quant_utils import find_by_name
|
||||
from pathlib import Path
|
||||
|
||||
|
|
@ -197,6 +198,7 @@ class ONNXModel:
|
|||
'''
|
||||
Save model to external data, which is needed for model size > 2GB
|
||||
'''
|
||||
self.topological_sort()
|
||||
if use_external_data_format:
|
||||
onnx.external_data_helper.convert_model_to_external_data(self.model,
|
||||
all_tensors_to_one_file=True,
|
||||
|
|
@ -254,3 +256,40 @@ class ONNXModel:
|
|||
if output.name == output_name:
|
||||
return True
|
||||
return False
|
||||
|
||||
def topological_sort(self):
|
||||
deps_count = [0]*len(self.nodes()) # dependency count of each node
|
||||
deps_to_nodes = {} # input to node indice
|
||||
for node_idx, node in enumerate(self.nodes()):
|
||||
deps_count[node_idx] = len(node.input)
|
||||
for input_name in node.input:
|
||||
if input_name not in deps_to_nodes:
|
||||
deps_to_nodes[input_name] = [node_idx]
|
||||
else:
|
||||
deps_to_nodes[input_name].append(node_idx)
|
||||
|
||||
|
||||
# initialize sorted_nodes
|
||||
sorted_nodes = []
|
||||
for input in itertools.chain(self.initializer(), self.model.graph.input):
|
||||
for node_idx in deps_to_nodes[input.name]:
|
||||
deps_count[node_idx] = deps_count[node_idx] - 1
|
||||
if deps_count[node_idx] == 0:
|
||||
sorted_nodes.append(self.nodes()[node_idx])
|
||||
|
||||
s = 0
|
||||
e = len(sorted_nodes)
|
||||
|
||||
while s < e:
|
||||
for output in sorted_nodes[s].output:
|
||||
if output in deps_to_nodes:
|
||||
for node_idx in deps_to_nodes[output]:
|
||||
deps_count[node_idx] = deps_count[node_idx] - 1
|
||||
if deps_count[node_idx] == 0:
|
||||
sorted_nodes.append(self.nodes()[node_idx])
|
||||
e = e + 1
|
||||
s = s + 1
|
||||
|
||||
assert(e == len(self.graph().node)), "Graph is not a DAG"
|
||||
self.graph().ClearField('node')
|
||||
self.graph().node.extend(sorted_nodes)
|
||||
|
|
@ -20,6 +20,14 @@ class TestDataFeeds(CalibrationDataReader):
|
|||
def rewind(self):
|
||||
self.iter_next = iter(self.data_feeds)
|
||||
|
||||
def check_op_type_order(testcase, model_path, ops):
|
||||
model = onnx.load(Path(model_path))
|
||||
testcase.assertEqual(len(ops), len(model.graph.node), 'op count is not same')
|
||||
for node_idx, node in enumerate(model.graph.node):
|
||||
testcase.assertEqual(
|
||||
ops[node_idx],
|
||||
node.op_type,
|
||||
'op {} is not in order. Expected: {}, Actual: {}'.format(node_idx, ops[node_idx], node.op_type))
|
||||
|
||||
def check_op_type_count(testcase, model_path, **kwargs):
|
||||
model = onnx.load(Path(model_path))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import onnx
|
|||
import numpy as np
|
||||
from onnx import helper, TensorProto
|
||||
from onnxruntime.quantization import quantize_static, QuantType, QuantFormat
|
||||
from op_test_utils import TestDataFeeds, check_model_correctness, check_op_type_count
|
||||
from op_test_utils import TestDataFeeds, check_model_correctness, check_op_type_count, check_op_type_order
|
||||
|
||||
class TestQDQFormat(unittest.TestCase):
|
||||
def input_feeds(self, n, name2shape):
|
||||
|
|
@ -163,8 +163,8 @@ class TestQDQFormatConvClip(TestQDQFormat):
|
|||
reduce_range = per_channel
|
||||
)
|
||||
data_reader.rewind()
|
||||
qdq_nodes = {'Conv': 1, 'QuantizeLinear': 1, 'DequantizeLinear': 2}
|
||||
check_op_type_count(self, model_int8_qdq_path, **qdq_nodes)
|
||||
#topo sort check
|
||||
check_op_type_order(self, model_int8_qdq_path, ['DequantizeLinear', 'QuantizeLinear', 'DequantizeLinear', 'Conv', 'Clip'])
|
||||
check_model_correctness(self, model_fp32_path, model_int8_qdq_path, data_reader.get_next())
|
||||
|
||||
data_reader.rewind()
|
||||
|
|
|
|||
Loading…
Reference in a new issue