Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make primary ops function step 2 #4512

Merged
merged 79 commits into from Nov 22, 2022
Merged

Conversation

liqunfu
Copy link
Contributor

@liqunfu liqunfu commented Sep 15, 2022

Description

update reduce ops so that axes is the second optional input
change reduce ops to function op

Motivation and Context

to reduce amount of primary ops

…e simple function?

Signed-off-by: Liqun Fu <liqfu@microsoft.com>
@liqunfu liqunfu requested a review from a team as a code owner September 15, 2022 00:31
@liqunfu liqunfu marked this pull request as draft September 15, 2022 00:31
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
@liqunfu liqunfu marked this pull request as ready for review September 26, 2022 19:58
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
@liqunfu liqunfu requested a review from a team as a code owner September 26, 2022 21:50
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
@xadupre
Copy link
Contributor

xadupre commented Oct 5, 2022

This PR will have a significant impact on converting librairies.

@liqunfu
Copy link
Contributor Author

liqunfu commented Oct 5, 2022

This PR will have a significant impact on converting librairies.

Yes it does. For updated ops, I have added appropriate adapters for model converter. Anything else I need to do?

@gramalingam
Copy link
Contributor

@BowenBao : for your awareness: this PR proposes to promote the axes attribute to input for various Reduce* ops. (This was already done for ReduceSum previously, but not for other ops.) I hope the impact on the converter won't be much? It would be good to know, thanks.

Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
all_function_opset_versions.end(),
context_dependent_function_opset_versions.begin(),
context_dependent_function_opset_versions.end());
std::sort(all_function_opset_versions.begin(), all_function_opset_versions.end());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a possibility the result contains duplicates?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, added code to remove duplications. op authors shall not define both type of functions with the same version. all_function_opset_versions is used to check whether there is any function so we generate doc properly.

noop_with_empty_axes = noop_with_empty_axes or self.noop_with_empty_axes # type: ignore
return self._run(data, axes, keepdims, noop_with_empty_axes)

def _run(self, data, axes, keepdims=1, noop_with_empty_axes=0): # type: ignore
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may remove def run and define the default values for def _run as None. If None, the main class automatically looks into the node definition to replace them or the schema if they are not specified.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But is this wrong? I find this current form useful since a reader can understand what happens (what is the default value) without having to look elsewhere.

Copy link
Contributor Author

@liqunfu liqunfu Nov 17, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xadupre , I agree with @gramalingam here. We need at least on call (_run here) to follow precisely the op schema signature. (I was thinking that _run does not have to use None as default for op attributes. It turned out it is not true)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition, I think the suggested _run signature does not work with nest calls - when the op is part of other function ops. There for now I like to keep the current code.

@@ -294,6 +295,10 @@ class ShapeInferenceImplBase {
} else if (attr.type() == AttributeProto::SPARSE_TENSOR && attr.has_sparse_tensor()) {
input_sparse_data_by_name[n.output(0)] = &attr.sparse_tensor();
}
} else if (attr.name() == "value_ints" && attr.type() == AttributeProto::INTS) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put attr.type() == AttributeProto::INTS first. Both conditions should be equivalent but checking an int is faster than a string.

@@ -60,6 +60,26 @@
# not implemented
"test__simple_gradient_of_add", # gradient not implemented
"test__simple_gradient_of_add_and_mul", # gradient not implemented
"test_layer_normalization_2d_axis1_expanded", # https://github.com/onnx/onnx/issues/4653
Copy link
Contributor

@xadupre xadupre Nov 16, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://github.com/onnx/onnx/blob/main/onnx/backend/test/case/node/split.py#L13, I followed the convention defined in this file. You can specify an opset with suffix _opset<opset>. This might not fully answer issue #4653. The test test_layer_normalization_4d_axis_negative_3_expanded_ver18 should work if the function is written with operator defined in opset 18.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right that every test ending with _ver18 shall pass. I enabled those tests.
regarding naming of expended tests, they are auto generated. I used _ver# for opset import for the function body.

@@ -461,7 +481,7 @@ class TestOnnxBackEndWithReferenceEvaluator(unittest.TestCase):

@classmethod
def add_test_methods(cls):
for folder in ["node", "pytorch-converted", "pytorch-operator", "simple"]:
for folder in ["node"]:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake. I commented for debugging. Forgot to bring it back.

for te in enumerate_onnx_tests("node", lambda folder: folder == name):
code.append(te)
self.assertEqual(len(code), 1)
# def test_onnx_backend_test_abs(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why disabling the test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

forgot bring it back after debugging

else
return false;
bool OpSchema::BuildContextDependentFunction(const FunctionBodyBuildContext& ctx, FunctionProto& function_proto) const {
return BuildContextDependentFunctionWithOpsetVersion(ctx, function_proto, since_version_);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Do we need these two different methods? Or, can we just use BuildContextDependentFunction with a default value for parameter requested_opset_version?

}

const FunctionProto* OpSchema::GetFunctionWithOpsetVersion(int requested_opset_version) const {
return const_cast<OpSchema*>(this)->GetFunctionWithOpsetInternal(requested_opset_version);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need this const_cast ? May be outdated. I don't see any UpdateFunctionProtoOpsetImportVersion any more. May be simpler to inline the internal function here.

Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Copy link
Member

@jcwchen jcwchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nit comments. I saw some test_data_set_0 only has input_1.pb without input_0.pb. Is it expected? Since this PR really introduces a lot of test files (model.onnx, input/output pb files), it would be super great if we can verify them in ORT in advance.

@@ -2309,24 +2310,70 @@ def test_gemm_no_bias(self) -> None:
graph, [make_tensor_value_info("out", TensorProto.FLOAT, (13, 17))]
)

def test_reduce_op_shape_2_axis(self) -> None:
def test_reduce_op_shape_2_axis_opset_version_13(self) -> None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: could we keep the test name short like test_reduce_op_shape_2_axis_opset13?
Existing test uses something like test_scan_opset9 actually.

onnx/version_converter/convert.h Show resolved Hide resolved
docs/Operators-ml.md Show resolved Hide resolved
onnx_ai_opset_imports = [
oi
for oi in kwargs["opset_imports"]
if oi.domain == "" or oi.domain == "ai.onnx"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny nit: more pythonic.

Suggested change
if oi.domain == "" or oi.domain == "ai.onnx"
if oi.domain in ("", "ai.onnx")

onnx/defs/schema.cc Outdated Show resolved Hide resolved
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
@liqunfu
Copy link
Contributor Author

liqunfu commented Nov 22, 2022

Some nit comments. I saw some test_data_set_0 only has input_1.pb without input_0.pb. Is it expected? Since this PR really introduces a lot of test files (model.onnx, input/output pb files), it would be super great if we can verify them in ORT in advance.

That is because due to the test change, only input1 is changed. input0 stays unchanged so it is not in the PR.

Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Signed-off-by: Liqun Fu <liqfu@microsoft.com>
Copy link
Contributor

@gramalingam gramalingam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Only nit comment left is whether HasContextDependentFunctionWithOpsetVersion can be renamed HasContextDependentFunction.

@liqunfu liqunfu merged commit 7a1fae4 into onnx:main Nov 22, 2022
@liqunfu liqunfu deleted the liqun/primary-to-function2 branch November 22, 2022 00:45
justinchuby pushed a commit to justinchuby/onnx that referenced this pull request Jan 27, 2023
broune pushed a commit to broune/onnx that referenced this pull request May 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants