From 1df264f4b371bd990084871c8801a40c746ba012 Mon Sep 17 00:00:00 2001 From: Dwayne Robinson Date: Tue, 24 Mar 2020 00:03:08 -0700 Subject: [PATCH] Fix Range. --- .../inc/MLOperatorAuthor.h | 2 +- .../src/ExecutionProvider.cpp | 2 +- .../src/Operators/DmlOperatorCumSum.cpp | 9 +- .../src/Operators/DmlOperatorRange.cpp | 47 +--- .../src/Operators/OperatorRegistration.cpp | 19 +- .../OperatorAuthorHelper/OperatorHelper.cpp | 237 ++++++++++++++++-- .../dml/OperatorAuthorHelper/OperatorHelper.h | 172 +++++++++---- 7 files changed, 355 insertions(+), 133 deletions(-) diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h index 29c806acf0..a821755092 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/inc/MLOperatorAuthor.h @@ -49,7 +49,7 @@ enum class MLOperatorAttributeType : uint32_t //! \brief Specifies the data type of a tensor. //! Each data type numerically matches corresponding ONNX types. enum class MLOperatorTensorDataType : uint32_t -{ +{ //! Undefined (unused). Undefined = 0, diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp index 84b298ca77..630e3bd3d8 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/ExecutionProvider.cpp @@ -181,7 +181,7 @@ namespace Dml // CPU Allocator used to create buffers for the MemcpyFromHost operator. m_cpuInputAllocator = std::make_shared(OrtMemType::OrtMemTypeCPUInput); m_cpuOutputAllocator = std::make_shared(OrtMemType::OrtMemTypeCPUOutput); - + CreateDmlKernelRegistry(&m_kernelRegistry, &m_internalRegInfoMap); } diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorCumSum.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorCumSum.cpp index 8eaa00f567..1f8cf4aa31 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorCumSum.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorCumSum.cpp @@ -29,13 +29,10 @@ public: int32_t onnxAxis = 0; if (kernelCreationContext.IsInputValid(1)) { + uint64_t rawAxisBytes; MLOperatorTensor axisTensor = kernelCreationContext.GetConstantInputTensor(1); - const uint32_t axisElementCount = ComputeElementCountFromDimensions(axisTensor.GetShape()); - ML_CHECK_VALID_ARGUMENT(axisTensor.IsCpuData(), "CumSum's 'axis' tensor must be a CPU Tensor."); - ML_CHECK_VALID_ARGUMENT(axisElementCount == 1, "CumSum's 'axis' tensor must have one element."); - - const void* tensorData = axisTensor.GetByteData(); - onnxAxis = static_cast(ReadAsInt64(axisTensor.GetTensorDataType(), tensorData)); + ReadScalarTensorData(axisTensor, /*out*/ &rawAxisBytes, sizeof(rawAxisBytes)); + onnxAxis = gsl::narrow_cast(ReadAsInt64(axisTensor.GetTensorDataType(), /*out*/ &rawAxisBytes)); } uint32_t dmlAxis = GetDmlAdjustedAxis(onnxAxis, kernelCreationContext, m_inputTensorDescs.front().GetDimensionCount()); diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRange.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRange.cpp index bd0f3936e4..821ba6aaa6 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRange.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlOperatorRange.cpp @@ -23,53 +23,16 @@ public: std::vector> inputIndices = {}; // All tensors are CPU bound. std::vector> outputIndices = { 0 }; DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices); - -//-- // Unsqueeze the indices tensor by inserting a flat dimension of size 1, -//-- // and compute the output tensor by expanding along the active axis. -//-- // This way they are both size-compatible and directly consumable by DirectML. -//-- std::vector indicesDimensions; -//-- indicesDimensions = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(0); -//-- indicesDimensions.insert(indicesDimensions.begin() + m_absoluteAxis, 1u); -//-- -//-- // Update the tensor descriptions with new sizes. -//-- m_inputTensorDescs[0] = -//-- TensorDesc( -//-- m_inputTensorDescs[0].GetMlOperatorDataType(), -//-- gsl::make_span(indicesDimensions), -//-- gsl::make_span(indicesDimensions), -//-- TensorAxis::DoNotCoerce, -//-- TensorAxis::W, -//-- TensorAxis::RightAligned, -//-- NchwDimensionCount, // minDimensionCount -//-- 0 -//-- ); -//-- -//-- m_outputTensorDescs[0] = -//-- TensorDesc( -//-- m_outputTensorDescs[0].GetMlOperatorDataType(), -//-- gsl::make_span(m_outputDimensions), -//-- gsl::make_span(m_outputDimensions), -//-- TensorAxis::DoNotCoerce, -//-- TensorAxis::W, -//-- TensorAxis::RightAligned, -//-- NchwDimensionCount, // minDimensionCount -//-- 0 -//-- ); -//-- -//-- // Adjust the axis so it's in DML's terms rather than the original ONNX indexing. -//-- uint32_t dmlAxis = GetDmlAdjustedAxis( -//-- m_absoluteAxis, -//-- gsl::narrow_cast(indicesDimensions.size()), -//-- m_inputTensorDescs.front().GetDimensionCount() -//-- ); - + std::vector inputDescs = GetDmlInputDescs(); std::vector outputDescs = GetDmlOutputDescs(); DML_FILL_VALUE_SEQUENCE_OPERATOR_DESC operatorDesc = {}; operatorDesc.ValueDataType = m_outputTensorDescs[0].GetDmlDataType();; - operatorDesc.ValueStart.Float32 = 1; // todo::: - operatorDesc.ValueDelta.Float32 = 1; + static_assert(sizeof(operatorDesc.ValueStart) == sizeof(m_valueStart)); + static_assert(sizeof(operatorDesc.ValueDelta) == sizeof(m_valueDelta)); + memcpy(&operatorDesc.ValueStart, &m_valueStart, sizeof(m_valueStart)); + memcpy(&operatorDesc.ValueDelta, &m_valueDelta, sizeof(m_valueDelta)); operatorDesc.OutputTensor = outputDescs.data(); DML_OPERATOR_DESC opDesc = { DML_OPERATOR_FILL_VALUE_SEQUENCE, &operatorDesc }; diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp index 695484a833..1dc7727749 100644 --- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp +++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp @@ -230,7 +230,7 @@ const static char* const typeNameListLogicalComparison[2] = { "T", "T1" }; const static char* const typeNameListT1T2[2] = { "T1", "T2" }; const static char* const typeNameListConstantOfShape[2] = { "T1", "T2" }; const static char* const typeNameListScatterGather[2] = { "T", "Tind" }; -const static char* const typeNameListScatterGatherND[2] = { "T" }; // Tind is curiously missing, only allowing 64-bit. +const static char* const typeNameListScatterGatherND[1] = { "T" }; // Tind is curiously missing, only allowing 64-bit. const static char* const typeNameListQuantize[2] = { "T1", "T2" }; const static char* const typeNameListWhere[2] = { "B", "T" }; const static char* const typeNameListOneHot[3] = { "T1", "T2", "T3" }; @@ -246,7 +246,7 @@ const static SupportedTensorDataTypes supportedTypeListTopK[2] = {SupportedTenso const static SupportedTensorDataTypes supportedTypeListIndices[1] = { SupportedTensorDataTypes::Int32|SupportedTensorDataTypes::Int64 }; const static SupportedTensorDataTypes supportedTypeListCast[2] = { SupportedTensorDataTypes::AllScalars, SupportedTensorDataTypes::Scalars8to32 }; const static SupportedTensorDataTypes supportedTypeListScatterGather[2] = { SupportedTensorDataTypes::NumericDefault, SupportedTensorDataTypes::Int32 | SupportedTensorDataTypes::Int64 }; -const static SupportedTensorDataTypes supportedTypeListScatterGatherND[2] = { SupportedTensorDataTypes::NumericDefault }; +const static SupportedTensorDataTypes supportedTypeListScatterGatherND[1] = { SupportedTensorDataTypes::NumericDefault }; const static SupportedTensorDataTypes supportedTypeListQuantizeLinear[2] = { SupportedTensorDataTypes::Float32 | SupportedTensorDataTypes::Int32, SupportedTensorDataTypes::UInt8 | SupportedTensorDataTypes::Int8 }; const static SupportedTensorDataTypes supportedTypeListDequantizeLinear[2] = { SupportedTensorDataTypes::Float32, SupportedTensorDataTypes::UInt8 | SupportedTensorDataTypes::Int8 | SupportedTensorDataTypes::Int32 }; const static SupportedTensorDataTypes supportedTypeListQuantize[2] = { SupportedTensorDataTypes::Float32, SupportedTensorDataTypes::UInt8 }; @@ -511,15 +511,16 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl {REG_INFO( 11, Round, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)}, {REG_INFO( 10, ReverseSequence, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)}, // TODO::: data types, why not registered?? {REG_INFO( 11, CumSum, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})}, - {REG_INFO( 11, Range, typeNameListDefault, supportedTypeListRange, DmGraphSupport::Supported), {0,1,2}}, + {REG_INFO( 11, Range, typeNameListDefault, supportedTypeListRange, DmGraphSupport::Supported, {0,1,2})}, + + {REG_INFO( 11, Gather, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)}, + {REG_INFO( 11, GatherElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)}, + {REG_INFO( 11, GatherND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)}, + {REG_INFO( 11, ScatterElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)}, + {REG_INFO( 11, ScatterND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)}, #if 0 - {REG_INFO( 9, MaxUnpool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {2})}, - {REG_INFO( 11, Gather, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)}, - -{REG_INFO( 11, GatherElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)}, - -{REG_INFO( 11, GatherND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)}, + {REG_INFO( 9, MaxUnpool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {2})}, {REG_INFO( 11, Resize, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})}, - -{REG_INFO( 11, ScatterElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)}, - -{REG_INFO( 11, ScatterND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)}, {REG_INFO( 11, QLinearConv, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)}, // T1 : tensor(int8), tensor(uint8) diff --git a/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.cpp b/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.cpp index 89909b97ef..24340b911e 100644 --- a/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.cpp +++ b/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.cpp @@ -6,36 +6,36 @@ namespace OperatorHelper { -bool ContainsEmptyDimensions(gsl::span dimensions) -{ - return std::find(dimensions.begin(), dimensions.end(), 0) != dimensions.end(); -} - -// Convert any negative axis into an absolute axis relative to the back end. -// So given 3 dimensions, a -1 refers to axis 2, and -3 to axis 0. -uint32_t HandleNegativeAxis(int32_t signedOnnxAxis, uint32_t dimCount) -{ - if (signedOnnxAxis < 0) + bool ContainsEmptyDimensions(gsl::span dimensions) { - signedOnnxAxis += dimCount; + return std::find(dimensions.begin(), dimensions.end(), 0) != dimensions.end(); } - uint32_t absoluteAxis = gsl::narrow_cast(signedOnnxAxis); - ML_CHECK_VALID_ARGUMENT(absoluteAxis < dimCount); - return absoluteAxis; -} -void HandleNegativeAxes(gsl::span onnxAxes, uint32_t dimCount) -{ - for (int32_t& axis : onnxAxes) + // Convert any negative axis into an absolute axis relative to the back end. + // So given 3 dimensions, a -1 refers to axis 2, and -3 to axis 0. + uint32_t HandleNegativeAxis(int32_t signedOnnxAxis, uint32_t dimCount) { - axis = HandleNegativeAxis(axis, dimCount); + if (signedOnnxAxis < 0) + { + signedOnnxAxis += dimCount; + } + uint32_t absoluteAxis = gsl::narrow_cast(signedOnnxAxis); + ML_CHECK_VALID_ARGUMENT(absoluteAxis < dimCount); + return absoluteAxis; } -} -int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p) -{ - switch (tensorDataType) + void HandleNegativeAxes(gsl::span onnxAxes, uint32_t dimCount) { + for (int32_t& axis : onnxAxes) + { + axis = HandleNegativeAxis(axis, dimCount); + } + } + + int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p) + { + switch (tensorDataType) + { case MLOperatorTensorDataType::Float: return static_cast(*reinterpret_cast(p)); case MLOperatorTensorDataType::UInt8: return static_cast(*reinterpret_cast(p)); case MLOperatorTensorDataType::Int8: return static_cast(*reinterpret_cast(p)); @@ -56,6 +56,57 @@ int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p) }; } + double ReadAsFloat64(MLOperatorTensorDataType tensorDataType, const void* p) + { + switch (tensorDataType) + { + case MLOperatorTensorDataType::Float: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::UInt8: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::Int8: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::UInt16: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::Int16: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::Int32: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::Int64: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::String: ML_INVALID_ARGUMENT("MLOperatorTensorDataType::String type is unsupported for reading as an integer."); + case MLOperatorTensorDataType::Bool: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::Float16: ML_INVALID_ARGUMENT("MLOperatorTensorDataType::Float16 type is unsupported for reading as an integer."); + case MLOperatorTensorDataType::Double: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::UInt32: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::UInt64: return static_cast(*reinterpret_cast(p)); + case MLOperatorTensorDataType::Complex64: return static_cast(*reinterpret_cast(p)); // Read the real component. + case MLOperatorTensorDataType::Complex128: return static_cast(*reinterpret_cast(p)); // Read the real component. + case MLOperatorTensorDataType::Undefined: + default: ML_INVALID_ARGUMENT("Unknown MLOperatorTensorDataType."); + }; + } + + int64_t IsFloatDataType(MLOperatorTensorDataType tensorDataType) + { + switch (tensorDataType) + { + case MLOperatorTensorDataType::Float: + case MLOperatorTensorDataType::Float16: + case MLOperatorTensorDataType::Double: + case MLOperatorTensorDataType::Complex64: + case MLOperatorTensorDataType::Complex128: + return true; + }; + return false; + } + + void ReadScalarTensorData(const MLOperatorTensor& tensor, /*out*/ void* data, size_t dataByteSize) + { + // Read the tensor bytes of a scalar value into the output data, + // validating dimensions and byte size. + const uint32_t elementCount = ComputeElementCountFromDimensions(tensor.GetShape()); + const size_t elementByteSize = GetByteSizeFromMlDataType(tensor.GetTensorDataType()); + ML_CHECK_VALID_ARGUMENT(tensor.IsCpuData(), "Tensor must be a CPU Tensor."); + ML_CHECK_VALID_ARGUMENT(elementCount == 1, "Scalar tensors must have exactly 1 element."); + ML_CHECK_VALID_ARGUMENT(dataByteSize >= elementByteSize, "Scalar tensor element byte size is too large."); + + memcpy(data, tensor.GetByteData(), elementByteSize); + } + // Calculates the spatial dimensions from input dimensions and a kernel. The non-spatial (leading) // dimensions will be initialized to match the input dimensions. This assumes the spatial dimensions // are ordered such that they are at the end (e.g. NCHW or NCDHW). @@ -526,6 +577,106 @@ int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p) return { EdgeShapes(std::move(outputDimensions)) }; } +// TODO::: + + void GatherNDHelper::Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions + ) + { + int32_t signedOnnxAxis = operatorAttributes.GetOptionalAttribute(AttrName::Axis, 0); + uint32_t inputRank = gsl::narrow_cast(inputDimensions.size()); + m_axis = HandleNegativeAxis(signedOnnxAxis, inputRank); + } + + std::vector GatherNDHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const + { + std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); + std::vector indicesDimensions = shapeInfo.GetInputTensorShape(1); + + ML_CHECK_VALID_ARGUMENT(inputDimensions.size() >= 1); + ML_CHECK_VALID_ARGUMENT(indicesDimensions.size() >= 0); + int outDimCount = gsl::narrow_cast(inputDimensions.size() + indicesDimensions.size() - 1); + ML_CHECK_VALID_ARGUMENT(outDimCount > 0 && outDimCount <= NchwDimensionCount); + + std::vector outputDimensions(outDimCount, 1); + + // The input dimensions following the gather axis determine the final output dimensions. + int outputDim = outDimCount - 1; + int inputDim = gsl::narrow_cast(inputDimensions.size() - 1); + for (; inputDim > m_axis; --outputDim, --inputDim) + { + outputDimensions[outputDim] = inputDimensions[inputDim]; + } + + // The shape of the index tensor is reflected in the middle dimensions of the output tensor. + int indexDim = gsl::narrow_cast(indicesDimensions.size() - 1); + for (; indexDim >= 0; --outputDim, --indexDim) + { + outputDimensions[outputDim] = indicesDimensions[indexDim]; + } + + // The gather dimension is skipped for the purposes of sizing because the index values choose slices + // across it. Preceding input dimensions determine the shape of the output's leading dimensions. + inputDim = m_axis - 1; + for (; outputDim >= 0 && inputDim >= 0; --outputDim, --inputDim) + { + outputDimensions[outputDim] = inputDimensions[inputDim]; + } + + return { EdgeShapes(std::move(outputDimensions)) }; + } + +// TODO::: + + void ScatterNDHelper::Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions + ) + { + int32_t signedOnnxAxis = operatorAttributes.GetOptionalAttribute(AttrName::Axis, 0); + uint32_t inputRank = gsl::narrow_cast(inputDimensions.size()); + m_axis = HandleNegativeAxis(signedOnnxAxis, inputRank); + } + + std::vector ScatterNDHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const + { + std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); + std::vector indicesDimensions = shapeInfo.GetInputTensorShape(1); + + ML_CHECK_VALID_ARGUMENT(inputDimensions.size() >= 1); + ML_CHECK_VALID_ARGUMENT(indicesDimensions.size() >= 0); + int outDimCount = gsl::narrow_cast(inputDimensions.size() + indicesDimensions.size() - 1); + ML_CHECK_VALID_ARGUMENT(outDimCount > 0 && outDimCount <= NchwDimensionCount); + + std::vector outputDimensions(outDimCount, 1); + + // The input dimensions following the gather axis determine the final output dimensions. + int outputDim = outDimCount - 1; + int inputDim = gsl::narrow_cast(inputDimensions.size() - 1); + for (; inputDim > m_axis; --outputDim, --inputDim) + { + outputDimensions[outputDim] = inputDimensions[inputDim]; + } + + // The shape of the index tensor is reflected in the middle dimensions of the output tensor. + int indexDim = gsl::narrow_cast(indicesDimensions.size() - 1); + for (; indexDim >= 0; --outputDim, --indexDim) + { + outputDimensions[outputDim] = indicesDimensions[indexDim]; + } + + // The gather dimension is skipped for the purposes of sizing because the index values choose slices + // across it. Preceding input dimensions determine the shape of the output's leading dimensions. + inputDim = m_axis - 1; + for (; outputDim >= 0 && inputDim >= 0; --outputDim, --inputDim) + { + outputDimensions[outputDim] = inputDimensions[inputDim]; + } + + return { EdgeShapes(std::move(outputDimensions)) }; + } + void TransposeHelper::Initialize( const MLOperatorAttributes& operatorAttributes, gsl::span inputDimensions @@ -1139,6 +1290,46 @@ int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p) return { m_outputDimensions }; } + void RangeHelper::Initialize( + const MLOperatorTensor& startTensor, + const MLOperatorTensor& limitTensor, + const MLOperatorTensor& deltaTensor + ) + { + ReadScalarTensorData(startTensor, &m_valueStart, sizeof(m_valueStart)); + ReadScalarTensorData(limitTensor, &m_valueLimit, sizeof(m_valueLimit)); + ReadScalarTensorData(deltaTensor, &m_valueDelta, sizeof(m_valueDelta)); + m_tensorDataType = startTensor.GetTensorDataType(); + + // The output size is a 1D tensor ranging from start up to limit, + // where: + // + // number_of_elements = max(ceil((limit - start) / delta), 0) + // + uint32_t totalElementCount = 0; + if (IsFloatDataType(m_tensorDataType)) + { + double start = ReadAsFloat64(m_tensorDataType, &m_valueStart); + double limit = ReadAsFloat64(m_tensorDataType, &m_valueLimit); + double delta = ReadAsFloat64(m_tensorDataType, &m_valueDelta); + totalElementCount = gsl::narrow_cast(ceil((limit - start) / delta)); + } + else + { + int64_t start = ReadAsInt64(m_tensorDataType, &m_valueStart); + int64_t limit = ReadAsInt64(m_tensorDataType, &m_valueLimit); + int64_t delta = ReadAsInt64(m_tensorDataType, &m_valueDelta); + int64_t range = limit - start; + totalElementCount = gsl::narrow_cast((range / delta) + (range % delta != 0)); + } + m_outputDimensions.push_back(totalElementCount); + } + + std::vector RangeHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const + { + return { m_outputDimensions }; + } + std::vector OneHotHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const { return { std::move(EdgeShapes(m_outputDimensions)) }; diff --git a/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h b/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h index cb4292c72d..44a15abc79 100644 --- a/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h +++ b/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h @@ -76,6 +76,8 @@ void RemoveValuesByIndex(gsl::span indices, bool keepOneValue, / } int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p); +double ReadAsFloat64(MLOperatorTensorDataType tensorDataType, const void* p); +void ReadScalarTensorData(const MLOperatorTensor& tensor, void* data, size_t dataByteSize); class EdgeShapes { public: @@ -174,13 +176,38 @@ class GetOutputShapeAsInputShapeHelper { public: // Info_t is used to obtain attributes which will be used for calculating the output shape later. // Shape_t is used to obtain input shape which will be used for adjusting attribute value. + // Default to first input tensor. template GetOutputShapeAsInputShapeHelper(const Info_t& info, const Shape_t& shape){ ORT_UNUSED_PARAMETER(info); ORT_UNUSED_PARAMETER(shape); }; + // Info_t is used to obtain attributes which will be used for calculating the output shape later. + // Shape_t is used to obtain input shape which will be used for adjusting attribute value. + // Pass specific tensor index. + template + GetOutputShapeAsInputShapeHelper(const Info_t& info, const Shape_t& shape, uint32_t inputTensorIndex) + : m_inputTensorIndex(inputTensorIndex) + { + ORT_UNUSED_PARAMETER(info); + ORT_UNUSED_PARAMETER(shape); + }; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + uint32_t m_inputTensorIndex = 0; +}; + +template +class GetOutputShapeAsSpecificInputShapeHelper : public GetOutputShapeAsInputShapeHelper { +public: + // Info_t is used to obtain attributes which will be used for calculating the output shape later. + // Shape_t is used to obtain input shape which will be used for adjusting attribute value. + template + GetOutputShapeAsSpecificInputShapeHelper(const Info_t& info, const Shape_t& shape) + : GetOutputShapeAsInputShapeHelper(info, shape, InputTensorIndex) + {} }; class GetBroadcastedOutputShapeHelper { @@ -329,10 +356,10 @@ public: ); } - const std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); - const std::vector filterDims = shapeInfo.GetInputTensorShape(1); + const std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); + const std::vector filterDims = shapeInfo.GetInputTensorShape(1); - ML_CHECK_VALID_ARGUMENT(inputDimensions.size() > NonspatialDimensionCount, "Input dimensions must be >= 3"); + ML_CHECK_VALID_ARGUMENT(inputDimensions.size() > NonspatialDimensionCount, "Input dimensions must be >= 3"); if (hasDynamicPads) { @@ -367,39 +394,39 @@ public: assert(m_outputShapes[0].GetShape().size() > C); m_outputShapes[0].GetShape()[C] = filterDims[C] * m_groupCount; - if (!outputShape.empty()) { - // Start padding, end padding, and output padding are all ignored if output shape is set. - std::fill(m_kernel.outputPadding, m_kernel.outputPadding + m_kernel.spatialDimensionCount, 0); + if (!outputShape.empty()) { + // Start padding, end padding, and output padding are all ignored if output shape is set. + std::fill(m_kernel.outputPadding, m_kernel.outputPadding + m_kernel.spatialDimensionCount, 0); - if (outputShape.size() > 2) { - ML_CHECK_VALID_ARGUMENT(outputShape[outputShape.size() - 3] == gsl::narrow_cast(m_outputShapes[0].GetShape()[C]), "Output channel must be equivalent to filter channel."); - } + if (outputShape.size() > 2) { + ML_CHECK_VALID_ARGUMENT(outputShape[outputShape.size() - 3] == gsl::narrow_cast(m_outputShapes[0].GetShape()[C]), "Output channel must be equivalent to filter channel."); + } - for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) { - size_t outputIndex = outputShape.size() - m_kernel.spatialDimensionCount + i; - ML_CHECK_VALID_ARGUMENT(outputShape[outputIndex] >= gsl::narrow_cast(inputDimensions[H + i]), "Output dimension cannot be smaller than input dimension."); - m_outputShapes[0].GetShape()[H + i] = outputShape[outputIndex]; - } + for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) { + size_t outputIndex = outputShape.size() - m_kernel.spatialDimensionCount + i; + ML_CHECK_VALID_ARGUMENT(outputShape[outputIndex] >= gsl::narrow_cast(inputDimensions[H + i]), "Output dimension cannot be smaller than input dimension."); + m_outputShapes[0].GetShape()[H + i] = outputShape[outputIndex]; + } - const int dimOffset = gsl::narrow_cast(inputDimensions.size() - m_kernel.spatialDimensionCount); + const int dimOffset = gsl::narrow_cast(inputDimensions.size() - m_kernel.spatialDimensionCount); - for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) { - int stride = m_kernel.strides[i]; - int windowSize = m_kernel.windowSize[i]; + for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) { + int stride = m_kernel.strides[i]; + int windowSize = m_kernel.windowSize[i]; - // Compute padding such that in reverse order, the logical input (m_outputShapes below) is fully defined - // for a convolution over the logical output region (inputDimensions below). - // - // The padding required is the first windowSize element (for the first logical output element), - // plus (logicalOutput - 1) steps of stride (the distance between each windowed set of logical - // input elements), minus the actual logical input size. - int paddings = gsl::narrow_cast((inputDimensions[i + dimOffset] - 1) * stride + windowSize - m_outputShapes[0].GetShape()[i + dimOffset]); - paddings = std::max(0, paddings); + // Compute padding such that in reverse order, the logical input (m_outputShapes below) is fully defined + // for a convolution over the logical output region (inputDimensions below). + // + // The padding required is the first windowSize element (for the first logical output element), + // plus (logicalOutput - 1) steps of stride (the distance between each windowed set of logical + // input elements), minus the actual logical input size. + int paddings = gsl::narrow_cast((inputDimensions[i + dimOffset] - 1) * stride + windowSize - m_outputShapes[0].GetShape()[i + dimOffset]); + paddings = std::max(0, paddings); - m_kernel.startPadding[i] = m_kernel.autoPadSameUpper ? (paddings + 1) / 2 : paddings / 2; - m_kernel.endPadding[i] = paddings - m_kernel.startPadding[i]; - } - } + m_kernel.startPadding[i] = m_kernel.autoPadSameUpper ? (paddings + 1) / 2 : paddings / 2; + m_kernel.endPadding[i] = paddings - m_kernel.startPadding[i]; + } + } } protected: @@ -898,6 +925,46 @@ class GatherHelper { int m_axis = 0; }; +class GatherNDHelper { + public: + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span dataDimensions + ); + + // Info_t is used to obtain attributes which will be used for calculating the output shape later. + // Shape_t is used to obtain input shape which will be used for adjusting attribute value. + template + GatherNDHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info, shape.GetInputTensorShape(0)); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int m_axis = 0; +}; + +class ScatterNDHelper { + public: + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span dataDimensions + ); + + // Info_t is used to obtain attributes which will be used for calculating the output shape later. + // Shape_t is used to obtain input shape which will be used for adjusting attribute value. + template + ScatterNDHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info, shape.GetInputTensorShape(0)); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int m_axis = 0; +}; + class PoolingHelperBase { public: // Info_t is used to obtain attributes which will be used for calculating the output shape later. @@ -1127,38 +1194,36 @@ class ResizeHelper { std::vector m_scales; // Cached scales to check for updates/invalidate operator. }; +//TODO::: class RangeHelper { public: // Info_t is used to obtain attributes which will be used for calculating the output shape later. // Shape_t is used to obtain input shape which will be used for adjusting attribute value. template - RangeHelper(const Info_t& info, const Shape_t& shape) { - // Read the scales from the 2nd tensor. - if (info.GetInputCount() > 1) { - MLOperatorTensor scalesTensor = info.GetConstantInputTensor(1); - Initialize(scalesTensor, shape.GetInputTensorShape(0)); - } else // From attribute. - { - Initialize(info, shape.GetInputTensorShape(0)); - } + RangeHelper(const Info_t& info, const Shape_t& shape) + { + auto startTensor = info.GetConstantInputTensor(0); + auto limitTensor = info.GetConstantInputTensor(1); + auto deltaTensor = info.GetConstantInputTensor(2); + Initialize(startTensor, limitTensor, deltaTensor); } void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions); - - void Initialize( - const MLOperatorTensor& scalesTensor, - gsl::span inputDimensions); - - void InitializeOutputDimensions( - gsl::span scales, - gsl::span inputDimensions); + const MLOperatorTensor& startTensor, + const MLOperatorTensor& limitTensor, + const MLOperatorTensor& deltaTensor + ); std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; protected: std::vector m_outputDimensions; + + MLOperatorTensorDataType m_tensorDataType = MLOperatorTensorDataType::Undefined; + using TensorScalarData = typename std::aligned_storage::type; + TensorScalarData m_valueStart; + TensorScalarData m_valueLimit; + TensorScalarData m_valueDelta; }; class OneHotHelper { @@ -1220,7 +1285,13 @@ using ShapeInferenceHelper_LpNormalization = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_RNN = RecurrentHelper; using ShapeInferenceHelper_GRU = RecurrentHelper; using ShapeInferenceHelper_LSTM = RecurrentHelper; + using ShapeInferenceHelper_Gather = GatherHelper; +using ShapeInferenceHelper_GatherElements = GetOutputShapeAsSpecificInputShapeHelper<1>; +using ShapeInferenceHelper_ScatterElements = GetOutputShapeAsInputShapeHelper; +using ShapeInferenceHelper_Scatter = ShapeInferenceHelper_ScatterElements; +using ShapeInferenceHelper_GatherND = GatherNDHelper; +using ShapeInferenceHelper_ScatterND = ScatterNDHelper; using ShapeInferenceHelper_Flatten = FlattenHelper; using ShapeInferenceHelper_Split = SplitHelper; @@ -1276,7 +1347,6 @@ using ShapeInferenceHelper_Atan = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_Affine = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_QuantizeLinear = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_DequantizeLinear = GetOutputShapeAsInputShapeHelper; -using ShapeInferenceHelper_Scatter = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_Sign = GetBroadcastedOutputShapeHelper; using ShapeInferenceHelper_IsNan = GetBroadcastedOutputShapeHelper; using ShapeInferenceHelper_Erf = GetBroadcastedOutputShapeHelper; @@ -1344,7 +1414,7 @@ using ShapeInferenceHelper_Multinomial = MultinomialHelper; using ShapeInferenceHelper_ReverseSequence = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_CumSum = GetOutputShapeAsInputShapeHelper; -using ShapeInferenceHelper_ShapeInferenceHelper_Range = RangeHelper; +using ShapeInferenceHelper_Range = RangeHelper; using ShapeInferenceHelper_FusedConv = ConvHelper; using ShapeInferenceHelper_FusedConvTranspose = ConvTransposeHelper;