Fix symbolic shape inference for faster_rcnn, mask_rcnn, yolov3 (#1867)

* Fix symbolic shape inference for faster_rcnn, mask_rcnn, yolov3

Force merge when --auto_merge, on symbolic dims which sympy cannot simplify
Add symbolic inference for Resize opset 10
Add support for step != 1 in Slice
Add support for computed dim in TopK
Bug fixes in passing symbolic dims from subgraph
Fix an outdate comment in Nuphar provider header
This commit is contained in:
KeDengMS 2019-09-18 14:18:32 -07:00 committed by GitHub
parent 582a27f546
commit 80bda77203
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 33 additions and 11 deletions

2
cmake/external/tvm vendored

@ -1 +1 @@
Subproject commit 638d7d2407de27f98f542f61a37a33c90a2e75a9
Subproject commit 2ad9c02cdcca2d78237e0a90f1f324383452511e

View file

@ -8,7 +8,7 @@ extern "C" {
#endif
/**
* \param device_id nuphar device id, starts from zero.
* \param target_str TVM target string.
* \param settings_str Nuphar settings string.
*/
ORT_API_STATUS(OrtSessionOptionsAppendExecutionProvider_Nuphar, _In_ OrtSessionOptions* options, int allow_unaligned_buffers, _In_ const char* settings_str);

View file

@ -84,6 +84,7 @@ class SymbolicShapeInference:
'Range' : self._infer_Range,
'ReduceProd' : self._infer_ReduceProd,
'Reshape' : self._infer_Reshape,
'Resize' : self._infer_Resize,
'Round' : self._pass_on_shape_and_type,
'Scan' : self._infer_Scan,
'Shape' : self._infer_Shape,
@ -113,7 +114,9 @@ class SymbolicShapeInference:
if type(self.symbolic_dims_[s]) == sympy.Symbol:
map_to = s
if not map_to:
raise Exception('Cannot merge between symbolic expressions: ({}), please modify model input dims to avoid this!'.format(','.join(symbols)))
if self.verbose_ > 0:
print('Potential unsafe merge between symbolic expressions: ({})'.format(','.join(symbols)))
map_to = symbols.pop() # force merge when unable to determine
for s in symbols:
if s == map_to:
continue
@ -307,7 +310,7 @@ class SymbolicShapeInference:
# for new symbolic dims from subgraph output, add to main graph symbolic dims
subgraph_shapes = [get_shape_from_type_proto(o.type) for o in symbolic_shape_inference.out_mp_.graph.output]
subgraph_new_symbolic_dims = set([d for s in subgraph_shapes if s for d in s if type(d) == str and not d in self.symbolic_dims_])
self.symbolic_dims_.update({d:symbolic_shape_inference[d] for d in subgraph_new_symbolic_dims})
self.symbolic_dims_.update({d:symbolic_shape_inference.symbolic_dims_[d] for d in subgraph_new_symbolic_dims})
def _get_int_values(self, node, broadcast=False):
values = [self._try_get_value(node, i) for i in range(len(node.input))]
@ -510,7 +513,7 @@ class SymbolicShapeInference:
vi.type.tensor_type.elem_type,
data_shape[:axis] + indices_shape + data_shape[axis+1:]))
if node.input[0] in self.sympy_data_:
assert 0 == get_attribute(node, 'axis') # only handle 1D sympy compute
assert 0 == get_attribute(node, 'axis', 0) # only handle 1D sympy compute
idx = self._get_value(node, 1)
data = self.sympy_data_[node.input[0]]
if type(data) == list:
@ -650,6 +653,16 @@ class SymbolicShapeInference:
get_shape_from_sympy_shape(new_sympy_shape)))
self._pass_on_sympy_data(node)
def _infer_Resize(self, node):
assert get_opset(self.out_mp_) <= 10 # only support opset 10 Resize for now
scales = self._try_get_value(node, 1)
if scales is not None:
input_sympy_shape = self._get_sympy_shape(node, 0)
new_sympy_shape = [sympy.simplify(sympy.floor(d*s)) for d,s in zip(input_sympy_shape, scales)]
self._update_computed_dims(new_sympy_shape)
vi = self.known_vi_[node.output[0]]
vi.CopyFrom(helper.make_tensor_value_info(node.output[0], self.known_vi_[node.input[0]].type.tensor_type.elem_type, get_shape_from_sympy_shape(new_sympy_shape)))
def _infer_Scan(self, node):
subgraph = get_attribute(node, 'body')
num_scan_inputs = get_attribute(node, 'num_scan_inputs')
@ -713,12 +726,12 @@ class SymbolicShapeInference:
new_shape[i] = self._new_symbolic_dim_from_output(node,0,i)
else:
for i,s,e,t in zip(axes, starts, ends, steps):
# TODO: handle step
assert t == 1
idx = handle_negative_axis(i, len(new_shape))
if is_literal(e):
if e >= int(2 ** 31 - 1): # max value of int32
e = new_shape[i]
elif e <= -int(2 ** 31): # min value of int32
e = 0
elif is_literal(new_shape[i]):
e = min(e, new_shape[i])
else:
@ -740,7 +753,7 @@ class SymbolicShapeInference:
if is_literal(s) and int(s) < 0:
s = new_shape[i] + s
new_shape[idx] = e - s
new_shape[idx] = (e - s + (-1 if t > 0 else 1)) // t + 1
self._update_computed_dims(new_shape)
new_shape = get_shape_from_sympy_shape(new_shape)
@ -787,18 +800,26 @@ class SymbolicShapeInference:
def _infer_TopK(self, node):
rank = self._get_shape_rank(node, 0)
axis = handle_negative_axis(get_attribute(node, 'axis'), rank)
axis = handle_negative_axis(get_attribute(node, 'axis', -1), rank)
new_shape = self._get_shape(node, 0)
if get_opset(self.out_mp_) <= 9:
k = get_attribute(node, 'k')
else:
k = self._try_get_value(node, 1)
k = self._get_int_values(node)[1]
if k == None:
k = self._new_symbolic_dim_from_output(node)
else:
k = as_scalar(k)
new_shape[axis] = k
if type(k) in [int, str]:
new_shape[axis] = k
else:
new_sympy_shape = self._get_sympy_shape(node, 0)
new_sympy_shape[axis] = k
self._update_computed_dims(new_sympy_shape) # note that TopK dim could be computed in sympy_data, so need to update computed_dims when it enters shape
new_shape = get_shape_from_sympy_shape(new_sympy_shape)
for i_o in range(len(node.output)):
vi = self.known_vi_[node.output[i_o]]
@ -874,6 +895,7 @@ class SymbolicShapeInference:
if self.verbose_ > 0 or not self.auto_merge_ or out_type_undefined:
print('Stopping at incomplete shape inference at ' + node.op_type + ': ' + node.name)
print(node)
print('node inputs:')
for i in node.input:
print(self.known_vi_[i])