sort quantized nodes in topo logical order (#7172)

This commit is contained in:
Yufeng Li 2021-03-30 09:01:15 -07:00 committed by GitHub
parent 4f30341253
commit c4ebc60870
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 50 additions and 3 deletions

View file

@ -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)

View file

@ -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))

View file

@ -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()