diff --git a/src/builder/CMakeLists.txt b/src/builder/CMakeLists.txt index a014dd7..3d8e603 100644 --- a/src/builder/CMakeLists.txt +++ b/src/builder/CMakeLists.txt @@ -1,5 +1,6 @@ add_library(builder frontend_dialect_transformer.cpp + op_build_table.inc ) target_include_directories(builder PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/src/builder/frontend_dialect_transformer.cpp b/src/builder/frontend_dialect_transformer.cpp index 25b7ff3..388650f 100644 --- a/src/builder/frontend_dialect_transformer.cpp +++ b/src/builder/frontend_dialect_transformer.cpp @@ -149,6 +149,33 @@ class FrontendGenImpl { } } +//if c++17 is used, these two def can be combined with 'if constexpr' +//leave n there for possible future use +//alternative is to use template and pass the outputTypes, inputs and attributes +//as parameter + +#define MultipleOuts(name, nIn, nOut)\ +{ \ + if (nIn == inputs.size() && nOut == outputTypes.size()) {\ + auto op = builder_.create(UnknownLoc(), outputTypes, inputs, attributes); \ + for (int i = 0; i < node.output().size(); i++) { \ + frontend_symbols_.AddMapping(\ + legalize_name(node.output()[i]), op.getResult(i));\ + }\ + return;\ + }\ +} + +#define OneOut(name, nIn, nOut)\ +{ \ + if (nIn == inputs.size() && nOut == outputTypes.size()) {\ + auto op = builder_.create(UnknownLoc(), outputTypes, inputs, attributes); \ + frontend_symbols_.AddMapping(\ + legalize_name(node.output()[0]), op.getResult());\ + return;\ + }\ +} + /*! * Import an onnx input tensor type by determining and recording its type * in a list of input tensor mlir types. @@ -206,39 +233,23 @@ class FrontendGenImpl { } } - // Handle ONNX Add Operation by using its representation in the - // ONNX Dialect. - llvm::StringRef OpName = node.op_type(); - if (OpName == "Add") { - auto op = builder_.create(UnknownLoc(), - mlir::UnrankedTensorType::get(builder_.getF32Type()), inputs[0], - inputs[1]); - frontend_symbols_.AddMapping( - legalize_name(node.output()[0]), op.getResult()); - return; - } else if (OpName == "MatMul") { - auto op = builder_.create(UnknownLoc(), - mlir::UnrankedTensorType::get(builder_.getF32Type()), inputs[0], - inputs[1]); - frontend_symbols_.AddMapping( - legalize_name(node.output()[0]), op.getResult()); - return; - } else if (OpName == "Gemm") { - if (inputs.size() == 3) { - auto op = builder_.create(UnknownLoc(), - mlir::UnrankedTensorType::get(builder_.getF32Type()), inputs[0], - inputs[1], inputs[2]); - frontend_symbols_.AddMapping( - legalize_name(node.output()[0]), op.getResult()); - } else { - auto op = builder_.create(UnknownLoc(), - mlir::UnrankedTensorType::get(builder_.getF32Type()), inputs); - frontend_symbols_.AddMapping( - legalize_name(node.output()[0]), op.getResult()); - } - return; + std::vector outputTypes; + for (auto item : node.output()) { + outputTypes.push_back(mlir::UnrankedTensorType::get(builder_.getF32Type())); } + std::vector attributes; + llvm::StringRef OpName = node.op_type(); + + //the following code is generated by gen_doc.py + //refer to dialect/onnx/onnx.td for details + //when the input or output of then op does not match the specification, + //the generic operator is used + //one known reeason is the optional input + +#include "src/builder/op_build_table.inc" + + // Old way of doing things. mlir::OperationState result(UnknownLoc(), "frontend." + node.op_type()); for (auto item : node.output()) { diff --git a/src/builder/op_build_table.inc b/src/builder/op_build_table.inc new file mode 100644 index 0000000..c8e75e0 --- /dev/null +++ b/src/builder/op_build_table.inc @@ -0,0 +1,313 @@ + if (OpName == "Abs") { + OneOut(Abs, 1, 1); + }else if (OpName == "Acos") { + OneOut(Acos, 1, 1); + }else if (OpName == "Acosh") { + OneOut(Acosh, 1, 1); + }else if (OpName == "Add") { + OneOut(Add, 2, 1); + }else if (OpName == "And") { + OneOut(And, 2, 1); + }else if (OpName == "ArgMax") { + OneOut(ArgMax, 1, 1); + }else if (OpName == "ArgMin") { + OneOut(ArgMin, 1, 1); + }else if (OpName == "Asin") { + OneOut(Asin, 1, 1); + }else if (OpName == "Asinh") { + OneOut(Asinh, 1, 1); + }else if (OpName == "Atan") { + OneOut(Atan, 1, 1); + }else if (OpName == "Atanh") { + OneOut(Atanh, 1, 1); + }else if (OpName == "AveragePool") { + OneOut(AveragePool, 1, 1); + }else if (OpName == "BatchNormalization") { + MultipleOuts(BatchNormalization, 5, 5); + }else if (OpName == "BitShift") { + OneOut(BitShift, 2, 1); + }else if (OpName == "Cast") { + OneOut(Cast, 1, 1); + }else if (OpName == "Ceil") { + OneOut(Ceil, 1, 1); + }else if (OpName == "Clip") { + OneOut(Clip, 3, 1); + }else if (OpName == "Compress") { + OneOut(Compress, 2, 1); + }else if (OpName == "Concat") { + OneOut(Concat, 1, 1); + }else if (OpName == "ConcatFromSequence") { + OneOut(ConcatFromSequence, 1, 1); + }else if (OpName == "Constant") { + OneOut(Constant, 0, 1); + }else if (OpName == "ConstantOfShape") { + OneOut(ConstantOfShape, 1, 1); + }else if (OpName == "Conv") { + OneOut(Conv, 3, 1); + }else if (OpName == "ConvInteger") { + OneOut(ConvInteger, 4, 1); + }else if (OpName == "ConvTranspose") { + OneOut(ConvTranspose, 3, 1); + }else if (OpName == "Cos") { + OneOut(Cos, 1, 1); + }else if (OpName == "Cosh") { + OneOut(Cosh, 1, 1); + }else if (OpName == "CumSum") { + OneOut(CumSum, 2, 1); + }else if (OpName == "DepthToSpace") { + OneOut(DepthToSpace, 1, 1); + }else if (OpName == "DequantizeLinear") { + OneOut(DequantizeLinear, 3, 1); + }else if (OpName == "Det") { + OneOut(Det, 1, 1); + }else if (OpName == "Div") { + OneOut(Div, 2, 1); + }else if (OpName == "Dropout") { + MultipleOuts(Dropout, 1, 2); + }else if (OpName == "DynamicQuantizeLinear") { + MultipleOuts(DynamicQuantizeLinear, 1, 3); + }else if (OpName == "Elu") { + OneOut(Elu, 1, 1); + }else if (OpName == "Equal") { + OneOut(Equal, 2, 1); + }else if (OpName == "Erf") { + OneOut(Erf, 1, 1); + }else if (OpName == "Exp") { + OneOut(Exp, 1, 1); + }else if (OpName == "Expand") { + OneOut(Expand, 2, 1); + }else if (OpName == "EyeLike") { + OneOut(EyeLike, 1, 1); + }else if (OpName == "Flatten") { + OneOut(Flatten, 1, 1); + }else if (OpName == "Floor") { + OneOut(Floor, 1, 1); + }else if (OpName == "GRU") { + MultipleOuts(GRU, 6, 2); + }else if (OpName == "Gather") { + OneOut(Gather, 2, 1); + }else if (OpName == "GatherElements") { + OneOut(GatherElements, 2, 1); + }else if (OpName == "GatherND") { + OneOut(GatherND, 2, 1); + }else if (OpName == "Gemm") { + OneOut(Gemm, 3, 1); + }else if (OpName == "GlobalAveragePool") { + OneOut(GlobalAveragePool, 1, 1); + }else if (OpName == "GlobalLpPool") { + OneOut(GlobalLpPool, 1, 1); + }else if (OpName == "GlobalMaxPool") { + OneOut(GlobalMaxPool, 1, 1); + }else if (OpName == "Greater") { + OneOut(Greater, 2, 1); + }else if (OpName == "HardSigmoid") { + OneOut(HardSigmoid, 1, 1); + }else if (OpName == "Hardmax") { + OneOut(Hardmax, 1, 1); + }else if (OpName == "Identity") { + OneOut(Identity, 1, 1); + }else if (OpName == "If") { + OneOut(If, 1, 1); + }else if (OpName == "InstanceNormalization") { + OneOut(InstanceNormalization, 3, 1); + }else if (OpName == "IsInf") { + OneOut(IsInf, 1, 1); + }else if (OpName == "IsNaN") { + OneOut(IsNaN, 1, 1); + }else if (OpName == "LRN") { + OneOut(LRN, 1, 1); + }else if (OpName == "LSTM") { + MultipleOuts(LSTM, 8, 3); + }else if (OpName == "LeakyRelu") { + OneOut(LeakyRelu, 1, 1); + }else if (OpName == "Less") { + OneOut(Less, 2, 1); + }else if (OpName == "Log") { + OneOut(Log, 1, 1); + }else if (OpName == "LogSoftmax") { + OneOut(LogSoftmax, 1, 1); + }else if (OpName == "Loop") { + OneOut(Loop, 3, 1); + }else if (OpName == "LpNormalization") { + OneOut(LpNormalization, 1, 1); + }else if (OpName == "LpPool") { + OneOut(LpPool, 1, 1); + }else if (OpName == "MatMul") { + OneOut(MatMul, 2, 1); + }else if (OpName == "MatMulInteger") { + OneOut(MatMulInteger, 4, 1); + }else if (OpName == "Max") { + OneOut(Max, 1, 1); + }else if (OpName == "MaxPool") { + MultipleOuts(MaxPool, 1, 2); + }else if (OpName == "MaxRoiPool") { + OneOut(MaxRoiPool, 2, 1); + }else if (OpName == "MaxUnpool") { + OneOut(MaxUnpool, 3, 1); + }else if (OpName == "Mean") { + OneOut(Mean, 1, 1); + }else if (OpName == "MeanVarianceNormalization") { + OneOut(MeanVarianceNormalization, 1, 1); + }else if (OpName == "Min") { + OneOut(Min, 1, 1); + }else if (OpName == "Mod") { + OneOut(Mod, 2, 1); + }else if (OpName == "Mul") { + OneOut(Mul, 2, 1); + }else if (OpName == "Multinomial") { + OneOut(Multinomial, 1, 1); + }else if (OpName == "Neg") { + OneOut(Neg, 1, 1); + }else if (OpName == "NonMaxSuppression") { + OneOut(NonMaxSuppression, 5, 1); + }else if (OpName == "NonZero") { + OneOut(NonZero, 1, 1); + }else if (OpName == "Not") { + OneOut(Not, 1, 1); + }else if (OpName == "OneHot") { + OneOut(OneHot, 3, 1); + }else if (OpName == "Or") { + OneOut(Or, 2, 1); + }else if (OpName == "PRelu") { + OneOut(PRelu, 2, 1); + }else if (OpName == "Pad") { + OneOut(Pad, 3, 1); + }else if (OpName == "Pow") { + OneOut(Pow, 2, 1); + }else if (OpName == "QLinearConv") { + OneOut(QLinearConv, 9, 1); + }else if (OpName == "QLinearMatMul") { + OneOut(QLinearMatMul, 8, 1); + }else if (OpName == "QuantizeLinear") { + OneOut(QuantizeLinear, 3, 1); + }else if (OpName == "RNN") { + MultipleOuts(RNN, 6, 2); + }else if (OpName == "RandomNormal") { + OneOut(RandomNormal, 0, 1); + }else if (OpName == "RandomNormalLike") { + OneOut(RandomNormalLike, 1, 1); + }else if (OpName == "RandomUniform") { + OneOut(RandomUniform, 0, 1); + }else if (OpName == "RandomUniformLike") { + OneOut(RandomUniformLike, 1, 1); + }else if (OpName == "Range") { + OneOut(Range, 3, 1); + }else if (OpName == "Reciprocal") { + OneOut(Reciprocal, 1, 1); + }else if (OpName == "ReduceL1") { + OneOut(ReduceL1, 1, 1); + }else if (OpName == "ReduceL2") { + OneOut(ReduceL2, 1, 1); + }else if (OpName == "ReduceLogSum") { + OneOut(ReduceLogSum, 1, 1); + }else if (OpName == "ReduceLogSumExp") { + OneOut(ReduceLogSumExp, 1, 1); + }else if (OpName == "ReduceMax") { + OneOut(ReduceMax, 1, 1); + }else if (OpName == "ReduceMean") { + OneOut(ReduceMean, 1, 1); + }else if (OpName == "ReduceMin") { + OneOut(ReduceMin, 1, 1); + }else if (OpName == "ReduceProd") { + OneOut(ReduceProd, 1, 1); + }else if (OpName == "ReduceSum") { + OneOut(ReduceSum, 1, 1); + }else if (OpName == "ReduceSumSquare") { + OneOut(ReduceSumSquare, 1, 1); + }else if (OpName == "Relu") { + OneOut(Relu, 1, 1); + }else if (OpName == "Reshape") { + OneOut(Reshape, 2, 1); + }else if (OpName == "Resize") { + OneOut(Resize, 4, 1); + }else if (OpName == "ReverseSequence") { + OneOut(ReverseSequence, 2, 1); + }else if (OpName == "RoiAlign") { + OneOut(RoiAlign, 3, 1); + }else if (OpName == "Round") { + OneOut(Round, 1, 1); + }else if (OpName == "Scan") { + OneOut(Scan, 1, 1); + }else if (OpName == "Scatter") { + OneOut(Scatter, 3, 1); + }else if (OpName == "ScatterElements") { + OneOut(ScatterElements, 3, 1); + }else if (OpName == "ScatterND") { + OneOut(ScatterND, 3, 1); + }else if (OpName == "Selu") { + OneOut(Selu, 1, 1); + }else if (OpName == "SequenceAt") { + OneOut(SequenceAt, 2, 1); + }else if (OpName == "SequenceConstruct") { + OneOut(SequenceConstruct, 1, 1); + }else if (OpName == "SequenceEmpty") { + OneOut(SequenceEmpty, 0, 1); + }else if (OpName == "SequenceErase") { + OneOut(SequenceErase, 2, 1); + }else if (OpName == "SequenceInsert") { + OneOut(SequenceInsert, 3, 1); + }else if (OpName == "SequenceLength") { + OneOut(SequenceLength, 1, 1); + }else if (OpName == "Shape") { + OneOut(Shape, 1, 1); + }else if (OpName == "Shrink") { + OneOut(Shrink, 1, 1); + }else if (OpName == "Sigmoid") { + OneOut(Sigmoid, 1, 1); + }else if (OpName == "Sign") { + OneOut(Sign, 1, 1); + }else if (OpName == "Sin") { + OneOut(Sin, 1, 1); + }else if (OpName == "Sinh") { + OneOut(Sinh, 1, 1); + }else if (OpName == "Size") { + OneOut(Size, 1, 1); + }else if (OpName == "Slice") { + OneOut(Slice, 5, 1); + }else if (OpName == "Softmax") { + OneOut(Softmax, 1, 1); + }else if (OpName == "Softplus") { + OneOut(Softplus, 1, 1); + }else if (OpName == "Softsign") { + OneOut(Softsign, 1, 1); + }else if (OpName == "SpaceToDepth") { + OneOut(SpaceToDepth, 1, 1); + }else if (OpName == "Split") { + OneOut(Split, 1, 1); + }else if (OpName == "SplitToSequence") { + OneOut(SplitToSequence, 2, 1); + }else if (OpName == "Sqrt") { + OneOut(Sqrt, 1, 1); + }else if (OpName == "Squeeze") { + OneOut(Squeeze, 1, 1); + }else if (OpName == "StringNormalizer") { + OneOut(StringNormalizer, 1, 1); + }else if (OpName == "Sub") { + OneOut(Sub, 2, 1); + }else if (OpName == "Sum") { + OneOut(Sum, 1, 1); + }else if (OpName == "Tan") { + OneOut(Tan, 1, 1); + }else if (OpName == "Tanh") { + OneOut(Tanh, 1, 1); + }else if (OpName == "TfIdfVectorizer") { + OneOut(TfIdfVectorizer, 1, 1); + }else if (OpName == "ThresholdedRelu") { + OneOut(ThresholdedRelu, 1, 1); + }else if (OpName == "Tile") { + OneOut(Tile, 2, 1); + }else if (OpName == "TopK") { + MultipleOuts(TopK, 2, 2); + }else if (OpName == "Transpose") { + OneOut(Transpose, 1, 1); + }else if (OpName == "Unique") { + MultipleOuts(Unique, 1, 4); + }else if (OpName == "Unsqueeze") { + OneOut(Unsqueeze, 1, 1); + }else if (OpName == "Upsample") { + OneOut(Upsample, 2, 1); + }else if (OpName == "Where") { + OneOut(Where, 3, 1); + }else if (OpName == "Xor") { + OneOut(Xor, 2, 1); + } \ No newline at end of file diff --git a/src/compiler/CMakeLists.txt b/src/compiler/CMakeLists.txt index 66d3d31..dbc9f3b 100644 --- a/src/compiler/CMakeLists.txt +++ b/src/compiler/CMakeLists.txt @@ -10,8 +10,9 @@ add_library( dialect/krnl/parser_helper.hpp pass/shape_inference_pass.cpp pass/shape_inference_interface.hpp - pass/onnx_combine.cpp - pass/passes.hpp) + pass/passes.hpp + dialect/onnx/onnxop.inc + pass/onnx_combine.cpp) # Include root src directory. target_include_directories(compiler PRIVATE ${ONNF_SRC_ROOT}) diff --git a/src/compiler/dialect/onnx/gen_doc.py b/src/compiler/dialect/onnx/gen_doc.py new file mode 100644 index 0000000..ad0b827 --- /dev/null +++ b/src/compiler/dialect/onnx/gen_doc.py @@ -0,0 +1,520 @@ +#!/usr/bin/env python +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +from collections import defaultdict +import io +import os +import sys + +import numpy as np # type: ignore + +from onnx import defs, FunctionProto, helper, OperatorStatus +from onnx.defs import OpSchema, ONNX_DOMAIN, ONNX_ML_DOMAIN +from onnx.backend.test.case import collect_snippets +from onnx.backend.sample.ops import collect_sample_implementations +from typing import Any, Text, Sequence, Dict, List, Type, Set, Tuple + + +SNIPPETS = collect_snippets() +SAMPLE_IMPLEMENTATIONS = collect_sample_implementations() +ONNX_ML = not bool(os.getenv('ONNX_ML') == '0') + +ONNX_ML = False +print("ONNX_ML", ONNX_ML) + + +if ONNX_ML: + ext = '-ml.md' +else: + ext = '.md' + + +def display_number(v): # type: (int) -> Text + if defs.OpSchema.is_infinite(v): + return '∞' + return Text(v) + + +def should_render_domain(domain): # type: (Text) -> bool + if domain == ONNX_ML_DOMAIN and not ONNX_ML: + return False + elif ONNX_ML and domain != ONNX_ML_DOMAIN: + return False + return True + + +def format_name_with_domain(domain, schema_name): # type: (Text, Text) -> Text + if domain: + return '{}.{}'.format(domain, schema_name) + else: + return schema_name + + +def display_attr_type(v): # type: (OpSchema.AttrType) -> Text + assert isinstance(v, OpSchema.AttrType) + s = Text(v) + s = s[s.rfind('.') + 1:].lower() + if s[-1] == 's': + s = 'list of ' + s + return s + + +def display_domain(domain): # type: (Text) -> Text + if domain: + return "the '{}' operator set".format(domain) + else: + return "the default ONNX operator set" + + +def display_domain_short(domain): # type: (Text) -> Text + if domain: + return domain + else: + return 'ai.onnx (default)' + + +def display_version_link(name, version): # type: (Text, int) -> Text + changelog_md = 'Changelog' + ext + name_with_ver = '{}-{}'.format(name, version) + return '{}'.format(changelog_md, name_with_ver, name_with_ver) + + +def display_schema(schema, versions): # type: (OpSchema, Sequence[OpSchema]) -> Text + s = '' + + # doc + if schema.doc: + s += '\n' + s += '\n'.join(' ' + line + for line in schema.doc.lstrip().splitlines()) + s += '\n' + + # since version + s += '\n#### Version\n' + if schema.support_level == OpSchema.SupportType.EXPERIMENTAL: + s += '\nNo versioning maintained for experimental ops.' + else: + s += '\nThis version of the operator has been ' + ('deprecated' if schema.deprecated else 'available') + ' since version {}'.format(schema.since_version) + s += ' of {}.\n'.format(display_domain(schema.domain)) + if len(versions) > 1: + # TODO: link to the Changelog.md + s += '\nOther versions of this operator: {}\n'.format( + ', '.join(display_version_link(format_name_with_domain(v.domain, v.name), + v.since_version) for v in versions[:-1])) + + # If this schema is deprecated, don't display any of the following sections + if schema.deprecated: + return s + + # attributes + if schema.attributes: + s += '\n#### Attributes\n\n' + s += '
\n' + for _, attr in sorted(schema.attributes.items()): + # option holds either required or default value + opt = '' + if attr.required: + opt = 'required' + elif attr.default_value.name: + default_value = helper.get_attribute_value(attr.default_value) + + def format_value(value): # type: (Any) -> Text + if isinstance(value, float): + formatted = str(np.round(value, 5)) + # use default formatting, unless too long. + if (len(formatted) > 10): + formatted = str("({:e})".format(value)) + return formatted + elif isinstance(value, (bytes, bytearray)) and sys.version_info[0] == 3: + return str(value.decode('utf-8')) + return str(value) + + if isinstance(default_value, list): + default_value = [format_value(val) for val in default_value] + else: + default_value = format_value(default_value) + opt = 'default is {}'.format(default_value) + + s += '
{} : {}{}
\n'.format( + attr.name, + display_attr_type(attr.type), + ' ({})'.format(opt) if opt else '') + s += '
{}
\n'.format(attr.description) + s += '
\n' + + # inputs + s += '\n#### Inputs' + if schema.min_input != schema.max_input: + s += ' ({} - {})'.format(display_number(schema.min_input), + display_number(schema.max_input)) + s += '\n\n' + if schema.inputs: + s += '
\n' + for input in schema.inputs: + option_str = "" + if OpSchema.FormalParameterOption.Optional == input.option: + option_str = " (optional)" + elif OpSchema.FormalParameterOption.Variadic == input.option: + if input.isHomogeneous: + option_str = " (variadic)" + else: + option_str = " (variadic, heterogeneous)" + s += '
{}{} : {}
\n'.format(input.name, option_str, input.typeStr) + s += '
{}
\n'.format(input.description) + s += '
\n' + + # outputs + s += '\n#### Outputs' + if schema.min_output != schema.max_output: + s += ' ({} - {})'.format(display_number(schema.min_output), + display_number(schema.max_output)) + s += '\n\n' + + if schema.outputs: + s += '
\n' + for output in schema.outputs: + option_str = "" + if OpSchema.FormalParameterOption.Optional == output.option: + option_str = " (optional)" + elif OpSchema.FormalParameterOption.Variadic == output.option: + if output.isHomogeneous: + option_str = " (variadic)" + else: + option_str = " (variadic, heterogeneous)" + s += '
{}{} : {}
\n'.format(output.name, option_str, output.typeStr) + s += '
{}
\n'.format(output.description) + s += '
\n' + + # type constraints + s += '\n#### Type Constraints' + s += '\n\n' + if schema.type_constraints: + s += '
\n' + for type_constraint in schema.type_constraints: + allowedTypes = type_constraint.allowed_type_strs + if (len(allowedTypes) > 0): + allowedTypeStr = allowedTypes[0] + for allowedType in allowedTypes[1:]: + allowedTypeStr += ', ' + allowedType + s += '
{} : {}
\n'.format( + type_constraint.type_param_str, allowedTypeStr) + s += '
{}
\n'.format(type_constraint.description) + s += '
\n' + + # Function Body + if schema.has_function: # type: ignore + s += '\n#### Function\n' + s += '\nThe Function can be represented as a function.\n' + + return s + + +def support_level_str(level): # type: (OpSchema.SupportType) -> Text + return \ + "experimental " if level == OpSchema.SupportType.EXPERIMENTAL else "" + +def convert_type(tstr) : + tfrom = np.array(['bool', 'int8', 'int16', 'int32', 'int64', + 'unkown', 'float16', 'float', 'double']) + tto =np.array(['I1', 'I8', 'I16', 'I32', 'I64', + 'BF16', 'F16', 'F32', 'F64']) + index = -1 + for i in range(len(tfrom)) : + if tfrom[i] in tstr : + index = i + break + if index == -1 : + print("error", tstr) + return '' + else : + return tto[i] + +def collect_types(schema, input) : + allowedTypeStr='' + #first step just ignore the type constraints + return allowedTypeStr + if input.typeStr : + tstr = input.typeStr + else : + return allwedTypeStr + if schema.type_constraints: + for type_constraint in schema.type_constraints: + if type_constraint.type_param_str != tstr : + continue + allowedTypes = type_constraint.allowed_type_strs + allowedTypeStr='' + if (len(allowedTypes) > 0): + t = convert_type(allowedTypes[0]) + if t == '' : + return '' + allowedTypeStr += t + for allowedType in allowedTypes[1:]: + t = convert_type(allowedType) + if t == '' : + return '' + if not t in allowedTypeStr : + allowedTypeStr += ', '+t + + return allowedTypeStr + + return allowedTypeStr + +def gen_schema(schema) : + ShapeInferenceList=['Add', 'MatMul', 'Gemm'] + CanonicalList=['Add'] + line_indent = ' ' + + #s = 'def ONNX'+schema.name+str(schema.since_version)+'Op:ONNX_Op<"'+schema.name+'", \n' + s = 'def ONNX'+schema.name+'Op:ONNX_Op<"'+schema.name+'", \n' + s += line_indent+' [NoSideEffect' + if schema.name in ShapeInferenceList : + s+= ', DeclareOpInterfaceMethods' + s += ']> {' + + if schema.name in CanonicalList: + s += '\n'+line_indent+'let hasCanonicalizer = 1;' + + #summary + s += '\n'+line_indent + s += 'let summary = "ONNX '+schema.name+' operation";' + + #description + s += '\n'+line_indent + s += 'let description = [{' + if schema.doc: + """ + s += '\n'.join(line_indent + line + for line in schema.doc.lstrip().splitlines()) + """ + for line in schema.doc.lstrip().splitlines(): + line = line.replace('}]', '\}\]') + s += '\n'+line_indent+' '+'"'+line+'"' + else : + s += '\n'+line_indent*2 +'no doc for this op from onnx' + s += '\n'+line_indent+'}];' + + #input + s+= '\n'+line_indent+'let arguments = (ins ' + if schema.inputs: + for input in schema.inputs: + if input != schema.inputs[0] : + s+= ', ' + etypes=collect_types(schema, input) + + if OpSchema.FormalParameterOption.Optional == input.option: + #TODO: handle optional + print("optional ", input.name) + elif OpSchema.FormalParameterOption.Variadic == input.option: + if input.isHomogeneous: + s+= 'Variadic<' + else: + #TODO handle (variadic, heterogeneous)" + print('variadic, heterogeneous', input.name) + if etypes == '': + s+= 'AnyTensor' + else: + s+= 'TensorOf<['+etypes+']>' + + if OpSchema.FormalParameterOption.Optional == input.option: + #TODO: handle optional + t='' + elif OpSchema.FormalParameterOption.Variadic == input.option: + if input.isHomogeneous: + s+= '>' + else: + #TODO handle (variadic, heterogeneous)" + t='' + s+=':$'+input.name + s+= ');' + + #output + s+= '\n'+line_indent+'let results = (outs ' + if schema.outputs: + for output in schema.outputs: + if output != schema.outputs[0] : + s+= ', ' + #need to interpret output.typeStr + etypes=collect_types(schema, output) + if etypes == '': + s+= 'AnyTensor' + else: + s+= 'TensorOf<['+etypes+']>' + s+= ');' + + #s+= 'let hasCanonicalizer = 1;' + + s += '\n}\n\n' + + return s + +def main(args): # type: (Type[Args]) -> None + with io.open(args.changelog, 'w', newline='') as fout: + fout.write('## Operator Changelog\n') + fout.write( + "*This file is automatically generated from the\n" + " [def files](/onnx/defs) via [this script](/onnx/defs/gen_doc.py).\n" + " Do not modify directly and instead edit operator definitions.*\n") + + # domain -> version -> [schema] + dv_index = defaultdict(lambda: defaultdict(list)) # type: Dict[Text, Dict[int, List[OpSchema]]] + for schema in defs.get_all_schemas_with_history(): + dv_index[schema.domain][schema.since_version].append(schema) + + fout.write('\n') + + for domain, versionmap in sorted(dv_index.items()): + print("domain", domain) + if not should_render_domain(domain): + continue + + s = '# {}\n'.format(display_domain_short(domain)) + + for version, unsorted_schemas in sorted(versionmap.items()): + s += '## Version {} of {}\n'.format(version, display_domain(domain)) + for schema in sorted(unsorted_schemas, key=lambda s: s.name): + name_with_ver = '{}-{}'.format(format_name_with_domain(domain, schema.name), + schema.since_version) + s += ('### **{}**' + (' (deprecated)' if schema.deprecated else '') + '\n').format(name_with_ver, name_with_ver) + s += display_schema(schema, [schema]) + s += '\n' + + fout.write(s) + + with io.open(args.output, 'w', newline='', encoding="utf-8") as fout: + fout.write('## Operator Schemas\n') + fout.write( + "*This file is automatically generated from the\n" + " [def files](/onnx/defs) via [this script](/onnx/defs/gen_doc.py).\n" + " Do not modify directly and instead edit operator definitions.*\n") + + # domain -> support level -> name -> [schema] + index = defaultdict(lambda: defaultdict(lambda: defaultdict(list))) # type: Dict[Text, Dict[int, Dict[Text, List[OpSchema]]]] + for schema in defs.get_all_schemas_with_history(): + #print("check point 0", schema.name, schema.domain, schema.support_level) + #gen_schema(schema) + index[schema.domain][int(schema.support_level)][schema.name].append(schema) + + fout.write('\n') + + # Preprocess the Operator Schemas + # [(domain, [(support_level, [(schema name, current schema, all versions schemas)])])] + operator_schemas = list() # type: List[Tuple[Text, List[Tuple[int, List[Tuple[Text, OpSchema, List[OpSchema]]]]]]] + exsting_ops = set() # type: Set[Text] + for domain, _supportmap in sorted(index.items()): + if not should_render_domain(domain): + continue + + processed_supportmap = list() + for _support, _namemap in sorted(_supportmap.items()): + processed_namemap = list() + for n, unsorted_versions in sorted(_namemap.items()): + versions = sorted(unsorted_versions, key=lambda s: s.since_version) + schema = versions[-1] + #print("check point 2", schema) + if schema.name in exsting_ops: + continue + exsting_ops.add(schema.name) + processed_namemap.append((n, schema, versions)) + processed_supportmap.append((_support, processed_namemap)) + operator_schemas.append((domain, processed_supportmap)) + + # Table of contents + for domain, supportmap in operator_schemas: + s = '* {}\n'.format(display_domain_short(domain)) + fout.write(s) + function_ops = list() + for _, namemap in supportmap: + for n, schema, versions in namemap: + if schema.has_function: # type: ignore + function_ops.append((n, schema, versions)) + continue + s = ' * {}{}\n'.format( + support_level_str(schema.support_level), + format_name_with_domain(domain, n), + format_name_with_domain(domain, n)) + fout.write(s) + if len(function_ops): + fout.write('\n') + fout.write(' **Operators with function registered:**\n') + for n, schema, versions in function_ops: + s = ' * {}{}\n'.format( + support_level_str(schema.support_level), + format_name_with_domain(domain, n), + format_name_with_domain(domain, n)) + fout.write(s) + + fout.write('\n') + tdfile= io.open(args.tdfile, 'w', newline='') + fefile=io.open('op_build_table.inc', 'w', newline='') + firstfunc = True + + for domain, supportmap in operator_schemas: + s = '## {}\n'.format(display_domain_short(domain)) + fout.write(s) + + for _, namemap in supportmap: + for op_type, schema, versions in namemap: + # op_type + #print("check point 1", schema.name, len(schema.inputs), len(schema.outputs)) + if firstfunc : + fefile.write(' '+'if (OpName == "'+schema.name+'") {\n') + firstfunc = False + else : + fefile.write(' '+'}else if (OpName == "'+schema.name+'") {\n') + if len(schema.outputs) > 1 : + fefile.write(' '+'MultipleOuts('+schema.name+', ' + +str(schema.since_version)+', ' + +str(len(schema.inputs))+', ' + +str(len(schema.outputs))+');\n') + else : + fefile.write(' '+'OneOut('+schema.name+', ' + +str(schema.since_version)+', ' + +str(len(schema.inputs))+', ' + +str(len(schema.outputs))+');\n') + r = gen_schema(schema) + tdfile.write(r) + s = ('### {}**{}**' + (' (deprecated)' if schema.deprecated else '') + '\n').format( + support_level_str(schema.support_level), + format_name_with_domain(domain, op_type), + format_name_with_domain(domain, op_type.lower()), + format_name_with_domain(domain, op_type)) + + s += display_schema(schema, versions) + + s += '\n\n' + + if op_type in SNIPPETS: + s += '#### Examples\n\n' + for summary, code in sorted(SNIPPETS[op_type]): + s += '
\n' + s += '{}\n\n'.format(summary) + s += '```python\n{}\n```\n\n'.format(code) + s += '
\n' + s += '\n\n' + if op_type.lower() in SAMPLE_IMPLEMENTATIONS: + s += '#### Sample Implementation\n\n' + s += '
\n' + s += '{}\n\n'.format(op_type) + s += '```python\n{}\n```\n\n'.format(SAMPLE_IMPLEMENTATIONS[op_type.lower()]) + s += '
\n' + s += '\n\n' + + fout.write(s) + fefile.write(' }') + fefile.close() + + +if __name__ == '__main__': + base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) + docs_dir = os.path.join(base_dir, 'docs') + print(docs_dir) + + class Args(object): + output = os.path.join(docs_dir, 'Operators' + ext) + changelog = os.path.join(docs_dir, 'Changelog' + ext) + tdfile = os.path.join(docs_dir, 'onnxop.inc') + print(Args) + main(Args) diff --git a/src/compiler/dialect/onnx/onnx.td b/src/compiler/dialect/onnx/onnx.td index c4150b7..0ca302e 100644 --- a/src/compiler/dialect/onnx/onnx.td +++ b/src/compiler/dialect/onnx/onnx.td @@ -39,66 +39,36 @@ class ONNX_Op traits = []> : // ONNX Operations //===----------------------------------------------------------------------===// -// We define an ONNX operation for adding two tensors elementwise. -def ONNXAddOp: ONNX_Op<"add", - [NoSideEffect, DeclareOpInterfaceMethods]> { - let summary = "ONNX add operation"; - let description = [{ +//the tablegen code onnxop.in is generated with gen_doc.py +//clone and install onnx +// git clone --recursive https://github.com/onnx/onnx.git +// set up env for anaconda3 and for DLC (BOOSTROOT, cmake, gcc ...) +// cd onnx +//install onnx +// CC=gcc CXX=g++ pip install -e . +//run the script +// python onnx/defs/gen_doc.py +//result is in docs/onnxop.inc +//current limitations: +// 1. Attributes are not processed +// 2. output type inference not implemented except Add +// 3. Type Attribute: 'optional' and 'Variadic hetergeneous' are ignored +// 4. type of string, complex64 and complex128 for input/output are ignored +// 5. unsigned int are treated as signed one - The "onnx.add" adds two tensors element-wise. +include "dialect/onnx/onnxop.inc" - }]; +def ONNXFullGemmOp: ONNX_Op<"full_gemm", + [NoSideEffect, DeclareOpInterfaceMethods]> { + let summary = "ONNX general matrix multiply operation"; + let description = [{ - // TODO: AnyTensor might be too wide for ONNX and may need to be constrained - // to fewer valid types. - // In the ONNX spec: - // T : tensor(uint32), tensor(uint64), - // tensor(int32), tensor(int64), - // tensor(float16), tensor(float), tensor(double) - // - let arguments = (ins AnyTensor:$lhs_in, AnyTensor:$rhs_in); - let results = (outs AnyTensor); - let hasCanonicalizer = 1; -} + The "onnx.gemm" generic matrix multiplication with bias. -def ONNXMatMulOp: ONNX_Op<"matmul", - [NoSideEffect, DeclareOpInterfaceMethods]> { - let summary = "ONNX matrix multiply operation"; - let description = [{ + }]; - The "onnx.mul" multiplies two matrices. - - }]; - - let arguments = (ins AnyTypeOf<[F32Tensor, F64Tensor]>:$lhs_in, - AnyTypeOf<[F32Tensor, F64Tensor]>:$rhs_in); - let results = (outs AnyTypeOf<[F32Tensor, F64Tensor]>); -} - -def ONNXGemmOp: ONNX_Op<"gemm", - [NoSideEffect, DeclareOpInterfaceMethods]> { - let summary = "ONNX general matrix multiply operation"; - let description = [{ - - The "onnx.gemm" generic matrix multiplication with bias. - - }]; - - let arguments = (ins Variadic:$inputs); - let results = (outs AnyTensor); -} - -def ONNXFullGemmOp: ONNX_Op<"full_gemm", - [NoSideEffect, DeclareOpInterfaceMethods]> { - let summary = "ONNX general matrix multiply operation"; - let description = [{ - - The "onnx.gemm" generic matrix multiplication with bias. - - }]; - - let arguments = (ins AnyTensor:$lhs_in, AnyTensor:$rhs_in, AnyTensor:$bias_in); - let results = (outs AnyTensor); + let arguments = (ins AnyTensor:$lhs_in, AnyTensor:$rhs_in, AnyTensor:$bias_in); + let results = (outs AnyTensor); } #endif // ONNX_OPS diff --git a/src/compiler/dialect/onnx/onnx_ops.cpp b/src/compiler/dialect/onnx/onnx_ops.cpp index 6d79313..1a5cd6e 100644 --- a/src/compiler/dialect/onnx/onnx_ops.cpp +++ b/src/compiler/dialect/onnx/onnx_ops.cpp @@ -39,9 +39,9 @@ ONNXOpsDialect::ONNXOpsDialect(mlir::MLIRContext* ctx) //===----------------------------------------------------------------------===// // ONNX Operations //===----------------------------------------------------------------------===// - // Add - +/// Infer the output shape of the ONNXAddOp. This method is required by the +/// shape inference interface. void ONNXAddOp::inferShapes() { getResult()->setType(getOperand(0)->getType()); } diff --git a/src/compiler/dialect/onnx/onnxop.inc b/src/compiler/dialect/onnx/onnxop.inc new file mode 100644 index 0000000..a0b0f20 --- /dev/null +++ b/src/compiler/dialect/onnx/onnxop.inc @@ -0,0 +1,3234 @@ +def ONNXAbsOp:ONNX_Op<"Abs", + [NoSideEffect]> { + let summary = "ONNX Abs operation"; + let description = [{ + "Absolute takes one input data (Tensor) and produces one output data" + "(Tensor) where the absolute is, y = abs(x), is applied to" + "the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXAcosOp:ONNX_Op<"Acos", + [NoSideEffect]> { + let summary = "ONNX Acos operation"; + let description = [{ + "Calculates the arccosine (inverse of cosine) of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXAcoshOp:ONNX_Op<"Acosh", + [NoSideEffect]> { + let summary = "ONNX Acosh operation"; + let description = [{ + "Calculates the hyperbolic arccosine of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXAddOp:ONNX_Op<"Add", + [NoSideEffect, DeclareOpInterfaceMethods]> { + let hasCanonicalizer = 1; + let summary = "ONNX Add operation"; + let description = [{ + "Performs element-wise binary addition (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXAndOp:ONNX_Op<"And", + [NoSideEffect]> { + let summary = "ONNX And operation"; + let description = [{ + "Returns the tensor resulted from performing the `and` logical operation" + "elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXArgMaxOp:ONNX_Op<"ArgMax", + [NoSideEffect]> { + let summary = "ONNX ArgMax operation"; + let description = [{ + "Computes the indices of the max elements of the input tensor's element along the " + "provided axis. The resulted tensor has the same rank as the input if keepdims equal 1." + "If keepdims equal 0, then the resulted tensor have the reduced dimension pruned. " + "The type of the output tensor is integer." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXArgMinOp:ONNX_Op<"ArgMin", + [NoSideEffect]> { + let summary = "ONNX ArgMin operation"; + let description = [{ + "Computes the indices of the min elements of the input tensor's element along the " + "provided axis. The resulted tensor has the same rank as the input if keepdims equal 1." + "If keepdims equal 0, then the resulted tensor have the reduced dimension pruned. " + "The type of the output tensor is integer." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXAsinOp:ONNX_Op<"Asin", + [NoSideEffect]> { + let summary = "ONNX Asin operation"; + let description = [{ + "Calculates the arcsine (inverse of sine) of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXAsinhOp:ONNX_Op<"Asinh", + [NoSideEffect]> { + let summary = "ONNX Asinh operation"; + let description = [{ + "Calculates the hyperbolic arcsine of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXAtanOp:ONNX_Op<"Atan", + [NoSideEffect]> { + let summary = "ONNX Atan operation"; + let description = [{ + "Calculates the arctangent (inverse of tangent) of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXAtanhOp:ONNX_Op<"Atanh", + [NoSideEffect]> { + let summary = "ONNX Atanh operation"; + let description = [{ + "Calculates the hyperbolic arctangent of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXAveragePoolOp:ONNX_Op<"AveragePool", + [NoSideEffect]> { + let summary = "ONNX AveragePool operation"; + let description = [{ + "AveragePool consumes an input tensor X and applies average pooling across" + " the tensor according to kernel sizes, stride sizes, and pad lengths." + " average pooling consisting of computing the average on all values of a" + " subset of the input tensor according to the kernel size and downsampling the" + " data into the output tensor Y for further processing. The output spatial shape will be following:" + " ```" + " output_spatial_shape[i] = floor((input_spatial_shape[i] + pad_shape[i] - kernel_spatial_shape[i]) / strides_spatial_shape[i] + 1)" + " ```" + " or" + " ```" + " output_spatial_shape[i] = ceil((input_spatial_shape[i] + pad_shape[i] - kernel_spatial_shape[i]) / strides_spatial_shape[i] + 1)" + " ```" + " if ceil_mode is enabled" + "" + " ```" + " * pad_shape[i] is sum of pads along axis i" + " ```" + "" + " `auto_pad` is a DEPRECATED attribute. If you are using them currently, the output spatial shape will be following:" + " ```" + " VALID: output_spatial_shape[i] = ceil((input_spatial_shape[i] - kernel_spatial_shape[i] + 1) / strides_spatial_shape[i])" + " SAME_UPPER or SAME_LOWER: output_spatial_shape[i] = ceil(input_spatial_shape[i] / strides_spatial_shape[i])" + " ```" + " And pad shape will be following if `SAME_UPPER` or `SAME_LOWER`:" + " ```" + " pad_shape[i] = (output_spatial_shape[i] - 1) * strides_spatial_shape[i] + kernel_spatial_shape[i] - input_spatial_shape[i]" + " ```" + " The output of each pooling window is divided by the number of elements (exclude pad when attribute count_include_pad is zero)." + " " + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXBatchNormalizationOp:ONNX_Op<"BatchNormalization", + [NoSideEffect]> { + let summary = "ONNX BatchNormalization operation"; + let description = [{ + "Carries out batch normalization as described in the paper" + "https://arxiv.org/abs/1502.03167. Depending on the mode it is being run," + "there are multiple cases for the number of outputs, which we list below:" + "" + "Output case #1: Y, mean, var, saved_mean, saved_var (training mode)" + "Output case #2: Y (test mode)" + "" + "For previous (depreciated) non-spatial cases, implementors are suggested" + "to flatten the input shape to (N x C*D1*D2 ..*Dn) before a BatchNormalization Op." + "This operator has **optional** inputs/outputs. See [the doc](IR.md) for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$scale, AnyTensor:$B, AnyTensor:$mean, AnyTensor:$var); + let results = (outs AnyTensor, AnyTensor, AnyTensor, AnyTensor, AnyTensor); +} + +def ONNXBitShiftOp:ONNX_Op<"BitShift", + [NoSideEffect]> { + let summary = "ONNX BitShift operation"; + let description = [{ + "Bitwise shift operator performs element-wise operation. For each input element, if the" + " attribute "direction" is "RIGHT", this operator moves its binary representation toward" + " the right side so that the input value is effectively decreased. If the attribute "direction"" + " is "LEFT", bits of binary representation moves toward the left side, which results the" + " increase of its actual value. The input X is the tensor to be shifted and another input" + " Y specifies the amounts of shifting. For example, if "direction" is "Right", X is [1, 4]," + " and S is [1, 1], the corresponding output Z would be [0, 2]. If "direction" is "LEFT" with" + " X=[1, 2] and S=[1, 2], the corresponding output Y would be [2, 8]." + " " + " Because this operator supports Numpy-style broadcasting, X's and Y's shapes are" + " not necessarily identical." + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$Y); + let results = (outs AnyTensor); +} + +def ONNXCastOp:ONNX_Op<"Cast", + [NoSideEffect]> { + let summary = "ONNX Cast operation"; + let description = [{ + "The operator casts the elements of a given input tensor to a data type" + "specified by the 'to' argument and returns an output tensor of the same size in" + "the converted type. The 'to' argument must be one of the data types specified" + "in the 'DataType' enum field in the TensorProto message." + "" + "Casting from string tensor in plain (e.g., "3.14" and "1000") and scientific numeric representations" + "(e.g., "1e-5" and "1E8") to float types is supported. For example, converting string "100.5" to an integer may" + "result 100. There are some string literals reserved for special floating-point values;" + ""+INF" (and "INF"), "-INF", and "NaN" are positive infinity, negative infinity, and not-a-number, respectively." + "Any string which can exactly match "+INF" in a case-insensitive way would be mapped to positive infinite. Similarly," + "this case-insensitive rule is applied to "INF" and "NaN". When casting from numeric tensors" + "to string tensors, plain floating-point representation (such as "314.15926") would be used. " + "Converting non-numerical-literal string such as "Hello World!" is an undefined behavior. Cases " + "of converting string representing floating-point arithmetic value, such as "2.718", to INT is an undefined behavior." + "" + "Conversion from a numerical type to any numerical type is always allowed." + "User must be aware of precision loss and value change caused by range difference between two types." + "For example, a 64-bit float 3.1415926459 may be round to a 32-bit float 3.141592. Similarly, converting" + "an integer 36 to Boolean may produce 1 because we truncate bits which can't be stored in the targeted type." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXCeilOp:ONNX_Op<"Ceil", + [NoSideEffect]> { + let summary = "ONNX Ceil operation"; + let description = [{ + "Ceil takes one input data (Tensor) and produces one output data" + "(Tensor) where the ceil is, y = ceil(x), is applied to" + "the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXClipOp:ONNX_Op<"Clip", + [NoSideEffect]> { + let summary = "ONNX Clip operation"; + let description = [{ + "Clip operator limits the given input within an interval. The interval is" + "specified by the inputs 'min' and 'max'. They default to" + "numeric_limits::lowest() and numeric_limits::max(), respectively." + }]; + let arguments = (ins AnyTensor:$input, AnyTensor:$min, AnyTensor:$max); + let results = (outs AnyTensor); +} + +def ONNXCompressOp:ONNX_Op<"Compress", + [NoSideEffect]> { + let summary = "ONNX Compress operation"; + let description = [{ + "Selects slices from an input tensor along a given axis where condition evaluates to True for each axis index." + " In case axis is not provided, input is flattened before elements are selected." + " Compress behaves like numpy.compress: https://docs.scipy.org/doc/numpy/reference/generated/numpy.compress.html" + " " + }]; + let arguments = (ins AnyTensor:$input, AnyTensor:$condition); + let results = (outs AnyTensor); +} + +def ONNXConcatOp:ONNX_Op<"Concat", + [NoSideEffect]> { + let summary = "ONNX Concat operation"; + let description = [{ + "Concatenate a list of tensors into a single tensor. All input tensors must have the same shape, except for the dimension size of the axis to concatenate on." + }]; + let arguments = (ins Variadic:$inputs); + let results = (outs AnyTensor); +} + +def ONNXConcatFromSequenceOp:ONNX_Op<"ConcatFromSequence", + [NoSideEffect]> { + let summary = "ONNX ConcatFromSequence operation"; + let description = [{ + "Concatenate a sequence of tensors into a single tensor." + "All input tensors must have the same shape, except for the dimension size of the axis to concatenate on." + "By default 'new_axis' is 0, the behavior is similar to numpy.concatenate." + "When 'new_axis' is 1, the behavior is similar to numpy.stack." + }]; + let arguments = (ins AnyTensor:$input_sequence); + let results = (outs AnyTensor); +} + +def ONNXConstantOp:ONNX_Op<"Constant", + [NoSideEffect]> { + let summary = "ONNX Constant operation"; + let description = [{ + "A constant tensor. Exactly one of the two attributes, either value or sparse_value," + "must be specified." + }]; + let arguments = (ins ); + let results = (outs AnyTensor); +} + +def ONNXConstantOfShapeOp:ONNX_Op<"ConstantOfShape", + [NoSideEffect]> { + let summary = "ONNX ConstantOfShape operation"; + let description = [{ + "Generate a tensor with given value and shape." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXConvOp:ONNX_Op<"Conv", + [NoSideEffect]> { + let summary = "ONNX Conv operation"; + let description = [{ + "The convolution operator consumes an input tensor and a filter, and" + "computes the output." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$W, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXConvIntegerOp:ONNX_Op<"ConvInteger", + [NoSideEffect]> { + let summary = "ONNX ConvInteger operation"; + let description = [{ + "The integer convolution operator consumes an input tensor, its zero-point, a filter, and its zero-point," + "and computes the output. The production MUST never overflow. The accumulation may overflow if and only if in 32 bits." + }]; + let arguments = (ins AnyTensor:$x, AnyTensor:$w, AnyTensor:$x_zero_point, AnyTensor:$w_zero_point); + let results = (outs AnyTensor); +} + +def ONNXConvTransposeOp:ONNX_Op<"ConvTranspose", + [NoSideEffect]> { + let summary = "ONNX ConvTranspose operation"; + let description = [{ + "The convolution transpose operator consumes an input tensor and a filter," + "and computes the output." + "" + "If the pads parameter is provided the shape of the output is calculated via the following equation:" + "" + " output_shape[i] = stride[i] * (input_size[i] - 1) + output_padding[i] + ((kernel_shape[i] - 1) * dilations[i] + 1) - pads[start_i] - pads[end_i]" + "" + "output_shape can also be explicitly specified in which case pads values are auto generated using these equations:" + "" + " total_padding[i] = stride[i] * (input_size[i] - 1) + output_padding[i] + ((kernel_shape[i] - 1) * dilations[i] + 1) - output_shape[i]" + " If (auto_pads != SAME_UPPER): pads[start_i] = total_padding[i]/2; pads[end_i] = total_padding[i] - (total_padding[i]/2)" + " Else: pads[start_i] = total_padding[i] - (total_padding[i]/2); pads[end_i] = (total_padding[i]/2)." + "" + " " + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$W, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXCosOp:ONNX_Op<"Cos", + [NoSideEffect]> { + let summary = "ONNX Cos operation"; + let description = [{ + "Calculates the cosine of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXCoshOp:ONNX_Op<"Cosh", + [NoSideEffect]> { + let summary = "ONNX Cosh operation"; + let description = [{ + "Calculates the hyperbolic cosine of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXCumSumOp:ONNX_Op<"CumSum", + [NoSideEffect]> { + let summary = "ONNX CumSum operation"; + let description = [{ + "Performs cumulative sum of the input elements along the given axis." + "By default, it will do the sum inclusively meaning the first element is copied as is." + "Through an `exclusive` attribute, this behavior can change to exclude the first element." + "It can also perform summation in the opposite direction of the axis. For that, set `reverse` attribute to 1." + "" + "Example:" + "```" + "input_x = [1, 2, 3]" + "axis=0" + "output = [1, 3, 6]" + "exclusive=1" + "output = [0, 1, 3]" + "exclusive=0" + "reverse=1" + "output = [6, 5, 3]" + "exclusive=1" + "reverse=1" + "output = [5, 3, 0]" + "```" + " " + }]; + let arguments = (ins AnyTensor:$x, AnyTensor:$axis); + let results = (outs AnyTensor); +} + +def ONNXDepthToSpaceOp:ONNX_Op<"DepthToSpace", + [NoSideEffect]> { + let summary = "ONNX DepthToSpace operation"; + let description = [{ + "DepthToSpace rearranges (permutes) data from depth into blocks of spatial data." + "This is the reverse transformation of SpaceToDepth. More specifically, this op outputs a copy of" + "the input tensor where values from the depth dimension are moved in spatial blocks to the height" + "and width dimensions. By default, `mode` = `DCR`." + "In the DCR mode, elements along the depth dimension from the input tensor are rearranged in the" + "following order: depth, column, and then row. The output y is computed from the input x as below:" + "" + "b, c, h, w = x.shape" + "" + "tmp = np.reshape(x, [b, blocksize, blocksize, c // (blocksize**2), h, w])" + "" + "tmp = np.transpose(tmp, [0, 3, 4, 1, 5, 2])" + "" + "y = np.reshape(tmp, [b, c // (blocksize**2), h * blocksize, w * blocksize])" + "" + "" + "In the CRD mode, elements along the depth dimension from the input tensor are rearranged in the" + "following order: column, row, and the depth. The output y is computed from the input x as below:" + "" + "b, c, h, w = x.shape" + "" + "tmp = np.reshape(x, [b, c // (blocksize ** 2), blocksize, blocksize, h, w])" + "" + "tmp = np.transpose(tmp, [0, 1, 4, 2, 5, 3])" + "" + "y = np.reshape(tmp, [b, c // (blocksize ** 2), h * blocksize, w * blocksize])" + "" + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXDequantizeLinearOp:ONNX_Op<"DequantizeLinear", + [NoSideEffect]> { + let summary = "ONNX DequantizeLinear operation"; + let description = [{ + "The linear dequantization operator. It consumes a quantized tensor, a scale, a zero point to compute the full precision tensor." + "The dequantization formula is y = (x - x_zero_point) * x_scale. 'x_scale' and 'x_zero_point' must have same shape." + "'x_zero_point' and 'x' must have same type. 'x' and 'y' must have same shape. In the case of dequantizing int32," + "there's no zero point (zero point is supposed to be 0)." + }]; + let arguments = (ins AnyTensor:$x, AnyTensor:$x_scale, AnyTensor:$x_zero_point); + let results = (outs AnyTensor); +} + +def ONNXDetOp:ONNX_Op<"Det", + [NoSideEffect]> { + let summary = "ONNX Det operation"; + let description = [{ + "Det calculates determinant of a square matrix or batches of square matrices." + "Det takes one input tensor of shape `[*, M, M]`, where `*` is zero or more batch dimensions," + "and the inner-most 2 dimensions form square matrices." + "The output is a tensor of shape `[*]`, containing the determinants of all input submatrices." + "e.g., When the input is 2-D, the output is a scalar(shape is empty: `[]`)." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXDivOp:ONNX_Op<"Div", + [NoSideEffect]> { + let summary = "ONNX Div operation"; + let description = [{ + "Performs element-wise binary division (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXDropoutOp:ONNX_Op<"Dropout", + [NoSideEffect]> { + let summary = "ONNX Dropout operation"; + let description = [{ + "Dropout takes one input floating tensor and produces two tensor outputs," + "output (floating tensor) and mask (`Tensor`). Depending on whether it is" + "in test mode or not, the output Y will either be a random dropout, or a simple" + "copy of the input. Note that our implementation of Dropout does scaling in" + "the training phase, so during testing nothing needs to be done." + "This operator has **optional** inputs/outputs. See [the doc](IR.md) for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor, AnyTensor); +} + +def ONNXDynamicQuantizeLinearOp:ONNX_Op<"DynamicQuantizeLinear", + [NoSideEffect]> { + let summary = "ONNX DynamicQuantizeLinear operation"; + let description = [{ + "A Function to fuse calculation for Scale, Zero Point and FP32->8Bit convertion of FP32 Input data." + "Outputs Scale, ZeroPoint and Quantized Input for a given FP32 Input." + "Scale is calculated as:" + "```" + " y_scale = (max(x) - min(x))/(qmax - qmin)" + " * where qmax and qmin are max and min values for quantization range .i.e [0, 255] in case of uint8" + " * data range is adjusted to include 0." + "```" + "Zero point is calculated as:" + "```" + "intermediate_zero_point = (qmin - min(x))/(qmax - qmin)" + "y_zero_point = cast(round(saturate(itermediate_zero_point)))" + "* where qmax and qmin are max and min values for quantization range .i.e [0, 255] in case of uint8" + "* for saturation, it saturates to [0, 255] if it's uint8, or [-127, 127] if it's int8. Right now only uint8 is supported." + "* rounding to nearest ties to even." + "```" + "Data quantization formula is:" + "```" + "y = saturate (round (x / y_scale) + y_zero_point)" + "* for saturation, it saturates to [0, 255] if it's uint8, or [-127, 127] if it's int8. Right now only uint8 is supported." + "* rounding to nearest ties to even." + "```" + }]; + let arguments = (ins AnyTensor:$x); + let results = (outs AnyTensor, AnyTensor, AnyTensor); +} + +def ONNXEluOp:ONNX_Op<"Elu", + [NoSideEffect]> { + let summary = "ONNX Elu operation"; + let description = [{ + "Elu takes one input data (Tensor) and produces one output data" + "(Tensor) where the function `f(x) = alpha * (exp(x) - 1.) for x <" + "0`, `f(x) = x for x >= 0`., is applied to the tensor elementwise." + "" + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXEqualOp:ONNX_Op<"Equal", + [NoSideEffect]> { + let summary = "ONNX Equal operation"; + let description = [{ + "Returns the tensor resulted from performing the `equal` logical operation" + "elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXErfOp:ONNX_Op<"Erf", + [NoSideEffect]> { + let summary = "ONNX Erf operation"; + let description = [{ + "Computes the error function of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXExpOp:ONNX_Op<"Exp", + [NoSideEffect]> { + let summary = "ONNX Exp operation"; + let description = [{ + "Calculates the exponential of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXExpandOp:ONNX_Op<"Expand", + [NoSideEffect]> { + let summary = "ONNX Expand operation"; + let description = [{ + "Broadcast the input tensor following the given shape and the broadcast rule." + "The broadcast rule is similar to numpy.array(input) * numpy.ones(shape):" + "Dimensions are right alignment;" + "Two corresponding dimension must have the same value, or one of them is equal to 1." + "Also, this operator is similar to numpy.broadcast_to(input, shape)," + "but the major difference is numpy.broadcast_to() does not allow shape to be smaller than input.size()." + "It is possible that the output.shape is not equal to shape, when some dimensions in shape is equal to 1," + "or the shape.ndim < input.shape.ndim." + }]; + let arguments = (ins AnyTensor:$input, AnyTensor:$shape); + let results = (outs AnyTensor); +} + +def ONNXEyeLikeOp:ONNX_Op<"EyeLike", + [NoSideEffect]> { + let summary = "ONNX EyeLike operation"; + let description = [{ + "Generate a 2D tensor (matrix) with ones on the diagonal and zeros everywhere else. Only 2D" + "tensors are supported, i.e. input T1 must be of rank 2. The shape of the output tensor is the" + "same as the input tensor. The data type can be specified by the 'dtype' argument. If" + "'dtype' is not specified, then the type of input tensor is used. By default, the main diagonal" + "is populated with ones, but attribute 'k' can be used to populate upper or lower diagonals." + "The 'dtype' argument must be one of the data types specified in the 'DataType' enum field in the" + "TensorProto message and be valid as an output type." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXFlattenOp:ONNX_Op<"Flatten", + [NoSideEffect]> { + let summary = "ONNX Flatten operation"; + let description = [{ + "Flattens the input tensor into a 2D matrix. If input tensor has shape" + "(d_0, d_1, ... d_n) then the output will have shape" + "(d_0 X d_1 ... d_(axis-1), d_axis X d_(axis+1) ... X dn)." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXFloorOp:ONNX_Op<"Floor", + [NoSideEffect]> { + let summary = "ONNX Floor operation"; + let description = [{ + "Floor takes one input data (Tensor) and produces one output data" + "(Tensor) where the floor is, y = floor(x), is applied to" + "the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXGRUOp:ONNX_Op<"GRU", + [NoSideEffect]> { + let summary = "ONNX GRU operation"; + let description = [{ + "Computes an one-layer GRU. This operator is usually supported via some custom" + "implementation such as CuDNN." + "" + "Notations:" + "" + "`X` - input tensor" + "" + "`z` - update gate" + "" + "`r` - reset gate" + "" + "`h` - hidden gate" + "" + "`t` - time step (t-1 means previous time step)" + "" + "`W[zrh]` - W parameter weight matrix for update, reset, and hidden gates" + "" + "`R[zrh]` - R recurrence weight matrix for update, reset, and hidden gates" + "" + "`Wb[zrh]` - W bias vectors for update, reset, and hidden gates" + "" + "`Rb[zrh]` - R bias vectors for update, reset, and hidden gates" + "" + "`WB[zrh]` - W parameter weight matrix for backward update, reset, and hidden gates" + "" + "`RB[zrh]` - R recurrence weight matrix for backward update, reset, and hidden gates" + "" + "`WBb[zrh]` - W bias vectors for backward update, reset, and hidden gates" + "" + "`RBb[zrh]` - R bias vectors for backward update, reset, and hidden gates" + "" + "`H` - Hidden state" + "" + "`num_directions` - 2 if direction == bidirectional else 1" + "" + "Activation functions:" + "" + " Relu(x) - max(0, x)" + "" + " Tanh(x) - (1 - e^{-2x})/(1 + e^{-2x})" + "" + " Sigmoid(x) - 1/(1 + e^{-x})" + "" + " (NOTE: Below are optional)" + "" + " Affine(x) - alpha*x + beta" + "" + " LeakyRelu(x) - x if x >= 0 else alpha * x" + "" + " ThresholdedRelu(x) - x if x >= alpha else 0" + "" + " ScaledTanh(x) - alpha*Tanh(beta*x)" + "" + " HardSigmoid(x) - min(max(alpha*x + beta, 0), 1)" + "" + " Elu(x) - x if x >= 0 else alpha*(e^x - 1)" + "" + " Softsign(x) - x/(1 + |x|)" + "" + " Softplus(x) - log(1 + e^x)" + "" + "Equations (Default: f=Sigmoid, g=Tanh):" + "" + " - zt = f(Xt*(Wz^T) + Ht-1*(Rz^T) + Wbz + Rbz)" + "" + " - rt = f(Xt*(Wr^T) + Ht-1*(Rr^T) + Wbr + Rbr)" + "" + " - ht = g(Xt*(Wh^T) + (rt (.) Ht-1)*(Rh^T) + Rbh + Wbh) # default, when linear_before_reset = 0" + "" + " - ht = g(Xt*(Wh^T) + (rt (.) (Ht-1*(Rh^T) + Rbh)) + Wbh) # when linear_before_reset != 0" + "" + " - Ht = (1 - zt) (.) ht + zt (.) Ht-1" + "This operator has **optional** inputs/outputs. See [the doc](IR.md) for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$W, AnyTensor:$R, AnyTensor:$B, AnyTensor:$sequence_lens, AnyTensor:$initial_h); + let results = (outs AnyTensor, AnyTensor); +} + +def ONNXGatherOp:ONNX_Op<"Gather", + [NoSideEffect]> { + let summary = "ONNX Gather operation"; + let description = [{ + "Given `data` tensor of rank r >= 1, and `indices` tensor of rank q, gather" + "entries of the axis dimension of `data` (by default outer-most one as axis=0) indexed by `indices`, and concatenates" + "them in an output tensor of rank q + (r - 1)." + "" + "axis = 0 :" + "" + "Let" + "k = indices[i_{0}, ..., i_{q-1\}\]" + "Then" + "output[i_{0}, ..., i_{q-1}, j_{0}, ..., j_{r-2\}\] = input[k , j_{0}, ..., j_{r-2\}\]" + "" + "```" + " data = [" + " [1.0, 1.2]," + " [2.3, 3.4]," + " [4.5, 5.7]," + " ]" + " indices = [" + " [0, 1]," + " [1, 2]," + " ]" + " output = [" + " [" + " [1.0, 1.2]," + " [2.3, 3.4]," + " ]," + " [" + " [2.3, 3.4]," + " [4.5, 5.7]," + " ]," + " ]" + "```" + "axis = 1 :" + "" + "Let" + "k = indices[i_{0}, ..., i_{q-1\}\]" + "Then" + "output[i_{0}, ..., i_{q-1}, j_{0}, ..., j_{r-2\}\] = input[j_{0}, k, j_{1}, ..., j_{r-2\}\]" + "" + "```" + " data = [" + " [1.0, 1.2, 1.9]," + " [2.3, 3.4, 3.9]," + " [4.5, 5.7, 5.9]," + " ]" + " indices = [" + " [0, 2]," + " ]" + " axis = 1," + " output = [" + " [" + " [1.0, 1.9]," + " [2.3, 3.9]," + " [4.5, 5.9]," + " ]," + " ]" + "```" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$indices); + let results = (outs AnyTensor); +} + +def ONNXGatherElementsOp:ONNX_Op<"GatherElements", + [NoSideEffect]> { + let summary = "ONNX GatherElements operation"; + let description = [{ + "GatherElements takes two inputs `data` and `indices` of the same rank r >= 1" + "and an optional attribute `axis` that identifies an axis of `data`" + "(by default, the outer-most axis, that is axis 0). It is an indexing operation" + "that produces its output by indexing into the input data tensor at index" + "positions determined by elements of the `indices` tensor." + "Its output shape is the same as the shape of `indices` and consists of one value" + "(gathered from the `data`) for each element in `indices`." + "" + "For instance, in the 3-D case (r = 3), the output produced is determined" + "by the following equations: " + "```" + " out[i][j][k] = input[index[i][j][k]][j][k] if axis = 0," + " out[i][j][k] = input[i][index[i][j][k]][k] if axis = 1," + " out[i][j][k] = input[i][j][index[i][j][k]] if axis = 2," + "```" + "" + "This operator is also the inverse of ScatterElements. It is similar to Torch's gather operation." + "" + "Example 1:" + "```" + " data = [" + " [1, 2]," + " [3, 4]," + " ]" + " indices = [" + " [0, 0]," + " [1, 0]," + " ]" + " axis = 1" + " output = [" + " [" + " [1, 1]," + " [4, 3]," + " ]," + " ]" + "```" + "Example 2:" + "```" + " data = [" + " [1, 2, 3]," + " [4, 5, 6]," + " [7, 8, 9]," + " ]" + " indices = [" + " [1, 2, 0]," + " [2, 0, 0]," + " ]" + " axis = 0" + " output = [" + " [" + " [4, 8, 3]," + " [7, 2, 3]," + " ]," + " ]" + "```" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$indices); + let results = (outs AnyTensor); +} + +def ONNXGatherNDOp:ONNX_Op<"GatherND", + [NoSideEffect]> { + let summary = "ONNX GatherND operation"; + let description = [{ + "Given `data` tensor of rank `r` >= 1, and `indices` tensor of rank `q` >= 1, this operator gathers " + "slices of `data` into an output tensor of rank `q + r - indices_shape[-1] - 1`." + "" + "`indices` is an q-dimensional integer tensor, best thought of as a `(q-1)`-dimensional tensor of index-tuples into `data`, " + "where each element defines a slice of `data`" + "" + "Some salient points about the inputs' rank and shape:" + " " + "1) r >= 1 and q >= 1 are to be honored. There is no dependency condition to be met between ranks `r` and `q`" + "" + "2) The `indices_shape[-1]` should have a value between 1 (inclusive) and rank `r` (inclusive) " + "" + "3) All values in `indices` are expected to be within bounds [-s, s-1] along axis of size `s` (i.e.) `-data_shape[i] <= indices[...,i] <= data_shape[i] - 1`." + " It is an error if any of the index values are out of bounds." + "" + "The output is computed as follows:" + "" + "The output tensor is obtained by mapping each index-tuple in the `indices` tensor to the corresponding slice of the input `data`." + " " + "1) If `indices_shape[-1] > r` => error condition" + "" + "2) If `indices_shape[-1] == r`, since the rank of `indices` is `q`, `indices` can be thought of as a `(q-1)`-dimensional tensor" + " containing 1-D tensors of dimension `r`. Let us think of each such `r` ranked tensor as `indices_slice`. " + " Each *scalar value* corresponding to `data[indices_slice]` is filled into the corresponding location of the `(q-1)`-dimensional tensor " + " to form the `output` tensor (Example 1 below)" + "" + "3) If `indices_shape[-1] < r`, since the rank of `indices` is `q`, `indices` can be thought of as a `(q-1)`-dimensional tensor" + " containing 1-D tensors of dimension `< r`. Let us think of each such tensors as `indices_slice`. " + " Each *tensor slice* corresponding to `data[indices_slice , :]` is filled into the corresponding location of the `(q-1)`-dimensional tensor " + " to form the `output` tensor (Examples 2, 3, and 4 below)" + "" + "This operator is the inverse of `ScatterND`." + "" + "`Example 1`" + "" + " data = [[0,1],[2,3]] # data_shape = [2, 2]" + "" + " indices = [[0,0],[1,1]] # indices_shape = [2, 2]" + "" + " output = [0,3] # output_shape = [2]" + "" + "`Example 2`" + "" + " data = [[0,1],[2,3]] # data_shape = [2, 2]" + "" + " indices = [[1],[0]] # indices_shape = [2, 1]" + "" + " output = [[2,3],[0,1]] # output_shape = [2, 2]" + "" + "`Example 3`" + "" + " data = [[[0,1],[2,3]],[[4,5],[6,7]]] # data_shape = [2, 2, 2]" + "" + " indices = [[0,1],[1,0]] # indices_shape = [2, 2]" + "" + " output = [[2,3],[4,5]] # output_shape = [2, 2] " + "" + "`Example 4`" + "" + " data = [[[0,1],[2,3]],[[4,5],[6,7]]] # data_shape = [2, 2, 2]" + "" + " indices = [[[0,1]],[[1,0]]] # indices_shape = [2, 1, 2]" + "" + " output = [[[2,3]],[[4,5]]] # output_shape = [2, 1, 2] " + "" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$indices); + let results = (outs AnyTensor); +} + +def ONNXGemmOp:ONNX_Op<"Gemm", + [NoSideEffect, DeclareOpInterfaceMethods]> { + let summary = "ONNX Gemm operation"; + let description = [{ + "General Matrix multiplication:" + "https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprograms#Level_3" + "" + "A' = transpose(A) if transA else A" + "" + "B' = transpose(B) if transB else B" + "" + "Compute Y = alpha * A' * B' + beta * C, where input tensor A has shape (M, K) or (K, M)," + "input tensor B has shape (K, N) or (N, K), input tensor C is broadcastable to shape (M, N)," + "and output tensor Y has shape (M, N). A will be transposed before doing the" + "computation if attribute transA is non-zero, same for B and transB." + "This operator supports **unidirectional broadcasting** (tensor C should be unidirectional broadcastable to tensor A * B); for more details please check [the doc](Broadcasting.md)." + "This operator has **optional** inputs/outputs. See [the doc](IR.md) for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B, AnyTensor:$C); + let results = (outs AnyTensor); +} + +def ONNXGlobalAveragePoolOp:ONNX_Op<"GlobalAveragePool", + [NoSideEffect]> { + let summary = "ONNX GlobalAveragePool operation"; + let description = [{ + "GlobalAveragePool consumes an input tensor X and applies average pooling across" + " the values in the same channel. This is equivalent to AveragePool with kernel size" + " equal to the spatial dimension of input tensor." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXGlobalLpPoolOp:ONNX_Op<"GlobalLpPool", + [NoSideEffect]> { + let summary = "ONNX GlobalLpPool operation"; + let description = [{ + "GlobalLpPool consumes an input tensor X and applies lp pool pooling across" + " the values in the same channel. This is equivalent to LpPool with kernel size" + " equal to the spatial dimension of input tensor." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXGlobalMaxPoolOp:ONNX_Op<"GlobalMaxPool", + [NoSideEffect]> { + let summary = "ONNX GlobalMaxPool operation"; + let description = [{ + "GlobalMaxPool consumes an input tensor X and applies max pooling across" + " the values in the same channel. This is equivalent to MaxPool with kernel size" + " equal to the spatial dimension of input tensor." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXGreaterOp:ONNX_Op<"Greater", + [NoSideEffect]> { + let summary = "ONNX Greater operation"; + let description = [{ + "Returns the tensor resulted from performing the `greater` logical operation" + "elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXHardSigmoidOp:ONNX_Op<"HardSigmoid", + [NoSideEffect]> { + let summary = "ONNX HardSigmoid operation"; + let description = [{ + "HardSigmoid takes one input data (Tensor) and produces one output data" + "(Tensor) where the HardSigmoid function, y = max(0, min(1, alpha * x + beta))," + "is applied to the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXHardmaxOp:ONNX_Op<"Hardmax", + [NoSideEffect]> { + let summary = "ONNX Hardmax operation"; + let description = [{ + "The operator computes the hardmax (1 for the first maximum value, and 0 for all others) values for each layer in the batch" + " of the given input." + "" + "The input does not need to explicitly be a 2D vector; rather, it will be" + "coerced into one. For an arbitrary n-dimensional tensor" + "input \in [a_0, a_1, ..., a_{k-1}, a_k, ..., a_{n-1\}\] and k is" + "the axis provided, then input will be coerced into a 2-dimensional tensor with" + "dimensions [a_0 * ... * a_{k-1}, a_k * ... * a_{n-1\}\]. For the default" + "case where axis=1, this means the input tensor will be coerced into a 2D tensor" + "of dimensions [a_0, a_1 * ... * a_{n-1\}\], where a_0 is often the batch size." + "In this situation, we must have a_0 = N and a_1 * ... * a_{n-1} = D." + "Each of these dimensions must be matched correctly, or else the operator" + "will throw errors. The output tensor has the same shape" + "and contains the hardmax values of the corresponding input." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXIdentityOp:ONNX_Op<"Identity", + [NoSideEffect]> { + let summary = "ONNX Identity operation"; + let description = [{ + "Identity operator" + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXIfOp:ONNX_Op<"If", + [NoSideEffect]> { + let summary = "ONNX If operation"; + let description = [{ + "If conditional" + }]; + let arguments = (ins AnyTensor:$cond); + let results = (outs AnyTensor); +} + +def ONNXInstanceNormalizationOp:ONNX_Op<"InstanceNormalization", + [NoSideEffect]> { + let summary = "ONNX InstanceNormalization operation"; + let description = [{ + "Carries out instance normalization as described in the paper" + "https://arxiv.org/abs/1607.08022." + "" + "y = scale * (x - mean) / sqrt(variance + epsilon) + B," + "where mean and variance are computed per instance per channel." + "" + }]; + let arguments = (ins AnyTensor:$input, AnyTensor:$scale, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXIsInfOp:ONNX_Op<"IsInf", + [NoSideEffect]> { + let summary = "ONNX IsInf operation"; + let description = [{ + "Map infinity to true and other values to false." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXIsNaNOp:ONNX_Op<"IsNaN", + [NoSideEffect]> { + let summary = "ONNX IsNaN operation"; + let description = [{ + "Returns which elements of the input are NaN." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXLRNOp:ONNX_Op<"LRN", + [NoSideEffect]> { + let summary = "ONNX LRN operation"; + let description = [{ + "Local Response Normalization proposed in the [AlexNet paper](https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf)." + "It normalizes over local input regions." + "The local region is defined across the channels. For an element X[n, c, d1, ..., dk] in a tensor" + "of shape (N x C x D1 x D2, ..., Dk), its region is" + "{X[n, i, d1, ..., dk] | max(0, c - floor((size - 1) / 2)) <= i <= min(C - 1, c + ceil((size - 1) / 2))}." + "" + "square_sum[n, c, d1, ..., dk] = sum(X[n, i, d1, ..., dk] ^ 2)," + "where max(0, c - floor((size - 1) / 2)) <= i <= min(C - 1, c + ceil((size - 1) / 2))." + "" + "Y[n, c, d1, ..., dk] = X[n, c, d1, ..., dk] / (bias + alpha / size * square_sum[n, c, d1, ..., dk] ) ^ beta" + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXLSTMOp:ONNX_Op<"LSTM", + [NoSideEffect]> { + let summary = "ONNX LSTM operation"; + let description = [{ + "Computes an one-layer LSTM. This operator is usually supported via some" + "custom implementation such as CuDNN." + "" + "Notations:" + "" + "`X` - input tensor" + "" + "`i` - input gate" + "" + "`o` - output gate" + "" + "`f` - forget gate" + "" + "`c` - cell gate" + "" + "`t` - time step (t-1 means previous time step)" + "" + "`W[iofc]` - W parameter weight matrix for input, output, forget, and cell gates" + "" + "`R[iofc]` - R recurrence weight matrix for input, output, forget, and cell gates" + "" + "`Wb[iofc]` - W bias vectors for input, output, forget, and cell gates" + "" + "`Rb[iofc]` - R bias vectors for input, output, forget, and cell gates" + "" + "`P[iof]` - P peephole weight vector for input, output, and forget gates" + "" + "`WB[iofc]` - W parameter weight matrix for backward input, output, forget, and cell gates" + "" + "`RB[iofc]` - R recurrence weight matrix for backward input, output, forget, and cell gates" + "" + "`WBb[iofc]` - W bias vectors for backward input, output, forget, and cell gates" + "" + "`RBb[iofc]` - R bias vectors for backward input, output, forget, and cell gates" + "" + "`PB[iof]` - P peephole weight vector for backward input, output, and forget gates" + "" + "`H` - Hidden state" + "" + "`num_directions` - 2 if direction == bidirectional else 1" + "" + "Activation functions:" + "" + " Relu(x) - max(0, x)" + "" + " Tanh(x) - (1 - e^{-2x})/(1 + e^{-2x})" + "" + " Sigmoid(x) - 1/(1 + e^{-x})" + "" + " (NOTE: Below are optional)" + "" + " Affine(x) - alpha*x + beta" + "" + " LeakyRelu(x) - x if x >= 0 else alpha * x" + "" + " ThresholdedRelu(x) - x if x >= alpha else 0" + "" + " ScaledTanh(x) - alpha*Tanh(beta*x)" + "" + " HardSigmoid(x) - min(max(alpha*x + beta, 0), 1)" + "" + " Elu(x) - x if x >= 0 else alpha*(e^x - 1)" + "" + " Softsign(x) - x/(1 + |x|)" + "" + " Softplus(x) - log(1 + e^x)" + "" + "Equations (Default: f=Sigmoid, g=Tanh, h=Tanh):" + "" + " - it = f(Xt*(Wi^T) + Ht-1*(Ri^T) + Pi (.) Ct-1 + Wbi + Rbi)" + "" + " - ft = f(Xt*(Wf^T) + Ht-1*(Rf^T) + Pf (.) Ct-1 + Wbf + Rbf)" + "" + " - ct = g(Xt*(Wc^T) + Ht-1*(Rc^T) + Wbc + Rbc)" + "" + " - Ct = ft (.) Ct-1 + it (.) ct" + "" + " - ot = f(Xt*(Wo^T) + Ht-1*(Ro^T) + Po (.) Ct + Wbo + Rbo)" + "" + " - Ht = ot (.) h(Ct)" + "This operator has **optional** inputs/outputs. See [the doc](IR.md) for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$W, AnyTensor:$R, AnyTensor:$B, AnyTensor:$sequence_lens, AnyTensor:$initial_h, AnyTensor:$initial_c, AnyTensor:$P); + let results = (outs AnyTensor, AnyTensor, AnyTensor); +} + +def ONNXLeakyReluOp:ONNX_Op<"LeakyRelu", + [NoSideEffect]> { + let summary = "ONNX LeakyRelu operation"; + let description = [{ + "LeakyRelu takes input data (Tensor) and an argument alpha, and produces one" + "output data (Tensor) where the function `f(x) = alpha * x for x < 0`," + "`f(x) = x for x >= 0`, is applied to the data tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXLessOp:ONNX_Op<"Less", + [NoSideEffect]> { + let summary = "ONNX Less operation"; + let description = [{ + "Returns the tensor resulted from performing the `less` logical operation" + "elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXLogOp:ONNX_Op<"Log", + [NoSideEffect]> { + let summary = "ONNX Log operation"; + let description = [{ + "Calculates the natural log of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXLogSoftmaxOp:ONNX_Op<"LogSoftmax", + [NoSideEffect]> { + let summary = "ONNX LogSoftmax operation"; + let description = [{ + "The operator computes the logsoftmax (log of softmax) values for each layer in the batch" + " of the given input." + "" + "The input does not need to explicitly be a 2D vector; rather, it will be" + "coerced into one. For an arbitrary n-dimensional tensor" + "input \in [a_0, a_1, ..., a_{k-1}, a_k, ..., a_{n-1\}\] and k is" + "the axis provided, then input will be coerced into a 2-dimensional tensor with" + "dimensions [a_0 * ... * a_{k-1}, a_k * ... * a_{n-1\}\]. For the default" + "case where axis=1, this means the input tensor will be coerced into a 2D tensor" + "of dimensions [a_0, a_1 * ... * a_{n-1\}\], where a_0 is often the batch size." + "In this situation, we must have a_0 = N and a_1 * ... * a_{n-1} = D." + "Each of these dimensions must be matched correctly, or else the operator" + "will throw errors. The output tensor has the same shape" + "and contains the logsoftmax values of the corresponding input." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXLoopOp:ONNX_Op<"Loop", + [NoSideEffect]> { + let summary = "ONNX Loop operation"; + let description = [{ + "Generic Looping construct. This loop has multiple termination conditions:" + "" + "1) Trip count. Iteration count specified at runtime. Set by" + " specifying the input M. Optional. Set to empty string to omit." + " Note that a static trip count (specified at graph construction time) can be" + " specified by passing in a constant node for input M." + "2) Loop termination condition. This is an input to the op that determines" + " whether to run the first iteration and also a loop-carried dependency for" + " the body graph. The body graph must yield a value for the condition variable," + " whether this input is provided or not." + "" + "This table summarizes the operating modes of this operator with equivalent" + "C-style code:" + "" + " Operator inputs defined as (max_trip_count, condition_var)." + "" + " input ("", ""):" + " for (int i=0; ; ++i) {" + " cond = ... // Note this value is ignored, but is required in the body" + " }" + "" + " input ("", cond) // Note this is analogous to a while loop" + " bool cond = ...;" + " for (int i=0; cond; ++i) {" + " cond = ...;" + " }" + "" + " input ("", 1) // Note this is analogous to a do-while loop" + " bool cond = true" + " for (int i=0; cond; ++i) {" + " cond = ...;" + " }" + "" + " input (trip_count, "") // Note this is analogous to a for loop" + " int trip_count = ..." + " for (int i=0; i < trip_count; ++i) {" + " cond = ...; // ignored" + " }" + "" + " input (trip_count, cond)" + " int trip_count = ...;" + " bool cond = ...;" + " for (int i=0; i < trip_count && cond; ++i) {" + " cond = ...;" + " }" + "" + "" + "*Sample usage - cond as well as trip count*" + "" + " graph predict-net {" + " %a = Constant[value = ]()" + " %b = Constant[value = ]()" + " %keepgoing = Constant[value = ]()" + " %max_trip_count = Constant[value = ]()" + " %keepgoing_out, %b_out, %user_defined_vals = Loop[body = ](%max_trip_count, %keepgoing, %b)" + " return" + " }" + "" + " graph body-net (" + " %i[INT32, scalar] // iteration number" + " %keepgoing_in[BOOL, scalar] // incoming loop-termination-condition; not used" + " %b_in[INT32, scalar] // incoming value of loop-carried-dependency b" + " ) {" + " %my_local = Add(%a, %b_in)" + " %b_out = Sub(%a, %b_in) // outgoing value of loop-carried-dependency b" + " %keepgoing_out = Greater(%my_local, %b_out) // outgoing loop-termination-condition" + " %user_defined_val = Add(%b_in, %b_in) // scan-output value to be accumulated" + " return %keepgoing_out, %b_out, %user_defined_val" + " }" + "" + "*Sample equivalent C code*" + "" + " {" + " /* User-defined code (enclosing scope) */" + " int a = 3, b = 6;" + " bool keepgoing = true; // Analogous to input cond" + " /* End user-defined code */" + "" + " /* Implicitly-defined code */" + " const int max_trip_count = 10; // Analogous to input M" + " int user_defined_vals[]; // Imagine this is resizable" + " /* End implicitly-defined code */" + " /* initialize loop-carried variables and scan-output variables */" + " bool keepgoing_out = keepgoing" + " int b_out = b" + "" + " for (int i=0; i < max_trip_count && keepgoing_out; ++i) {" + " /* Implicitly-defined code: bind actual parameter values" + " to formal parameter variables of loop-body */" + " bool keepgoing_in = keepgoing_out; " + " bool b_in = b_out;" + "" + " /* User-defined code (loop body) */" + " int my_local = a + b_in; // Reading value "a" from the enclosing scope is fine" + " b_out = a - b_in;" + " keepgoing_out = my_local > b_out; " + " user_defined_val = b_in + b_in; // b_in and b_out are different variables" + " /* End user-defined code */" + "" + " /* Implicitly defined-code */" + " user_defined_vals[i] = user_defined_val // accumulate scan-output values" + " }" + " // int t = my_local; // Can't do this. my_local is not accessible here." + "" + " // The values below are bound to the output variables of the loop and therefore accessible" + " // b_out; user_defined_vals; keepgoing_out;" + " }" + "" + "There are several things of note in this code snippet:" + "" + "1) Values from the enclosing scope (i.e. variable "a" here) are in scope and can" + " be referenced in the inputs of the loop." + "2) Any values computed in the loop body that needs to be used in a subsequent" + " iteration or after the loop are modelled using a pair of variables in the loop-body," + " consisting of an input variable (eg., b_in) and an output variable (eg., b_out)." + " These are referred to as loop-carried dependences. The loop operation node" + " supplies the input value of the input variable for the first iteration, and" + " returns the output value of the output variable produced by the final" + " iteration." + "3) Scan_output variables are used to implicitly concatenate values computed across" + " all the iterations. In the above example, the value of user_defined_val computed" + " over all iterations are concatenated and returned as the value of user_defined_vals" + " after the loop." + "4) Values created in the body cannot be accessed in the enclosing scope," + " except using the mechanism described above." + "" + "Note that the semantics of this op support "diagonal" or "wavefront" execution." + "(See Step 3 here for an example:" + "https://devblogs.nvidia.com/optimizing-recurrent-neural-networks-cudnn-5/)." + "Frontends should emit multi-layer RNNs as a series of While operators (with" + "time being the inner looping dimension), with each successive layer consuming" + "the scan_outputs from the previous layer, possibly going through several" + "point-wise operators (e.g. dropout, residual connections, linear layer)." + }]; + let arguments = (ins AnyTensor:$M, AnyTensor:$cond, AnyTensor:$v_initial); + let results = (outs AnyTensor); +} + +def ONNXLpNormalizationOp:ONNX_Op<"LpNormalization", + [NoSideEffect]> { + let summary = "ONNX LpNormalization operation"; + let description = [{ + "Given a matrix, apply Lp-normalization along the provided axis." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXLpPoolOp:ONNX_Op<"LpPool", + [NoSideEffect]> { + let summary = "ONNX LpPool operation"; + let description = [{ + "LpPool consumes an input tensor X and applies Lp pooling across" + " the tensor according to kernel sizes, stride sizes, and pad lengths." + " Lp pooling consisting of computing the Lp norm on all values of a subset" + " of the input tensor according to the kernel size and downsampling the" + " data into the output tensor Y for further processing." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXMatMulOp:ONNX_Op<"MatMul", + [NoSideEffect, DeclareOpInterfaceMethods]> { + let summary = "ONNX MatMul operation"; + let description = [{ + "Matrix product that behaves like numpy.matmul: https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.matmul.html" + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXMatMulIntegerOp:ONNX_Op<"MatMulInteger", + [NoSideEffect]> { + let summary = "ONNX MatMulInteger operation"; + let description = [{ + "Matrix product that behaves like numpy.matmul: https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.matmul.html." + "The production MUST never overflow. The accumulation may overflow if and only if in 32 bits." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B, AnyTensor:$a_zero_point, AnyTensor:$b_zero_point); + let results = (outs AnyTensor); +} + +def ONNXMaxOp:ONNX_Op<"Max", + [NoSideEffect]> { + let summary = "ONNX Max operation"; + let description = [{ + "Element-wise max of each of the input tensors (with Numpy-style broadcasting support)." + "All inputs and outputs must have the same data type." + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins Variadic:$data_0); + let results = (outs AnyTensor); +} + +def ONNXMaxPoolOp:ONNX_Op<"MaxPool", + [NoSideEffect]> { + let summary = "ONNX MaxPool operation"; + let description = [{ + "MaxPool consumes an input tensor X and applies max pooling across" + " the tensor according to kernel sizes, stride sizes, and pad lengths." + " max pooling consisting of computing the max on all values of a" + " subset of the input tensor according to the kernel size and downsampling the" + " data into the output tensor Y for further processing. The output spatial shape will be following:" + " ```" + " output_spatial_shape[i] = floor((input_spatial_shape[i] + pad_shape[i] - ((kernel_spatial_shape[i] - 1) * dilations[i] + 1)) / strides_spatial_shape[i] + 1)" + " ```" + " or" + " ```" + " output_spatial_shape[i] = ceil((input_spatial_shape[i] + pad_shape[i] - ((kernel_spatial_shape[i] - 1) * dilations[i] + 1)) / strides_spatial_shape[i] + 1)" + " ```" + " if ceil_mode is enabled" + "" + " ```" + " * pad_shape[i] is sum of pads along axis i" + " ```" + "" + " `auto_pad` is a DEPRECATED attribute. If you are using them currently, the output spatial shape will be following:" + " ```" + " VALID: output_spatial_shape[i] = ceil((input_spatial_shape[i] - ((kernel_spatial_shape[i] - 1) * dilations[i] + 1) + 1) / strides_spatial_shape[i])" + " SAME_UPPER or SAME_LOWER: output_spatial_shape[i] = ceil(input_spatial_shape[i] / strides_spatial_shape[i])" + " ```" + " And pad shape will be following if `SAME_UPPER` or `SAME_LOWER`:" + " ```" + " pad_shape[i] = (output_spatial_shape[i] - 1) * strides_spatial_shape[i] + ((kernel_spatial_shape[i] - 1) * dilations[i] + 1) - input_spatial_shape[i]" + " ```" + " The output of each pooling window is maximum number of elements exclude pad." + " " + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor, AnyTensor); +} + +def ONNXMaxRoiPoolOp:ONNX_Op<"MaxRoiPool", + [NoSideEffect]> { + let summary = "ONNX MaxRoiPool operation"; + let description = [{ + "ROI max pool consumes an input tensor X and region of interests (RoIs) to" + " apply max pooling across each RoI, to produce output 4-D tensor of shape" + " (num_rois, channels, pooled_shape[0], pooled_shape[1])." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$rois); + let results = (outs AnyTensor); +} + +def ONNXMaxUnpoolOp:ONNX_Op<"MaxUnpool", + [NoSideEffect]> { + let summary = "ONNX MaxUnpool operation"; + let description = [{ + "MaxUnpool essentially computes the partial inverse of the MaxPool op." + " The input information to this op is typically the the output information from a MaxPool op. The first" + " input tensor X is the tensor that needs to be unpooled, which is typically the pooled tensor (first output)" + " from MaxPool. The second input tensor, I, contains the indices to the (locally maximal) elements corrsponding" + " to the elements in the first input tensor X. Input tensor I is typically the second output of the MaxPool op." + " The third (optional) input is a tensor that specifies the output size of the unpooling operation." + "" + "MaxUnpool is intended to do 'partial' inverse of the MaxPool op. 'Partial' because all the non-maximal" + " values from the original input to MaxPool are set to zero in the output of the MaxUnpool op. Pooling" + " the result of an unpooling operation should give back the original input to the unpooling op." + "" + "MaxUnpool can produce the same output size for several input sizes, which makes unpooling op ambiguous." + " The third input argument, output_size, is meant to disambiguate the op and produce output tensor of" + " known/predictable size." + "" + "In addition to the inputs, MaxUnpool takes three attributes, namely kernel_shape, strides, and pads," + " which define the exact unpooling op. The attributes typically have the same values as the corrsponding" + " pooling op that the unpooling op is trying to invert." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$I, AnyTensor:$output_shape); + let results = (outs AnyTensor); +} + +def ONNXMeanOp:ONNX_Op<"Mean", + [NoSideEffect]> { + let summary = "ONNX Mean operation"; + let description = [{ + "Element-wise mean of each of the input tensors (with Numpy-style broadcasting support)." + "All inputs and outputs must have the same data type." + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins Variadic:$data_0); + let results = (outs AnyTensor); +} + +def ONNXMeanVarianceNormalizationOp:ONNX_Op<"MeanVarianceNormalization", + [NoSideEffect]> { + let summary = "ONNX MeanVarianceNormalization operation"; + let description = [{ + "A MeanVarianceNormalization Function: Perform mean variance normalization" + " on the input tensor X using formula:
``` (X-EX)/sqrt(E(X-EX)^2) ```" + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXMinOp:ONNX_Op<"Min", + [NoSideEffect]> { + let summary = "ONNX Min operation"; + let description = [{ + "Element-wise min of each of the input tensors (with Numpy-style broadcasting support)." + "All inputs and outputs must have the same data type." + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins Variadic:$data_0); + let results = (outs AnyTensor); +} + +def ONNXModOp:ONNX_Op<"Mod", + [NoSideEffect]> { + let summary = "ONNX Mod operation"; + let description = [{ + "Performs element-wise binary modulus (with Numpy-style broadcasting support). " + " The sign of the remainder is the same as that of the Divisor." + " " + " Mod operator can also behave like C fmod() or numpy.fmod. In this case, the sign of the remainder however, will be the same as the Dividend " + " (in contrast to integer mod). To force a behavior like numpy.fmod() an 'fmod' Attribute is provided." + " This attribute is set to 0 by default causing the behavior to be like integer mod. " + " Setting this attribute to 1 causes the remainder to be calculated similar to that of numpy.fmod()." + "" + " If the input type is floating point, then `fmod` attribute must be set to 1." + " " + " In case of dividend being zero, the results will be platform dependent." + "" + " This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXMulOp:ONNX_Op<"Mul", + [NoSideEffect]> { + let summary = "ONNX Mul operation"; + let description = [{ + "Performs element-wise binary multiplication (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXMultinomialOp:ONNX_Op<"Multinomial", + [NoSideEffect]> { + let summary = "ONNX Multinomial operation"; + let description = [{ + "Generate a tensor of samples from a multinomial distribution according to the probabilities" + "of each of the possible outcomes." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXNegOp:ONNX_Op<"Neg", + [NoSideEffect]> { + let summary = "ONNX Neg operation"; + let description = [{ + "Neg takes one input data (Tensor) and produces one output data" + "(Tensor) where each element flipped sign, y = -x, is applied to" + "the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXNonMaxSuppressionOp:ONNX_Op<"NonMaxSuppression", + [NoSideEffect]> { + let summary = "ONNX NonMaxSuppression operation"; + let description = [{ + "Filter out boxes that have high intersection-over-union (IOU) overlap with previously selected boxes." + "Bounding boxes with score less than score_threshold are removed. Bounding box format is indicated by attribute center_point_box." + "Note that this algorithm is agnostic to where the origin is in the coordinate system and more generally is invariant to" + "orthogonal transformations and translations of the coordinate system; thus translating or reflections of the coordinate system" + "result in the same boxes being selected by the algorithm." + "The selected_indices output is a set of integers indexing into the input collection of bounding boxes representing the selected boxes." + "The bounding box coordinates corresponding to the selected indices can then be obtained using the Gather or GatherND operation." + }]; + let arguments = (ins AnyTensor:$boxes, AnyTensor:$scores, AnyTensor:$max_output_boxes_per_class, AnyTensor:$iou_threshold, AnyTensor:$score_threshold); + let results = (outs AnyTensor); +} + +def ONNXNonZeroOp:ONNX_Op<"NonZero", + [NoSideEffect]> { + let summary = "ONNX NonZero operation"; + let description = [{ + "Returns the indices of the elements that are non-zero" + " (in row-major order - by dimension)." + " NonZero behaves similar to numpy.nonzero:" + " https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html" + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXNotOp:ONNX_Op<"Not", + [NoSideEffect]> { + let summary = "ONNX Not operation"; + let description = [{ + "Returns the negation of the input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXOneHotOp:ONNX_Op<"OneHot", + [NoSideEffect]> { + let summary = "ONNX OneHot operation"; + let description = [{ + "Produces a one-hot tensor based on inputs." + " The locations represented by the index values in the 'indices' input tensor will have 'on_value'" + " and the other locations will have 'off_value' in the output tensor, where 'on_value' and 'off_value'" + " are specified as part of required input argument 'values', which is a two-element tensor of format" + " [off_value, on_value]. The rank of the output tensor will be one greater than the rank of the" + " input tensor. The additional dimension is for one-hot representation. The additional dimension will" + " be inserted at the position specified by 'axis'. If 'axis' is not specified then then additional" + " dimension will be inserted as the innermost dimension, i.e. axis=-1. The size of the additional" + " dimension is specified by required scalar input 'depth'. The type of the output tensor is the same" + " as the type of the 'values' input. Any entries in the 'indices' input tensor with values outside" + " the range [-depth, depth-1] will result in one-hot representation with all 'off_value' values in the" + " output tensor." + "" + " when axis = 0:" + " output[input[i, j, k], i, j, k] = 1 for all i, j, k and 0 otherwise." + "" + " when axis = -1:" + " output[i, j, k, input[i, j, k]] = 1 for all i, j, k and 0 otherwise." + "" + }]; + let arguments = (ins AnyTensor:$indices, AnyTensor:$depth, AnyTensor:$values); + let results = (outs AnyTensor); +} + +def ONNXOrOp:ONNX_Op<"Or", + [NoSideEffect]> { + let summary = "ONNX Or operation"; + let description = [{ + "Returns the tensor resulted from performing the `or` logical operation" + "elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXPReluOp:ONNX_Op<"PRelu", + [NoSideEffect]> { + let summary = "ONNX PRelu operation"; + let description = [{ + "PRelu takes input data (Tensor) and slope tensor as input, and produces one" + "output data (Tensor) where the function `f(x) = slope * x for x < 0`," + "`f(x) = x for x >= 0`., is applied to the data tensor elementwise." + "This operator supports **unidirectional broadcasting** (tensor slope should be unidirectional broadcastable to input tensor X); for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$slope); + let results = (outs AnyTensor); +} + +def ONNXPadOp:ONNX_Op<"Pad", + [NoSideEffect]> { + let summary = "ONNX Pad operation"; + let description = [{ + "Given a tensor containing the data to be padded (`data`), a tensor containing the number of start and end pad values for axis (`pads`), (optionally) a `mode`, and (optionally) `constant_value`, " + "a padded tensor (`output`) is generated." + "" + "The three supported `modes` are (similar to corresponding modes supported by `numpy.pad`):" + "" + "1) `constant`(default) - pads with a given constant value as specified by `constant_value` (which defaults to 0)" + "" + "2) `reflect` - pads with the reflection of the vector mirrored on the first and last values of the vector along each axis" + "" + "3) `edge` - pads with the edge values of array" + "" + "" + "Example 1 (`constant` mode):" + " Insert 0 pads to the beginning of the second dimension." + "" + " data = " + " [" + " [1.0, 1.2]," + " [2.3, 3.4]," + " [4.5, 5.7]," + " ] " + "" + " pads = [0, 2, 0, 0]" + "" + " mode = 'constant'" + "" + " constant_value = 0.0" + "" + " output = " + " [" + " [" + " [0.0, 0.0, 1.0, 1.2]," + " [0.0, 0.0, 2.3, 3.4]," + " [0.0, 0.0, 4.5, 5.7]," + " ]," + " ]" + "" + "" + "Example 2 (`reflect` mode):" + " data = " + " [" + " [1.0, 1.2]," + " [2.3, 3.4]," + " [4.5, 5.7]," + " ] " + "" + " pads = [0, 2, 0, 0]" + "" + " mode = 'reflect'" + "" + " output = " + " [" + " [" + " [1.0, 1.2, 1.0, 1.2]," + " [2.3, 3.4, 2.3, 3.4]," + " [4.5, 5.7, 4.5, 5.7]," + " ]," + " ]" + "" + "" + "Example 3 (`edge` mode):" + " data = " + " [" + " [1.0, 1.2]," + " [2.3, 3.4]," + " [4.5, 5.7]," + " ] " + "" + " pads = [0, 2, 0, 0]" + "" + " mode = 'edge'" + "" + " output = " + " [" + " [" + " [1.0, 1.0, 1.0, 1.2]," + " [2.3, 2.3, 2.3, 3.4]," + " [4.5, 4.5, 4.5, 5.7]," + " ]," + " ]" + "" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$pads, AnyTensor:$constant_value); + let results = (outs AnyTensor); +} + +def ONNXPowOp:ONNX_Op<"Pow", + [NoSideEffect]> { + let summary = "ONNX Pow operation"; + let description = [{ + "Pow takes input data (Tensor) and exponent Tensor, and" + "produces one output data (Tensor) where the function `f(x) = x^exponent`," + "is applied to the data tensor elementwise." + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$Y); + let results = (outs AnyTensor); +} + +def ONNXQLinearConvOp:ONNX_Op<"QLinearConv", + [NoSideEffect]> { + let summary = "ONNX QLinearConv operation"; + let description = [{ + "The convolution operator consumes a quantized input tensor, its scale and zero point," + "a quantized filter, its scale and zero point, and output's scale and zero point," + "and computes the quantized output. Each scale and zero-point pair must have same shape." + "It means they must be either scalars (per tensor) or 1-D tensors (per output channel)." + "Each input or output and its related zero point must have same type." + }]; + let arguments = (ins AnyTensor:$x, AnyTensor:$x_scale, AnyTensor:$x_zero_point, AnyTensor:$w, AnyTensor:$w_scale, AnyTensor:$w_zero_point, AnyTensor:$y_scale, AnyTensor:$y_zero_point, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXQLinearMatMulOp:ONNX_Op<"QLinearMatMul", + [NoSideEffect]> { + let summary = "ONNX QLinearMatMul operation"; + let description = [{ + "Matrix product that behaves like numpy.matmul: https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.matmul.html." + "It consumes two quantized input tensors, their scales and zero points, scale and zero point of output, and computes the quantized output." + "The quantization formula is y = saturate((x / y_scale) + y_zero_point). For (x / y_scale), it is rounding to nearest ties to even." + "Refer to https://en.wikipedia.org/wiki/Rounding for details. Scale and zero point must have same shape." + "They must be either scalar (per tensor) or 1-D tensor (per row for 'a' and per column for 'b'). If scale and zero point are 1-D tensor," + "the number of elements of scale and zero point tensor of input 'a' and output 'y' should be equal to the number of rows of input 'a'," + "and the number of elements of scale and zero point tensor of input 'b' should be equal to the number of columns of input 'b'." + "Production must never overflow, and accumulation may overflow if and only if in 32 bits." + }]; + let arguments = (ins AnyTensor:$a, AnyTensor:$a_scale, AnyTensor:$a_zero_point, AnyTensor:$b, AnyTensor:$b_scale, AnyTensor:$b_zero_point, AnyTensor:$y_scale, AnyTensor:$y_zero_point); + let results = (outs AnyTensor); +} + +def ONNXQuantizeLinearOp:ONNX_Op<"QuantizeLinear", + [NoSideEffect]> { + let summary = "ONNX QuantizeLinear operation"; + let description = [{ + "The linear per-tensor/layer quantization operator. It consumes a high precision tensor, a scale, a zero point to compute the low precision / quantized tensor." + "The quantization formula is y = saturate ((x / y_scale) + y_zero_point). For saturation, it saturates to [0, 255] if it's uint8, or [-128, 127] if it's int8." + "For (x / y_scale), it's rounding to nearest ties to even. Refer to https://en.wikipedia.org/wiki/Rounding for details. 'y_zero_point' and 'y' must have same type." + }]; + let arguments = (ins AnyTensor:$x, AnyTensor:$y_scale, AnyTensor:$y_zero_point); + let results = (outs AnyTensor); +} + +def ONNXRNNOp:ONNX_Op<"RNN", + [NoSideEffect]> { + let summary = "ONNX RNN operation"; + let description = [{ + "Computes an one-layer simple RNN. This operator is usually supported" + "via some custom implementation such as CuDNN." + "" + "Notations:" + "" + "`X` - input tensor" + "" + "`i` - input gate" + "" + "`t` - time step (t-1 means previous time step)" + "" + "`Wi` - W parameter weight matrix for input gate" + "" + "`Ri` - R recurrence weight matrix for input gate" + "" + "`Wbi` - W parameter bias vector for input gate" + "" + "`Rbi` - R parameter bias vector for input gate" + "" + "`WBi` - W parameter weight matrix for backward input gate" + "" + "`RBi` - R recurrence weight matrix for backward input gate" + "" + "`WBbi` - WR bias vectors for backward input gate" + "" + "`RBbi` - RR bias vectors for backward input gate" + "" + "`H` - Hidden state" + "" + "`num_directions` - 2 if direction == bidirectional else 1" + "" + "Activation functions:" + "" + " Relu(x) - max(0, x)" + "" + " Tanh(x) - (1 - e^{-2x})/(1 + e^{-2x})" + "" + " Sigmoid(x) - 1/(1 + e^{-x})" + "" + " (NOTE: Below are optional)" + "" + " Affine(x) - alpha*x + beta" + "" + " LeakyRelu(x) - x if x >= 0 else alpha * x" + "" + " ThresholdedRelu(x) - x if x >= alpha else 0" + "" + " ScaledTanh(x) - alpha*Tanh(beta*x)" + "" + " HardSigmoid(x) - min(max(alpha*x + beta, 0), 1)" + "" + " Elu(x) - x if x >= 0 else alpha*(e^x - 1)" + "" + " Softsign(x) - x/(1 + |x|)" + "" + " Softplus(x) - log(1 + e^x)" + "" + "Equations (Default: f=Tanh):" + "" + " - Ht = f(Xt*(Wi^T) + Ht-1*(Ri^T) + Wbi + Rbi)" + "This operator has **optional** inputs/outputs. See [the doc](IR.md) for more details about the representation of optional arguments. An empty string may be used in the place of an actual argument's name to indicate a missing argument. Trailing optional arguments (those not followed by an argument that is present) may also be simply omitted." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$W, AnyTensor:$R, AnyTensor:$B, AnyTensor:$sequence_lens, AnyTensor:$initial_h); + let results = (outs AnyTensor, AnyTensor); +} + +def ONNXRandomNormalOp:ONNX_Op<"RandomNormal", + [NoSideEffect]> { + let summary = "ONNX RandomNormal operation"; + let description = [{ + "Generate a tensor with random values drawn from a normal distribution. The shape" + "of the tensor is specified by the `shape` argument and the parameter of the normal distribution" + "specified by `mean` and `scale`." + "" + "The data type is specified by the 'dtype' argument. The 'dtype' argument must" + "be one of the data types specified in the 'DataType' enum field in the" + "TensorProto message." + }]; + let arguments = (ins ); + let results = (outs AnyTensor); +} + +def ONNXRandomNormalLikeOp:ONNX_Op<"RandomNormalLike", + [NoSideEffect]> { + let summary = "ONNX RandomNormalLike operation"; + let description = [{ + "Generate a tensor with random values drawn from a normal distribution." + "The shape of the output tensor is copied from the shape of the input tensor," + "and the parameters of the normal distribution are specified by `mean` and `scale`." + "" + "The data type is specified by the 'dtype' argument, or copied from the input tensor if not provided." + "The 'dtype' argument must be one of the data types specified in the 'DataType' enum field in the" + "TensorProto message, and be valid as an output type." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXRandomUniformOp:ONNX_Op<"RandomUniform", + [NoSideEffect]> { + let summary = "ONNX RandomUniform operation"; + let description = [{ + "Generate a tensor with random values drawn from a uniform distribution. The shape" + "of the tensor is specified by the `shape` argument and the range by `low` and `high`." + "" + "The data type is specified by the 'dtype' argument. The 'dtype' argument must" + "be one of the data types specified in the 'DataType' enum field in the" + "TensorProto message." + }]; + let arguments = (ins ); + let results = (outs AnyTensor); +} + +def ONNXRandomUniformLikeOp:ONNX_Op<"RandomUniformLike", + [NoSideEffect]> { + let summary = "ONNX RandomUniformLike operation"; + let description = [{ + "Generate a tensor with random values drawn from a uniform distribution." + "The shape of the output tensor is copied from the shape of the input tensor," + "and the parameters of the uniform distribution are specified by `low` and `high`." + "" + "The data type is specified by the 'dtype' argument, or copied from the input tensor if not provided." + "The 'dtype' argument must be one of the data types specified in the 'DataType' enum field in the" + "TensorProto message and be valid as an output type." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXRangeOp:ONNX_Op<"Range", + [NoSideEffect]> { + let summary = "ONNX Range operation"; + let description = [{ + "Generate a tensor containing a sequence of numbers that begin at `start` and extends by increments of `delta` " + "up to `limit` (exclusive)." + "" + "The number of elements in the output of range is computed as below-" + "" + "`number_of_elements = max( ceil( (limit - start) / delta ) , 0 )`" + "" + "The pseudocode determining the contents of the output is shown below-" + "" + "`for(int i=0; i { + let summary = "ONNX Reciprocal operation"; + let description = [{ + "Reciprocal takes one input data (Tensor) and produces one output data" + "(Tensor) where the reciprocal is, y = 1/x, is applied to" + "the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXReduceL1Op:ONNX_Op<"ReduceL1", + [NoSideEffect]> { + let summary = "ONNX ReduceL1 operation"; + let description = [{ + "Computes the L1 norm of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceL2Op:ONNX_Op<"ReduceL2", + [NoSideEffect]> { + let summary = "ONNX ReduceL2 operation"; + let description = [{ + "Computes the L2 norm of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceLogSumOp:ONNX_Op<"ReduceLogSum", + [NoSideEffect]> { + let summary = "ONNX ReduceLogSum operation"; + let description = [{ + "Computes the log sum of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceLogSumExpOp:ONNX_Op<"ReduceLogSumExp", + [NoSideEffect]> { + let summary = "ONNX ReduceLogSumExp operation"; + let description = [{ + "Computes the log sum exponent of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceMaxOp:ONNX_Op<"ReduceMax", + [NoSideEffect]> { + let summary = "ONNX ReduceMax operation"; + let description = [{ + "Computes the max of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceMeanOp:ONNX_Op<"ReduceMean", + [NoSideEffect]> { + let summary = "ONNX ReduceMean operation"; + let description = [{ + "Computes the mean of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceMinOp:ONNX_Op<"ReduceMin", + [NoSideEffect]> { + let summary = "ONNX ReduceMin operation"; + let description = [{ + "Computes the min of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceProdOp:ONNX_Op<"ReduceProd", + [NoSideEffect]> { + let summary = "ONNX ReduceProd operation"; + let description = [{ + "Computes the product of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceSumOp:ONNX_Op<"ReduceSum", + [NoSideEffect]> { + let summary = "ONNX ReduceSum operation"; + let description = [{ + "Computes the sum of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReduceSumSquareOp:ONNX_Op<"ReduceSumSquare", + [NoSideEffect]> { + let summary = "ONNX ReduceSumSquare operation"; + let description = [{ + "Computes the sum square of the input tensor's element along the provided axes. The resulted" + "tensor has the same rank as the input if keepdims equal 1. If keepdims equal 0, then" + "the resulted tensor have the reduced dimension pruned." + "" + "The above behavior is similar to numpy, with the exception that numpy default keepdims to" + "False instead of True." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXReluOp:ONNX_Op<"Relu", + [NoSideEffect]> { + let summary = "ONNX Relu operation"; + let description = [{ + "Relu takes one input data (Tensor) and produces one output data" + "(Tensor) where the rectified linear function, y = max(0, x), is applied to" + "the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXReshapeOp:ONNX_Op<"Reshape", + [NoSideEffect]> { + let summary = "ONNX Reshape operation"; + let description = [{ + "Reshape the input tensor similar to numpy.reshape." + "First input is the data tensor, second input is a shape tensor which specifies the output shape. It outputs the reshaped tensor." + "At most one dimension of the new shape can be -1. In this case, the value is" + "inferred from the size of the tensor and the remaining dimensions. A dimension" + "could also be 0, in which case the actual dimension value is unchanged (i.e. taken" + "from the input tensor)." + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$shape); + let results = (outs AnyTensor); +} + +def ONNXResizeOp:ONNX_Op<"Resize", + [NoSideEffect]> { + let summary = "ONNX Resize operation"; + let description = [{ + "Resize the input tensor. In general, it calculates every value in the output tensor as a weighted average of neighborhood (a.k.a. sampling locations) in the input tensor." + "Each dimension value of the output tensor is:" + " output_dimension = floor(input_dimension * (roi_end - roi_start) * scale) if input \"sizes\" is not specified." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$roi, AnyTensor:$scales, AnyTensor:$sizes); + let results = (outs AnyTensor); +} + +def ONNXReverseSequenceOp:ONNX_Op<"ReverseSequence", + [NoSideEffect]> { + let summary = "ONNX ReverseSequence operation"; + let description = [{ + "Reverse batch of sequences having different lengths specified by `sequence_lens`." + "" + "For each slice i iterating on batch axis, the operator reverses the first sequence_lens[i] elements on time axis," + "and copies elements whose index's beyond sequence_lens[i] to the output. So the output slice i contains reversed" + "sequences on the first sequence_lens[i] elements, then have original values copied for the other elements." + "" + "Example 1:" + " input = [[0.0, 4.0, 8.0, 12.0]," + " [1.0, 5.0, 9.0, 13.0]," + " [2.0, 6.0, 10.0, 14.0]," + " [3.0, 7.0, 11.0, 15.0]]" + " sequence_lens = [4, 3, 2, 1]" + " time_axis = 0" + " batch_axis = 1" + "" + " output = [[3.0, 6.0, 9.0, 12.0]," + " [2.0, 5.0, 8.0, 13.0]," + " [1.0, 4.0, 10.0, 14.0]," + " [0.0, 7.0, 11.0, 15.0]]" + "" + "Example 2:" + " input = [[0.0, 1.0, 2.0, 3.0 ]," + " [4.0, 5.0, 6.0, 7.0 ]," + " [8.0, 9.0, 10.0, 11.0]," + " [12.0, 13.0, 14.0, 15.0]]" + " sequence_lens = [1, 2, 3, 4]" + " time_axis = 1" + " batch_axis = 0" + "" + " output = [[0.0, 1.0, 2.0, 3.0 ]," + " [5.0, 4.0, 6.0, 7.0 ]," + " [10.0, 9.0, 8.0, 11.0]," + " [15.0, 14.0, 13.0, 12.0]]" + }]; + let arguments = (ins AnyTensor:$input, AnyTensor:$sequence_lens); + let results = (outs AnyTensor); +} + +def ONNXRoiAlignOp:ONNX_Op<"RoiAlign", + [NoSideEffect]> { + let summary = "ONNX RoiAlign operation"; + let description = [{ + "Region of Interest (RoI) align operation described in the" + "[Mask R-CNN paper](https://arxiv.org/abs/1703.06870)." + "RoiAlign consumes an input tensor X and region of interests (rois)" + "to apply pooling across each RoI; it produces a 4-D tensor of shape" + "(num_rois, C, output_height, output_width)." + "" + "RoiAlign is proposed to avoid the misalignment by removing" + "quantizations while converting from original image into feature" + "map and from feature map into RoI feature; in each ROI bin," + "the value of the sampled locations are computed directly" + "through bilinear interpolation." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$rois, AnyTensor:$batch_indices); + let results = (outs AnyTensor); +} + +def ONNXRoundOp:ONNX_Op<"Round", + [NoSideEffect]> { + let summary = "ONNX Round operation"; + let description = [{ + "Round takes one input Tensor and rounds the values, element-wise, meaning" + "it finds the nearest integer for each value." + "In case of halfs, the rule is to round them to the nearest even integer." + "The output tensor has the same shape and type as the input." + "" + "Examples:" + "```" + "round([0.9]) = [1.0]" + "round([2.5]) = [2.0]" + "round([2.3]) = [2.0]" + "round([1.5]) = [2.0]" + "round([-4.5]) = [-4.0]" + "```" + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXScanOp:ONNX_Op<"Scan", + [NoSideEffect]> { + let summary = "ONNX Scan operation"; + let description = [{ + "Scan can be used to iterate over one or more scan_input tensors," + "constructing zero or more scan_output tensors. It combines ideas from general recurrences," + "functional programming constructs such as scan, fold, map, and zip and is intended to enable" + "generalizations of RNN-like constructs for sequence-to-sequence processing." + "Other tensors (referred to as state_variables here) can be used to carry a state" + "when iterating from one element to another (similar to hidden-state in RNNs, also referred" + "to as loop-carried dependences in the context of loops)." + "Many common usages involve a single scan_input tensor (where functionality" + "similar to scan, fold and map can be obtained). When more than one scan_input is used," + "a behavior similar to zip is obtained." + "" + "The attribute body must be a graph, specifying the computation to be performed in" + "every iteration. It takes as input the current values of the state_variables and" + "the current iterated element of the scan_inputs. It must return the (updated) values" + "of the state_variables and zero or more scan_output_element tensors. The values of the" + "scan_output_element tensors are concatenated over all the iterations to produce the" + "scan_output values of the scan construct (similar to the concatenated intermediate" + "hidden-state values of RNN-like constructs). All the output tensors (state_variables as" + "well as scan_output_element tensors) are required to have the same shape in each iteration" + "of the loop (a restriction imposed to enable efficient memory allocation)." + "" + "Note that the iterated element passed to the body subgraph does not have a sequence" + "axis. It will have a rank one less than the rank of the corresponding scan_input." + "" + "The scan operation returns the final values of the state_variables as well as the" + "scan_outputs." + "" + "The optional attribute scan_input_directions specifies the direction (forward or backward)" + "for each scan input. If this attribute is omitted, all sequences are scanned in the forward" + "direction. A bidirectional scan may be performed by specifying the same tensor input twice" + "in the scan_inputs, once with a forward direction, and once with a backward direction." + "" + "The scan_output of the operation is produced by concatenating the scan_output_element" + "values produced by the body in each iteration. The optional attribute scan_output_directions" + "specifies the direction in which scan_output is constructed (by appending or prepending the" + "scan_output_element to scan_output in each iteration) for each scan_output. If this attribute" + "is omitted, the scan_output_element is appended to the scan_output in each iteration." + "" + "The optional attribute scan_input_axes specifies the axis to be scanned for each scan_input." + "If omitted, every scan_input will be scanned in axis 0. For example, if axis 0 is the" + "batch axis and axis 1 is the time axis (to be scanned), specify an axis value of 1." + "Note that scanning a non-zero axis may be less efficient than scanning axis zero." + "" + "The optional attribute scan_output_axes specifies the axis along which the scan_outputs" + "are accumulated for each scan_output. For example, if axis 1 is the time axis (to be" + "scanned) for both inputs and outputs, specify a scan_input axis and scan_output axis" + "value of 1." + "" + "Note that because of the ONNX restriction that only the last parameter of an operator can" + "be variadic, the initial-states and scan-inputs are listed together as one input parameter." + "Similarly, the final-states and scan-outputs are listed together as one output parameter." + "The attribute num_scan_inputs indicates the number M of scan-inputs." + "" + "The behavior of" + "" + " Scan <" + " num_scan_inputs = m," + " body = loop-body," + " scan_input_axes = [axis_1, ..., axis_m]" + " > (init_1, ..., init_n, scan_1, ..., scan_m)" + "" + "is equivalent to the following pseudo-code:" + "" + " // scan_i.shape[axis_i] denotes the (max) sequence-length of scan_i" + " // scan_i.shape[axis_i] is required to be equal to scan_j.shape[axis_j] for all i,j." + " sequence_length = scan_1.shape[axis_1];" + "" + " // initialize state-variables" + " st_1 = init_1; ... st_n = init_n;" + " // initialize scan-output variables: [] denotes an empty tensor" + " scan_out_1 = []; ...; scan_out_k = [];" + " // identify number of iterations:" + "" + " // execute loop" + " for (int t = 0; t < sequence_length; ++t) {" + " // generate the scan-input elements: the notation T[t] indicates the sub-tensor" + " // of rank one less than T obtained by indexing T at position t along axis k." + " si_1 = scan_1[t];" + " ... ;" + " si_m = scan_m[t];" + " // execute loop-body" + " st_1, ..., st_n, so_1, ..., so_k = loop-body(st_1, ..., st_n, si_1, ..., si_m)" + " // accumulate the scan-output elements" + " scan_out_1 = Concat(scan_out_1, so_1); ... ; scan_out_k = Concat(scan_out_k, so_k);" + " }" + "" + " return st_1, ..., st_n, scan_out_1, ..., scan_out_k;" + "" + "*Sample usage: Encoding RNN using a Scan*" + "" + "The following example shows how a simple RNN over an input tensor %X, with weight tensor %Wi," + "recurrence weight tensor %Ri, bias tensors %Wbi and %Rbi, and initial hidden-state %H_0 can" + "be encoded as a ScanLoop. Note that the loop-body is a nested graph, and it directly computes" + "%Wi, %Ri, %Wbi, and %Rbi (typically constants or initializers in the body graph). If these" + "values are computed in the outer graph, they need to be passed in as extra state_variables." + "" + " graph rnn-encoding {" + " %H_0 = ... " + " %X = ..." + " %Y_h, %Y = Scan[body = , num_scan_inputs=1](%H_0, %X)" + " return %Y, %Y_h" + " }" + "" + " graph rnn-cell-1 (" + " %H_tminus1[FLOAT, tensor]" + " %X_t[FLOAT, tensor]" + " ) {" + " %Wi = ..." + " %Ri = ..." + " %Wbi = ..." + " %Rbi = ..." + " %t1 = X_t * (Wi^T)" + " %t2 = H_tminus1*(Ri^T)" + " %t3 = Add(%t1, %t2)" + " %t4 = Add(%t3, %Wbi)" + " %t5 = Add(%t4, %Rbi)" + " %Ht = Tanh(%t5)" + " %Accumulate = Identity(%Ht)" + " return %Ht, %Accumulate" + " }" + "" + }]; + let arguments = (ins AnyTensor:$initial_state_and_scan_inputs); + let results = (outs AnyTensor); +} + +def ONNXScatterOp:ONNX_Op<"Scatter", + [NoSideEffect]> { + let summary = "ONNX Scatter operation"; + let description = [{ + "This operator is deprecated. Please use ScatterElements, which provides the same functionality." + "" + "Scatter takes three inputs `data`, `updates`, and `indices` of the same" + "rank r >= 1 and an optional attribute axis that identifies an axis of `data`" + "(by default, the outer-most axis, that is axis 0). The output of the operation" + "is produced by creating a copy of the input `data`, and then updating its value" + "to values specified by `updates` at specific index positions specified by" + "`indices`. Its output shape is the same as the shape of `data`." + "" + "For each entry in `updates`, the target index in `data` is obtained by combining" + "the corresponding entry in `indices` with the index of the entry itself: the" + "index-value for dimension = axis is obtained from the value of the corresponding" + "entry in `indices` and the index-value for dimension != axis is obtained from the" + "index of the entry itself." + "" + "For instance, in a 2-D tensor case, the update corresponding to the [i][j] entry" + "is performed as below:" + "```" + " output[indices[i][j]][j] = updates[i][j] if axis = 0, " + " output[i][indices[i][j]] = updates[i][j] if axis = 1," + "```" + "" + "This operator is the inverse of GatherElements. It is similar to Torch's Scatter operation." + "" + "Example 1:" + "```" + " data = [" + " [0.0, 0.0, 0.0]," + " [0.0, 0.0, 0.0]," + " [0.0, 0.0, 0.0]," + " ]" + " indices = [" + " [1, 0, 2]," + " [0, 2, 1]," + " ]" + " updates = [" + " [1.0, 1.1, 1.2]," + " [2.0, 2.1, 2.2]," + " ]" + " output = [" + " [2.0, 1.1, 0.0]" + " [1.0, 0.0, 2.2]" + " [0.0, 2.1, 1.2]" + " ]" + "```" + "Example 2:" + "```" + " data = [[1.0, 2.0, 3.0, 4.0, 5.0]]" + " indices = [[1, 3]]" + " updates = [[1.1, 2.1]]" + " axis = 1" + " output = [[1.0, 1.1, 3.0, 2.1, 5.0]]" + "```" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$indices, AnyTensor:$updates); + let results = (outs AnyTensor); +} + +def ONNXScatterElementsOp:ONNX_Op<"ScatterElements", + [NoSideEffect]> { + let summary = "ONNX ScatterElements operation"; + let description = [{ + "ScatterElements takes three inputs `data`, `updates`, and `indices` of the same" + "rank r >= 1 and an optional attribute axis that identifies an axis of `data`" + "(by default, the outer-most axis, that is axis 0). The output of the operation" + "is produced by creating a copy of the input `data`, and then updating its value" + "to values specified by `updates` at specific index positions specified by" + "`indices`. Its output shape is the same as the shape of `data`." + "" + "For each entry in `updates`, the target index in `data` is obtained by combining" + "the corresponding entry in `indices` with the index of the entry itself: the" + "index-value for dimension = axis is obtained from the value of the corresponding" + "entry in `indices` and the index-value for dimension != axis is obtained from the" + "index of the entry itself." + "" + "For instance, in a 2-D tensor case, the update corresponding to the [i][j] entry" + "is performed as below:" + "```" + " output[indices[i][j]][j] = updates[i][j] if axis = 0, " + " output[i][indices[i][j]] = updates[i][j] if axis = 1," + "```" + "" + "This operator is the inverse of GatherElements. It is similar to Torch's Scatter operation." + "" + "Example 1:" + "```" + " data = [" + " [0.0, 0.0, 0.0]," + " [0.0, 0.0, 0.0]," + " [0.0, 0.0, 0.0]," + " ]" + " indices = [" + " [1, 0, 2]," + " [0, 2, 1]," + " ]" + " updates = [" + " [1.0, 1.1, 1.2]," + " [2.0, 2.1, 2.2]," + " ]" + " output = [" + " [2.0, 1.1, 0.0]" + " [1.0, 0.0, 2.2]" + " [0.0, 2.1, 1.2]" + " ]" + "```" + "Example 2:" + "```" + " data = [[1.0, 2.0, 3.0, 4.0, 5.0]]" + " indices = [[1, 3]]" + " updates = [[1.1, 2.1]]" + " axis = 1" + " output = [[1.0, 1.1, 3.0, 2.1, 5.0]]" + "```" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$indices, AnyTensor:$updates); + let results = (outs AnyTensor); +} + +def ONNXScatterNDOp:ONNX_Op<"ScatterND", + [NoSideEffect]> { + let summary = "ONNX ScatterND operation"; + let description = [{ + "ScatterND takes three inputs `data` tensor of rank r >= 1, `indices` tensor of rank q >= 1," + "and `updates` tensor of rank q + r - indices.shape[-1] - 1. The output of the operation" + "is produced by creating a copy of the input `data`, and then updating its value to values" + "specified by `updates` at specific index positions specified by `indices`. Its output shape" + "is the same as the shape of `data`. Note that `indices` should not have duplicate entries." + "That is, two or more `updates` for the same index-location is not supported." + "" + "`indices` is an integer tensor. Let k denote indices.shape[-1], the last dimension in the shape of `indices`." + " `indices` is treated as a (q-1)-dimensional tensor of k-tuples, where each k-tuple is a partial-index into `data`." + "Hence, k can be a value at most the rank of `data`. When k equals rank(data), each update entry specifies an" + "update to a single element of the tensor. When k is less than rank(data) each update entry specifies an" + "update to a slice of the tensor." + "" + "`updates` is treated as a (q-1)-dimensional tensor of replacement-slice-values. Thus, the" + "first (q-1) dimensions of updates.shape must match the first (q-1) dimensions of indices.shape." + "The remaining dimensions of `updates` correspond to the dimensions of the" + "replacement-slice-values. Each replacement-slice-value is a (r-k) dimensional tensor," + "corresponding to the trailing (r-k) dimensions of `data`. Thus, the shape of `updates`" + "must equal indices.shape[0:q-1] ++ data.shape[k:r-1], where ++ denotes the concatenation" + "of shapes." + "" + "The `output` is calculated via the following equation:" + "" + " output = np.copy(data)" + " update_indices = indices.shape[:-1]" + " for idx in np.ndindex(update_indices):" + " output[indices[idx]] = updates[idx]" + "" + "The order of iteration in the above loop is not specified." + "In particular, indices should not have duplicate entries: that is, if idx1 != idx2, then indices[idx1] != indices[idx2]." + "This ensures that the output value does not depend on the iteration order." + "" + "This operator is the inverse of GatherND." + "" + "Example 1:" + "```" + " data = [1, 2, 3, 4, 5, 6, 7, 8]" + " indices = [[4], [3], [1], [7]]" + " updates = [9, 10, 11, 12]" + " output = [1, 11, 3, 10, 9, 6, 7, 12]" + "```" + "" + "Example 2:" + "```" + " data = [[[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]]," + " [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]]," + " [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]," + " [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]]" + " indices = [[0], [2]]" + " updates = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]]," + " [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]]" + " output = [[[5, 5, 5, 5], [6, 6, 6, 6], [7, 7, 7, 7], [8, 8, 8, 8]]," + " [[1, 2, 3, 4], [5, 6, 7, 8], [8, 7, 6, 5], [4, 3, 2, 1]]," + " [[1, 1, 1, 1], [2, 2, 2, 2], [3, 3, 3, 3], [4, 4, 4, 4]]," + " [[8, 7, 6, 5], [4, 3, 2, 1], [1, 2, 3, 4], [5, 6, 7, 8]]]" + "```" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$indices, AnyTensor:$updates); + let results = (outs AnyTensor); +} + +def ONNXSeluOp:ONNX_Op<"Selu", + [NoSideEffect]> { + let summary = "ONNX Selu operation"; + let description = [{ + "Selu takes one input data (Tensor) and produces one output data" + "(Tensor) where the scaled exponential linear unit function," + "`y = gamma * (alpha * e^x - alpha) for x <= 0`, `y = gamma * x for x > 0`," + "is applied to the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXSequenceAtOp:ONNX_Op<"SequenceAt", + [NoSideEffect]> { + let summary = "ONNX SequenceAt operation"; + let description = [{ + "Outputs a tensor copy from the tensor at 'position' in 'input_sequence'." + "Accepted range for 'position' is in `[-n, n - 1]`, where `n` is the number of tensors in 'input_sequence'." + "Negative value means counting positions from the back." + }]; + let arguments = (ins AnyTensor:$input_sequence, AnyTensor:$position); + let results = (outs AnyTensor); +} + +def ONNXSequenceConstructOp:ONNX_Op<"SequenceConstruct", + [NoSideEffect]> { + let summary = "ONNX SequenceConstruct operation"; + let description = [{ + "Construct a tensor sequence containing 'inputs' tensors." + "All tensors in 'inputs' must have the same data type." + }]; + let arguments = (ins Variadic:$inputs); + let results = (outs AnyTensor); +} + +def ONNXSequenceEmptyOp:ONNX_Op<"SequenceEmpty", + [NoSideEffect]> { + let summary = "ONNX SequenceEmpty operation"; + let description = [{ + "Construct an empty tensor sequence, with given data type." + }]; + let arguments = (ins ); + let results = (outs AnyTensor); +} + +def ONNXSequenceEraseOp:ONNX_Op<"SequenceErase", + [NoSideEffect]> { + let summary = "ONNX SequenceErase operation"; + let description = [{ + "Outputs a tensor sequence that removes the tensor at 'position' from 'input_sequence'." + "Accepted range for 'position' is in `[-n, n - 1]`, where `n` is the number of tensors in 'input_sequence'." + "Negative value means counting positions from the back." + "'position' is optional, by default it erases the last tensor from 'input_sequence'." + }]; + let arguments = (ins AnyTensor:$input_sequence, AnyTensor:$position); + let results = (outs AnyTensor); +} + +def ONNXSequenceInsertOp:ONNX_Op<"SequenceInsert", + [NoSideEffect]> { + let summary = "ONNX SequenceInsert operation"; + let description = [{ + "Outputs a tensor sequence that inserts 'tensor' into 'input_sequence' at 'position'." + "'tensor' must have the same data type as 'input_sequence'." + "Accepted range for 'position' is in `[-n, n]`, where `n` is the number of tensors in 'input_sequence'." + "Negative value means counting positions from the back." + "'position' is optional, by default it inserts 'tensor' to the back of 'input_sequence'." + }]; + let arguments = (ins AnyTensor:$input_sequence, AnyTensor:$tensor, AnyTensor:$position); + let results = (outs AnyTensor); +} + +def ONNXSequenceLengthOp:ONNX_Op<"SequenceLength", + [NoSideEffect]> { + let summary = "ONNX SequenceLength operation"; + let description = [{ + "Produces a scalar(tensor of empty shape) containing the number of tensors in 'input_sequence'." + }]; + let arguments = (ins AnyTensor:$input_sequence); + let results = (outs AnyTensor); +} + +def ONNXShapeOp:ONNX_Op<"Shape", + [NoSideEffect]> { + let summary = "ONNX Shape operation"; + let description = [{ + "Takes a tensor as input and outputs an 1D int64 tensor containing the shape of the input tensor." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXShrinkOp:ONNX_Op<"Shrink", + [NoSideEffect]> { + let summary = "ONNX Shrink operation"; + let description = [{ + "Shrink takes one input data (Tensor) and produces one Tensor output," + "having same datatype and shape with input. It has two attributes, lambd and" + "bias. The formula of this operator is: If x < -lambd, y = x + bias;" + "If x > lambd, y = x - bias; Otherwise, y = 0." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSigmoidOp:ONNX_Op<"Sigmoid", + [NoSideEffect]> { + let summary = "ONNX Sigmoid operation"; + let description = [{ + "Sigmoid takes one input data (Tensor) and produces one output data" + "(Tensor) where the sigmoid function, y = 1 / (1 + exp(-x)), is applied to the" + "tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXSignOp:ONNX_Op<"Sign", + [NoSideEffect]> { + let summary = "ONNX Sign operation"; + let description = [{ + "Calculate the sign of the given input tensor element-wise." + "If input > 0, output 1. if input < 0, output -1. if input == 0, output 0." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSinOp:ONNX_Op<"Sin", + [NoSideEffect]> { + let summary = "ONNX Sin operation"; + let description = [{ + "Calculates the sine of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSinhOp:ONNX_Op<"Sinh", + [NoSideEffect]> { + let summary = "ONNX Sinh operation"; + let description = [{ + "Calculates the hyperbolic sine of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSizeOp:ONNX_Op<"Size", + [NoSideEffect]> { + let summary = "ONNX Size operation"; + let description = [{ + "Takes a tensor as input and outputs a int64 scalar that equals to the total number of elements of the input tensor." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXSliceOp:ONNX_Op<"Slice", + [NoSideEffect]> { + let summary = "ONNX Slice operation"; + let description = [{ + "Produces a slice of the input tensor along multiple axes. Similar to numpy:" + "https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html" + "Slices uses `starts`, `ends`, `axes` and `steps` inputs to specify the start and end" + "dimension and step for each axis in the list of axes, it uses this information to" + "slice the input `data` tensor. If a negative value is passed for any of the" + "start or end indices, it represent number of elements before the end of that" + "dimension. If the value passed to start or end is larger than the `n` (the" + "number of elements in this dimension), it represents `n`. For slicing to the" + "end of a dimension with unknown size, it is recommended to pass in `INT_MAX`." + "If a negative value is passed for step, it represents slicing backward." + "If `axes` are omitted, they are set to `[0, ..., ndim-1]`." + "If `steps` are omitted, they are set to `[1, ..., 1]` of length `len(starts)`" + "Example 1:" + " data = [" + " [1, 2, 3, 4]," + " [5, 6, 7, 8]," + " ]" + " axes = [0, 1]" + " starts = [1, 0]" + " ends = [2, 3]" + " steps = [1, 2]" + " result = [" + " [5, 7]," + " ]" + "Example 2:" + " data = [" + " [1, 2, 3, 4]," + " [5, 6, 7, 8]," + " ]" + " starts = [0, 1]" + " ends = [-1, 1000]" + " result = [" + " [2, 3, 4]," + " ]" + }]; + let arguments = (ins AnyTensor:$data, AnyTensor:$starts, AnyTensor:$ends, AnyTensor:$axes, AnyTensor:$steps); + let results = (outs AnyTensor); +} + +def ONNXSoftmaxOp:ONNX_Op<"Softmax", + [NoSideEffect]> { + let summary = "ONNX Softmax operation"; + let description = [{ + "The operator computes the softmax (normalized exponential) values for each layer in the batch" + " of the given input." + "" + "The input does not need to explicitly be a 2D vector; rather, it will be" + "coerced into one. For an arbitrary n-dimensional tensor" + "input \in [a_0, a_1, ..., a_{k-1}, a_k, ..., a_{n-1\}\] and k is" + "the axis provided, then input will be coerced into a 2-dimensional tensor with" + "dimensions [a_0 * ... * a_{k-1}, a_k * ... * a_{n-1\}\]. For the default" + "case where axis=1, this means the input tensor will be coerced into a 2D tensor" + "of dimensions [a_0, a_1 * ... * a_{n-1\}\], where a_0 is often the batch size." + "In this situation, we must have a_0 = N and a_1 * ... * a_{n-1} = D." + "Each of these dimensions must be matched correctly, or else the operator" + "will throw errors. The output tensor has the same shape" + "and contains the softmax values of the corresponding input." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSoftplusOp:ONNX_Op<"Softplus", + [NoSideEffect]> { + let summary = "ONNX Softplus operation"; + let description = [{ + "Softplus takes one input data (Tensor) and produces one output data" + "(Tensor) where the softplus function, y = ln(exp(x) + 1), is applied to" + "the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXSoftsignOp:ONNX_Op<"Softsign", + [NoSideEffect]> { + let summary = "ONNX Softsign operation"; + let description = [{ + "Calculates the softsign (x/(1+|x|)) of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSpaceToDepthOp:ONNX_Op<"SpaceToDepth", + [NoSideEffect]> { + let summary = "ONNX SpaceToDepth operation"; + let description = [{ + "SpaceToDepth rearranges blocks of spatial data into depth. More specifically," + "this op outputs a copy of the input tensor where values from the height and width dimensions" + "are moved to the depth dimension." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSplitOp:ONNX_Op<"Split", + [NoSideEffect]> { + let summary = "ONNX Split operation"; + let description = [{ + "Split a tensor into a list of tensors, along the specified" + "'axis'. Lengths of the parts can be specified using argument 'split'." + "Otherwise, the tensor is split to equal sized parts." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXSplitToSequenceOp:ONNX_Op<"SplitToSequence", + [NoSideEffect]> { + let summary = "ONNX SplitToSequence operation"; + let description = [{ + "Split a tensor into a sequence of tensors, along the specified" + "'axis'. Lengths of the parts can be specified using argument 'split'." + "'split' must contain only positive numbers." + "'split' is either a scalar (tensor of empty shape), or a 1-D tensor." + "If 'split' is a scalar, then 'input' will be split into equally sized chunks(if possible)." + "Last chunk will be smaller if the 'input' size along the given axis 'axis' is not divisible" + "by 'split'." + "Otherwise, the tensor is split into 'size(split)' chunks, with lengths of the parts on 'axis'" + "specified in 'split'. In this scenario, the sum of entries in 'split' must be equal to the" + "dimension size of input tensor on 'axis'." + }]; + let arguments = (ins AnyTensor:$input, AnyTensor:$split); + let results = (outs AnyTensor); +} + +def ONNXSqrtOp:ONNX_Op<"Sqrt", + [NoSideEffect]> { + let summary = "ONNX Sqrt operation"; + let description = [{ + "Square root takes one input data (Tensor) and produces one output data" + "(Tensor) where the square root is, y = x^0.5, is applied to" + "the tensor elementwise. If x is negative, then it will return NaN." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXSqueezeOp:ONNX_Op<"Squeeze", + [NoSideEffect]> { + let summary = "ONNX Squeeze operation"; + let description = [{ + "Remove single-dimensional entries from the shape of a tensor." + "Takes a parameter `axes` with a list of axes to squeeze." + "If `axes` is not provided, all the single dimensions will be removed from" + "the shape. If an axis is selected with shape entry not equal to one, an error is raised." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXStringNormalizerOp:ONNX_Op<"StringNormalizer", + [NoSideEffect]> { + let summary = "ONNX StringNormalizer operation"; + let description = [{ + "StringNormalization performs string operations for basic cleaning." + "This operator has only one input (denoted by X) and only one output" + "(denoted by Y). This operator first examines the elements in the X," + "and removes elements specified in "stopwords" attribute." + "After removing stop words, the intermediate result can be further lowercased," + "uppercased, or just returned depending the "case_change_action" attribute." + "This operator only accepts [C]- and [1, C]-tensor." + "If all elements in X are dropped, the output will be the empty value of string tensor with shape [1]" + "if input shape is [C] and shape [1, 1] if input shape is [1, C]." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXSubOp:ONNX_Op<"Sub", + [NoSideEffect]> { + let summary = "ONNX Sub operation"; + let description = [{ + "Performs element-wise binary subtraction (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + +def ONNXSumOp:ONNX_Op<"Sum", + [NoSideEffect]> { + let summary = "ONNX Sum operation"; + let description = [{ + "Element-wise sum of each of the input tensors (with Numpy-style broadcasting support)." + "All inputs and outputs must have the same data type." + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins Variadic:$data_0); + let results = (outs AnyTensor); +} + +def ONNXTanOp:ONNX_Op<"Tan", + [NoSideEffect]> { + let summary = "ONNX Tan operation"; + let description = [{ + "Calculates the tangent of the given input tensor, element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXTanhOp:ONNX_Op<"Tanh", + [NoSideEffect]> { + let summary = "ONNX Tanh operation"; + let description = [{ + "Calculates the hyperbolic tangent of the given input tensor element-wise." + }]; + let arguments = (ins AnyTensor:$input); + let results = (outs AnyTensor); +} + +def ONNXTfIdfVectorizerOp:ONNX_Op<"TfIdfVectorizer", + [NoSideEffect]> { + let summary = "ONNX TfIdfVectorizer operation"; + let description = [{ + "This transform extracts n-grams from the input sequence and save them as a vector. Input can" + "be either a 1-D or 2-D tensor. For 1-D input, output is the n-gram representation of that input." + "For 2-D input, the output is also a 2-D tensor whose i-th row is the n-gram representation of the i-th input row." + "More specifically, if input shape is [C], the corresponding output shape would be [max(ngram_indexes) + 1]." + "If input shape is [N, C], this operator produces a [N, max(ngram_indexes) + 1]-tensor." + "" + "In contrast to standard n-gram extraction, here, the indexes of extracting an n-gram from the original" + "sequence are not necessarily consecutive numbers. The discontinuity between indexes are controlled by the number of skips." + "If the number of skips is 2, we should skip two tokens when scanning through the original sequence." + "Let's consider an example. Assume that input sequence is [94, 17, 36, 12, 28] and the number of skips is 2." + "The associated 2-grams are [94, 12] and [17, 28] respectively indexed by [0, 3] and [1, 4]." + "If the number of skips becomes 0, the 2-grams generated are [94, 17], [17, 36], [36, 12], [12, 28]" + "indexed by [0, 1], [1, 2], [2, 3], [3, 4], respectively." + "" + "The output vector (denoted by Y) stores the count of each n-gram;" + "Y[ngram_indexes[i]] indicates the times that the i-th n-gram is found. The attribute ngram_indexes is used to determine the mapping" + "between index i and the corresponding n-gram's output coordinate. If pool_int64s is [94, 17, 17, 36], ngram_indexes is [1, 0]," + "ngram_counts=[0, 0], then the Y[0] (first element in Y) and Y[1] (second element in Y) are the counts of [17, 36] and [94, 17]," + "respectively. An n-gram which cannot be found in pool_strings/pool_int64s should be ignored and has no effect on the output." + "Note that we may consider all skips up to S when generating the n-grams." + "" + "The examples used above are true if mode is "TF". If mode is "IDF", all the counts larger than 1 would be truncated to 1 and" + "the i-th element in weights would be used to scale (by multiplication) the count of the i-th n-gram in pool. If mode is "TFIDF"," + "this operator first computes the counts of all n-grams and then scale them by the associated values in the weights attribute." + "" + "Only one of pool_strings and pool_int64s can be set. If pool_int64s is set, the input should be an integer tensor." + "If pool_strings is set, the input must be a string tensor." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXThresholdedReluOp:ONNX_Op<"ThresholdedRelu", + [NoSideEffect]> { + let summary = "ONNX ThresholdedRelu operation"; + let description = [{ + "ThresholdedRelu takes one input data (Tensor) and produces one output data" + "(Tensor) where the rectified linear function, y = x for x > alpha, y = 0 otherwise," + "is applied to the tensor elementwise." + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor); +} + +def ONNXTileOp:ONNX_Op<"Tile", + [NoSideEffect]> { + let summary = "ONNX Tile operation"; + let description = [{ + "Constructs a tensor by tiling a given tensor." + "This is the same as function `tile` in Numpy, but no broadcast." + "For example A = [[1, 2], [3, 4]], B = [1, 2], tile(A, B) = [[1, 2, 1, 2], [3, 4, 3, 4]]" + }]; + let arguments = (ins AnyTensor:$input, AnyTensor:$repeats); + let results = (outs AnyTensor); +} + +def ONNXTopKOp:ONNX_Op<"TopK", + [NoSideEffect]> { + let summary = "ONNX TopK operation"; + let description = [{ + "Retrieve the top-K largest or smallest elements along a specified axis. Given an input tensor of" + "shape [a_1, a_2, ..., a_n, r] and integer argument k, return two outputs:" + " -Value tensor of shape [a_1, a_2, ..., a_{axis-1}, k, a_{axis+1}, ... a_n]" + " which contains the values of the top k elements along the specified axis" + " -Index tensor of shape [a_1, a_2, ..., a_{axis-1}, k, a_{axis+1}, ... a_n] which" + " contains the indices of the top k elements (original indices from the input" + " tensor)." + "" + "If "largest" is 1 (the default value) then the k largest elements are returned." + "If "sorted" is 1 (the default value) then the resulting k elements will be sorted." + "If "sorted" is 0, order of returned 'Values' and 'Indices' are undefined." + "" + "Given two equivalent values, this operator uses the indices along the axis as" + " a tiebreaker. That is, the element with the lower index will appear first." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$K); + let results = (outs AnyTensor, AnyTensor); +} + +def ONNXTransposeOp:ONNX_Op<"Transpose", + [NoSideEffect]> { + let summary = "ONNX Transpose operation"; + let description = [{ + "Transpose the input tensor similar to numpy.transpose. For example, when" + "perm=(1, 0, 2), given an input tensor of shape (1, 2, 3), the output shape" + "will be (2, 1, 3)." + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXUniqueOp:ONNX_Op<"Unique", + [NoSideEffect]> { + let summary = "ONNX Unique operation"; + let description = [{ + "Find the unique elements of a tensor. When an optional attribute 'axis' is provided, unique subtensors sliced along the 'axis' are returned. " + "Otherwise the input tensor is flattened and unique values of the flattened tensor are returned. " + "" + "This operator returns the unique values or sliced unique subtensors of the input tensor and three optional outputs. " + "The first output tensor 'Y' contains all unique values or subtensors of the input. " + "The second optional output tensor 'indices' contains indices of 'Y' elements' first occurance in 'X'.. " + "The third optional output tensor 'inverse_indices' contains, for elements of 'X', its corresponding indices in 'Y'. ". " + "The fourth optional output tensor 'counts' contains the count of each element of 'Y' in the input. " + "" + "Outputs are either sorted in ascending order or optionally in the order of the first occurrence of the values in the input. " + "" + "https://docs.scipy.org/doc/numpy/reference/generated/numpy.unique.html" + "" + "Example 1:" + " input_X = [2, 1, 1, 3, 4, 3]" + " attribute_sorted = 0" + " attribute_axis = None" + " output_Y = [2, 1, 3, 4]" + " output_indices = [0, 1, 3, 4]" + " output_inverse_indices = [0, 1, 1, 2, 3, 2]" + " output_counts = [1, 2, 2, 1]" + "" + "Example 2:" + " input_X = [[1, 3], [2, 3]]" + " attribute_sorted = 1" + " attribute_axis = None" + " output_Y = [1, 2, 3]" + " output_indices = [0, 2, 1]" + " output_inverse_indices = [0, 2, 1, 2]" + " output_counts = [1, 1, 2]" + "" + "Example 3:" + " input_X = [[1, 0, 0], [1, 0, 0], [2, 3, 4]]" + " attribute_sorted = 1" + " attribute_axis = 0" + " output_Y = [[1, 0, 0], [2, 3, 4]]" + " output_indices = [0, 2]" + " output_inverse_indices = [0, 0, 1]" + " output_counts = [2, 1]" + "" + "Example 4:" + " input_x = [[[1., 1.], [0., 1.], [2., 1.], [0., 1.]], " + " [[1., 1.], [0., 1.], [2., 1.], [0., 1.]]]" + " attribute_sorted = 1" + " attribute_axis = 1" + "" + " intermediate data are presented below for better understanding: " + " " + " there are 4 subtensors sliced along axis 1 of input_x (shape = (2, 4, 2)):" + " A: [[1, 1], [1, 1]], " + " [[0, 1], [0, 1]], " + " [[2, 1], [2, 1]], " + " [[0, 1], [0, 1]]." + " " + " there are 3 unique subtensors: " + " [[1, 1], [1, 1]], " + " [[0, 1], [0, 1]], " + " [[2, 1], [2, 1]]." + " " + " sorted unique subtensors:" + " B: [[0, 1], [0, 1]], " + " [[1, 1], [1, 1]], " + " [[2, 1], [2, 1]]." + " " + " output_Y is constructed from B:" + " [[[0. 1.], [1. 1.], [2. 1.]], " + " [[0. 1.], [1. 1.], [2. 1.]]]" + "" + " output_indices is to map from B to A:" + " [1, 0, 2]" + " " + " output_inverse_indices is to map from A to B:" + " [1, 0, 2, 0]" + "" + " output_counts = [2 1 1]" + }]; + let arguments = (ins AnyTensor:$X); + let results = (outs AnyTensor, AnyTensor, AnyTensor, AnyTensor); +} + +def ONNXUnsqueezeOp:ONNX_Op<"Unsqueeze", + [NoSideEffect]> { + let summary = "ONNX Unsqueeze operation"; + let description = [{ + "Insert single-dimensional entries to the shape of an input tensor (`data`)." + "Takes one required argument `axes` - which contains a list of dimension indices and this operator will insert a dimension of value `1` into the corresponding index of the output tensor (`expanded`)." + "" + "For example:" + " Given an input tensor (`data`) of shape [3, 4, 5], then" + " Unsqueeze(data, axes=[0, 4]) outputs a tensor (`expanded`) containing same data as `data` but with shape [1, 3, 4, 5, 1]." + "" + "The attribute `axes` should not contain any duplicate entries. It is an error if it contains duplicates." + "The rank of the output tensor (`output_rank`) is the rank of the input tensor (`data`) plus the number of values in `axes`." + "Each value in `axes` should be within the (inclusive) range [-output_rank , output_rank - 1]. " + "The order of values in `axes` does not matter and can come in any order. " + "" + }]; + let arguments = (ins AnyTensor:$data); + let results = (outs AnyTensor); +} + +def ONNXUpsampleOp:ONNX_Op<"Upsample", + [NoSideEffect]> { + let summary = "ONNX Upsample operation"; + let description = [{ + "Upsample the input tensor." + "Each dimension value of the output tensor is:" + " output_dimension = floor(input_dimension * scale)." + }]; + let arguments = (ins AnyTensor:$X, AnyTensor:$scales); + let results = (outs AnyTensor); +} + +def ONNXWhereOp:ONNX_Op<"Where", + [NoSideEffect]> { + let summary = "ONNX Where operation"; + let description = [{ + "Return elements, either from X or Y, depending on condition" + " (with Numpy-style broadcasting support)." + " Where behaves like numpy.where with three parameters:" + " https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html" + }]; + let arguments = (ins AnyTensor:$condition, AnyTensor:$X, AnyTensor:$Y); + let results = (outs AnyTensor); +} + +def ONNXXorOp:ONNX_Op<"Xor", + [NoSideEffect]> { + let summary = "ONNX Xor operation"; + let description = [{ + "Returns the tensor resulted from performing the `xor` logical operation" + "elementwise on the input tensors `A` and `B` (with Numpy-style broadcasting support)." + "" + "This operator supports **multidirectional (i.e., Numpy-style) broadcasting**; for more details please check [the doc](Broadcasting.md)." + }]; + let arguments = (ins AnyTensor:$A, AnyTensor:$B); + let results = (outs AnyTensor); +} + diff --git a/test/mlir/onnx/onnx_canonicalization.mlir b/test/mlir/onnx/onnx_canonicalization.mlir index f71efe7..7b7a79c 100644 --- a/test/mlir/onnx/onnx_canonicalization.mlir +++ b/test/mlir/onnx/onnx_canonicalization.mlir @@ -7,8 +7,8 @@ module { %1 = "frontend.input t2"() : () -> tensor<10x10xf32> %2 = "frontend.input t3"() : () -> tensor<10x10xf32> // CHECK: %{{[0-9]+}} = "onnx.full_gemm"(%{{.*}}, %{{.*}}, %{{.*}}) : (tensor<10x10xf32>, tensor<10x10xf32>, tensor<10x10xf32>) -> tensor<10x10xf32> - %3 = "onnx.matmul"(%0, %1) : (tensor<10x10xf32>, tensor<10x10xf32>) -> tensor<10x10xf32> - %4 = "onnx.add"(%3, %2) : (tensor<10x10xf32>, tensor<10x10xf32>) -> tensor<10x10xf32> + %3 = "onnx.MatMul"(%0, %1) : (tensor<10x10xf32>, tensor<10x10xf32>) -> tensor<10x10xf32> + %4 = "onnx.Add"(%3, %2) : (tensor<10x10xf32>, tensor<10x10xf32>) -> tensor<10x10xf32> %5 = "frontend.output t4"(%4) : (tensor<10x10xf32>) -> tensor<10x10xf32> } -} \ No newline at end of file +}