Register opset-11 CPU kernel for 'If' op (#1948)

* Initial commit

* Update

* Update

* Update

* Update

* PR comments
This commit is contained in:
Hariharan Seshadri 2019-10-01 16:40:26 -07:00 committed by GitHub
parent d1b1cdc5c4
commit 31aff686e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 20 deletions

View file

@ -46,12 +46,21 @@ ONNX_OPERATOR_SET_SCHEMA(
.TypeConstraint("B", {"tensor(bool)"}, "Only bool"));
*/
ONNX_CPU_OPERATOR_VERSIONED_KERNEL(If,
1, 10,
KernelDefBuilder()
.TypeConstraint("B", DataTypeImpl::GetTensorType<bool>())
.TypeConstraint("V", DataTypeImpl::AllTensorTypes()),
If);
// output shape rules requiring the output shapes of the 'THEN' and 'ELSE'
// branches to be the same were relaxed in opset-11
ONNX_CPU_OPERATOR_KERNEL(If,
1,
KernelDefBuilder()
.TypeConstraint("B", DataTypeImpl::GetTensorType<bool>())
.TypeConstraint("V", DataTypeImpl::AllTensorTypes()),
If);
11,
KernelDefBuilder()
.TypeConstraint("B", DataTypeImpl::GetTensorType<bool>())
.TypeConstraint("V", DataTypeImpl::AllTensorTypes()),
If);
struct If::Info {
Info(const onnxruntime::Node& node, const GraphViewer& subgraph_in) : subgraph(subgraph_in) {

View file

@ -212,7 +212,7 @@ class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain,
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 8, bool, Expand);
class ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 8, MLFloat16, Expand);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 8, 8, Scan);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, If);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 10, If);
class ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 10, Loop);
// Opset 9
@ -357,6 +357,7 @@ class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Ma
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, LpPool);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Conv);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, ConvTranspose);
class ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, If);
void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
static const BuildKernelCreateInfoFn function_table[] = {
@ -554,7 +555,7 @@ void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 8, bool, Expand)>,
BuildKernelCreateInfo<ONNX_OPERATOR_TYPED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 8, MLFloat16, Expand)>,
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 8, 8, Scan)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, If)>,
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 10, If)>,
BuildKernelCreateInfo<ONNX_OPERATOR_VERSIONED_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 1, 10, Loop)>,
// Opset 9
@ -699,6 +700,7 @@ void RegisterOnnxOperatorKernels(KernelRegistry& kernel_registry) {
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, LpPool)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, Conv)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, ConvTranspose)>,
BuildKernelCreateInfo<ONNX_OPERATOR_KERNEL_CLASS_NAME(kCpuExecutionProvider, kOnnxDomain, 11, If)>,
};
for (auto& function_table_entry : function_table) {

View file

@ -44,7 +44,8 @@ static const ONNX_NAMESPACE::GraphProto CreateSubgraph(bool then_branch, const R
class IfOpTester : public OpTester {
public:
IfOpTester(const RunOptions& options) : OpTester("If"), options_{options} {
IfOpTester(const RunOptions& options, int opset_version = 10) :
OpTester("If", opset_version), options_{options}, opset_version_(opset_version) {
}
protected:
@ -73,7 +74,18 @@ class IfOpTester : public OpTester {
inputs = {split_input};
outputs = {&split_out_0, &split_out_1};
graph.AddNode("split", "Split", "Split into 2", inputs, outputs);
auto& split_node = graph.AddNode("split", "Split", "Split into 2", inputs, outputs);
if (opset_version_ > 10) {
AttributeProto attr_proto;
attr_proto.set_name("split");
attr_proto.set_type(AttributeProto_AttributeType_INTS);
auto* split_attribute = attr_proto.mutable_ints();
*split_attribute->Add() = 1; // split "unevenly" to create different shapes across the "then" and "else" branches
*split_attribute->Add() = 2;
split_node.AddAttribute("split", attr_proto);
}
}
// add If node
@ -99,13 +111,14 @@ class IfOpTester : public OpTester {
private:
RunOptions options_;
int opset_version_;
};
/* Subgraphs looks like this. All inputs come from outer scope so we just
/* Subgraphs looks like this. All inputs come from outer scope so we just
create a NodeArg with the input name. The numbers in [] are the values the tests are expected to produce
as output from each node.
THEN branch
THEN branch (all opset versions)
split_out_0 if_input_0 [1]
\ |
[1] \ |
@ -113,13 +126,21 @@ THEN branch
|
add_out_0 [2]
ELSE branch
ELSE branch (opset 10 and below)
split_out_1 if_input_0 [1]
\ |
[10] \ |
\------[Add]
|
add_out_1 [11]
ELSE branch (opset 11 and above)
split_out_1 if_input_0 [1]
\ |
[10, 10] \ |
\------[Add]
|
add_out_1 [11, 11]
*/
static const ONNX_NAMESPACE::GraphProto CreateSubgraph(bool then_branch, const RunOptions& options) {
@ -185,8 +206,9 @@ void RunTest(bool condition_value,
RunOptions options,
bool is_tensorrt_supported = true,
OpTester::ExpectResult expect_result = OpTester::ExpectResult::kExpectSuccess,
const std::string& failure_message = "") {
IfOpTester test{options};
const std::string& failure_message = "",
int opset_version = 10) {
IfOpTester test{options, opset_version};
test.AddShapeToTensorData(options.include_dim_values_in_main_graph,
options.symbolic_dim_value_in_main_graph);
@ -196,18 +218,26 @@ void RunTest(bool condition_value,
// it's outputs are 1:1 with the graph outputs.
// simple tensor that we split into 2, and use one output for the 'then' and one for the 'else' branch in the If
test.AddInput<float>("split_input", {2}, {1.f, 10.f});
if (opset_version != 11) {
test.AddInput<float>("split_input", {2}, {1.f, 10.f});
} else {
// in the opset 11 test case, we are going to split "unevenly", to create different shapes in "then" and "else" branches
test.AddInput<float>("split_input", {3}, {1.f, 10.f, 10.f});
}
// graph input to specify which branch to take
test.AddInput<bool>("if_cond", {1}, {condition_value});
test.AddInput<float>("if_graph_input_0", {1}, {1.f});
std::vector<int64_t> output_shape{1};
if (condition_value) {
test.AddOutput<float>("if_out_0", output_shape, {2.f});
} else {
test.AddOutput<float>("if_out_0", output_shape, {11.f});
if (opset_version != 11 && condition_value) {
test.AddOutput<float>("if_out_0", {1}, {2.f});
} else if (opset_version != 11) {
test.AddOutput<float>("if_out_0", {1}, {11.f});
} else if (opset_version == 11 && condition_value) {
test.AddOutput<float>("if_out_0", {1}, {2.f});
} else if (opset_version == 11) {
test.AddOutput<float>("if_out_0", {2}, {11.f, 11.f});
}
std::unordered_set<std::string> excluded_providers;
@ -286,5 +316,13 @@ TEST(If, SymbolicShapeInMainGraph_NoShapeInSubgraph_False) {
RunTest(false, options, false);
}
TEST(If, Opset11ThenAndElseBranchesProduceDifferentOutputShapes) {
RunOptions options{};
options.include_dim_values_in_main_graph = true;
options.include_dim_values_in_subgraph = false;
RunTest(false, options, false, OpTester::ExpectResult::kExpectSuccess, "", 11);
}
} // namespace test
} // namespace onnxruntime