Skip to content

Commit 31b6337

Browse files
jcwchengramalingam
andauthored
Clarify NonZero behavior for scalar input in spec (onnx#4113)
* bump NonZero with updated shape inference Signed-off-by: Chun-Wei Chen <jacky82226@gmail.com> * revert and add tests for NonZero and Unsqueeze Signed-off-by: Chun-Wei Chen <jacky82226@gmail.com> * clarify in spec Signed-off-by: Chun-Wei Chen <jacky82226@gmail.com> * update spec Signed-off-by: Chun-Wei Chen <jacky82226@gmail.com> * use extern to handle shared string across files Signed-off-by: Chun-Wei Chen <jacky82226@gmail.com> Co-authored-by: G. Ramalingam <grama@microsoft.com>
1 parent 77bdf2d commit 31b6337

File tree

6 files changed

+29
-13
lines changed

6 files changed

+29
-13
lines changed

docs/Changelog.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8648,7 +8648,8 @@ This version of the operator has been available since version 9 of the default O
86488648
Returns the indices of the elements that are non-zero
86498649
(in row-major order - by dimension).
86508650
NonZero behaves similar to numpy.nonzero:
8651-
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html
8651+
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html,
8652+
but for scalar input, NonZero produces output shape (0, N) instead of (1, N), which is different from Numpy's behavior.
86528653

86538654
#### Version
86548655

@@ -16905,7 +16906,8 @@ This version of the operator has been available since version 13 of the default
1690516906
Returns the indices of the elements that are non-zero
1690616907
(in row-major order - by dimension).
1690716908
NonZero behaves similar to numpy.nonzero:
16908-
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html
16909+
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html,
16910+
but for scalar input, NonZero produces output shape (0, N) instead of (1, N), which is different from Numpy's behavior.
1690916911

1691016912
#### Version
1691116913

docs/Operators.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13418,7 +13418,8 @@ expect(node, inputs=[boxes, scores, max_output_boxes_per_class, iou_threshold, s
1341813418
Returns the indices of the elements that are non-zero
1341913419
(in row-major order - by dimension).
1342013420
NonZero behaves similar to numpy.nonzero:
13421-
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html
13421+
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html,
13422+
but for scalar input, NonZero produces output shape (0, N) instead of (1, N), which is different from Numpy's behavior.
1342213423

1342313424
#### Version
1342413425

onnx/defs/tensor/defs.cc

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3108,18 +3108,11 @@ ONNX_OPERATOR_SET_SCHEMA(
31083108
}
31093109
}));
31103110

3111-
static const char* NonZero_ver13_doc = R"DOC(
3112-
Returns the indices of the elements that are non-zero
3113-
(in row-major order - by dimension).
3114-
NonZero behaves similar to numpy.nonzero:
3115-
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html
3116-
)DOC";
3117-
31183111
ONNX_OPERATOR_SET_SCHEMA(
31193112
NonZero,
31203113
13,
31213114
OpSchema()
3122-
.SetDoc(NonZero_ver13_doc)
3115+
.SetDoc(NonZero_ver9_doc)
31233116
.Input(
31243117
0,
31253118
"X",

onnx/defs/tensor/old.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2203,11 +2203,12 @@ ONNX_OPERATOR_SET_SCHEMA(
22032203
}
22042204
}));
22052205

2206-
static const char* NonZero_ver9_doc = R"DOC(
2206+
const char* NonZero_ver9_doc = R"DOC(
22072207
Returns the indices of the elements that are non-zero
22082208
(in row-major order - by dimension).
22092209
NonZero behaves similar to numpy.nonzero:
2210-
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html
2210+
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html,
2211+
but for scalar input, NonZero produces output shape (0, N) instead of (1, N), which is different from Numpy's behavior.
22112212
)DOC";
22122213

22132214
ONNX_OPERATOR_SET_SCHEMA(

onnx/defs/tensor/utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ void resizeShapeInferenceHelper_opset7_to_10(
3131
const TensorShapeProto& input_shape,
3232
const std::vector<float>& scales_data,
3333
TensorShapeProto* output_shape);
34+
35+
extern const char* NonZero_ver9_doc;
3436
} // namespace ONNX_NAMESPACE

onnx/test/shape_inference_test.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ def _compare_value_infos(self, vi_type: TypeProto, inferred_vi_type: TypeProto)
6969
assert vi_type.tensor_type.elem_type == inferred_vi_type.tensor_type.elem_type
7070
assert vi_type.tensor_type.HasField('shape') == inferred_vi_type.tensor_type.HasField('shape')
7171
if vi_type.tensor_type.HasField('shape'):
72+
assert len(vi_type.tensor_type.shape.dim) == len(inferred_vi_type.tensor_type.shape.dim)
7273
for dim_i in range(len(vi_type.tensor_type.shape.dim)):
7374
dim = vi_type.tensor_type.shape.dim[dim_i]
7475
inferred_dim = inferred_vi_type.tensor_type.shape.dim[dim_i]
@@ -632,6 +633,15 @@ def test_unsqueeze_negative_axes(self) -> None:
632633
initializer=[make_tensor('axes', TensorProto.INT64, (2,), (0, -1))])
633634
self._assert_inferred(graph, [make_tensor_value_info('y', TensorProto.FLOAT, (1, 3, 4, 5, 1))])
634635

636+
def test_unsqueeze_scalar(self) -> None:
637+
graph = self._make_graph(
638+
[('x', TensorProto.FLOAT, ()),
639+
('axes', TensorProto.INT64, ())],
640+
[make_node('Unsqueeze', ['x', 'axes'], 'y')],
641+
[],
642+
initializer=[make_tensor('axes', TensorProto.INT64, (), (-1,))])
643+
self._assert_inferred(graph, [make_tensor_value_info('y', TensorProto.FLOAT, (1,))])
644+
635645
def test_slice_without_input_shape(self) -> None:
636646
graph = self._make_graph(
637647
[('x', TensorProto.FLOAT, (3, 2)), ('starts', TensorProto.INT64, (1,)), ('ends', TensorProto.INT64, (1,))],
@@ -3816,6 +3826,13 @@ def test_nonzero_existing_dim_param(self) -> None:
38163826
[make_tensor_value_info('y', TensorProto.INT64, (None, 'NZ'))])
38173827
self._assert_inferred(graph, [make_tensor_value_info('y', TensorProto.INT64, (1, 'NZ'))]) # type: ignore
38183828

3829+
def test_nonzero_scalar(self) -> None:
3830+
graph = self._make_graph(
3831+
[('x', TensorProto.FLOAT, ())],
3832+
[make_node('NonZero', ['x'], ['out'])],
3833+
[])
3834+
self._assert_inferred(graph, [make_tensor_value_info('out', TensorProto.INT64, (0, None))]) # type: ignore
3835+
38193836
def test_optional_construct_empty_tensor(self) -> None:
38203837
tensor_type_proto = helper.make_tensor_type_proto(elem_type=TensorProto.FLOAT, shape=[1, 2, 3])
38213838
optional_type_proto = helper.make_optional_type_proto(tensor_type_proto)

0 commit comments

Comments
 (0)