diff --git a/cmake/winml.cmake b/cmake/winml.cmake index cd6fd862ca..9d092e2c28 100644 --- a/cmake/winml.cmake +++ b/cmake/winml.cmake @@ -456,7 +456,7 @@ set_target_properties(winml_dll set_target_properties(winml_dll PROPERTIES LINK_FLAGS - "/DEF:${WINML_DIR}/windows.ai.machinelearning.def ${os_component_link_flags} /DELAYLOAD:d3d12.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:dxgi.dll") + "/DEF:${WINML_DIR}/windows.ai.machinelearning.def ${os_component_link_flags} /DELAYLOAD:d3d12.dll /DELAYLOAD:d3d11.dll /DELAYLOAD:dxgi.dll /DELAYLOAD:directml.dll") set_target_properties(winml_dll PROPERTIES diff --git a/include/onnxruntime/core/session/onnxruntime_cxx_inline.h b/include/onnxruntime/core/session/onnxruntime_cxx_inline.h index 26a764e84b..e1a4449e9a 100644 --- a/include/onnxruntime/core/session/onnxruntime_cxx_inline.h +++ b/include/onnxruntime/core/session/onnxruntime_cxx_inline.h @@ -358,7 +358,7 @@ inline Value Value::CreateTensor(const OrtMemoryInfo* info, T* p_data, size_t p_ } template <> -inline Value Value::CreateTensor(const OrtMemoryInfo* info, std::string* p_data, size_t p_data_element_count, const int64_t* shape, size_t shape_len) { +inline Value Value::CreateTensor(const OrtMemoryInfo*, std::string* p_data, size_t p_data_element_count, const int64_t* shape, size_t shape_len) { // convert the array of std::string to an array of const char * std::vector string_vector; for (int i = 0; i < p_data_element_count; ++i) { diff --git a/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h b/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h index ad6da14f76..dccb9e5455 100644 --- a/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h +++ b/onnxruntime/core/providers/dml/OperatorAuthorHelper/OperatorHelper.h @@ -6,15 +6,14 @@ #include "Common.h" #include "Attributes.h" #include "MLOperatorAuthorHelper.h" +#include "core/common/common.h" -namespace OperatorHelper -{ +namespace OperatorHelper { bool ContainsEmptyDimensions(gsl::span dimensions); std::vector BroadcastTensorShape( gsl::span inputShape0, - gsl::span inputShape1 - ); + gsl::span inputShape1); // Find all the occurrences of a value, and return the array indices (in ascending order). // @@ -22,19 +21,16 @@ std::vector BroadcastTensorShape( // value = 1 // output indices = {1,3,4} #pragma optimize("", off) -template -void FindValueIndices(gsl::span values, T value, /*out*/ std::vector& indices) -{ - indices.clear(); - for (size_t i = 0, valuesCount = values.size(); i < valuesCount; ++i) - { - // Work around compiler bug on x86 release by using data() rather than operator [] directly. - // cl.exe 19.20.27412.4 for x86 - if (values.data()[i] == value) - { - indices.push_back(gsl::narrow_cast(i)); - } +template +void FindValueIndices(gsl::span values, T value, /*out*/ std::vector& indices) { + indices.clear(); + for (size_t i = 0, valuesCount = values.size(); i < valuesCount; ++i) { + // Work around compiler bug on x86 release by using data() rather than operator [] directly. + // cl.exe 19.20.27412.4 for x86 + if (values.data()[i] == value) { + indices.push_back(gsl::narrow_cast(i)); } + } } #pragma optimize("", on) @@ -51,1049 +47,940 @@ void HandleNegativeAxes(gsl::span onnxAxes, uint32_t dimCount); // e.g. input values = {2,1,3,1,1,5} // ellidable input indices = {1,3,4} // output values = {2,3,5} -template -void RemoveValuesByIndex(gsl::span indices, bool keepOneValue, /*inout*/ std::vector& values) -{ - assert(std::is_sorted(indices.begin(), indices.end())); +template +void RemoveValuesByIndex(gsl::span indices, bool keepOneValue, /*inout*/ std::vector& values) { + assert(std::is_sorted(indices.begin(), indices.end())); - // Keep the last value at least, if all values would otherwise be removed. - if (keepOneValue && !indices.empty() && indices.size() == values.size()) + // Keep the last value at least, if all values would otherwise be removed. + if (keepOneValue && !indices.empty() && indices.size() == values.size()) { + indices = indices.first(indices.size() - 1); + } + + auto indicesIterator = indices.begin(); + auto indicesEnd = indices.end(); + size_t oldValuesCount = values.size(); + size_t newValuesCount = 0; + size_t nextIndex = (indicesIterator == indicesEnd) ? SIZE_MAX : *(indicesIterator++); + + // For every value, either skip the entry, or copy it to the output. + for (size_t i = 0; i < oldValuesCount; ++i) { + if (i == nextIndex) // Skip and remove entry. { - indices = indices.first(indices.size() - 1); - } - - auto indicesIterator = indices.begin(); - auto indicesEnd = indices.end(); - size_t oldValuesCount = values.size(); - size_t newValuesCount = 0; - size_t nextIndex = (indicesIterator == indicesEnd) ? SIZE_MAX : *(indicesIterator++); - - // For every value, either skip the entry, or copy it to the output. - for (size_t i = 0; i < oldValuesCount; ++i) + nextIndex = (indicesIterator == indicesEnd) ? SIZE_MAX : *(indicesIterator++); + } else // Keep and copy entry. { - if (i == nextIndex) // Skip and remove entry. - { - nextIndex = (indicesIterator == indicesEnd) ? SIZE_MAX : *(indicesIterator++); - } - else // Keep and copy entry. - { - values[newValuesCount++] = values[i]; - } - + values[newValuesCount++] = values[i]; } - values.resize(newValuesCount); + } + values.resize(newValuesCount); } int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p); -class EdgeShapes -{ -public: - EdgeShapes() = default; - EdgeShapes(const std::vector& dim){ m_shapes = dim; } - EdgeShapes(const std::initializer_list& dim) { m_shapes.assign(dim.begin(), dim.end()); } - EdgeShapes(const gsl::span dim) { m_shapes.assign(dim.begin(), dim.end()); } - - bool IsTensor() { return true; } - bool IsUnused() { return m_shapes.empty(); } +class EdgeShapes { + public: + EdgeShapes() = default; + EdgeShapes(const std::vector& dim) { m_shapes = dim; } + EdgeShapes(const std::initializer_list& dim) { m_shapes.assign(dim.begin(), dim.end()); } + EdgeShapes(const gsl::span dim) { m_shapes.assign(dim.begin(), dim.end()); } - std::vector& GetShape() { return m_shapes; } -private: - std::vector m_shapes; + bool IsTensor() { return true; } + bool IsUnused() { return m_shapes.empty(); } + + std::vector& GetShape() { return m_shapes; } + + private: + std::vector m_shapes; }; -struct KernelArgs -{ - // Initialize arrays up to NcdhwSpatialDimensionCount to avoid vector allocations, - // but it's important to use .spatialDimensionCount when accessing them because - // values beyond that may be bogus. - uint32_t strides[NcdhwSpatialDimensionCount]; - uint32_t dilations[NcdhwSpatialDimensionCount]; - uint32_t windowSize[NcdhwSpatialDimensionCount]; - uint32_t startPadding[NcdhwSpatialDimensionCount]; - uint32_t endPadding[NcdhwSpatialDimensionCount]; - uint32_t outputPadding[NcdhwSpatialDimensionCount]; +struct KernelArgs { + // Initialize arrays up to NcdhwSpatialDimensionCount to avoid vector allocations, + // but it's important to use .spatialDimensionCount when accessing them because + // values beyond that may be bogus. + uint32_t strides[NcdhwSpatialDimensionCount]; + uint32_t dilations[NcdhwSpatialDimensionCount]; + uint32_t windowSize[NcdhwSpatialDimensionCount]; + uint32_t startPadding[NcdhwSpatialDimensionCount]; + uint32_t endPadding[NcdhwSpatialDimensionCount]; + uint32_t outputPadding[NcdhwSpatialDimensionCount]; - KernelArgs(uint32_t spatialDimensionCount) : - autoPad(false), - autoPadSameUpper(false), - spatialDimensionCount(spatialDimensionCount) - { - ML_CHECK_VALID_ARGUMENT(spatialDimensionCount <= NcdhwSpatialDimensionCount); - } + KernelArgs(uint32_t spatialDimensionCount) : autoPad(false), + autoPadSameUpper(false), + spatialDimensionCount(spatialDimensionCount) { + ML_CHECK_VALID_ARGUMENT(spatialDimensionCount <= NcdhwSpatialDimensionCount); + } - void FillWithLeadingValues(gsl::span input, gsl::span output, uint32_t fillCount, uint32_t value) - { - // e.g. - // input = [5,6,7,8] - // fillcount = 2 - // value = 1 - // output = [1,1,5,6,7,8] + void FillWithLeadingValues(gsl::span input, gsl::span output, uint32_t fillCount, uint32_t value) { + // e.g. + // input = [5,6,7,8] + // fillcount = 2 + // value = 1 + // output = [1,1,5,6,7,8] - const size_t inputCount = input.size(); - const size_t outputCount = output.size(); - const size_t clampedFillCount = std::min(size_t(fillCount), outputCount); - const size_t copyCount = std::min(outputCount - fillCount, inputCount); + const size_t inputCount = input.size(); + const size_t outputCount = output.size(); + const size_t clampedFillCount = std::min(size_t(fillCount), outputCount); + const size_t copyCount = std::min(outputCount - fillCount, inputCount); - std::fill_n(output.data(), fillCount, value); - std::copy_n(input.data(), copyCount, output.data() + fillCount); - } + std::fill_n(output.data(), fillCount, value); + std::copy_n(input.data(), copyCount, output.data() + fillCount); + } - // Create a copy of an existing kernel args with a minimum dimension count, - // filling the leading attribute values with 1's or 0's respectively. - KernelArgs(KernelArgs const& kernelArgs, uint32_t minimumDimensionCount) : - autoPad(kernelArgs.autoPad), - autoPadSameUpper(kernelArgs.autoPadSameUpper), - spatialDimensionCount(std::max(kernelArgs.spatialDimensionCount, minimumDimensionCount)) - { - ML_CHECK_VALID_ARGUMENT(spatialDimensionCount <= NcdhwSpatialDimensionCount); + // Create a copy of an existing kernel args with a minimum dimension count, + // filling the leading attribute values with 1's or 0's respectively. + KernelArgs(KernelArgs const& kernelArgs, uint32_t minimumDimensionCount) : autoPad(kernelArgs.autoPad), + autoPadSameUpper(kernelArgs.autoPadSameUpper), + spatialDimensionCount(std::max(kernelArgs.spatialDimensionCount, minimumDimensionCount)) { + ML_CHECK_VALID_ARGUMENT(spatialDimensionCount <= NcdhwSpatialDimensionCount); - uint32_t fillCount = (minimumDimensionCount > kernelArgs.spatialDimensionCount) ? minimumDimensionCount - kernelArgs.spatialDimensionCount : 0; - FillWithLeadingValues(kernelArgs.strides, this->strides, fillCount, 1u); - FillWithLeadingValues(kernelArgs.dilations, this->dilations, fillCount, 1u); - FillWithLeadingValues(kernelArgs.windowSize, this->windowSize, fillCount, 1u); - FillWithLeadingValues(kernelArgs.startPadding, this->startPadding, fillCount, 0u); - FillWithLeadingValues(kernelArgs.endPadding, this->endPadding, fillCount, 0u); - FillWithLeadingValues(kernelArgs.outputPadding, this->outputPadding, fillCount, 0u); - } + uint32_t fillCount = (minimumDimensionCount > kernelArgs.spatialDimensionCount) ? minimumDimensionCount - kernelArgs.spatialDimensionCount : 0; + FillWithLeadingValues(kernelArgs.strides, this->strides, fillCount, 1u); + FillWithLeadingValues(kernelArgs.dilations, this->dilations, fillCount, 1u); + FillWithLeadingValues(kernelArgs.windowSize, this->windowSize, fillCount, 1u); + FillWithLeadingValues(kernelArgs.startPadding, this->startPadding, fillCount, 0u); + FillWithLeadingValues(kernelArgs.endPadding, this->endPadding, fillCount, 0u); + FillWithLeadingValues(kernelArgs.outputPadding, this->outputPadding, fillCount, 0u); + } - // This is true if padding must be automatically computed based on input sizes. - // ResolveAutoPadding must happen during Compute rather than initialization. - // This is temporary until kernel initialization routine once Lotus can provide - // sizes at operator initialization. - bool autoPad; - bool autoPadSameUpper; - uint32_t spatialDimensionCount; + // This is true if padding must be automatically computed based on input sizes. + // ResolveAutoPadding must happen during Compute rather than initialization. + // This is temporary until kernel initialization routine once Lotus can provide + // sizes at operator initialization. + bool autoPad; + bool autoPadSameUpper; + uint32_t spatialDimensionCount; }; std::vector InitializeKernelOutputDimensions( gsl::span inputDimensions, - const KernelArgs& args -); + const KernelArgs& args); std::vector InitializeKernelOutputDimsTranspose( gsl::span inputDimensions, - const KernelArgs& args -); + const KernelArgs& args); KernelArgs InitializeGlobalKernel(gsl::span inputDimensions); KernelArgs InitializeKernel( const MLOperatorAttributes& kernelInfo, uint32_t inputDimensionCount, - gsl::span filterTensorShape -); + gsl::span filterTensorShape); void ResolveAutoPadding( KernelArgs& args, - gsl::span inputDimensions -); + gsl::span inputDimensions); -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. - template - GetOutputShapeAsInputShapeHelper(const Info_t& info, const Shape_t& shape) {}; +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. + template + GetOutputShapeAsInputShapeHelper(const Info_t& info, const Shape_t& shape){ + ORT_UNUSED_PARAMETER(info); + ORT_UNUSED_PARAMETER(shape); + }; - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; }; -class GetBroadcastedOutputShapeHelper -{ -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 - GetBroadcastedOutputShapeHelper(const Info_t& info, const Shape_t& shape) {}; +class GetBroadcastedOutputShapeHelper { + 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 + GetBroadcastedOutputShapeHelper(const Info_t& info, const Shape_t& shape){}; - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; }; -class RandomUniformHelperBase -{ -public: - // Info_t is used to obtain attributes which will be used for calculating the output shape later. - template - RandomUniformHelperBase(const Info_t& info) - { - m_high = info.GetOptionalAttribute(AttrName::High, 1.0f); - m_low = info.GetOptionalAttribute(AttrName::Low, 0.0f); +class RandomUniformHelperBase { + public: + // Info_t is used to obtain attributes which will be used for calculating the output shape later. + template + RandomUniformHelperBase(const Info_t& info) { + m_high = info.GetOptionalAttribute(AttrName::High, 1.0f); + m_low = info.GetOptionalAttribute(AttrName::Low, 0.0f); - if (info.HasAttribute(AttrName::Seed, MLOperatorAttributeType::Float)) - { - m_seed = info.GetAttribute(AttrName::Seed); - } - else - { - m_seed = static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); - } + if (info.HasAttribute(AttrName::Seed, MLOperatorAttributeType::Float)) { + m_seed = info.GetAttribute(AttrName::Seed); + } else { + m_seed = static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); } -protected: - float m_high; - float m_low; - float m_seed; + } + + protected: + float m_high; + float m_low; + float m_seed; }; -class RandomUniformHelper : public RandomUniformHelperBase -{ -public: - template - RandomUniformHelper(const Info_t& info, const Shape_t& shape) : RandomUniformHelperBase(info) - { - auto shapeAttribute = info.GetOptionalAttributeVectorInt32(AttrName::Shape); - ML_CHECK_VALID_ARGUMENT(!shapeAttribute.empty(), "Attribute shape is missing."); - m_tensorShape.assign(shapeAttribute.begin(), shapeAttribute.end()); +class RandomUniformHelper : public RandomUniformHelperBase { + public: + template + RandomUniformHelper(const Info_t& info, const Shape_t& shape) : RandomUniformHelperBase(info) { + auto shapeAttribute = info.GetOptionalAttributeVectorInt32(AttrName::Shape); + ML_CHECK_VALID_ARGUMENT(!shapeAttribute.empty(), "Attribute shape is missing."); + m_tensorShape.assign(shapeAttribute.begin(), shapeAttribute.end()); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + private: + // Returns an empty vector if the optional attribute is missing. + std::vector m_tensorShape; +}; + +class RandomNormalHelperBase { + public: + // Info_t is used to obtain attributes which will be used for calculating the output shape later. + template + RandomNormalHelperBase(const Info_t& info) { + m_mean = info.GetOptionalAttribute(AttrName::Mean, 0.0f); + m_scale = info.GetOptionalAttribute(AttrName::Scale, 1.0f); + + if (info.HasAttribute(AttrName::Seed, MLOperatorAttributeType::Float)) { + m_seed = info.GetAttribute(AttrName::Seed); + } else { + m_seed = static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); + } + } + + protected: + float m_mean; + float m_scale; + float m_seed; +}; + +class RandomNormalHelper : public RandomNormalHelperBase { + public: + template + RandomNormalHelper(const Info_t& info, const Shape_t& shape) : RandomNormalHelperBase(info) { + auto shapeAttribute = info.GetOptionalAttributeVectorInt32(AttrName::Shape); + ML_CHECK_VALID_ARGUMENT(!shapeAttribute.empty(), "Attribute shape is missing."); + m_tensorShape.assign(shapeAttribute.begin(), shapeAttribute.end()); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + private: + // Returns an empty vector if the optional attribute is missing. + std::vector m_tensorShape; +}; + +class ConvolutionHelperBase { + public: + enum FilterDims { K }; + enum InputTensor { X, + Filter, + Bias }; + enum InputDims { N, + C, + H, + W }; + + public: + // Info_t is used to obtain attributes which will be used for calculating the output shape later. + template + ConvolutionHelperBase(const Info_t& info, const Shape_t& shape, bool transpose) : m_kernel(InitializeKernel(info, shape.GetInputTensorDimensionCount(0), shape.GetInputTensorShape(1))) { + m_groupCount = info.GetOptionalAttribute(AttrName::Group, 1); + + if (!transpose) { + InitializeKernelAndShapes(shape); + } else { + InitializeKernelAndShapesTransposed(info, shape); + } + } + + void ResolvingPadding(gsl::span inputDimensions); + + const std::vector& GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const { + ORT_UNUSED_PARAMETER(shapeInfo); + return m_outputShapes; + } + + template + void InitializeKernelAndShapes(const Shape_t& shapeInfo) { + const std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); + const std::vector filterDims = shapeInfo.GetInputTensorShape(1); + + ML_CHECK_VALID_ARGUMENT( + inputDimensions.size() >= 3 && inputDimensions.size() <= 5, + "Input dimensions must be: 3, 4, 5."); + + ResolvingPadding(inputDimensions); + + m_outputShapes.resize(1); + m_outputShapes[0] = InitializeKernelOutputDimensions(inputDimensions, m_kernel); + m_outputShapes[0].GetShape()[C] = filterDims[K]; + } + + template + void InitializeKernelAndShapesTransposed(const Info_t& info, const Shape_t& shapeInfo) { + std::vector outputShape = info.GetOptionalAttributeVectorInt32(AttrName::OutputShape); + if (!outputShape.empty()) { + ML_CHECK_VALID_ARGUMENT( + outputShape.size() >= m_kernel.spatialDimensionCount, + "The output shape must equal the number of spatial dimensions"); } - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -private: - // Returns an empty vector if the optional attribute is missing. - std::vector m_tensorShape; -}; + const std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); + const std::vector filterDims = shapeInfo.GetInputTensorShape(1); -class RandomNormalHelperBase -{ -public: - // Info_t is used to obtain attributes which will be used for calculating the output shape later. - template - RandomNormalHelperBase(const Info_t& info) - { - m_mean = info.GetOptionalAttribute(AttrName::Mean, 0.0f); - m_scale = info.GetOptionalAttribute(AttrName::Scale, 1.0f); + ML_CHECK_VALID_ARGUMENT(inputDimensions.size() > NonspatialDimensionCount, "Input dimensions must be >= 3"); - if (info.HasAttribute(AttrName::Seed, MLOperatorAttributeType::Float)) - { - m_seed = info.GetAttribute(AttrName::Seed); - } - else - { - m_seed = static_cast(std::chrono::high_resolution_clock::now().time_since_epoch().count()); - } + ResolvingPadding(inputDimensions); + m_outputShapes.resize(1); + m_outputShapes[0] = InitializeKernelOutputDimsTranspose(inputDimensions, m_kernel); + static_assert(C < NonspatialDimensionCount); + 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.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]; + } + + 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]; + + // 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]; + } } -protected: - float m_mean; - float m_scale; - float m_seed; + } + + protected: + uint32_t m_groupCount; + KernelArgs m_kernel; + std::vector m_outputShapes; }; -class RandomNormalHelper : public RandomNormalHelperBase -{ -public: - template - RandomNormalHelper(const Info_t& info, const Shape_t& shape) : RandomNormalHelperBase(info) - { - auto shapeAttribute = info.GetOptionalAttributeVectorInt32(AttrName::Shape); - ML_CHECK_VALID_ARGUMENT(!shapeAttribute.empty(), "Attribute shape is missing."); - m_tensorShape.assign(shapeAttribute.begin(), shapeAttribute.end()); +class ConvHelper : public ConvolutionHelperBase { + public: + template + ConvHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, false) {} +}; + +class ConvTransposeHelper : public ConvolutionHelperBase { + public: + template + ConvTransposeHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, true) {} +}; + +class GemmHelper { + 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 + GemmHelper(const Info_t& info, const Shape_t& shape) { + ORT_UNUSED_PARAMETER(shape); + m_transA = info.GetOptionalAttribute(AttrName::TransA, 0); + m_transB = info.GetOptionalAttribute(AttrName::TransB, 0); + m_broadcast = info.GetOptionalAttribute(AttrName::Broadcast, 0); + m_alpha = info.GetOptionalAttribute(AttrName::Alpha, 1.0f); + m_beta = info.GetOptionalAttribute(AttrName::Beta, 0.0f); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + enum InputTensors { IN_A, + IN_B, + IN_C }; + + protected: + bool m_transA = false; + bool m_transB = false; + bool m_broadcast = false; + float m_alpha = 0.0f; + float m_beta = 0.0f; +}; + +class TransposeHelper { + public: + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions); + + // 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 + TransposeHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info, shape.GetInputTensorShape(0)); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + std::vector m_permutations; +}; + +class SplitHelper { + public: + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions); + + // 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 + SplitHelper(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; + std::vector m_split; +}; + +class SliceHelper { + public: + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions); + + // 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 + SliceHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info, shape.GetInputTensorShape(0)); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + std::vector m_outputDimensions; + std::vector m_offsets; + std::vector m_sizes; + std::vector m_strides; +}; + +class PaddingHelper { + public: + void Initialize(const MLOperatorAttributes& operatorAttributes); + + // 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 + PaddingHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + std::vector m_startPadding; + std::vector m_endPadding; +}; + +class ReduceHelperBase { + 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 + ReduceHelperBase(const Info_t& info, const Shape_t& shape, bool usingAxes) { + m_keepDims = info.GetOptionalAttribute(AttrName::KeepDims, 1); + if (usingAxes) { + m_axes = info.GetOptionalAttributeVectorInt32(AttrName::Axes); + } else { + int axis = info.GetOptionalAttribute(AttrName::Axis, 0); + m_axes.push_back(axis); } + std::vector inputShape = shape.GetInputTensorShape(0); + HandleNegativeAxes(/*inout*/ m_axes, gsl::narrow_cast(inputShape.size())); + AdjustAxesAndOutputShape(inputShape); + } + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -private: - // Returns an empty vector if the optional attribute is missing. - std::vector m_tensorShape; + private: + void AdjustAxesAndOutputShape(const std::vector& inputShape); + + protected: + std::vector m_axes; + int m_keepDims = 0; }; -class ConvolutionHelperBase -{ -public: - enum FilterDims { K }; - enum InputTensor { X, Filter, Bias }; - enum InputDims { N, C, H, W }; +class ArgMinArgMaxHelper : public ReduceHelperBase { + 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 + ArgMinArgMaxHelper(const Info_t& info, const Shape_t& shape) : ReduceHelperBase(info, shape, false) {} +}; -public: - // Info_t is used to obtain attributes which will be used for calculating the output shape later. - template - ConvolutionHelperBase(const Info_t& info, const Shape_t& shape, bool transpose) : - m_kernel(InitializeKernel(info, shape.GetInputTensorDimensionCount(0), shape.GetInputTensorShape(1))) - { - m_groupCount = info.GetOptionalAttribute(AttrName::Group, 1); - - if (!transpose) - { - InitializeKernelAndShapes(shape); - } - else - { - InitializeKernelAndShapesTransposed(info, shape); - } +class ReduceHelper : public ReduceHelperBase { + 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 + ReduceHelper(const Info_t& info, const Shape_t& shape) : ReduceHelperBase(info, shape, true) {} +}; + +class MatMulHelper { + 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 + MatMulHelper(const Info_t& info, const Shape_t& shape) {} + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; +}; + +class TopKHelper { + 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 + TopKHelper(const Info_t& info, const Shape_t& shape) { + m_k = info.GetOptionalAttribute(AttrName::K, -1); + ML_CHECK_VALID_ARGUMENT(m_k >= 0, "Attribute k is missing."); + + m_axis = info.GetOptionalAttribute(AttrName::Axis, -1); + auto inputShape = shape.GetInputTensorShape(0); + + if (m_axis < 0) { + m_axis = m_axis + gsl::narrow_cast(inputShape.size()); } + ML_CHECK_VALID_ARGUMENT(m_axis >= 0 && m_axis < gsl::narrow_cast(inputShape.size())); + } - void ResolvingPadding(gsl::span inputDimensions); + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - const std::vector& GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const - { - return m_outputShapes; + protected: + int32_t m_k; + int32_t m_axis; +}; + +class RecurrentHelper { + 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 + RecurrentHelper(const Info_t& info, const Shape_t& shape) { + m_hiddenSize = info.GetOptionalAttribute(AttrName::HiddenSize, 1); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int m_hiddenSize = 0; +}; + +class ConcatHelper { + public: + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions); + + // 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 + ConcatHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info, shape.GetInputTensorShape(0)); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int m_axis; +}; + +class CropHelper { + public: + enum BorderDim { Left, + Top, + Right, + Bottom }; + enum ScaleDim { Height, + Width }; + + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions); + + // 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 + CropHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info, shape.GetInputTensorShape(0)); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + uint32_t m_offsets[NchwDimensionCount]; + uint32_t m_sizes[NchwSpatialDimensionCount]; +}; + +class DepthToSpaceHelper { + 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 + DepthToSpaceHelper(const Info_t& info, const Shape_t& shape) { + m_blockSize = info.GetOptionalAttribute(AttrName::BlockSize, -1); + ML_CHECK_VALID_ARGUMENT(m_blockSize > 0, "Attribute blocksize is missing or equal to zero."); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int32_t m_blockSize; +}; + +class SpaceToDepthHelper { + 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 + SpaceToDepthHelper(const Info_t& info, const Shape_t& shape) { + m_blockSize = info.GetOptionalAttribute(AttrName::BlockSize, -1); + ML_CHECK_VALID_ARGUMENT(m_blockSize > 0, "Attribute blocksize is missing or equal to zero."); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int32_t m_blockSize; +}; + +class FlattenHelper { + public: + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions); + + // 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 + FlattenHelper(const Info_t& info, const Shape_t& shape) { + Initialize(info, shape.GetInputTensorShape(0)); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int m_axis = 1; +}; + +class MultinomialHelper { + 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 + MultinomialHelper(const Info_t& info, const Shape_t& shape) {} + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; +}; + +class GatherHelper { + 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 + GatherHelper(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. + // Shape_t is used to obtain input shape which will be used for adjusting attribute value. + template + PoolingHelperBase( + const Info_t& info, + const Shape_t& shape, + bool useGlobalPooling) : m_kernel(useGlobalPooling + ? InitializeGlobalKernel(shape.GetInputTensorShape(0)) + : InitializeKernel(info, static_cast(shape.GetInputTensorShape(0).size()), gsl::span())) { + if (!useGlobalPooling) { + ResolveAutoPadding(m_kernel, shape.GetInputTensorShape(0)); } - - template - void InitializeKernelAndShapes(const Shape_t& shapeInfo) - { - const std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); - const std::vector filterDims = shapeInfo.GetInputTensorShape(1); + } - ML_CHECK_VALID_ARGUMENT( - inputDimensions.size() >= 3 && inputDimensions.size() <= 5, - "Input dimensions must be: 3, 4, 5." - ); - - ResolvingPadding(inputDimensions); - - m_outputShapes.resize(1); - m_outputShapes[0] = InitializeKernelOutputDimensions(inputDimensions, m_kernel); - m_outputShapes[0].GetShape()[C] = filterDims[K]; - } - - - template - void InitializeKernelAndShapesTransposed(const Info_t& info, const Shape_t& shapeInfo) - { - std::vector outputShape = info.GetOptionalAttributeVectorInt32(AttrName::OutputShape); - if (!outputShape.empty()) - { - ML_CHECK_VALID_ARGUMENT( - outputShape.size() >= m_kernel.spatialDimensionCount, - "The output shape must equal the number of spatial dimensions" - ); - } - - 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"); - - ResolvingPadding(inputDimensions); - m_outputShapes.resize(1); - m_outputShapes[0] = InitializeKernelOutputDimsTranspose(inputDimensions, m_kernel); - static_assert(C < NonspatialDimensionCount); - 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.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]; - } - - 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]; - - // 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]; - } - } - } - -protected: - uint32_t m_groupCount; - KernelArgs m_kernel; - std::vector m_outputShapes; -}; - -class ConvHelper : public ConvolutionHelperBase -{ -public: - template - ConvHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, false) {} -}; - -class ConvTransposeHelper : public ConvolutionHelperBase -{ -public: - template - ConvTransposeHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, true) {} -}; - -class GemmHelper -{ -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 - GemmHelper(const Info_t& info, const Shape_t& shape) - { - m_transA = info.GetOptionalAttribute(AttrName::TransA, 0); - m_transB = info.GetOptionalAttribute(AttrName::TransB, 0); - m_broadcast = info.GetOptionalAttribute(AttrName::Broadcast, 0); - m_alpha = info.GetOptionalAttribute(AttrName::Alpha, 1.0f); - m_beta = info.GetOptionalAttribute(AttrName::Beta, 0.0f); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - - enum InputTensors { IN_A, IN_B, IN_C }; - -protected: - bool m_transA = false; - bool m_transB = false; - bool m_broadcast = false; - float m_alpha = 0.0f; - float m_beta = 0.0f; -}; - -class TransposeHelper -{ -public: - void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions - ); - - // 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 - TransposeHelper(const Info_t& info, const Shape_t& shape) - { - Initialize(info, shape.GetInputTensorShape(0)); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - std::vector m_permutations; -}; - -class SplitHelper -{ -public: - void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions - ); - - // 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 - SplitHelper(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; - std::vector m_split; -}; - -class SliceHelper -{ -public: - void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions - ); - - // 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 - SliceHelper(const Info_t& info, const Shape_t& shape) - { - Initialize(info, shape.GetInputTensorShape(0)); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - std::vector m_outputDimensions; - std::vector m_offsets; - std::vector m_sizes; - std::vector m_strides; -}; - -class PaddingHelper -{ -public: - void Initialize(const MLOperatorAttributes& operatorAttributes); - - // 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 - PaddingHelper(const Info_t& info, const Shape_t& shape) - { - Initialize(info); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - std::vector m_startPadding; - std::vector m_endPadding; -}; - -class ReduceHelperBase -{ -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 - ReduceHelperBase(const Info_t& info, const Shape_t& shape, bool usingAxes) - { - m_keepDims = info.GetOptionalAttribute(AttrName::KeepDims, 1); - if (usingAxes) - { - m_axes = info.GetOptionalAttributeVectorInt32(AttrName::Axes); - } - else - { - int axis = info.GetOptionalAttribute(AttrName::Axis, 0); - m_axes.push_back(axis); - } - std::vector inputShape = shape.GetInputTensorShape(0); - HandleNegativeAxes(/*inout*/ m_axes, gsl::narrow_cast(inputShape.size())); - AdjustAxesAndOutputShape(inputShape); - } - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -private: - void AdjustAxesAndOutputShape(const std::vector& inputShape); - -protected: - std::vector m_axes; - int m_keepDims = 0; -}; - -class ArgMinArgMaxHelper : public ReduceHelperBase -{ -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 - ArgMinArgMaxHelper(const Info_t& info, const Shape_t& shape) : ReduceHelperBase(info, shape, false) {} -}; - -class ReduceHelper : public ReduceHelperBase -{ -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 - ReduceHelper(const Info_t& info, const Shape_t& shape) : ReduceHelperBase(info, shape, true) {} -}; - -class MatMulHelper -{ -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 - MatMulHelper(const Info_t& info, const Shape_t& shape) {} - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -}; - -class TopKHelper -{ -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 - TopKHelper(const Info_t& info, const Shape_t& shape) - { - m_k = info.GetOptionalAttribute(AttrName::K, -1); - ML_CHECK_VALID_ARGUMENT(m_k >= 0, "Attribute k is missing."); - - m_axis = info.GetOptionalAttribute(AttrName::Axis, -1); - auto inputShape = shape.GetInputTensorShape(0); - - if (m_axis < 0) - { - m_axis = m_axis + gsl::narrow_cast(inputShape.size()); - } - ML_CHECK_VALID_ARGUMENT(m_axis >= 0 && m_axis < gsl::narrow_cast(inputShape.size())); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - int32_t m_k; - int32_t m_axis; -}; - -class RecurrentHelper -{ -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 - RecurrentHelper(const Info_t& info, const Shape_t& shape) - { - m_hiddenSize = info.GetOptionalAttribute(AttrName::HiddenSize, 1); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - int m_hiddenSize = 0; -}; - -class ConcatHelper -{ -public: - void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions - ); - - // 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 - ConcatHelper(const Info_t& info, const Shape_t& shape) - { - Initialize(info, shape.GetInputTensorShape(0)); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - int m_axis; -}; - -class CropHelper -{ -public: - enum BorderDim { Left, Top, Right, Bottom }; - enum ScaleDim { Height, Width }; - - void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions - ); - - // 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 - CropHelper(const Info_t& info, const Shape_t& shape) - { - Initialize(info, shape.GetInputTensorShape(0)); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - uint32_t m_offsets[NchwDimensionCount]; - uint32_t m_sizes[NchwSpatialDimensionCount]; -}; - -class DepthToSpaceHelper -{ -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 - DepthToSpaceHelper(const Info_t& info, const Shape_t& shape) - { - m_blockSize = info.GetOptionalAttribute(AttrName::BlockSize, -1); - ML_CHECK_VALID_ARGUMENT(m_blockSize > 0, "Attribute blocksize is missing or equal to zero."); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - int32_t m_blockSize; -}; - -class SpaceToDepthHelper -{ -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 - SpaceToDepthHelper(const Info_t& info, const Shape_t& shape) - { - m_blockSize = info.GetOptionalAttribute(AttrName::BlockSize, -1); - ML_CHECK_VALID_ARGUMENT(m_blockSize > 0, "Attribute blocksize is missing or equal to zero."); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - int32_t m_blockSize; -}; - -class FlattenHelper -{ -public: - void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions - ); - - // 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 - FlattenHelper(const Info_t& info, const Shape_t& shape) - { - Initialize(info, shape.GetInputTensorShape(0)); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - int m_axis = 1; -}; - -class MultinomialHelper -{ -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 - MultinomialHelper(const Info_t& info, const Shape_t& shape) - {} - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -}; - -class GatherHelper -{ -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 - GatherHelper(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. - // Shape_t is used to obtain input shape which will be used for adjusting attribute value. - template - PoolingHelperBase( - const Info_t& info, - const Shape_t& shape, - bool useGlobalPooling - ) : m_kernel(useGlobalPooling - ? InitializeGlobalKernel(shape.GetInputTensorShape(0)) - : InitializeKernel(info, static_cast(shape.GetInputTensorShape(0).size()), gsl::span()) - ) - { - if (!useGlobalPooling) - { - ResolveAutoPadding(m_kernel, shape.GetInputTensorShape(0)); - } - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - KernelArgs m_kernel; -}; - -class GlobalPoolingHelper : public PoolingHelperBase -{ -public: - template - GlobalPoolingHelper(const Info_t& info, const Shape_t& shape) : PoolingHelperBase(info, shape, true) {} -}; - -class PoolingHelper : public PoolingHelperBase -{ -public: - template - PoolingHelper(const Info_t& info, const Shape_t& shape) : PoolingHelperBase(info, shape, false) {} -}; - -class RoiPoolingHelper -{ -public: - enum InputTensors { INPUT, ROIS }; - - // 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 - RoiPoolingHelper(const Info_t& info, const Shape_t& shape) - { - std::vector pooledShape = info.GetOptionalAttributeVectorInt32(AttrName::PooledShape); - ML_CHECK_VALID_ARGUMENT(pooledShape.size() == 2, "Pooled shape must be 2."); - m_pooledSizeH = pooledShape[0]; - m_pooledSizeW = pooledShape[1]; - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - uint32_t m_pooledSizeW; - uint32_t m_pooledSizeH; -}; - -class SqueezeHelper -{ -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 - SqueezeHelper(const Info_t& info, const Shape_t& shape) - { - m_axes = info.GetOptionalAttributeVectorInt32(AttrName::Axes); - std::sort(m_axes.begin(), m_axes.end()); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - std::vector m_axes; -}; - -class UnsqueezeHelper -{ -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 - UnsqueezeHelper(const Info_t& info, const Shape_t& shape) - { - m_axes = info.GetOptionalAttributeVectorInt32(AttrName::Axes); - std::sort(m_axes.begin(), m_axes.end()); - } - - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; - -protected: - std::vector m_axes; -}; - -template -void CALLBACK ShapeInferenceFunction(IMLOperatorShapeInferenceContext* inference_context) -{ - MLShapeInferenceContext helperContext(inference_context); - T opHelper(helperContext, helperContext); - - // EdgeInfo to contain whether tensor, whether unused, and what shape is - std::vector outputShapes = opHelper.GetOutputShapes(helperContext); - - for (uint32_t i = 0; i < outputShapes.size(); ++i) - { - if (outputShapes[i].IsTensor() && !outputShapes[i].IsUnused()) - { - helperContext.SetOutputTensorShape(i, outputShapes[i].GetShape()); - } + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + KernelArgs m_kernel; +}; + +class GlobalPoolingHelper : public PoolingHelperBase { + public: + template + GlobalPoolingHelper(const Info_t& info, const Shape_t& shape) : PoolingHelperBase(info, shape, true) {} +}; + +class PoolingHelper : public PoolingHelperBase { + public: + template + PoolingHelper(const Info_t& info, const Shape_t& shape) : PoolingHelperBase(info, shape, false) {} +}; + +class RoiPoolingHelper { + public: + enum InputTensors { INPUT, + ROIS }; + + // 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 + RoiPoolingHelper(const Info_t& info, const Shape_t& shape) { + std::vector pooledShape = info.GetOptionalAttributeVectorInt32(AttrName::PooledShape); + ML_CHECK_VALID_ARGUMENT(pooledShape.size() == 2, "Pooled shape must be 2."); + m_pooledSizeH = pooledShape[0]; + m_pooledSizeW = pooledShape[1]; + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + uint32_t m_pooledSizeW; + uint32_t m_pooledSizeH; +}; + +class SqueezeHelper { + 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 + SqueezeHelper(const Info_t& info, const Shape_t& shape) { + m_axes = info.GetOptionalAttributeVectorInt32(AttrName::Axes); + std::sort(m_axes.begin(), m_axes.end()); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + std::vector m_axes; +}; + +class UnsqueezeHelper { + 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 + UnsqueezeHelper(const Info_t& info, const Shape_t& shape) { + m_axes = info.GetOptionalAttributeVectorInt32(AttrName::Axes); + std::sort(m_axes.begin(), m_axes.end()); + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + std::vector m_axes; +}; + +template +void CALLBACK ShapeInferenceFunction(IMLOperatorShapeInferenceContext* inference_context) { + MLShapeInferenceContext helperContext(inference_context); + T opHelper(helperContext, helperContext); + + // EdgeInfo to contain whether tensor, whether unused, and what shape is + std::vector outputShapes = opHelper.GetOutputShapes(helperContext); + + for (uint32_t i = 0; i < outputShapes.size(); ++i) { + if (outputShapes[i].IsTensor() && !outputShapes[i].IsUnused()) { + helperContext.SetOutputTensorShape(i, outputShapes[i].GetShape()); } + } } -class ReshapeHelper -{ -public: - template - ReshapeHelper(const Info_t& info, const Shape_t& shape) - { - ML_CHECK_VALID_ARGUMENT(info.GetInputCount() >= 2); - ML_CHECK_VALID_ARGUMENT(info.GetOutputCount() >= 1); +class ReshapeHelper { + public: + template + ReshapeHelper(const Info_t& info, const Shape_t& shape) { + ML_CHECK_VALID_ARGUMENT(info.GetInputCount() >= 2); + ML_CHECK_VALID_ARGUMENT(info.GetOutputCount() >= 1); - MLOperatorTensor shapeTensor = info.GetConstantInputTensor(1); + MLOperatorTensor shapeTensor = info.GetConstantInputTensor(1); - // The 'shape' tensor is a 1D tensor holding the new shape to reshape to, - // and the first element of its own shape holds how many dimensions there - // will be for the output. - std::vector shapeTensorDimensions = shapeTensor.GetShape(); - ML_CHECK_VALID_ARGUMENT(shapeTensorDimensions.size() == 1, "Reshape's shape tensor must be 1D."); - size_t dimCount = shapeTensorDimensions[0]; + // The 'shape' tensor is a 1D tensor holding the new shape to reshape to, + // and the first element of its own shape holds how many dimensions there + // will be for the output. + std::vector shapeTensorDimensions = shapeTensor.GetShape(); + ML_CHECK_VALID_ARGUMENT(shapeTensorDimensions.size() == 1, "Reshape's shape tensor must be 1D."); + size_t dimCount = shapeTensorDimensions[0]; - ML_CHECK_VALID_ARGUMENT(shapeTensor.IsCpuData(), "Reshape's shape tensor must be CPU Tensor."); - const int64_t* shapeData = shapeTensor.GetData(); - - // Shape of shape tensor is how many dims to reshape to. - for (size_t i = 0; i < dimCount; ++i) - { - m_shapeDims.push_back(gsl::narrow_cast(shapeData[i])); - } + ML_CHECK_VALID_ARGUMENT(shapeTensor.IsCpuData(), "Reshape's shape tensor must be CPU Tensor."); + const int64_t* shapeData = shapeTensor.GetData(); + + // Shape of shape tensor is how many dims to reshape to. + for (size_t i = 0; i < dimCount; ++i) { + m_shapeDims.push_back(gsl::narrow_cast(shapeData[i])); } + } - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -protected: - std::vector m_shapeDims; + protected: + std::vector m_shapeDims; }; -class ExpandHelper -{ -public: - template - ExpandHelper(const Info_t& info, const Shape_t& shape) - { - } +class ExpandHelper { + public: + template + ExpandHelper(const Info_t& info, const Shape_t& shape) { + } - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -protected: + protected: }; -class ConstantOfShapeHelper -{ -public: - template - ConstantOfShapeHelper(const Info_t& info, const Shape_t& shape) - { - } +class ConstantOfShapeHelper { + public: + template + ConstantOfShapeHelper(const Info_t& info, const Shape_t& shape) { + } - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -protected: + protected: }; -class TileHelper -{ -public: - template - TileHelper(const Info_t& info, const Shape_t& shapeInfo) - { - m_inputDimensions = shapeInfo.GetInputTensorShape(0); +class TileHelper { + public: + template + TileHelper(const Info_t& info, const Shape_t& shapeInfo) { + m_inputDimensions = shapeInfo.GetInputTensorShape(0); - // Read the repeats tensor. - const std::vector repeatsTensorDimensions = shapeInfo.GetInputTensorShape(1); - ML_CHECK_VALID_ARGUMENT(repeatsTensorDimensions.size() == 1, "Tile's repeats tensor must be 1D."); - const size_t dimCount = repeatsTensorDimensions[0]; + // Read the repeats tensor. + const std::vector repeatsTensorDimensions = shapeInfo.GetInputTensorShape(1); + ML_CHECK_VALID_ARGUMENT(repeatsTensorDimensions.size() == 1, "Tile's repeats tensor must be 1D."); + const size_t dimCount = repeatsTensorDimensions[0]; - MLOperatorTensor repeatsTensor = info.GetConstantInputTensor(1); - const int64_t* repeatsData = repeatsTensor.GetData(); - ML_CHECK_VALID_ARGUMENT(m_inputDimensions.size() == dimCount, "Tile's repeats tensor must be the same dimension count as the input tensor."); - ML_CHECK_VALID_ARGUMENT(repeatsTensor.IsCpuData(), "Tile's repeats tensor must be CPU Tensor."); + MLOperatorTensor repeatsTensor = info.GetConstantInputTensor(1); + const int64_t* repeatsData = repeatsTensor.GetData(); + ML_CHECK_VALID_ARGUMENT(m_inputDimensions.size() == dimCount, "Tile's repeats tensor must be the same dimension count as the input tensor."); + ML_CHECK_VALID_ARGUMENT(repeatsTensor.IsCpuData(), "Tile's repeats tensor must be CPU Tensor."); - for (size_t i = 0; i < dimCount; ++i) - { - ML_CHECK_VALID_ARGUMENT(repeatsData[i] > 0, "Repeat values should be > 0."); - m_repeatsData.push_back(gsl::narrow_cast(repeatsData[i])); - } - - // Update the computed output shape accordingly, repeat every axis's length by the repeat count. - m_outputDimensions.assign(m_inputDimensions.begin(), m_inputDimensions.end()); - - for (size_t dimIndex = 0; dimIndex < dimCount; ++dimIndex) - { - m_outputDimensions[dimIndex] *= m_repeatsData[dimIndex]; - } + for (size_t i = 0; i < dimCount; ++i) { + ML_CHECK_VALID_ARGUMENT(repeatsData[i] > 0, "Repeat values should be > 0."); + m_repeatsData.push_back(gsl::narrow_cast(repeatsData[i])); } - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + // Update the computed output shape accordingly, repeat every axis's length by the repeat count. + m_outputDimensions.assign(m_inputDimensions.begin(), m_inputDimensions.end()); -protected: - std::vector m_repeatsData; - std::vector m_inputDimensions; - std::vector m_outputDimensions; + for (size_t dimIndex = 0; dimIndex < dimCount; ++dimIndex) { + m_outputDimensions[dimIndex] *= m_repeatsData[dimIndex]; + } + } + + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + std::vector m_repeatsData; + std::vector m_inputDimensions; + std::vector m_outputDimensions; }; -class ResizeHelper -{ -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 - ResizeHelper(const Info_t& info, const Shape_t& shape) +class ResizeHelper { + 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 + ResizeHelper(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. { - // 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)); - } + Initialize(info, shape.GetInputTensorShape(0)); } + } - void Initialize( - const MLOperatorAttributes& operatorAttributes, - gsl::span inputDimensions - ); + void Initialize( + const MLOperatorAttributes& operatorAttributes, + gsl::span inputDimensions); - void Initialize( - const MLOperatorTensor& scalesTensor, - gsl::span inputDimensions - ); + void Initialize( + const MLOperatorTensor& scalesTensor, + gsl::span inputDimensions); - void InitializeOutputDimensions( - gsl::span scales, - gsl::span inputDimensions - ); + void InitializeOutputDimensions( + gsl::span scales, + gsl::span inputDimensions); - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; -protected: - std::vector m_inputDimensions; - std::vector m_outputDimensions; - std::vector m_scales; // Cached scales to check for updates/invalidate operator. + protected: + std::vector m_inputDimensions; + std::vector m_outputDimensions; + std::vector m_scales; // Cached scales to check for updates/invalidate operator. }; -class OneHotHelper -{ -public: - template - OneHotHelper(const Info_t& info, const Shape_t& shapeInfo) - { - ML_CHECK_VALID_ARGUMENT(info.GetInputCount() == 3); - ML_CHECK_VALID_ARGUMENT(info.GetOutputCount() == 1); +class OneHotHelper { + public: + template + OneHotHelper(const Info_t& info, const Shape_t& shapeInfo) { + ML_CHECK_VALID_ARGUMENT(info.GetInputCount() == 3); + ML_CHECK_VALID_ARGUMENT(info.GetOutputCount() == 1); - const std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); - std::vector outputDimensions; - - m_onnxAxis = info.GetOptionalAttribute(AttrName::Axis, -1); + const std::vector inputDimensions = shapeInfo.GetInputTensorShape(0); + std::vector outputDimensions; - // Get 'depth' tensor, which is really a scalar for the output size along the given axis. - MLOperatorTensor shapeTensor = info.GetConstantInputTensor(1); + m_onnxAxis = info.GetOptionalAttribute(AttrName::Axis, -1); - auto indicesShape = shapeInfo.GetInputTensorShape(0); - m_absoluteAxis = HandleNegativeAxis(m_onnxAxis, gsl::narrow_cast(indicesShape.size() + 1)); + // Get 'depth' tensor, which is really a scalar for the output size along the given axis. + MLOperatorTensor shapeTensor = info.GetConstantInputTensor(1); - // The shape tensor ('depth') is a 0D tensor holding the size for the output tensor along the specified axis. - // It must be registered as OrtMemType::OrtMemTypeCPUInput for CPU read access. - const uint32_t depthElementCount = ComputeElementCountFromDimensions(shapeTensor.GetShape()); - ML_CHECK_VALID_ARGUMENT(shapeTensor.IsCpuData(), "OneHots's 'depth' tensor must be a CPU Tensor."); - ML_CHECK_VALID_ARGUMENT(depthElementCount == 1, "OneHots's 'depth' tensor must have one element."); - const void* tensorData = shapeTensor.GetByteData(); - const int64_t depth64 = ReadAsInt64(shapeTensor.GetTensorDataType(), tensorData); - ML_CHECK_VALID_ARGUMENT(depth64 > 0, "Negative or zero 'depth' values for OneHot are illegal."); - const uint32_t depth = gsl::narrow_cast(depth64); - m_outputDimensions.assign(indicesShape.begin(), indicesShape.end()); - m_outputDimensions.insert(m_outputDimensions.begin() + m_absoluteAxis, depth); - } + auto indicesShape = shapeInfo.GetInputTensorShape(0); + m_absoluteAxis = HandleNegativeAxis(m_onnxAxis, gsl::narrow_cast(indicesShape.size() + 1)); - std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + // The shape tensor ('depth') is a 0D tensor holding the size for the output tensor along the specified axis. + // It must be registered as OrtMemType::OrtMemTypeCPUInput for CPU read access. + const uint32_t depthElementCount = ComputeElementCountFromDimensions(shapeTensor.GetShape()); + ML_CHECK_VALID_ARGUMENT(shapeTensor.IsCpuData(), "OneHots's 'depth' tensor must be a CPU Tensor."); + ML_CHECK_VALID_ARGUMENT(depthElementCount == 1, "OneHots's 'depth' tensor must have one element."); + const void* tensorData = shapeTensor.GetByteData(); + const int64_t depth64 = ReadAsInt64(shapeTensor.GetTensorDataType(), tensorData); + ML_CHECK_VALID_ARGUMENT(depth64 > 0, "Negative or zero 'depth' values for OneHot are illegal."); + const uint32_t depth = gsl::narrow_cast(depth64); + m_outputDimensions.assign(indicesShape.begin(), indicesShape.end()); + m_outputDimensions.insert(m_outputDimensions.begin() + m_absoluteAxis, depth); + } -protected: - int32_t m_onnxAxis = 0; // Original ONNX attribute value, including negative value. - uint32_t m_absoluteAxis = 0; // Absolute index value. - std::vector m_indicesDimensions; - std::vector m_outputDimensions; + std::vector GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const; + + protected: + int32_t m_onnxAxis = 0; // Original ONNX attribute value, including negative value. + uint32_t m_absoluteAxis = 0; // Absolute index value. + std::vector m_indicesDimensions; + std::vector m_outputDimensions; }; using ShapeInferenceHelper_Conv = ConvHelper; @@ -1107,7 +994,7 @@ using ShapeInferenceHelper_GlobalLpPool = GlobalPoolingHelper; using ShapeInferenceHelper_MaxRoiPool = RoiPoolingHelper; using ShapeInferenceHelper_InstanceNormalization = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_BatchNormalization = GetOutputShapeAsInputShapeHelper; - + using ShapeInferenceHelper_LRN = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_MeanVarianceNormalization = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_LpNormalization = GetOutputShapeAsInputShapeHelper; @@ -1115,7 +1002,7 @@ using ShapeInferenceHelper_RNN = RecurrentHelper; using ShapeInferenceHelper_GRU = RecurrentHelper; using ShapeInferenceHelper_LSTM = RecurrentHelper; using ShapeInferenceHelper_Gather = GatherHelper; - + using ShapeInferenceHelper_Flatten = FlattenHelper; using ShapeInferenceHelper_Split = SplitHelper; using ShapeInferenceHelper_Transpose = TransposeHelper; @@ -1193,11 +1080,11 @@ using ShapeInferenceHelper_ArgMax = ArgMinArgMaxHelper; using ShapeInferenceHelper_ArgMin = ArgMinArgMaxHelper; using ShapeInferenceHelper_Gemm = GemmHelper; using ShapeInferenceHelper_Neg = GetOutputShapeAsInputShapeHelper; - + using ShapeInferenceHelper_Crop = CropHelper; using ShapeInferenceHelper_ImageScaler = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_Upsample = ResizeHelper; - + using ShapeInferenceHelper_Sigmoid = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_HardSigmoid = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_Tanh = GetOutputShapeAsInputShapeHelper; @@ -1216,14 +1103,14 @@ using ShapeInferenceHelper_Softplus = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_ParametricSoftplus = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_Dropout = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_Shrink = GetOutputShapeAsInputShapeHelper; - + using ShapeInferenceHelper_Identity = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_MatMul = MatMulHelper; using ShapeInferenceHelper_Cast = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_MemcpyFromHost = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_MemcpyToHost = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_TopK = TopKHelper; - + using ShapeInferenceHelper_RandomUniform = RandomUniformHelper; using ShapeInferenceHelper_RandomUniformLike = GetOutputShapeAsInputShapeHelper; using ShapeInferenceHelper_RandomNormal = RandomNormalHelper; @@ -1240,4 +1127,4 @@ using ShapeInferenceHelper_FusedMatMul = MatMulHelper; using ShapeInferenceHelper_FusedAdd = GetBroadcastedOutputShapeHelper; using ShapeInferenceHelper_FusedSum = GetBroadcastedOutputShapeHelper; -} // namespace OperatorHelper +} // namespace OperatorHelper diff --git a/winml/lib/Api.Core/WinMLAdapter.cpp b/winml/lib/Api.Core/WinMLAdapter.cpp index 4dd12dad7a..b25b92e7c2 100644 --- a/winml/lib/Api.Core/WinMLAdapter.cpp +++ b/winml/lib/Api.Core/WinMLAdapter.cpp @@ -91,29 +91,48 @@ class ModelInfo : public Microsoft::WRL::RuntimeClass< Initialize(model_proto); } - std::string& STDMETHODCALLTYPE author() override { - return author_; + const char* STDMETHODCALLTYPE author() override { + return author_.c_str(); } - std::string& STDMETHODCALLTYPE name() override { - return name_; + const char* STDMETHODCALLTYPE name() override { + return name_.c_str(); } - std::string& STDMETHODCALLTYPE domain() override { - return domain_; + const char* STDMETHODCALLTYPE domain() override { + return domain_.c_str(); } - std::string& STDMETHODCALLTYPE description() override { - return description_; + const char* STDMETHODCALLTYPE description() override { + return description_.c_str(); } int64_t STDMETHODCALLTYPE version() override { return version_; } - std::unordered_map& STDMETHODCALLTYPE model_metadata() override { - return model_metadata_; + HRESULT STDMETHODCALLTYPE GetModelMetadata( + ABI::Windows::Foundation::Collections::IMapView** metadata) override { + *metadata = nullptr; + std::unordered_map map_copy; + for (auto& pair : model_metadata_) { + auto key = WinML::Strings::HStringFromUTF8(pair.first); + auto map_value = WinML::Strings::HStringFromUTF8(pair.second); + map_copy.emplace(std::move(key), std::move(map_value)); + } + auto out = winrt::single_threaded_map( + std::move(map_copy)); + + winrt::copy_to_abi(out.GetView(), *(void**)metadata); + return S_OK; } - wfc::IVector& STDMETHODCALLTYPE input_features() override { - return input_features_; + + HRESULT STDMETHODCALLTYPE GetInputFeatures( + ABI::Windows::Foundation::Collections::IVectorView** features) override{ + *features = nullptr; + winrt::copy_to_abi(input_features_.GetView(), *(void**)features); + return S_OK; } - wfc::IVector& STDMETHODCALLTYPE output_features() override { - return output_features_; + HRESULT STDMETHODCALLTYPE GetOutputFeatures( + ABI::Windows::Foundation::Collections::IVectorView** features) override { + *features = nullptr; + winrt::copy_to_abi(output_features_.GetView(), *(void**)features); + return S_OK; } static std::vector diff --git a/winml/lib/Api.Core/inc/WinMLAdapter.h b/winml/lib/Api.Core/inc/WinMLAdapter.h index cb57534cac..eeb50a15b9 100644 --- a/winml/lib/Api.Core/inc/WinMLAdapter.h +++ b/winml/lib/Api.Core/inc/WinMLAdapter.h @@ -10,14 +10,14 @@ TRACELOGGING_DECLARE_PROVIDER(winml_trace_logging_provider); MIDL_INTERFACE("eaae30b5-7381-432d-9730-322136b02371") IModelInfo : IUnknown{ // model metadata - virtual std::string& STDMETHODCALLTYPE author() = 0; - virtual std::string& STDMETHODCALLTYPE name() = 0; - virtual std::string& STDMETHODCALLTYPE domain() = 0; - virtual std::string& STDMETHODCALLTYPE description() = 0; - virtual int64_t STDMETHODCALLTYPE version() = 0; - virtual std::unordered_map& STDMETHODCALLTYPE model_metadata() = 0; - virtual wfc::IVector& STDMETHODCALLTYPE input_features() = 0; - virtual wfc::IVector& STDMETHODCALLTYPE output_features() = 0; + virtual const char* STDMETHODCALLTYPE author() = 0; + virtual const char* STDMETHODCALLTYPE name() = 0; + virtual const char* STDMETHODCALLTYPE domain() = 0; + virtual const char* STDMETHODCALLTYPE description() = 0; + virtual int64_t STDMETHODCALLTYPE version() = 0; + virtual HRESULT STDMETHODCALLTYPE GetModelMetadata(ABI::Windows::Foundation::Collections::IMapView ** metadata) = 0; + virtual HRESULT STDMETHODCALLTYPE GetInputFeatures(ABI::Windows::Foundation::Collections::IVectorView * *features) = 0; + virtual HRESULT STDMETHODCALLTYPE GetOutputFeatures(ABI::Windows::Foundation::Collections::IVectorView * *features) = 0; }; MIDL_INTERFACE("438e7719-554a-4058-84d9-eb6226c34887") IIOBinding : IUnknown{ @@ -80,9 +80,6 @@ MIDL_INTERFACE("b19385e7-d9af-441a-ba7f-3993c7b1c9db") IWinMLAdapter : IUnknown IModelProto* p_model_proto, bool is_float16_supported) = 0; - virtual ID3D12Resource* STDMETHODCALLTYPE GetD3D12ResourceFromAllocation(onnxruntime::IExecutionProvider * provider, void* allocation) = 0; - - // factory method for creating an ortsessionbuilder from a device virtual HRESULT STDMETHODCALLTYPE CreateOrtSessionBuilder( ID3D12Device* device, @@ -105,6 +102,8 @@ MIDL_INTERFACE("b19385e7-d9af-441a-ba7f-3993c7b1c9db") IWinMLAdapter : IUnknown virtual void* STDMETHODCALLTYPE CreateGPUAllocationFromD3DResource(ID3D12Resource* pResource) = 0; virtual void STDMETHODCALLTYPE FreeGPUAllocation(void* ptr) = 0; virtual HRESULT STDMETHODCALLTYPE CopyTensor(onnxruntime::IExecutionProvider* provider, OrtValue* src, OrtValue* dst) = 0; + // note: this returns a weak ref + virtual ID3D12Resource* STDMETHODCALLTYPE GetD3D12ResourceFromAllocation(onnxruntime::IExecutionProvider * provider, void* allocation) = 0; // schema overrides (dml does this for us) virtual HRESULT STDMETHODCALLTYPE OverrideSchemaInferenceFunctions() = 0; diff --git a/winml/lib/Api.Image/DeviceHelpers.cpp b/winml/lib/Api.Image/DeviceHelpers.cpp index c07c31b08f..093fba0d62 100644 --- a/winml/lib/Api.Image/DeviceHelpers.cpp +++ b/winml/lib/Api.Image/DeviceHelpers.cpp @@ -3,10 +3,7 @@ #include "pch.h" -#ifdef USE_DML #include "DirectML.h" -#endif USE_DML - #include #include #include "inc/DeviceHelpers.h" @@ -147,7 +144,6 @@ bool IsFloat16Supported(ID3D12Device* device) { return false; } -#ifdef USE_DML winrt::com_ptr dmlDevice; winrt::check_hresult(DMLCreateDevice( device, @@ -165,9 +161,6 @@ bool IsFloat16Supported(ID3D12Device* device) { &float16Data)); return float16Data.IsSupported; -#else - return false; -#endif USE_DML } // uses Structured Exception Handling (SEH) to detect for delay load failures of target API. diff --git a/winml/lib/Api/LearningModel.cpp b/winml/lib/Api/LearningModel.cpp index 5223ed5c56..6e5ea3b3aa 100644 --- a/winml/lib/Api/LearningModel.cpp +++ b/winml/lib/Api/LearningModel.cpp @@ -66,6 +66,7 @@ void LearningModel::LogCreationEvent(bool fromStream) { break; } } +#ifdef LAYERING_DONE telemetry_helper.LogModelCreation( fromStream, model_info_->author(), @@ -75,6 +76,7 @@ void LearningModel::LogCreationEvent(bool fromStream) { model_info_->version(), use_fp16, model_info_->model_metadata()); +#endif } void LearningModel::ModelUseFP16( @@ -140,15 +142,11 @@ WINML_CATCH_ALL wfc::IMapView LearningModel::Metadata() try { - std::unordered_map map_copy; - for (auto& pair : model_info_->model_metadata()) { - auto key = WinML::Strings::HStringFromUTF8(pair.first); - auto value = WinML::Strings::HStringFromUTF8(pair.second); - map_copy.emplace(std::move(key), std::move(value)); - } - auto metadata = winrt::single_threaded_map( - std::move(map_copy)); - return metadata.GetView(); + ABI::Windows::Foundation::Collections::IMapView* metadata; + wfc::IMapView out; + WINML_THROW_IF_FAILED(model_info_->GetModelMetadata(&metadata)); + winrt::attach_abi(out, metadata); + return out; } WINML_CATCH_ALL @@ -169,13 +167,21 @@ LearningModel::GetOperatorRegistry() { wfc::IVectorView LearningModel::InputFeatures() try { - return model_info_->input_features().GetView(); + ABI::Windows::Foundation::Collections::IVectorView* features; + wfc::IVectorView out; + WINML_THROW_IF_FAILED(model_info_->GetInputFeatures(&features)); + winrt::attach_abi(out, features); + return out; } WINML_CATCH_ALL wfc::IVectorView LearningModel::OutputFeatures() try { - return model_info_->output_features().GetView(); + ABI::Windows::Foundation::Collections::IVectorView* features; + wfc::IVectorView out; + WINML_THROW_IF_FAILED(model_info_->GetOutputFeatures(&features)); + winrt::attach_abi(out, features); + return out; } WINML_CATCH_ALL diff --git a/winml/lib/Api/LearningModelBinding.cpp b/winml/lib/Api/LearningModelBinding.cpp index 85dd7a9621..f126ffab7c 100644 --- a/winml/lib/Api/LearningModelBinding.cpp +++ b/winml/lib/Api/LearningModelBinding.cpp @@ -213,6 +213,8 @@ bool LearningModelBinding::HasKey(hstring const& key) { void LearningModelBinding::Split( Windows::Foundation::Collections::IMapView& first, Windows::Foundation::Collections::IMapView& second) { + ORT_UNUSED_PARAMETER(first); + ORT_UNUSED_PARAMETER(second); throw hresult_not_implemented(); } diff --git a/winml/lib/Api/impl/MapBase.h b/winml/lib/Api/impl/MapBase.h index 09357a716f..7c9757ff60 100644 --- a/winml/lib/Api/impl/MapBase.h +++ b/winml/lib/Api/impl/MapBase.h @@ -160,6 +160,7 @@ struct MapBase : winrt::implements< STDMETHOD(GetOrtValue) (WinML::BindingContext& context, OrtValue** ort_value) { + ORT_UNUSED_PARAMETER(context); // TODO: Tensorized data should be cached so multiple bindings work more efficiently // TODO : we need to handle inputs. for now only handle outputs and don't pre allocate anything @@ -185,6 +186,7 @@ struct MapBase : winrt::implements< STDMETHOD(UpdateSourceResourceData) (BindingContext& context, OrtValue* ort_value) { + ORT_UNUSED_PARAMETER(context); data_.Clear(); Ort::AllocatorWithDefaultOptions allocator; diff --git a/winml/lib/Api/impl/SequenceBase.h b/winml/lib/Api/impl/SequenceBase.h index 43ac2d3ed0..8df40aba39 100644 --- a/winml/lib/Api/impl/SequenceBase.h +++ b/winml/lib/Api/impl/SequenceBase.h @@ -266,6 +266,7 @@ struct SequenceBase : public winrt::implements< STDMETHOD(UpdateSourceResourceData)( BindingContext& context, OrtValue* ort_value) { + ORT_UNUSED_PARAMETER(context); auto writable_vector = data_.as>(); writable_vector.Clear(); diff --git a/winml/lib/Common/inc/TimerHelper.h b/winml/lib/Common/inc/TimerHelper.h index 3776d95e8d..33c690ec57 100644 --- a/winml/lib/Common/inc/TimerHelper.h +++ b/winml/lib/Common/inc/TimerHelper.h @@ -12,6 +12,7 @@ #include #include #include +#include "core/common/common.h" #define TIMER_SLOT_SIZE (128) #define CONVERT_100NS_TO_SECOND(x) ((x)*0.0000001) @@ -330,6 +331,7 @@ class GpuPerfCounter : public IPerfCounter { } void GetValues(double (&values)[CounterType::TYPE_COUNT], double time) override { + ORT_UNUSED_PARAMETER(time); values[CounterType::GPU_USAGE] = GetGpuUsage(); values[CounterType::GPU_DEDICATED_MEM_USAGE] = GetDedicatedMemory(); values[CounterType::GPU_SHARED_MEM_USAGE] = GetSharedMemory(); diff --git a/winml/lib/Common/inc/WinMLTelemetryHelper.h b/winml/lib/Common/inc/WinMLTelemetryHelper.h index b1d3c21fdb..01e42e7a75 100644 --- a/winml/lib/Common/inc/WinMLTelemetryHelper.h +++ b/winml/lib/Common/inc/WinMLTelemetryHelper.h @@ -84,10 +84,10 @@ class WinMLTelemetryHelper { void LogDllAttachEvent(); void LogSessionCreation(const std::string& modelname, bool isCpu, LUID adapterLuid); void LogModelCreation(bool fromStream, - const std::string& author, - const std::string& name, - const std::string& domain, - const std::string& description, + const char* author, + const char* name, + const char* domain, + const char* description, int64_t version, bool bUseFP16, const std::unordered_map& modelMetadata); diff --git a/winml/lib/Telemetry/WinMLTelemetryHelper.cpp b/winml/lib/Telemetry/WinMLTelemetryHelper.cpp index 3d02a9448f..d3683956aa 100644 --- a/winml/lib/Telemetry/WinMLTelemetryHelper.cpp +++ b/winml/lib/Telemetry/WinMLTelemetryHelper.cpp @@ -51,10 +51,10 @@ void WinMLTelemetryHelper::LogSessionCreation(const std::string& modelname, bool } void WinMLTelemetryHelper::LogModelCreation(bool fromStream, - const std::string& author, - const std::string& name, - const std::string& domain, - const std::string& description, + const char* author, + const char* name, + const char* domain, + const char* description, int64_t version, bool bUseFP16, const std::unordered_map& modelMetadata) { @@ -87,10 +87,10 @@ void WinMLTelemetryHelper::LogModelCreation(bool fromStream, //stream TraceLoggingBool(fromStream, "fromStream"), // Model Desc - TraceLoggingString(author.c_str(), "author"), - TraceLoggingString(name.c_str(), "name"), - TraceLoggingString(domain.c_str(), "domain"), - TraceLoggingString(description.c_str(), "description"), + TraceLoggingString(author, "author"), + TraceLoggingString(name, "name"), + TraceLoggingString(domain, "domain"), + TraceLoggingString(description, "description"), TraceLoggingInt64(version, "version"), TraceLoggingBool(bUseFP16, "usefp16"), TraceLoggingString(BitmapPixelFormatString.c_str(), "bitmappixelformat"), diff --git a/winml/test/common/SqueezeNetValidator.cpp b/winml/test/common/SqueezeNetValidator.cpp index 2b1377868e..6d0c1fb22d 100644 --- a/winml/test/common/SqueezeNetValidator.cpp +++ b/winml/test/common/SqueezeNetValidator.cpp @@ -149,6 +149,7 @@ void ModelValidator::FnsCandy16( bool bindInputsAsIInspectable, float dataTolerance) { + ORT_UNUSED_PARAMETER(dataTolerance); WINML_PROFILING_START(g_RuntimeProfiler, WINML_RUNTIME_TEST_PERF::PREP_TEST); // file name strings static wchar_t* modelFileName = L"winmlperf_coreml_FNS-Candy_prerelease_fp16.onnx"; diff --git a/winml/test/scenario/cppwinrt/CustomNullOp.h b/winml/test/scenario/cppwinrt/CustomNullOp.h index e3b93b0d5e..d7dfdf75ac 100644 --- a/winml/test/scenario/cppwinrt/CustomNullOp.h +++ b/winml/test/scenario/cppwinrt/CustomNullOp.h @@ -41,6 +41,7 @@ struct NullOperatorFactory : winrt::implements(m_callCount); op.copy_to(kernel); return S_OK; @@ -48,6 +49,7 @@ struct NullOperatorFactory : winrt::implements { @@ -144,6 +145,7 @@ struct NoisyReluOperatorFactory : winrt::implements { @@ -104,6 +105,7 @@ struct ReluOperatorFactory : winrt::implements(); reluOperator.copy_to(kernel); return S_OK; @@ -111,6 +113,7 @@ struct ReluOperatorFactory : winrt::implements