Merge remote-tracking branch 'origin/DmlDev' into user/jeffbloo/MergeGithubMasterToDmlDevPlusPending

This commit is contained in:
Jeff Bloomfield 2020-04-19 13:44:25 -07:00
commit acbfa42647
24 changed files with 1093 additions and 434 deletions

View file

@ -1,6 +1,5 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace ApiTraits
@ -25,7 +24,7 @@ struct EnumTraits<DML_TENSOR_TYPE>
template <>
struct EnumTraits<DML_OPERATOR_TYPE>
{
static constexpr auto ValueCount = 119;
static constexpr auto ValueCount = 120;
static constexpr size_t ActivationFunctionCount = 19;
};
@ -748,6 +747,12 @@ struct OperatorDescTraits<DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_DESC>
static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION1;
};
template <>
struct OperatorDescTraits<DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_DESC>
{
static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_MATRIX_MULTIPLY_INTEGER;
};
template <>
struct OperatorDescTraits<DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_DESC>
{
@ -755,15 +760,15 @@ struct OperatorDescTraits<DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_DESC>
};
template <>
struct OperatorDescTraits<DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC>
struct OperatorDescTraits<DML_CONVOLUTION_INTEGER_OPERATOR_DESC>
{
static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION;
static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_CONVOLUTION_INTEGER;
};
template <>
struct OperatorDescTraits<DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_DESC>
struct OperatorDescTraits<DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC>
{
static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR;
static constexpr DML_OPERATOR_TYPE Type = DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION;
};
template <>
@ -1462,6 +1467,12 @@ struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_MEAN_VARIANCE_NORMALIZ
using DescType = DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_DESC;
};
template <>
struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_MATRIX_MULTIPLY_INTEGER>
{
using DescType = DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_DESC;
};
template <>
struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_QUANTIZED_LINEAR_MATRIX_MULTIPLY>
{
@ -1469,15 +1480,15 @@ struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_QUANTIZED_LINEAR_MATRI
};
template <>
struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION>
struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_CONVOLUTION_INTEGER>
{
using DescType = DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC;
using DescType = DML_CONVOLUTION_INTEGER_OPERATOR_DESC;
};
template <>
struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR>
struct OperatorTypeTraits<(DML_OPERATOR_TYPE)DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION>
{
using DescType = DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_DESC;
using DescType = DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC;
};
template <>
@ -1799,12 +1810,16 @@ auto OperatorTypeVisitor(DML_OPERATOR_TYPE type, Visitor&& visitor, Ts&&... args
return std::invoke(std::forward<Visitor>(visitor), DML_SPACE_TO_DEPTH1_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION1:
return std::invoke(std::forward<Visitor>(visitor), DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_RESAMPLE1:
return std::invoke(std::forward<Visitor>(visitor), DML_RESAMPLE1_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_MATRIX_MULTIPLY_INTEGER:
return std::invoke(std::forward<Visitor>(visitor), DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_QUANTIZED_LINEAR_MATRIX_MULTIPLY:
return std::invoke(std::forward<Visitor>(visitor), DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_CONVOLUTION_INTEGER:
return std::invoke(std::forward<Visitor>(visitor), DML_CONVOLUTION_INTEGER_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION:
return std::invoke(std::forward<Visitor>(visitor), DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR:
return std::invoke(std::forward<Visitor>(visitor), DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_ACTIVATION_ELU:
return std::invoke(std::forward<Visitor>(visitor), DML_ACTIVATION_ELU_OPERATOR_DESC{}, std::forward<Ts>(args)...);
case DML_OPERATOR_ACTIVATION_HARDMAX:
@ -1951,9 +1966,11 @@ inline gsl::czstring ToString(DML_OPERATOR_TYPE value)
case DML_OPERATOR_DEPTH_TO_SPACE1: return "DML_OPERATOR_DEPTH_TO_SPACE1";
case DML_OPERATOR_SPACE_TO_DEPTH1: return "DML_OPERATOR_SPACE_TO_DEPTH1";
case DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION1: return "DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION1";
case DML_OPERATOR_RESAMPLE1: return "DML_OPERATOR_RESAMPLE1";
case DML_OPERATOR_MATRIX_MULTIPLY_INTEGER: return "DML_OPERATOR_MATRIX_MULTIPLY_INTEGER";
case DML_OPERATOR_QUANTIZED_LINEAR_MATRIX_MULTIPLY: return "DML_OPERATOR_QUANTIZED_LINEAR_MATRIX_MULTIPLY";
case DML_OPERATOR_CONVOLUTION_INTEGER: return "DML_OPERATOR_CONVOLUTION_INTEGER";
case DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION: return "DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION";
case DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR: return "DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR";
default:
assert(false);
return "<unknown>";

View file

@ -1545,15 +1545,49 @@ constexpr DML_OPERATOR_SCHEMA DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_SCHEMA {
DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_SCHEMA_FIELDS,
};
constexpr DML_SCHEMA_FIELD DML_RESAMPLE1_OPERATOR_SCHEMA_FIELDS[7] {
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT, "InterpolationMode", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT, "DimensionCount", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_FLOAT_ARRAY, "Scales", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_FLOAT_ARRAY, "InputPixelOffsets", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_FLOAT_ARRAY, "OutputPixelOffsets", false },
};
constexpr DML_OPERATOR_SCHEMA DML_RESAMPLE1_OPERATOR_SCHEMA {
"DML_OPERATOR_RESAMPLE1",
DML_OPERATOR_RESAMPLE1,
DML_SCHEMA_OPERATOR_SUPPORT_FLAG_NONE,
7,
DML_RESAMPLE1_OPERATOR_SCHEMA_FIELDS,
};
constexpr DML_SCHEMA_FIELD DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA_FIELDS[5] {
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "ATensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "AZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false },
};
constexpr DML_OPERATOR_SCHEMA DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA {
"DML_OPERATOR_MATRIX_MULTIPLY_INTEGER",
DML_OPERATOR_MATRIX_MULTIPLY_INTEGER,
DML_SCHEMA_OPERATOR_SUPPORT_FLAG_NONE,
5,
DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA_FIELDS,
};
constexpr DML_SCHEMA_FIELD DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_SCHEMA_FIELDS[9] {
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "ATensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "AScaleTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "AZeroPointTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "AZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BScaleTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BZeroPointTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputScaleTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputZeroPointTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false },
};
@ -1565,16 +1599,38 @@ constexpr DML_OPERATOR_SCHEMA DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_SCHE
DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_SCHEMA_FIELDS,
};
constexpr DML_SCHEMA_FIELD DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA_FIELDS[11] {
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "FilterTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "FilterZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT, "DimensionCount", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT_ARRAY, "Strides", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT_ARRAY, "Dilations", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT_ARRAY, "StartPadding", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT_ARRAY, "EndPadding", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT, "GroupCount", false },
};
constexpr DML_OPERATOR_SCHEMA DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA {
"DML_OPERATOR_CONVOLUTION_INTEGER",
DML_OPERATOR_CONVOLUTION_INTEGER,
DML_SCHEMA_OPERATOR_SUPPORT_FLAG_NONE,
11,
DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA_FIELDS,
};
constexpr DML_SCHEMA_FIELD DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_SCHEMA_FIELDS[16] {
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputScaleTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputZeroPointTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "FilterTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "FilterScaleTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "FilterZeroPointTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "FilterZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "BiasTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputScaleTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputZeroPointTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputZeroPointTensor", true },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT, "DimensionCount", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_ATTRIBUTE, DML_SCHEMA_FIELD_TYPE_UINT_ARRAY, "Strides", false },
@ -1592,21 +1648,6 @@ constexpr DML_OPERATOR_SCHEMA DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_SCHEMA {
DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_SCHEMA_FIELDS,
};
constexpr DML_SCHEMA_FIELD DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA_FIELDS[4] {
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputScaleTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputZeroPointTensor", false },
};
constexpr DML_OPERATOR_SCHEMA DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA {
"DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR",
DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR,
DML_SCHEMA_OPERATOR_SUPPORT_FLAG_NONE,
4,
DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA_FIELDS,
};
constexpr DML_SCHEMA_FIELD DML_ACTIVATION_ELU_OPERATOR_SCHEMA_FIELDS[3] {
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_INPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "InputTensor", false },
DML_SCHEMA_FIELD { DML_SCHEMA_FIELD_KIND_OUTPUT_TENSOR, DML_SCHEMA_FIELD_TYPE_TENSOR_DESC, "OutputTensor", false },

View file

@ -920,6 +920,28 @@ inline std::vector<OperatorField> GetFields(const DML_MEAN_VARIANCE_NORMALIZATIO
OperatorField(&DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_SCHEMA.Fields[8], ToOperatorFieldType(static_cast<const DML_OPERATOR_DESC*>(desc.FusedActivation))),
};
}
inline std::vector<OperatorField> GetFields(const DML_RESAMPLE1_OPERATOR_DESC& desc)
{
return {
OperatorField(&DML_RESAMPLE1_OPERATOR_SCHEMA.Fields[0], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.InputTensor))),
OperatorField(&DML_RESAMPLE1_OPERATOR_SCHEMA.Fields[1], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.OutputTensor))),
OperatorField(&DML_RESAMPLE1_OPERATOR_SCHEMA.Fields[2], ToOperatorFieldType(static_cast<UINT>(desc.InterpolationMode))),
OperatorField(&DML_RESAMPLE1_OPERATOR_SCHEMA.Fields[3], ToOperatorFieldType(static_cast<UINT>(desc.DimensionCount))),
OperatorField(&DML_RESAMPLE1_OPERATOR_SCHEMA.Fields[4], ToOperatorFieldType(static_cast<const FLOAT*>(desc.Scales), desc.DimensionCount)),
OperatorField(&DML_RESAMPLE1_OPERATOR_SCHEMA.Fields[5], ToOperatorFieldType(static_cast<const FLOAT*>(desc.InputPixelOffsets), desc.DimensionCount)),
OperatorField(&DML_RESAMPLE1_OPERATOR_SCHEMA.Fields[6], ToOperatorFieldType(static_cast<const FLOAT*>(desc.OutputPixelOffsets), desc.DimensionCount)),
};
}
inline std::vector<OperatorField> GetFields(const DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_DESC& desc)
{
return {
OperatorField(&DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA.Fields[0], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.ATensor))),
OperatorField(&DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA.Fields[1], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.AZeroPointTensor))),
OperatorField(&DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA.Fields[2], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.BTensor))),
OperatorField(&DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA.Fields[3], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.BZeroPointTensor))),
OperatorField(&DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA.Fields[4], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.OutputTensor))),
};
}
inline std::vector<OperatorField> GetFields(const DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_DESC& desc)
{
return {
@ -934,6 +956,22 @@ inline std::vector<OperatorField> GetFields(const DML_QUANTIZED_LINEAR_MATRIX_MU
OperatorField(&DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_SCHEMA.Fields[8], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.OutputTensor))),
};
}
inline std::vector<OperatorField> GetFields(const DML_CONVOLUTION_INTEGER_OPERATOR_DESC& desc)
{
return {
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[0], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.InputTensor))),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[1], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.InputZeroPointTensor))),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[2], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.FilterTensor))),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[3], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.FilterZeroPointTensor))),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[4], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.OutputTensor))),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[5], ToOperatorFieldType(static_cast<UINT>(desc.DimensionCount))),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[6], ToOperatorFieldType(static_cast<const UINT*>(desc.Strides), desc.DimensionCount)),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[7], ToOperatorFieldType(static_cast<const UINT*>(desc.Dilations), desc.DimensionCount)),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[8], ToOperatorFieldType(static_cast<const UINT*>(desc.StartPadding), desc.DimensionCount)),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[9], ToOperatorFieldType(static_cast<const UINT*>(desc.EndPadding), desc.DimensionCount)),
OperatorField(&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA.Fields[10], ToOperatorFieldType(static_cast<UINT>(desc.GroupCount))),
};
}
inline std::vector<OperatorField> GetFields(const DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC& desc)
{
return {
@ -955,15 +993,6 @@ inline std::vector<OperatorField> GetFields(const DML_QUANTIZED_LINEAR_CONVOLUTI
OperatorField(&DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_SCHEMA.Fields[15], ToOperatorFieldType(static_cast<UINT>(desc.GroupCount))),
};
}
inline std::vector<OperatorField> GetFields(const DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_DESC& desc)
{
return {
OperatorField(&DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA.Fields[0], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.InputTensor))),
OperatorField(&DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA.Fields[1], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.OutputTensor))),
OperatorField(&DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA.Fields[2], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.OutputScaleTensor))),
OperatorField(&DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA.Fields[3], ToOperatorFieldType(static_cast<const DML_TENSOR_DESC*>(desc.OutputZeroPointTensor))),
};
}
inline std::vector<OperatorField> GetFields(const DML_ACTIVATION_ELU_OPERATOR_DESC& desc)
{
return {
@ -1215,9 +1244,11 @@ inline const DML_OPERATOR_SCHEMA& GetSchema(DML_OPERATOR_TYPE operatorType)
case DML_OPERATOR_DEPTH_TO_SPACE1: return DML_DEPTH_TO_SPACE1_OPERATOR_SCHEMA;
case DML_OPERATOR_SPACE_TO_DEPTH1: return DML_SPACE_TO_DEPTH1_OPERATOR_SCHEMA;
case DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION1: return DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_SCHEMA;
case DML_OPERATOR_RESAMPLE1: return DML_RESAMPLE1_OPERATOR_SCHEMA;
case DML_OPERATOR_MATRIX_MULTIPLY_INTEGER: return DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA;
case DML_OPERATOR_QUANTIZED_LINEAR_MATRIX_MULTIPLY: return DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_SCHEMA;
case DML_OPERATOR_CONVOLUTION_INTEGER: return DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA;
case DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION: return DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_SCHEMA;
case DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR: return DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA;
case DML_OPERATOR_ACTIVATION_ELU: return DML_ACTIVATION_ELU_OPERATOR_SCHEMA;
case DML_OPERATOR_ACTIVATION_HARDMAX: return DML_ACTIVATION_HARDMAX_OPERATOR_SCHEMA;
case DML_OPERATOR_ACTIVATION_HARD_SIGMOID: return DML_ACTIVATION_HARD_SIGMOID_OPERATOR_SCHEMA;
@ -1630,18 +1661,26 @@ inline AbstractOperatorDesc ConvertOperatorDesc(const DML_OPERATOR_DESC& opDesc)
return AbstractOperatorDesc(
&DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_SCHEMA,
GetFields(*static_cast<const DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_DESC*>(opDesc.Desc)));
case DML_OPERATOR_RESAMPLE1:
return AbstractOperatorDesc(
&DML_RESAMPLE1_OPERATOR_SCHEMA,
GetFields(*static_cast<const DML_RESAMPLE1_OPERATOR_DESC*>(opDesc.Desc)));
case DML_OPERATOR_MATRIX_MULTIPLY_INTEGER:
return AbstractOperatorDesc(
&DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_SCHEMA,
GetFields(*static_cast<const DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_DESC*>(opDesc.Desc)));
case DML_OPERATOR_QUANTIZED_LINEAR_MATRIX_MULTIPLY:
return AbstractOperatorDesc(
&DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_SCHEMA,
GetFields(*static_cast<const DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_DESC*>(opDesc.Desc)));
case DML_OPERATOR_CONVOLUTION_INTEGER:
return AbstractOperatorDesc(
&DML_CONVOLUTION_INTEGER_OPERATOR_SCHEMA,
GetFields(*static_cast<const DML_CONVOLUTION_INTEGER_OPERATOR_DESC*>(opDesc.Desc)));
case DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION:
return AbstractOperatorDesc(
&DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_SCHEMA,
GetFields(*static_cast<const DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC*>(opDesc.Desc)));
case DML_OPERATOR_DYNAMIC_QUANTIZE_LINEAR:
return AbstractOperatorDesc(
&DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_SCHEMA,
GetFields(*static_cast<const DML_DYNAMIC_QUANTIZE_LINEAR_OPERATOR_DESC*>(opDesc.Desc)));
case DML_OPERATOR_ACTIVATION_ELU:
return AbstractOperatorDesc(
&DML_ACTIVATION_ELU_OPERATOR_SCHEMA,

View file

@ -6,31 +6,62 @@
namespace Dml
{
class DmlOperatorConvInteger : public DmlOperator
class DmlOperatorConvInteger : public DmlOperator, public ConvolutionHelperBase
{
private:
enum InputTensors
{
IN_X,
IN_X_ZERO_POINT,
IN_F,
IN_F_ZERO_POINT,
};
public:
using Self = DmlOperatorConvInteger;
DmlOperatorConvInteger(const MLOperatorKernelCreationContext& kernelCreationContext)
: DmlOperator(kernelCreationContext)
DmlOperatorConvInteger(
const MLOperatorKernelCreationContext& kernelInfo
)
: DmlOperator(kernelInfo),
ConvolutionHelperBase(kernelInfo, kernelInfo.GetTensorShapeDescription(), false, false, 0, 1)
{
#if 0 // TODO:NickFe - https://github.com/onnx/onnx/blob/master/docs/Operators.md#convinteger
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetInputCount() >= 2 && kernelCreationContext.GetInputCount() <= 4);
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() == 1);
DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices);
std::vector<std::optional<uint32_t>> kernelInputIndices = {0, 2, 1, 3};
std::vector<std::optional<uint32_t>> kernelOutputIndices = {0};
DmlOperator::Initialize(kernelInfo, kernelInputIndices);
// DirectML is limited to handle only 2D. So for 1D tensors, massage the tensor descriptions. By default, the
// TensorDesc simply right aligns all the values up to 4D (padding the leading dimensions with 1's),
// but 1D tensors actually need to insert the 1 between C and W. e.g. [2,3,4] becomes [2,3,1,4]
m_inputTensorDescs[IN_X] = CreateTensorDescFromInput(kernelInfo, 0/*Onnx Index*/, TensorAxis::DoNotCoerce, TensorAxis::NoPlacementAdjustment, NonspatialDimensionCount, std::nullopt);
m_inputTensorDescs[IN_F] = CreateTensorDescFromInput(kernelInfo, 1/*Onnx Index*/, TensorAxis::DoNotCoerce, TensorAxis::NoPlacementAdjustment, NonspatialDimensionCount, std::nullopt);
m_outputTensorDescs[0] = CreateTensorDescFromOutput(kernelInfo, 0, TensorAxis::DoNotCoerce, TensorAxis::NoPlacementAdjustment, NonspatialDimensionCount, std::nullopt);
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
DML_PLACEHOLDER_OPERATOR_DESC operatorDesc = {};
operatorDesc.IndicesTensor = &inputDescs[0];
operatorDesc.ValuesTensor = &inputDescs[1];
operatorDesc.OutputTensor = outputDescs.data();
operatorDesc.Axis = dmlAxis;
// Form transient kernel arguments with spatial dimensions padded up to at least 2,
// since the DirectML API rejects 1D convolution. Leave the base m_kernel alone
// so that all output tensor size computations are correct.
KernelArgs kernelArgs(m_kernel, NchwSpatialDimensionCount);
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_PLACEHOLDER, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
#endif
DML_CONVOLUTION_INTEGER_OPERATOR_DESC convDesc = {};
convDesc.InputTensor = &inputDescs[IN_X];
convDesc.InputZeroPointTensor = inputDescs[IN_X_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_X_ZERO_POINT] : nullptr;
convDesc.FilterTensor = &inputDescs[IN_F];
convDesc.FilterZeroPointTensor = inputDescs[IN_F_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_F_ZERO_POINT] : nullptr;
convDesc.OutputTensor = &outputDescs[0];
convDesc.DimensionCount = kernelArgs.spatialDimensionCount;
convDesc.Strides = kernelArgs.strides;
convDesc.Dilations = kernelArgs.dilations;
convDesc.StartPadding = kernelArgs.startPadding;
convDesc.EndPadding = kernelArgs.endPadding;
convDesc.GroupCount = m_groupCount;
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_CONVOLUTION_INTEGER, &convDesc };
SetDmlOperatorDesc(opDesc, kernelInfo);
}
};

View file

@ -18,7 +18,7 @@ public:
bool hasDynamicPads
)
: DmlOperator(kernelInfo),
ConvolutionHelperBase(kernelInfo, kernelInfo.GetTensorShapeDescription(), direction == DML_CONVOLUTION_DIRECTION_BACKWARD, hasDynamicPads)
ConvolutionHelperBase(kernelInfo, kernelInfo.GetTensorShapeDescription(), direction == DML_CONVOLUTION_DIRECTION_BACKWARD, hasDynamicPads, 0, 1)
{
uint32_t biasIndex = hasDynamicPads ? 3 : 2;
bool hasBiasInput = kernelInfo.GetInputCount() > biasIndex;

View file

@ -20,12 +20,16 @@ public:
ML_CHECK_VALID_ARGUMENT(inputDescs.size() == 1);
ML_CHECK_VALID_ARGUMENT(outputDescs.size() == 1);
DML_DEPTH_TO_SPACE_OPERATOR_DESC operatorDesc = {};
std::string mode = kernelCreationContext.GetOptionalAttribute<std::string>(AttrName::Mode, "DCR");
DML_DEPTH_SPACE_ORDER depthSpaceOrder = Dml::MapStringToDepthSpaceMode(mode);
DML_DEPTH_TO_SPACE1_OPERATOR_DESC operatorDesc = {};
operatorDesc.InputTensor = inputDescs.data();
operatorDesc.OutputTensor = outputDescs.data();
operatorDesc.BlockSize = m_blockSize;
operatorDesc.Order = depthSpaceOrder;
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_DEPTH_TO_SPACE, &operatorDesc };
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_DEPTH_TO_SPACE1, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
}
};

View file

@ -23,26 +23,7 @@ public:
std::vector<DimensionType> inputShape1 = kernelInfo.GetTensorShapeDescription().GetInputTensorShape(1);
std::vector<DimensionType> outputShape = kernelInfo.GetTensorShapeDescription().GetOutputTensorShape(0);
// Get the padded input shapes and undo the effect of padding removal from the output shape
if (inputShape1.size() == 1)
{
inputShape1.push_back(1);
outputShape.push_back(1);
}
if (inputShape0.size() == 1)
{
inputShape0.insert(inputShape0.begin(), 1);
outputShape.insert(outputShape.end() - 1, 1);
}
// Remove the batch dimensions from each input, then re-add the broadcasted batch dimensions
// based on the output shape
inputShape0.erase(inputShape0.begin(), inputShape0.end() - 2);
inputShape1.erase(inputShape1.begin(), inputShape1.end() - 2);
inputShape0.insert(inputShape0.begin(), outputShape.begin(), outputShape.end() - 2);
inputShape1.insert(inputShape1.begin(), outputShape.begin(), outputShape.end() - 2);
OperatorHelper::MatMulShapeMapping(inputShape0, inputShape1, outputShape);
// Initialize the input descriptions with broadcasting
m_inputTensorDescs[0] = CreateTensorDescFromInput(kernelInfo, 0, TensorAxis::DoNotCoerce, TensorAxis::W, TensorAxis::RightAligned, inputShape0);

View file

@ -8,32 +8,49 @@ namespace Dml
class DmlOperatorMatMulInteger : public DmlOperator
{
public:
using Self = DmlOperatorMatMulInteger;
enum InputTensors {
IN_A,
IN_A_ZERO_POINT,
IN_B,
IN_B_ZERO_POINT
};
DmlOperatorMatMulInteger(const MLOperatorKernelCreationContext& kernelCreationContext)
: DmlOperator(kernelCreationContext)
public:
DmlOperatorMatMulInteger(const MLOperatorKernelCreationContext& kernelInfo)
: DmlOperator(kernelInfo)
{
#if 0 // TODO:NickFe - https://github.com/onnx/onnx/blob/master/docs/Operators.md#MatMulInteger
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetInputCount() >= 2 || kernelCreationContext.GetInputCount() <= 4);
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() == 1);
DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices);
std::vector<std::optional<uint32_t>> inputIndices = { 0, 2, 1, 3 };
DmlOperator::Initialize(kernelInfo, inputIndices);
std::vector<DimensionType> inputShape0 = kernelInfo.GetTensorShapeDescription().GetInputTensorShape(0);
std::vector<DimensionType> inputShape1 = kernelInfo.GetTensorShapeDescription().GetInputTensorShape(1);
std::vector<DimensionType> outputShape = kernelInfo.GetTensorShapeDescription().GetOutputTensorShape(0);
OperatorHelper::MatMulShapeMapping(inputShape0, inputShape1, outputShape);
// Initialize the input descriptions with broadcasting
m_inputTensorDescs[IN_A] = CreateTensorDescFromInput(kernelInfo, 0/*OnnxIndex*/, TensorAxis::DoNotCoerce, TensorAxis::W, TensorAxis::RightAligned, inputShape0);
m_inputTensorDescs[IN_B] = CreateTensorDescFromInput(kernelInfo, 1/*OnnxIndex*/, TensorAxis::DoNotCoerce, TensorAxis::W, TensorAxis::RightAligned, inputShape1);
// Initialize the output description while overriding the shape
m_outputTensorDescs[0] = CreateTensorDescFromOutput(kernelInfo, 0, TensorAxis::DoNotCoerce, TensorAxis::W, TensorAxis::RightAligned, outputShape);
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
DML_PLACEHOLDER_OPERATOR_DESC operatorDesc = {};
operatorDesc.IndicesTensor = &inputDescs[0];
operatorDesc.ValuesTensor = &inputDescs[1];
operatorDesc.OutputTensor = outputDescs.data();
operatorDesc.Axis = dmlAxis;
DML_MATRIX_MULTIPLY_INTEGER_OPERATOR_DESC matmulDesc = {};
matmulDesc.ATensor = &inputDescs[IN_A];
matmulDesc.AZeroPointTensor = inputDescs[IN_A_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_A_ZERO_POINT] : nullptr;
matmulDesc.BTensor = &inputDescs[IN_B];
matmulDesc.BZeroPointTensor = inputDescs[IN_B_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_B_ZERO_POINT] : nullptr;
matmulDesc.OutputTensor = &outputDescs[0];
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_PLACEHOLDER, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
#endif
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_MATRIX_MULTIPLY_INTEGER, &matmulDesc };
SetDmlOperatorDesc(opDesc, kernelInfo);
}
};
DML_OP_DEFINE_CREATION_FUNCTION(MatMulInteger, DmlOperatorMatMulInteger);
} // namespace Dml

View file

@ -16,24 +16,40 @@ public:
DmlOperator::Initialize(kernelCreationContext, kernelInputIndices);
const bool acrossChannels = (static_cast<bool>(kernelCreationContext.GetOptionalAttribute<int>(AttrName::AcrossChannels, 0)));
const bool normalizeVariance = (static_cast<bool>(kernelCreationContext.GetOptionalAttribute<int>(AttrName::NormalizeVariance, 0)));
const bool normalizeVariance = (static_cast<bool>(kernelCreationContext.GetOptionalAttribute<int>(AttrName::NormalizeVariance, 1)));
// If not specified, the default axes are [0,2,3].
std::vector<int32_t> onnxAxes = kernelCreationContext.GetOptionalAttributeVectorInt32(AttrName::Axes);
if (onnxAxes.empty())
{
int32_t crossChannelAxes[] = { 0, 1, 2, 3 };
int32_t nonChannelAxes[] = {0, 2, 3};
gsl::span<int32_t> defaultAxes(acrossChannels ? gsl::make_span(crossChannelAxes) : gsl::make_span(nonChannelAxes));
onnxAxes.assign(defaultAxes.begin(), defaultAxes.end());
}
std::vector<uint32_t> dmlAxes;
const std::vector<DimensionType> inputDimensions = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(0);
const int32_t inputDimCount = gsl::narrow_cast<int32_t>(inputDimensions.size());
GetDmlAdjustedAxes(onnxAxes, inputDimCount, m_inputTensorDescs.front().GetDimensionCount(), /*out*/ dmlAxes);
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
std::optional<ActivationOperatorDesc> fusedActivation = FusionHelpers::TryGetFusedActivationDesc(kernelCreationContext);
DML_OPERATOR_DESC fusedActivationDmlDesc = fusedActivation ? fusedActivation->GetDmlDesc() : DML_OPERATOR_DESC();
DML_MEAN_VARIANCE_NORMALIZATION_OPERATOR_DESC operatorDesc = {};
DML_MEAN_VARIANCE_NORMALIZATION1_OPERATOR_DESC operatorDesc = {};
operatorDesc.InputTensor = &inputDescs[0];
operatorDesc.ScaleTensor = nullptr;
operatorDesc.BiasTensor = nullptr;
operatorDesc.OutputTensor = outputDescs.data();
operatorDesc.CrossChannel = acrossChannels;
operatorDesc.Axes = dmlAxes.data();
operatorDesc.AxisCount = gsl::narrow_cast<uint32_t>(dmlAxes.size());
operatorDesc.NormalizeVariance = normalizeVariance;
operatorDesc.Epsilon = DefaultEpsilon;
operatorDesc.FusedActivation = fusedActivation ? &fusedActivationDmlDesc : nullptr;
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION, &operatorDesc };
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_MEAN_VARIANCE_NORMALIZATION1, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
}
};

View file

@ -9,13 +9,17 @@ namespace Dml
class DmlOperatorPadding : public DmlOperator, public PaddingHelper
{
public:
DmlOperatorPadding(const MLOperatorKernelCreationContext& kernelInfo)
DmlOperatorPadding(const MLOperatorKernelCreationContext& kernelInfo, uint32_t opsetVersion)
: DmlOperator(kernelInfo),
PaddingHelper(kernelInfo, kernelInfo.GetTensorShapeDescription())
PaddingHelper(kernelInfo, kernelInfo.GetTensorShapeDescription(), opsetVersion)
{
ML_CHECK_VALID_ARGUMENT(kernelInfo.GetInputCount() == 1);
const uint32_t inputCount = kernelInfo.GetInputCount();
ML_CHECK_VALID_ARGUMENT((opsetVersion >= 2 && opsetVersion < 11 && inputCount == 1)
|| (opsetVersion >= 11 && inputCount >= 2 && inputCount <= 3));
ML_CHECK_VALID_ARGUMENT(kernelInfo.GetOutputCount() == 1);
DmlOperator::Initialize(kernelInfo);
std::vector<std::optional<uint32_t>> kernelInputIndices = { 0 }; // Only bind GPU to first 'data' tensor.
DmlOperator::Initialize(kernelInfo, kernelInputIndices);
assert(m_inputTensorDescs[0].GetDimensionCount() >= gsl::narrow_cast<uint32_t>(m_startPadding.size()));
assert(m_inputTensorDescs[0].GetDimensionCount() >= gsl::narrow_cast<uint32_t>(m_endPadding.size()));
@ -52,7 +56,20 @@ public:
ML_INVALID_ARGUMENT("Unknown Pad mode attribute.");
}
float value = kernelInfo.GetOptionalAttribute<float>(AttrName::Value, 0.0f);
// Read the constant value which can come from an attribute or tensor.
float value = 0.0f;
if (opsetVersion >= 11)
{
if (kernelInfo.IsInputValid(2))
{
auto valueTensor = kernelInfo.GetConstantInputTensor(2);
value = static_cast<float>(ReadScalarTensorCastToFloat64(valueTensor));
}
}
else
{
value = kernelInfo.GetOptionalAttribute<float>(AttrName::Value, 0.0f);
}
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
@ -72,6 +89,18 @@ public:
}
};
DML_OP_DEFINE_CREATION_FUNCTION(Pad, DmlOperatorPadding);
// A specific type of operation for registration.
template <uint32_t opsetVersion>
class DmlOperatorPaddingTemplate : public DmlOperatorPadding
{
public:
DmlOperatorPaddingTemplate(const MLOperatorKernelCreationContext& kernelInfo)
: DmlOperatorPadding(kernelInfo, opsetVersion)
{
}
};
DML_OP_DEFINE_CREATION_FUNCTION(Pad7, DmlOperatorPaddingTemplate<7>);
DML_OP_DEFINE_CREATION_FUNCTION(Pad11, DmlOperatorPaddingTemplate<11>);
} // namespace Dml

View file

@ -30,17 +30,15 @@ public:
assert(m_kernel.spatialDimensionCount <= ARRAYSIZE(m_kernel.windowSize));
// The below attributes are temporarily not supported:
int ceilMode = kernelInfo.GetOptionalAttribute<int>(AttrName::CeilMode, 0);
THROW_HR_IF(E_NOTIMPL, ceilMode != 0);
int storageOrder = kernelInfo.GetOptionalAttribute<int>(AttrName::StorageOrder, 0);
THROW_HR_IF(E_NOTIMPL, storageOrder != 0);
auto dilations = kernelInfo.GetOptionalAttributeVectorInt32(AttrName::Dilations);
for (int dilation : dilations)
{
THROW_HR_IF(E_NOTIMPL, dilation != 1);
}
const bool hasDilations =
std::any_of(
m_kernel.dilations,
m_kernel.dilations + m_kernel.spatialDimensionCount,
[](auto d) {return d != 1; }
);
// DML requires that DimensionCount be equal to Input.DimCount - 2 for Pooling
uint32_t expectedSpatialDimCount = m_inputTensorDescs[0].GetDimensionCount() - 2;
@ -61,6 +59,9 @@ public:
m_kernel.endPadding[i + shift] = m_kernel.endPadding[i];
m_kernel.endPadding[i] = 0;
m_kernel.dilations[i + shift] = m_kernel.dilations[i];
m_kernel.dilations[i] = 1;
}
m_kernel.spatialDimensionCount = expectedSpatialDimCount;
@ -101,11 +102,14 @@ public:
}
case DML_OPERATOR_MAX_POOLING:
case DML_OPERATOR_MAX_POOLING1:
case DML_OPERATOR_MAX_POOLING2:
{
if (outputDescs.size() > 1 && outputDescs[1].Desc != nullptr)
bool hasOutputIndices = (outputDescs.size() > 1 && outputDescs[1].Desc != nullptr);
if (hasOutputIndices || hasDilations)
{
DML_MAX_POOLING1_OPERATOR_DESC desc = {};
desc.OutputIndicesTensor = &outputDescs[1];
DML_MAX_POOLING2_OPERATOR_DESC desc = {};
desc.OutputIndicesTensor = hasOutputIndices ? &outputDescs[1] : nullptr;
desc.Dilations = m_kernel.dilations;
SetOpDesc(desc);
}
else
@ -134,40 +138,24 @@ public:
}
};
void CALLBACK QueryMaxPool(IMLOperatorSupportQueryContextPrivate* context, bool *isSupported)
void CALLBACK QueryMaxPool(IMLOperatorSupportQueryContextPrivate* context, bool* isSupported)
{
*isSupported = false;
MLOperatorAttributes attributes(context);
// The below attributes are temporarily not supported:
int ceilMode = attributes.GetOptionalAttribute<int>(AttrName::CeilMode, 0);
if (ceilMode != 0)
{
return;
}
int storageOrder = attributes.GetOptionalAttribute<int>(AttrName::StorageOrder, 0);
if (storageOrder != 0)
{
return;
}
auto dilations = attributes.GetOptionalAttributeVectorInt32(AttrName::Dilations);
for (int dilation : dilations)
{
if (dilation != 1)
{
return;
}
}
*isSupported = true;
}
DML_OP_DEFINE_CREATION_FUNCTION(AveragePool, DmlOperatorPoolingTemplate<DML_OPERATOR_AVERAGE_POOLING, false>);
DML_OP_DEFINE_CREATION_FUNCTION(GlobalAveragePool, DmlOperatorPoolingTemplate<DML_OPERATOR_AVERAGE_POOLING, true>);
DML_OP_DEFINE_CREATION_FUNCTION(MaxPool, DmlOperatorPoolingTemplate<DML_OPERATOR_MAX_POOLING1, false>);
DML_OP_DEFINE_CREATION_FUNCTION(MaxPool, DmlOperatorPoolingTemplate<DML_OPERATOR_MAX_POOLING2, false>);
DML_OP_DEFINE_CREATION_FUNCTION(GlobalMaxPool, DmlOperatorPoolingTemplate<DML_OPERATOR_MAX_POOLING, true>);
DML_OP_DEFINE_CREATION_FUNCTION(LpPool, DmlOperatorPoolingTemplate<DML_OPERATOR_LP_POOLING, false>);
DML_OP_DEFINE_CREATION_FUNCTION(GlobalLpPool, DmlOperatorPoolingTemplate<DML_OPERATOR_LP_POOLING, true>);

View file

@ -6,34 +6,98 @@
namespace Dml
{
class DmlOperatorQLinearConv : public DmlOperator
class DmlOperatorQLinearConv : public DmlOperator, public ConvolutionHelperBase
{
private:
enum InputTensors
{
IN_X,
IN_X_SCALE,
IN_X_ZERO_POINT,
IN_F,
IN_F_SCALE,
IN_F_ZERO_POINT,
IN_BIAS,
IN_Y_SCALE,
IN_Y_ZERO_POINT
};
public:
using Self = DmlOperatorQLinearConv;
DmlOperatorQLinearConv(const MLOperatorKernelCreationContext& kernelCreationContext)
: DmlOperator(kernelCreationContext)
DmlOperatorQLinearConv(
const MLOperatorKernelCreationContext& kernelInfo
)
: DmlOperator(kernelInfo),
ConvolutionHelperBase(kernelInfo, kernelInfo.GetTensorShapeDescription(), false, false, 0, 3)
{
#if 0 // TODO:NickFe - https://github.com/onnx/onnx/blob/master/docs/Operators.md#qlinearconv
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetInputCount() >= 8 && kernelCreationContext.GetInputCount() <= 9);
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() == 1);
DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices);
std::vector<std::optional<uint32_t>> kernelInputIndices = {0, 1, 2, 3, 4, 5, 8, 6, 7};
std::vector<std::optional<uint32_t>> kernelOutputIndices = {0};
DmlOperator::Initialize(kernelInfo, kernelInputIndices);
// DirectML is limited to handle only 2D. So for 1D tensors, massage the tensor descriptions. By default, the
// TensorDesc simply right aligns all the values up to 4D (padding the leading dimensions with 1's),
// but 1D tensors actually need to insert the 1 between C and W. e.g. [2,3,4] becomes [2,3,1,4]
m_inputTensorDescs[IN_X] = CreateTensorDescFromInput(kernelInfo, 0/*Onnx Index*/, TensorAxis::DoNotCoerce, TensorAxis::NoPlacementAdjustment, NonspatialDimensionCount, std::nullopt);
m_inputTensorDescs[IN_F] = CreateTensorDescFromInput(kernelInfo, 3/*Onnx Index*/, TensorAxis::DoNotCoerce, TensorAxis::NoPlacementAdjustment, NonspatialDimensionCount, std::nullopt);
// Bias is optional so only adjust it if it exists.
if (m_inputTensorDescs[IN_BIAS].GetDmlDesc().Desc != nullptr)
{
uint32_t inputDimSize = kernelInfo.GetTensorShapeDescription().GetInputTensorDimensionCount(0);
ML_CHECK_VALID_ARGUMENT(
inputDimSize >= 3 && inputDimSize <= 5,
"Bias can only be used with 3D/4D/5D tensors."
);
uint32_t dmlDimSize = m_inputTensorDescs[0].GetDimensionCount();
// Resize the bias to be the same dimension as the input tensor.
// The 1D tensor needs to be moved to the C channel.
m_inputTensorDescs[IN_BIAS] = CreateTensorDescFromInput(
kernelInfo,
8/*Onnx Index*/,
TensorAxis::DoNotCoerce,
TensorAxis::C,
TensorAxis::LeftAligned,
std::nullopt,
dmlDimSize
);
}
m_outputTensorDescs[0] = CreateTensorDescFromOutput(kernelInfo, 0, TensorAxis::DoNotCoerce, TensorAxis::NoPlacementAdjustment, NonspatialDimensionCount, std::nullopt);
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
DML_PLACEHOLDER_OPERATOR_DESC operatorDesc = {};
operatorDesc.IndicesTensor = &inputDescs[0];
operatorDesc.ValuesTensor = &inputDescs[1];
operatorDesc.OutputTensor = outputDescs.data();
operatorDesc.Axis = dmlAxis;
// Form transient kernel arguments with spatial dimensions padded up to at least 2,
// since the DirectML API rejects 1D convolution. Leave the base m_kernel alone
// so that all output tensor size computations are correct.
KernelArgs kernelArgs(m_kernel, NchwSpatialDimensionCount);
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_PLACEHOLDER, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
#endif
DML_QUANTIZED_LINEAR_CONVOLUTION_OPERATOR_DESC convDesc = {};
convDesc.InputTensor = &inputDescs[IN_X];
convDesc.InputScaleTensor = &inputDescs[IN_X_SCALE];
convDesc.InputZeroPointTensor = inputDescs[IN_X_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_X_ZERO_POINT] : nullptr;
convDesc.FilterTensor = &inputDescs[IN_F];
convDesc.FilterScaleTensor = &inputDescs[IN_F_SCALE];
convDesc.FilterZeroPointTensor = inputDescs[IN_F_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_F_ZERO_POINT] : nullptr;
convDesc.BiasTensor = inputDescs[IN_BIAS].Desc != nullptr ? &inputDescs[IN_BIAS] : nullptr;
convDesc.OutputScaleTensor = &inputDescs[IN_Y_SCALE];
convDesc.OutputZeroPointTensor = inputDescs[IN_Y_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_Y_ZERO_POINT] : nullptr;
convDesc.OutputTensor = &outputDescs[0];
convDesc.DimensionCount = kernelArgs.spatialDimensionCount;
convDesc.Strides = kernelArgs.strides;
convDesc.Dilations = kernelArgs.dilations;
convDesc.StartPadding = kernelArgs.startPadding;
convDesc.EndPadding = kernelArgs.endPadding;
convDesc.GroupCount = m_groupCount;
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_QUANTIZED_LINEAR_CONVOLUTION, &convDesc };
SetDmlOperatorDesc(opDesc, kernelInfo);
}
};
DML_OP_DEFINE_CREATION_FUNCTION(QLinearConv, DmlOperatorQLinearConv);
DML_OP_DEFINE_CREATION_FUNCTION(QLinearConv, DmlOperatorQLinearConv);
} // namespace Dml

View file

@ -8,32 +8,57 @@ namespace Dml
class DmlOperatorQLinearMatMul : public DmlOperator
{
public:
using Self = DmlOperatorQLinearMatMul;
enum InputTensors {
IN_A,
IN_A_SCALE,
IN_A_ZERO_POINT,
IN_B,
IN_B_SCALE,
IN_B_ZERO_POINT,
IN_Y_SCALE,
IN_Y_ZERO_POINT
};
DmlOperatorQLinearMatMul(const MLOperatorKernelCreationContext& kernelCreationContext)
: DmlOperator(kernelCreationContext)
public:
DmlOperatorQLinearMatMul(const MLOperatorKernelCreationContext& kernelInfo)
: DmlOperator(kernelInfo)
{
#if 0 // TODO:NickFe - https://github.com/onnx/onnx/blob/master/docs/Operators.md#qlinearmatmul
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetInputCount() == 8);
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() == 1);
DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices);
std::vector<std::optional<uint32_t>> inputIndices = { 0, 1, 2, 3, 4, 5, 6, 7 };
DmlOperator::Initialize(kernelInfo, inputIndices);
std::vector<DimensionType> inputShape0 = kernelInfo.GetTensorShapeDescription().GetInputTensorShape(0/*A OnnxIndex*/);
std::vector<DimensionType> inputShape1 = kernelInfo.GetTensorShapeDescription().GetInputTensorShape(3/*B OnnxIndex*/);
std::vector<DimensionType> outputShape = kernelInfo.GetTensorShapeDescription().GetOutputTensorShape(0);
OperatorHelper::MatMulShapeMapping(inputShape0, inputShape1, outputShape);
// Initialize the input descriptions with broadcasting
m_inputTensorDescs[IN_A] = CreateTensorDescFromInput(kernelInfo, 0/*A OnnxIndex*/, TensorAxis::DoNotCoerce, TensorAxis::W, TensorAxis::RightAligned, inputShape0);
m_inputTensorDescs[IN_B] = CreateTensorDescFromInput(kernelInfo, 3/*B OnnxIndex*/, TensorAxis::DoNotCoerce, TensorAxis::W, TensorAxis::RightAligned, inputShape1);
// Initialize the output description while overriding the shape
m_outputTensorDescs[0] = CreateTensorDescFromOutput(kernelInfo, 0, TensorAxis::DoNotCoerce, TensorAxis::W, TensorAxis::RightAligned, outputShape);
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
DML_PLACEHOLDER_OPERATOR_DESC operatorDesc = {};
operatorDesc.IndicesTensor = &inputDescs[0];
operatorDesc.ValuesTensor = &inputDescs[1];
operatorDesc.OutputTensor = outputDescs.data();
operatorDesc.Axis = dmlAxis;
DML_QUANTIZED_LINEAR_MATRIX_MULTIPLY_OPERATOR_DESC matMulDesc = {};
matMulDesc.ATensor = &inputDescs[IN_A];
matMulDesc.AScaleTensor = &inputDescs[IN_A_SCALE];
matMulDesc.AZeroPointTensor = inputDescs[IN_A_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_A_ZERO_POINT] : nullptr;
matMulDesc.BTensor = &inputDescs[IN_B];
matMulDesc.BScaleTensor = &inputDescs[IN_B_SCALE];
matMulDesc.BZeroPointTensor = inputDescs[IN_B_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_B_ZERO_POINT] : nullptr;
matMulDesc.OutputScaleTensor = &inputDescs[IN_Y_SCALE];
matMulDesc.OutputZeroPointTensor = inputDescs[IN_Y_ZERO_POINT].Desc != nullptr ? &inputDescs[IN_Y_ZERO_POINT] : nullptr;
matMulDesc.OutputTensor = &outputDescs[0];
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_PLACEHOLDER, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
#endif
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_QUANTIZED_LINEAR_MATRIX_MULTIPLY, &matMulDesc };
SetDmlOperatorDesc(opDesc, kernelInfo);
}
};
DML_OP_DEFINE_CREATION_FUNCTION(QLinearMatMul, DmlOperatorQLinearMatMul);
} // namespace Dml

View file

@ -6,13 +6,165 @@
namespace Dml
{
void ComputePixelOffsetsAndScales(
const MLOperatorKernelCreationContext& kernelCreationContext,
gsl::span<const float> regionOfInterest, // May be empty depending on mode.
gsl::span<const uint32_t> inputDimensions,
gsl::span<const uint32_t> outputDimensions,
/*inout*/ gsl::span<float> scales,
/*out*/ gsl::span<float> inputPixelOffsets,
/*out*/ gsl::span<float> outputPixelOffsets
)
{
assert(inputDimensions.size() == outputDimensions.size());
assert(inputPixelOffsets.size() == outputPixelOffsets.size());
assert(inputPixelOffsets.size() == scales.size());
assert(inputPixelOffsets.size() == inputDimensions.size());
assert(regionOfInterest.empty() || regionOfInterest.size() == inputDimensions.size() * 2);
std::string coordinateTransformationMode = kernelCreationContext.GetOptionalAttribute<std::string>(AttrName::CoordinateTransformationMode, "half_pixel");
uint32_t coordinateTransformationModeValue = UINT32_MAX;
const char* modes[] = { "half_pixel", "pytorch_half_pixel", "align_corners", "asymmetric", "tf_half_pixel_for_nn", "tf_crop_and_resize" };
for (uint32_t i = 0; i < std::size(modes); ++i)
{
if (strcmp(modes[i], coordinateTransformationMode.c_str()) == 0)
{
coordinateTransformationModeValue = i;
break;
}
}
ML_CHECK_VALID_ARGUMENT(
!regionOfInterest.empty() || coordinateTransformationModeValue != 5 /*tf_crop_and_resize*/,
"Resize expects 'roi' tensor for 'tf_crop_and_resize' mode."
);
const uint32_t rank = gsl::narrow_cast<uint32_t>(inputDimensions.size());
// Fill in all the input/output pixel offset for each axis,
// and recompute the scale for certain modes.
for (uint32_t i = 0; i < rank; ++i)
{
float inputPixelOffset = 0;
float outputPixelOffset = 0;
// All these mapping modes can be generalized to the equations:
//
// output_coordinate = (input_coordinate + input_offset ) * scale + output_offset
// input_coordinate = (output_coordinate - output_offset) / scale - input_offset
//
// With DML, a scale > 1 maps input to an upsampled output, and a positive pixel
// offset shifts the input contents to the right/down in the output.
//
// Since the equations from ONNX are in terms of mapping the output coordinate back
// to the input coordinate, any offsets need their signs flipped. e.g. For "half_pixel",
// the "x_resized" is the output coordinate, and the "+ 0.5" is the output coordinate
// adjustment which needs to be -0.5 when passed to DML.
switch (coordinateTransformationModeValue)
{
case 0:
// coordinate_transformation_mode is "half_pixel",
// x_original = (x_resized + 0.5) / scale - 0.5
inputPixelOffset = 0.5;
outputPixelOffset = -0.5;
// Keep existing scales.
break;
case 1:
// if coordinate_transformation_mode is "pytorch_half_pixel",
// x_original = length_resized > 1 ? (x_resized + 0.5) / scale - 0.5 : 0
if (inputDimensions[i] <= 1)
{
inputPixelOffset = 0.0;
outputPixelOffset = 0.0;
scales[i] = FLT_MAX; // Set large scale so all output pixels map to 0th input pixel.
}
else
{
inputPixelOffset = 0.5;
outputPixelOffset = -0.5;
// Keep existing scales.
}
break;
case 2:
// if coordinate_transformation_mode is "align_corners",
// x_original = x_resized * (length_original - 1) / (length_resized - 1)
inputPixelOffset = 0.0;
outputPixelOffset = 0.0;
if (outputDimensions[i] <= 1 || inputDimensions[i] <= 1)
{
// Protect against division by zero when either input/output is a single pixel.
scales[i] = FLT_MAX;
}
else
{
// Recalcalculate scale, ignoring existing one (only used to determine output size).
scales[i] = float(outputDimensions[i] - 1) / (inputDimensions[i] - 1);
}
break;
case 3:
// if coordinate_transformation_mode is "asymmetric",
// x_original = x_resized / scale
inputPixelOffset = 0.0;
outputPixelOffset = 0.0;
// Keep existing scales.
break;
case 4:
// if coordinate_transformation_mode is "tf_half_pixel_for_nn",
// x_original = (x_resized + 0.5) / scale
inputPixelOffset = 0.0;
outputPixelOffset = -0.5;
// Keep existing scales.
break;
case 5:
// if coordinate_transformation_mode is "tf_crop_and_resize",
// x_original = length_resized > 1 ? start_x * (length_original - 1) + x_resized * (end_x - start_x) * (length_original - 1) / (length_resized - 1)
// : 0.5 * (start_x + end_x) * (length_original - 1)
if (inputDimensions[i] > 1)
{
assert(regionOfInterest.size() == rank * 2);
// Fold this part of the equation into the input offset: start_x * (length_original - 1)
inputPixelOffset = -(regionOfInterest[i] * (inputDimensions[i] - 1));
outputPixelOffset = 0.0;
// Fold this part to scale: (end_x - start_x) * (length_original - 1) / (length_resized - 1)
float computedScale = float(outputDimensions[i] - 1)
/ std::max((regionOfInterest[i + rank] - regionOfInterest[i]) * (inputDimensions[i] - 1), 1.0f);
scales[i] = computedScale;
}
else // inputDimensions[i] <= 1
{
// 0.5 * (start_x + end_x) * (length_original - 1)
inputPixelOffset = -0.5 * (regionOfInterest[i] + regionOfInterest[i + rank]) * (inputDimensions[i] - 1);
outputPixelOffset = 0.0;
scales[i] = 1;
}
break;
default:
ML_INVALID_ARGUMENT("Unknown 'coordinate_transformation_mode'");
}
inputPixelOffsets[i] = inputPixelOffset;
outputPixelOffsets[i] = outputPixelOffset;
}
}
class DmlOperatorResize : public DmlOperator, public ResizeHelper
{
public:
// Resample a multidimensional image to a new size.
DmlOperatorResize(const MLOperatorKernelCreationContext& kernelCreationContext)
DmlOperatorResize(const MLOperatorKernelCreationContext& kernelCreationContext, uint32_t opsetVersion)
: DmlOperator(kernelCreationContext),
ResizeHelper(kernelCreationContext, kernelCreationContext.GetTensorShapeDescription())
ResizeHelper(kernelCreationContext, kernelCreationContext.GetTensorShapeDescription(), opsetVersion)
{
ML_CHECK_VALID_ARGUMENT(!m_scales.empty(), "Resize/Upsample expect scales, either a 2nd input tensors or 'scales' attribute.");
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() == 1, "Resize/Upsample expect 1 output tensor.");
@ -32,9 +184,31 @@ public:
std::vector<uint32_t> squeezedOutputShape = m_outputDimensions;
std::vector<uint32_t> squeezableDimensionIndices;
std::vector<float> paddedScales = m_scales;
FindValueIndices<uint32_t>(gsl::make_span(m_outputDimensions), 1u, /*out*/ squeezableDimensionIndices);
std::vector<float> inputPixelOffsets(paddedScales.size());
std::vector<float> outputPixelOffsets(paddedScales.size());
ComputePixelOffsetsAndScales(
kernelCreationContext,
m_regionOfInterest, // May be empty depending on mode.
m_inputDimensions,
m_outputDimensions,
/*inout*/ paddedScales,
/*out*/ inputPixelOffsets,
/*out*/ outputPixelOffsets
);
// Find any useless dimensions of size 1 that occur in both input and output.
for (size_t i = 0, rank = m_outputDimensions.size(); i < rank; ++i)
{
if (m_inputDimensions[i] = 1 && m_outputDimensions[i] == 1)
{
squeezableDimensionIndices.push_back(gsl::narrow_cast<uint32_t>(i));
}
}
RemoveValuesByIndex(squeezableDimensionIndices, /*keepOneValue*/ true, /*inout*/ squeezedInputShape);
RemoveValuesByIndex(squeezableDimensionIndices, /*keepOneValue*/ true, /*inout*/ paddedScales);
RemoveValuesByIndex(squeezableDimensionIndices, /*keepOneValue*/ true, /*inout*/ inputPixelOffsets);
RemoveValuesByIndex(squeezableDimensionIndices, /*keepOneValue*/ true, /*inout*/ outputPixelOffsets);
RemoveValuesByIndex(squeezableDimensionIndices, /*keepOneValue*/ true, /*inout*/ squeezedOutputShape);
// Update the tensor descriptions.
@ -52,6 +226,8 @@ public:
if (dmlCompatibleDimCount > squeezedDimCount)
{
paddedScales.insert(paddedScales.begin(), dmlCompatibleDimCount - squeezedDimCount, 1.0f);
inputPixelOffsets.insert(inputPixelOffsets.begin(), dmlCompatibleDimCount - squeezedDimCount, 0.5f);
outputPixelOffsets.insert(outputPixelOffsets.begin(), dmlCompatibleDimCount - squeezedDimCount, -0.5f);
}
std::string mode = kernelCreationContext.GetOptionalAttribute<std::string>(AttrName::Mode, "NEAREST");
@ -61,19 +237,77 @@ public:
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
DML_RESAMPLE_OPERATOR_DESC operatorDesc = {};
DML_RESAMPLE1_OPERATOR_DESC operatorDesc = {};
operatorDesc.InputTensor = inputDescs.data();
operatorDesc.OutputTensor = outputDescs.data();
operatorDesc.InterpolationMode = interpolationMode;
operatorDesc.Scales = paddedScales.data();
operatorDesc.ScaleCount = gsl::narrow_cast<uint32_t>(paddedScales.size());
operatorDesc.DimensionCount = gsl::narrow_cast<uint32_t>(paddedScales.size());
operatorDesc.InputPixelOffsets = inputPixelOffsets.data();
operatorDesc.OutputPixelOffsets = outputPixelOffsets.data();
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_RESAMPLE, &operatorDesc };
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_RESAMPLE1, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
}
};
DML_OP_DEFINE_CREATION_FUNCTION(Resize, DmlOperatorResize);
DML_OP_DEFINE_CREATION_FUNCTION(Upsample, DmlOperatorResize);
// A specific type of operation for registration.
template <uint32_t OpsetVersion>
struct DmlOperatorResizeTemplate : public DmlOperatorResize
{
public:
DmlOperatorResizeTemplate(const MLOperatorKernelCreationContext& kernelInfo)
: DmlOperatorResize(kernelInfo, OpsetVersion)
{
}
};
void CALLBACK QueryResize(IMLOperatorSupportQueryContextPrivate* context, bool* isSupported)
{
*isSupported = false;
MLOperatorAttributes attributes(context);
// DML does not support cubic.
std::string mode = attributes.GetOptionalAttribute<std::string>(AttrName::Mode, "nearest");
if (mode == "cubic")
{
return;
}
// DML clamps the input coordinates to the edges and essentially repeats the last pixel.
// So rescaling the input kernel total denominator is not supported.
int32_t excludeOutside = attributes.GetOptionalAttribute<int32_t>(AttrName::ExcludeOutside, 0);
if (excludeOutside != 0)
{
return;
}
// DML does not support specifying a specific element value for reading outside the edges.
// Note the extrapolation value is only pertinent for "tf_crop_and_resize" mode.
float extrapolationValue = attributes.GetOptionalAttribute<float>(AttrName::ExtrapolationValue, 0.0);
if (extrapolationValue != 0.0)
{
return;
}
// DML's nearest neighbor mode uses half pixels rounded down.
std::string nearestMode = attributes.GetOptionalAttribute<std::string>(AttrName::NearestMode, "round_prefer_floor");
if (nearestMode != "round_prefer_floor")
{
return;
}
// Ignore parameter "cubic_coeff_a" since Cubic interpolation unsupported in DML.
// Ignore parameter "extrapolation_value" as DML clamps to the input rather than reading black pixels.
*isSupported = true;
}
DML_OP_DEFINE_CREATION_FUNCTION(Resize10, DmlOperatorResizeTemplate<10>);
DML_OP_DEFINE_CREATION_FUNCTION(Resize11, DmlOperatorResizeTemplate<11>);
DML_OP_DEFINE_CREATION_FUNCTION(Upsample7, DmlOperatorResizeTemplate<7>);
DML_OP_DEFINE_CREATION_FUNCTION(Upsample9, DmlOperatorResizeTemplate<9>);
DML_OP_DEFINE_CREATION_FUNCTION(Upsample10, DmlOperatorResizeTemplate<10>);
} // namespace Dml

View file

@ -6,16 +6,16 @@
namespace Dml
{
class DmlOperatorSlice : public DmlOperator, public SliceHelperBase
class DmlOperatorSlice : public DmlOperator, public SliceHelper
{
public:
DmlOperatorSlice(const MLOperatorKernelCreationContext& kernelInfo, uint32_t opsetVersion)
: DmlOperator(kernelInfo),
SliceHelperBase(kernelInfo, kernelInfo.GetTensorShapeDescription(), opsetVersion)
SliceHelper(kernelInfo, kernelInfo.GetTensorShapeDescription(), opsetVersion)
{
const uint32_t inputCount = kernelInfo.GetInputCount();
ML_CHECK_VALID_ARGUMENT((opsetVersion < 10 && inputCount == 1)
|| (opsetVersion >= 10 && opsetVersion <= 11 && inputCount >= 3 && inputCount <= 5));
|| (opsetVersion >= 10 && inputCount >= 3 && inputCount <= 5));
ML_CHECK_VALID_ARGUMENT(kernelInfo.GetOutputCount() == 1);
std::vector<std::optional<uint32_t>> kernelInputIndices = { 0 }; // Only bind GPU to first 'data' tensor.

View file

@ -11,11 +11,17 @@ class DmlOperatorTopK : public DmlOperator, public TopKHelper
public:
using Self = DmlOperatorTopK;
DmlOperatorTopK(const MLOperatorKernelCreationContext& kernelCreationContext)
DmlOperatorTopK(const MLOperatorKernelCreationContext& kernelCreationContext, uint32_t opsetVersion)
: DmlOperator(kernelCreationContext),
TopKHelper(kernelCreationContext, kernelCreationContext.GetTensorShapeDescription())
TopKHelper(kernelCreationContext, kernelCreationContext.GetTensorShapeDescription(), opsetVersion)
{
DmlOperator::Initialize(kernelCreationContext);
ML_CHECK_VALID_ARGUMENT(((opsetVersion >= 1 && opsetVersion < 10) && kernelCreationContext.GetInputCount() == 1)
|| ((opsetVersion >= 10) && kernelCreationContext.GetInputCount() == 2));
ML_CHECK_VALID_ARGUMENT(kernelCreationContext.GetOutputCount() == 2, "TopK expects 2 output tensors.");
std::vector<std::optional<uint32_t>> inputIndices = { 0 }; // Use only the first tensor. The second tensor is CPU-based.
std::vector<std::optional<uint32_t>> outputIndices = { 0, 1 };
DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices);
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
@ -23,19 +29,25 @@ public:
ML_CHECK_VALID_ARGUMENT(outputDescs.size() == 2);
uint32_t dmlAxis = GetDmlAdjustedAxis(m_axis, kernelCreationContext, m_inputTensorDescs.front().GetDimensionCount());
int32_t largest = kernelCreationContext.GetOptionalAttribute<int32_t>(AttrName::Largest, 1);
// Note the "sorted" attribute is not needed because the specification only dictates that
// when sorted is true that elements are returned in order, but when false, the order of
// returned 'Values' and 'Indices' are undefined. So returning them in order is a superset
// of returning them in arbitrary order.
DML_TOP_K_OPERATOR_DESC operatorDesc = {};
DML_TOP_K1_OPERATOR_DESC operatorDesc = {};
operatorDesc.InputTensor = inputDescs.data();
operatorDesc.OutputValueTensor = &outputDescs[0];
operatorDesc.OutputIndexTensor = &outputDescs[1];
operatorDesc.Axis = dmlAxis;
operatorDesc.K = m_k;
operatorDesc.AxisDirection = largest ? DML_AXIS_DIRECTION_DECREASING : DML_AXIS_DIRECTION_INCREASING;
// Index tensor is always of type int64. We need to create an extra DML operator to
// initialize the tensor data.
m_zeroOperator = InitializeZeroInt64Tensor(m_outputTensorDescs[1].GetBufferSizeInBytes());
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_TOP_K, &operatorDesc };
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_TOP_K1, &operatorDesc };
SetDmlOperatorDesc(opDesc, kernelCreationContext);
}
@ -58,6 +70,19 @@ private:
ComPtr<IDMLCompiledOperator> m_zeroOperator;
};
DML_OP_DEFINE_CREATION_FUNCTION(TopK, DmlOperatorTopK);
// A specific type of operation for registration.
template <uint32_t OpsetVersion>
class DmlOperatorTopKTemplate : public DmlOperatorTopK
{
public:
DmlOperatorTopKTemplate(const MLOperatorKernelCreationContext& kernelInfo)
: DmlOperatorTopK(kernelInfo, OpsetVersion)
{
}
};
DML_OP_DEFINE_CREATION_FUNCTION(TopK7, DmlOperatorTopKTemplate<7>);
DML_OP_DEFINE_CREATION_FUNCTION(TopK10, DmlOperatorTopKTemplate<10>);
DML_OP_DEFINE_CREATION_FUNCTION(TopK11, DmlOperatorTopKTemplate<11>);
} // namespace Dml

View file

@ -38,8 +38,9 @@ enum class SupportedTensorDataTypes : uint32_t
Int32to64 = UInt32|Int32|UInt64|Int64,
Float16to32 = Float16|Float32, // Float64 is not supported by DirectML.
NumericDefault = Int8to32|Float16to32,
Scalars8to32 = UInt8|Int8|UInt16|Int16|UInt32|Int32|Float16to32|Bool,
Scalars8to32 = UInt8|Int8|UInt16|Int16|UInt32|Int32|Float16to32|Bool,
AllScalars = UInt8|Int8|UInt16|Int16|UInt32|Int32|UInt64|Int64|Float16to32|Bool,
Ints8Bit = UInt8|Int8,
All = static_cast<uint32_t>(-1),
};
DEFINE_ENUM_FLAG_OPERATORS(Dml::SupportedTensorDataTypes);
@ -64,7 +65,7 @@ struct OperatorRegistrationInformation
gsl::span<const SupportedTensorDataTypes> supportedTensorDataTypes;
DmGraphSupport DmGraphSupport;
std::vector<uint32_t> requiresFloatFormatsExceptConstInputs;
std::vector<uint32_t> requiredConstantCpuInputs;
// For use by operators such as Sum, which may require multiple calls to DML, in which case they
// can't be represented as nodes in an optimized graph yet.
@ -102,7 +103,8 @@ DML_OP_EXTERN_CREATION_FUNCTION(Concat);
DML_OP_EXTERN_CREATION_FUNCTION(Slice7);
DML_OP_EXTERN_CREATION_FUNCTION(Slice10);
DML_OP_EXTERN_CREATION_FUNCTION(Slice11);
DML_OP_EXTERN_CREATION_FUNCTION(Pad);
DML_OP_EXTERN_CREATION_FUNCTION(Pad7);
DML_OP_EXTERN_CREATION_FUNCTION(Pad11);
DML_OP_EXTERN_CREATION_FUNCTION(SpaceToDepth);
DML_OP_EXTERN_CREATION_FUNCTION(DepthToSpace);
DML_OP_EXTERN_CREATION_FUNCTION(Sqrt);
@ -146,7 +148,9 @@ DML_OP_EXTERN_CREATION_FUNCTION(Gemm);
DML_OP_EXTERN_CREATION_FUNCTION(Neg);
DML_OP_EXTERN_CREATION_FUNCTION(Crop);
DML_OP_EXTERN_CREATION_FUNCTION(ImageScaler);
DML_OP_EXTERN_CREATION_FUNCTION(Upsample);
DML_OP_EXTERN_CREATION_FUNCTION(Upsample7);
DML_OP_EXTERN_CREATION_FUNCTION(Upsample9);
DML_OP_EXTERN_CREATION_FUNCTION(Upsample10);
DML_OP_EXTERN_CREATION_FUNCTION(Sigmoid);
DML_OP_EXTERN_CREATION_FUNCTION(HardSigmoid);
DML_OP_EXTERN_CREATION_FUNCTION(Tanh);
@ -169,7 +173,9 @@ DML_OP_EXTERN_CREATION_FUNCTION(MatMul);
DML_OP_EXTERN_CREATION_FUNCTION(Cast);
DML_OP_EXTERN_CREATION_FUNCTION(MemcpyFromHost);
DML_OP_EXTERN_CREATION_FUNCTION(MemcpyToHost);
DML_OP_EXTERN_CREATION_FUNCTION(TopK);
DML_OP_EXTERN_CREATION_FUNCTION(TopK7);
DML_OP_EXTERN_CREATION_FUNCTION(TopK10);
DML_OP_EXTERN_CREATION_FUNCTION(TopK11);
DML_OP_EXTERN_CREATION_FUNCTION(Expand);
DML_OP_EXTERN_CREATION_FUNCTION(Cos);
DML_OP_EXTERN_CREATION_FUNCTION(Sin);
@ -204,7 +210,8 @@ DML_OP_EXTERN_CREATION_FUNCTION(EyeLike);
DML_OP_EXTERN_CREATION_FUNCTION(MaxUnpool);
DML_OP_EXTERN_CREATION_FUNCTION(Scatter9);
DML_OP_EXTERN_CREATION_FUNCTION(Scatter11);
DML_OP_EXTERN_CREATION_FUNCTION(Resize);
DML_OP_EXTERN_CREATION_FUNCTION(Resize10);
DML_OP_EXTERN_CREATION_FUNCTION(Resize11);
DML_OP_EXTERN_CREATION_FUNCTION(ConstantOfShape);
DML_OP_EXTERN_CREATION_FUNCTION(IsInf);
DML_OP_EXTERN_CREATION_FUNCTION(Mod);
@ -225,31 +232,35 @@ DML_OP_EXTERN_CREATION_FUNCTION(ConvInteger);
DML_OP_EXTERN_QUERY_FUNCTION(MaxPool);
DML_OP_EXTERN_QUERY_FUNCTION(Slice);
DML_OP_EXTERN_QUERY_FUNCTION(Resize);
const static char* const typeNameListDefault[1] = {"T"};
const static char* const typeNameListTwo[2] = { "T1", "T2" };
const static char* const typeNameListThree[3] = { "T1", "T2", "T3" };
const static char* const typeNameListFour[4] = { "T1", "T2", "T3", "T4" };
const static char* const typeNameListTopK[2] = { "T", "I" };
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[1] = { "T" }; // Tind is curiously missing, only allowing 64-bit.
const static char* const typeNameListSlice10[2] = { "T", "Tind" };
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" };
const static char* const typeNameListEyeLike[1] = { "T2" };
const static SupportedTensorDataTypes supportedTypeListAll[1] = {SupportedTensorDataTypes::All};
const static SupportedTensorDataTypes supportedTypeListFloat32[1] = {SupportedTensorDataTypes::Float32};
const static SupportedTensorDataTypes supportedTypeListFloat16to32[1] = {SupportedTensorDataTypes::Float16to32};
const static SupportedTensorDataTypes supportedTypeListFloat16to32Int32[1] = {SupportedTensorDataTypes::Float16to32 | SupportedTensorDataTypes::Int32 | SupportedTensorDataTypes::UInt32};
const static SupportedTensorDataTypes supportedTypeListInt8to32[1] = {SupportedTensorDataTypes::Int8to32};
const static SupportedTensorDataTypes supportedTypeListInt32to64AndFloat16to32[1] = {SupportedTensorDataTypes::Int32to64|SupportedTensorDataTypes::Float16to32};
const static SupportedTensorDataTypes supportedTypeListNumericDefault[1] = { SupportedTensorDataTypes::NumericDefault };
const static SupportedTensorDataTypes supportedTypeListAllScalars[1] = { SupportedTensorDataTypes::AllScalars };
const static SupportedTensorDataTypes supportedTypeListBool[1] = {SupportedTensorDataTypes::Bool};
const static SupportedTensorDataTypes supportedTypeListTopK[2] = {SupportedTensorDataTypes::Float16to32, SupportedTensorDataTypes::Int64};
const static SupportedTensorDataTypes supportedTypeListTopK[2] = {SupportedTensorDataTypes::NumericDefault, SupportedTensorDataTypes::Int64};
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[1] = { SupportedTensorDataTypes::NumericDefault };
const static SupportedTensorDataTypes supportedTypeListScalars8to32[1] = { SupportedTensorDataTypes::Scalars8to32 };
const static SupportedTensorDataTypes supportedTypeListScatterGather[2] = { SupportedTensorDataTypes::Scalars8to32, SupportedTensorDataTypes::Int32 | SupportedTensorDataTypes::Int64 };
const static SupportedTensorDataTypes supportedTypeListScatterGatherND[1] = { SupportedTensorDataTypes::Scalars8to32 };
const static SupportedTensorDataTypes supportedTypeListSlice10[2] = { SupportedTensorDataTypes::NumericDefault, SupportedTensorDataTypes::Int32 | SupportedTensorDataTypes::Int64 };
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 };
@ -257,12 +268,25 @@ const static SupportedTensorDataTypes supportedTypeListQuantize[2] = { Supported
const static SupportedTensorDataTypes supportedTypeListIsNan[2] = { SupportedTensorDataTypes::Float16to32, SupportedTensorDataTypes::Bool };
const static SupportedTensorDataTypes supportedTypeListIsInf[2] = { SupportedTensorDataTypes::Float32, SupportedTensorDataTypes::Bool };
const static SupportedTensorDataTypes supportedTypeListConstantOfShape[2] = { SupportedTensorDataTypes::Int32|SupportedTensorDataTypes::Int64, SupportedTensorDataTypes::Float16to32 };
const static SupportedTensorDataTypes supportedTypeListWhere[2] = { SupportedTensorDataTypes::Bool, SupportedTensorDataTypes::Float16to32 };
const static SupportedTensorDataTypes supportedTypeListOneHot[3] = /* indices, depth, values */ { SupportedTensorDataTypes::Int32to64, SupportedTensorDataTypes::AllScalars, SupportedTensorDataTypes::Float16to32 };
const static SupportedTensorDataTypes supportedTypeListWhere[2] = { SupportedTensorDataTypes::Bool, SupportedTensorDataTypes::AllScalars };
const static SupportedTensorDataTypes supportedTypeListOneHot[3] = /* indices, depth, values */ { SupportedTensorDataTypes::Int32to64, SupportedTensorDataTypes::AllScalars, SupportedTensorDataTypes::Scalars8to32 };
const static SupportedTensorDataTypes supportedTypeListLogicalComparison7[2] = /* A&B,C */ { SupportedTensorDataTypes::Float16to32, SupportedTensorDataTypes::Bool };
const static SupportedTensorDataTypes supportedTypeListLogicalComparison9[2] = /* A&B,C */ { SupportedTensorDataTypes::NumericDefault, SupportedTensorDataTypes::Bool };
const static SupportedTensorDataTypes supportedTypeListSigned[1] = { SupportedTensorDataTypes::Float16to32 | SupportedTensorDataTypes::Int32 | SupportedTensorDataTypes::Int16 | SupportedTensorDataTypes::Int8 };
const static SupportedTensorDataTypes supportedTypeListRange[1] = {SupportedTensorDataTypes::Int16|SupportedTensorDataTypes::Int32|SupportedTensorDataTypes::Float32};
const static SupportedTensorDataTypes supportedTypeListInteger[3] = {SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8, SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8, SupportedTensorDataTypes::Int32 };
const static SupportedTensorDataTypes supportedTypeListPadWithoutFloat16[1] = { SupportedTensorDataTypes::Int8to32 | SupportedTensorDataTypes::Float32 };
const static SupportedTensorDataTypes supportedTypeListQLinearMatMul[3] = {
SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8,
SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8,
SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8
};
const static SupportedTensorDataTypes supportedTypeListQLinearConv[4] = {
SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8,
SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8,
SupportedTensorDataTypes::Int8|SupportedTensorDataTypes::UInt8,
SupportedTensorDataTypes::Int32
};
// Define a single row of registration information.
#define REG_INFO(version, operatorName, ...) \
@ -295,24 +319,21 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
// Deep Learning Standard Layers
{REG_INFO( 7, Conv, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, Conv, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, ConvTranspose, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, ConvTranspose, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, AveragePool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
#if 0
// TODO:DwayneR add ceil mode https://microsoft.visualstudio.com/OS/_workitems/edit/24674310
{REG_INFO( 10, AveragePool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, AveragePool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
#endif
{REG_INFO( 7, GlobalAveragePool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, MaxPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 8, MaxPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {}, std::nullopt, QueryMaxPool)},
{REG_INFO( 10, MaxPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {}, std::nullopt, QueryMaxPool)},
#if 0
// TODO:DwayneR add ceil mode https://microsoft.visualstudio.com/OS/_workitems/edit/24674310
{REG_INFO( 11, MaxPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {}, std::nullopt, QueryMaxPool)},
#endif
{REG_INFO( 7, GlobalMaxPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, LpPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, LpPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, GlobalLpPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, MaxRoiPool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, InstanceNormalization, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
@ -320,6 +341,7 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 9, BatchNormalization, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)}, // v9 just removes 'spatial' attribute.
{REG_INFO( 7, LRN, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, MeanVarianceNormalization, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, MeanVarianceNormalization, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, LpNormalization, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, RNN, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::NotSupported)},
{REG_INFO( 7, GRU, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::NotSupported)},
@ -335,17 +357,12 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO_VER( 7, Slice, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO_VER( 10, Slice, typeNameListSlice10, supportedTypeListSlice10, DmGraphSupport::Supported, {1, 2, 3, 4}, std::nullopt, QuerySlice)}, // Adds negative axes.
{REG_INFO_VER( 11, Slice, typeNameListSlice10, supportedTypeListSlice10, DmGraphSupport::Supported, {1, 2, 3, 4}, std::nullopt, QuerySlice)},
{REG_INFO( 7, Pad, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
#if 0 // TODO:NickFe Pads and Value are inputs. https://microsoft.visualstudio.com/OS/_workitems/edit/24674281, https://github.com/onnx/onnx/blob/master/docs/Changelog.md#Pad-11
{REG_INFO( 11, Pad, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
#endif
{REG_INFO( 7, SpaceToDepth, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, DepthToSpace, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
#if 0
// TODO:DwayneR Update operator DepthToSpace-11 - added column-row-depth shuffle order mode https://microsoft.visualstudio.com/OS/_workitems/edit/24672169
{REG_INFO( 11, DepthToSpace, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
#endif
{REG_INFO( 7, Tile, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported, {1})},
{REG_INFO_VER( 7, Pad, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO_VER( 11, Pad, typeNameListDefault, supportedTypeListPadWithoutFloat16, DmGraphSupport::Supported, {1, 2} /*pads, value*/)}, // https://microsoft.visualstudio.com/OS/_workitems/edit/26007728
{REG_INFO( 7, SpaceToDepth, typeNameListDefault, supportedTypeListScalars8to32, DmGraphSupport::Supported)},
{REG_INFO( 7, DepthToSpace, typeNameListDefault, supportedTypeListScalars8to32, DmGraphSupport::Supported)},
{REG_INFO( 11, DepthToSpace, typeNameListDefault, supportedTypeListScalars8to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Tile, typeNameListDefault, supportedTypeListScalars8to32, DmGraphSupport::Supported, {1})},
{REG_INFO( 8, Expand, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})},
{REG_INFO( 9, ConstantOfShape, typeNameListConstantOfShape, supportedTypeListConstantOfShape, DmGraphSupport::NotSupported, {0})},
{REG_INFO( 7, Gather, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
@ -356,7 +373,7 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO_VER( 11, Scatter, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
{REG_INFO( 11, ScatterElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
{REG_INFO( 11, ScatterND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)},
{REG_INFO( 9, EyeLike, typeNameListEyeLike, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, EyeLike, typeNameListEyeLike, supportedTypeListScalars8to32, DmGraphSupport::Supported)},
// Data reorganization that merely changes the dimensions while keeping the data identical.
{REG_INFO_ID( 7, Identity, typeNameListDefault, supportedTypeListAllScalars, DmGraphSupport::Supported)},
@ -380,10 +397,10 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 7, Floor, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO_VER( 7, Clip, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO_VER( 11, Clip, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1,2})},
{REG_INFO( 7, Add, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Sub, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Mul, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Div, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Add, typeNameListDefault, supportedTypeListFloat16to32Int32, DmGraphSupport::Supported)},
{REG_INFO( 7, Sub, typeNameListDefault, supportedTypeListFloat16to32Int32, DmGraphSupport::Supported)},
{REG_INFO( 7, Mul, typeNameListDefault, supportedTypeListFloat16to32Int32, DmGraphSupport::Supported)},
{REG_INFO( 7, Div, typeNameListDefault, supportedTypeListFloat16to32Int32, DmGraphSupport::Supported)},
{REG_INFO( 7, Sum, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {}, 2)},
{REG_INFO( 8, Sum, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {}, 2)},
{REG_INFO( 7, Mean, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {}, 2)},
@ -399,12 +416,12 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 7, Asin, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Atan, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Affine, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 10, QuantizeLinear, typeNameListQuantize, supportedTypeListQuantizeLinear, DmGraphSupport::Supported)},
{REG_INFO( 10, DequantizeLinear, typeNameListQuantize, supportedTypeListDequantizeLinear, DmGraphSupport::Supported)},
{REG_INFO_MS( 1, QuantizeLinear, typeNameListQuantize, supportedTypeListQuantize, DmGraphSupport::Supported)},
{REG_INFO_MS( 1, DequantizeLinear, typeNameListQuantize, supportedTypeListQuantize, DmGraphSupport::Supported)},
{REG_INFO( 10, QuantizeLinear, typeNameListTwo, supportedTypeListQuantizeLinear, DmGraphSupport::Supported)},
{REG_INFO( 10, DequantizeLinear, typeNameListTwo, supportedTypeListDequantizeLinear, DmGraphSupport::Supported)},
{REG_INFO_MS( 1, QuantizeLinear, typeNameListTwo, supportedTypeListQuantize, DmGraphSupport::Supported)},
{REG_INFO_MS( 1, DequantizeLinear, typeNameListTwo, supportedTypeListQuantize, DmGraphSupport::Supported)},
{REG_INFO( 9, Sign, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO( 9, IsNan, typeNameListT1T2, supportedTypeListIsNan, DmGraphSupport::Supported)},
{REG_INFO( 9, IsNan, typeNameListTwo, supportedTypeListIsNan, DmGraphSupport::Supported)},
{REG_INFO( 9, Sinh, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, Cosh, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, Asinh, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
@ -432,10 +449,10 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 11, ReduceMax, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, ReduceMin, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, ReduceMin, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, ArgMax, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, ArgMax, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, ArgMin, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, ArgMin, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, ArgMax, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO( 11, ArgMax, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO( 7, ArgMin, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO( 11, ArgMin, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO( 7, Gemm, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 11, Gemm, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, Gemm, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
@ -451,14 +468,16 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 7, Or, typeNameListDefault, supportedTypeListBool, DmGraphSupport::Supported)},
{REG_INFO( 7, Xor, typeNameListDefault, supportedTypeListBool, DmGraphSupport::Supported)},
// Imaging Operators
// Imaging Operators
{REG_INFO( 7, Crop, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, ImageScaler, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Upsample, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, Upsample, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})},
{REG_INFO( 10, Resize, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})},
// Activation Functions
{REG_INFO_VER( 7, Upsample, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO_VER( 9, Upsample, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1} /*scales*/)},
{REG_INFO_VER( 10, Upsample, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1} /*scales*/)},
{REG_INFO_VER( 10, Resize, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1} /*scales*/)},
{REG_INFO_VER( 11, Resize, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1, 2, 3} /*roi, scales, sizes*/, std::nullopt, QueryResize)},
// Activation Functions
{REG_INFO( 7, Sigmoid, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, HardSigmoid, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Tanh, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
@ -482,25 +501,21 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 7, ParametricSoftplus, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Dropout, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, Shrink, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
// Uncategorized
// Uncategorized
{REG_INFO( 7, MatMul, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 9, MatMul, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 7, Cast, typeNameListT1T2, supportedTypeListCast, DmGraphSupport::Supported)},
{REG_INFO( 9, Cast, typeNameListT1T2, supportedTypeListCast, DmGraphSupport::Supported)},
{REG_INFO( 7, Cast, typeNameListTwo, supportedTypeListCast, DmGraphSupport::Supported)},
{REG_INFO( 9, Cast, typeNameListTwo, supportedTypeListCast, DmGraphSupport::Supported)},
{REG_INFO( 7, MemcpyFromHost, typeNameListDefault, supportedTypeListAll)},
{REG_INFO( 7, MemcpyToHost, typeNameListDefault, supportedTypeListAll)},
{REG_INFO( 7, TopK, typeNameListTopK, supportedTypeListTopK, DmGraphSupport::Supported)},
#if 0
// TODO:Dwayner https://microsoft.visualstudio.com/OS/_workitems/edit/24674287
{REG_INFO( 10, TopK, typeNameListTopK, supportedTypeListTopK, DmGraphSupport::Supported)},
// TODO:Dwayner https://microsoft.visualstudio.com/OS/_workitems/edit/24671996
{REG_INFO( 11, TopK, typeNameListTopK, supportedTypeListTopK, DmGraphSupport::Supported)},
#endif
{REG_INFO( 9, OneHot, typeNameListOneHot, supportedTypeListOneHot, DmGraphSupport::Supported, {1})},
{REG_INFO( 11, OneHot, typeNameListOneHot, supportedTypeListOneHot, DmGraphSupport::Supported, {1})},
// Fused operators
{REG_INFO_VER( 7, TopK, typeNameListTopK, supportedTypeListTopK, DmGraphSupport::Supported)},
{REG_INFO_VER( 10, TopK, typeNameListTopK, supportedTypeListTopK, DmGraphSupport::Supported, {1})},
{REG_INFO_VER( 11, TopK, typeNameListTopK, supportedTypeListTopK, DmGraphSupport::Supported, {1})},
{REG_INFO( 9, OneHot, typeNameListThree, supportedTypeListOneHot, DmGraphSupport::Supported, {1})},
{REG_INFO( 11, OneHot, typeNameListThree, supportedTypeListOneHot, DmGraphSupport::Supported, {1})},
// Fused operators
{REG_INFO_MSDML(1, FusedConv, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO_MSDML(1, FusedConvTranspose, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO_MSDML(1, FusedInstanceNormalization, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
@ -511,7 +526,7 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO_MSDML(1, FusedAdd, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO_MSDML(1, FusedSum, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {}, 2)},
{REG_INFO( 10, IsInf, typeNameListT1T2, supportedTypeListIsInf, DmGraphSupport::Supported)},
{REG_INFO( 10, IsInf, typeNameListTwo, supportedTypeListIsInf, DmGraphSupport::Supported)},
{REG_INFO( 10, Mod, typeNameListDefault, supportedTypeListNumericDefault, DmGraphSupport::Supported)},
{REG_INFO( 11, BitShift, typeNameListDefault, supportedTypeListInt8to32, DmGraphSupport::Supported)},
{REG_INFO( 11, Round, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
@ -521,32 +536,12 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 9, MaxUnpool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {2})},
{REG_INFO( 11, MaxUnpool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {2})}, // 11 is identical to 9.
#if 0 // TODO:DwayneR
{REG_INFO( 11, Resize, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})},
#endif
#if 0 // TODO:NickFe
{REG_INFO( 11, QLinearConv, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
// T1 : tensor(int8), tensor(uint8) - Constrain input type to 8-bit integer tensor.
// T2 : tensor(int8), tensor(uint8) - Constrain filter type to 8-bit integer tensor.
// T3 : tensor(int8), tensor(uint8) - Constrain output type to 8-bit integer tensor.
// T4 : tensor(int32) - Constrain bias type to 32-bit integer tensor.
{REG_INFO( 11, QLinearMatMul, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
// T1 : tensor(int8), tensor(uint8) - Constrain input a and its zero point data type to 8-bit integer tensor.
// T2 : tensor(int8), tensor(uint8) - Constrain input b and its zero point data type to 8-bit integer tensor.
// T3 : tensor(int8), tensor(uint8) - Constrain output y and its zero point data type to 8-bit integer tensor.
{REG_INFO( 11, DynamicQuantizeLinear, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
//T1 : tensor(float) - Constrain 'x' to float tensor.
//T2 : tensor(uint8)
{REG_INFO( 11, MatMulInteger, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
//T1 : tensor(int8), tensor(uint8) - Constrain input A data type to 8-bit integer tensor.
//T2 : tensor(int8), tensor(uint8) - Constrain input B data type to 8-bit integer tensor.
//T3 : tensor(int32) - Constrain output Y data type as 32-bit integer tensor.
{REG_INFO( 11, ConvInteger, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
// T1 : tensor(int8), tensor(uint8) - Constrain input x and its zero point data type to 8-bit integer tensor.
// T2 : tensor(int8), tensor(uint8) - Constrain input w and its zero point data type to 8-bit integer tensor.
// T3 : tensor(int32) - Constrain output y data type to 32-bit integer tensor.
#endif
{REG_INFO( 10, QLinearConv, typeNameListFour, supportedTypeListQLinearConv, DmGraphSupport::NotSupported)},
{REG_INFO( 10, QLinearMatMul, typeNameListThree, supportedTypeListQLinearMatMul, DmGraphSupport::NotSupported)},
{REG_INFO( 10, MatMulInteger, typeNameListThree, supportedTypeListInteger, DmGraphSupport::NotSupported)},
{REG_INFO( 10, ConvInteger, typeNameListThree, supportedTypeListInteger, DmGraphSupport::NotSupported)},
};
template<typename T>
@ -649,8 +644,8 @@ void RegisterDmlOperators(IMLOperatorRegistry* registry)
kernelSupportsGraph, // supportsGraph
information.requiredInputCountForDmlGraphSupport ? &(*information.requiredInputCountForDmlGraphSupport) : nullptr,
information.requiresFloatFormatsForGraph,
information.requiresFloatFormatsExceptConstInputs.empty() ? nullptr : information.requiresFloatFormatsExceptConstInputs.data(),
static_cast<uint32_t>(information.requiresFloatFormatsExceptConstInputs.size())
information.requiredConstantCpuInputs.empty() ? nullptr : information.requiredConstantCpuInputs.data(),
static_cast<uint32_t>(information.requiredConstantCpuInputs.size())
));
}
}

View file

@ -348,6 +348,16 @@ namespace Dml
return dmlAxis;
}
void GetDmlAdjustedAxes(gsl::span<const int32_t> onnxAxes, uint32_t onnxDimCount, uint32_t dmlDimCount, std::vector<uint32_t>& dmlAxes)
{
dmlAxes.clear();
dmlAxes.reserve(onnxAxes.size());
for (auto& axis : onnxAxes)
{
dmlAxes.push_back(GetDmlAdjustedAxis(axis, onnxDimCount, dmlDimCount));
}
}
DML_INTERPOLATION_MODE MapStringToInteropolationMode(std::string_view mode)
{
// The ONNX modes are "nearest" and "linear." Other modes exist for compatibility,
@ -365,4 +375,20 @@ namespace Dml
}
}
DML_DEPTH_SPACE_ORDER MapStringToDepthSpaceMode(std::string_view mode)
{
if (mode == "DCR")
{
return DML_DEPTH_SPACE_ORDER_DEPTH_COLUMN_ROW;
}
else if (mode == "CRD")
{
return DML_DEPTH_SPACE_ORDER_COLUMN_ROW_DEPTH;
}
else
{
ML_INVALID_ARGUMENT("Unknown depth space mode.");
}
}
} // namespace Dml

View file

@ -55,6 +55,10 @@ namespace Dml
uint32_t GetDmlAdjustedAxis(int32_t onnxAxis, uint32_t onnxDimCount, uint32_t dmlDimCount);
void GetDmlAdjustedAxes(/*inout*/ gsl::span<const int32_t> axes, uint32_t onnxDimCount, uint32_t dmlDimCount, std::vector<uint32_t>& dmlAxes);
DML_INTERPOLATION_MODE MapStringToInteropolationMode(std::string_view mode);
DML_DEPTH_SPACE_ORDER MapStringToDepthSpaceMode(std::string_view mode);
} // namespace Dml

View file

@ -22,7 +22,9 @@ namespace AttrName
static constexpr const char* Broadcast = "broadcast";
static constexpr const char* CeilMode = "ceil_mode";
static constexpr const char* Clip = "clip";
static constexpr const char* CoordinateTransformationMode = "coordinate_transformation_mode";
static constexpr const char* CountIncludePad = "count_include_pad";
static constexpr const char* CubicCoefficientA = "cubic_coeff_a";
static constexpr const char* DetectPositive = "detect_positive";
static constexpr const char* DetectNegative = "detect_negative";
static constexpr const char* Dilations = "dilations";
@ -30,11 +32,13 @@ namespace AttrName
static constexpr const char* Dtype = "dtype";
static constexpr const char* Ends = "ends";
static constexpr const char* Epsilon = "epsilon";
static constexpr const char* ExcludeOutside = "exclude_outside";
static constexpr const char* Exclusive = "exclusive";
static constexpr const char* Exponent = "exponent";
static constexpr const char* ExtrapolationValue = "extrapolation_value";
static constexpr const char* Fmod = "fmod";
static constexpr const char* Gamma = "gamma";
static constexpr const char* Group = "group";
static constexpr const char* Exclusive = "exclusive";
static constexpr const char* HeightScale = "height_scale";
static constexpr const char* HiddenSize = "hidden_size";
static constexpr const char* High = "high";
@ -44,11 +48,13 @@ namespace AttrName
static constexpr const char* KernelShape = "kernel_shape";
static constexpr const char* LinearBeforeReset = "linear_before_reset";
static constexpr const char* Lambda = "lambd"; // Deliberate typo to match ONNX spec.
static constexpr const char* Largest = "largest";
static constexpr const char* Low = "low";
static constexpr const char* Max = "max";
static constexpr const char* Mean = "mean";
static constexpr const char* Min = "min";
static constexpr const char* Mode = "mode";
static constexpr const char* NearestMode = "nearest_mode";
static constexpr const char* NormalizeVariance = "normalize_variance";
static constexpr const char* P = "p";
static constexpr const char* OutputShape = "output_shape";
@ -62,6 +68,7 @@ namespace AttrName
static constexpr const char* Seed = "seed";
static constexpr const char* Shape = "shape";
static constexpr const char* Size = "size";
static constexpr const char* Sorted = "sorted";
static constexpr const char* Spatial = "spatial";
static constexpr const char* SpatialScale = "spatial_scale";
static constexpr const char* Split = "split";

View file

@ -76,6 +76,32 @@ namespace OperatorHelper
}
}
void ReadCpuLocalTensorIntoFloat32(
const MLOperatorTensor& tensor,
std::vector<float>& result
)
{
result.clear();
ML_CHECK_VALID_ARGUMENT(tensor.IsCpuData(), "Tensor must be CPU Tensor.");
const std::vector<uint32_t>& tensorDimensions = tensor.GetShape();
const uint32_t elementCount = ComputeElementCountFromDimensions(tensorDimensions);
switch (tensor.GetTensorDataType())
{
case MLOperatorTensorDataType::Float:
{
const float* data = tensor.GetData<float>();
result.assign(data, data + elementCount);
}
break;
default:
ML_INVALID_ARGUMENT("Expecting CPU local tensor of type float32.");
break;
}
}
void DowncastDimensions(gsl::span<const int64_t> inputDimensions, std::vector<DimensionType>& outputDimensions)
{
outputDimensions.reserve(inputDimensions.size());
@ -197,8 +223,12 @@ namespace OperatorHelper
ML_CHECK_VALID_ARGUMENT(kernelLength <= paddedLength, "kernelLength must be < paddedLength.");
ML_CHECK_VALID_ARGUMENT(args.strides[dim] != 0, "strides must be non-zero.");
uint32_t stride = args.strides[dim];
uint32_t strideableOutputLength = paddedLength - kernelLength;
uint32_t outputLength = 1 + (strideableOutputLength / stride)
+ (args.useCeilingOutputShape && (strideableOutputLength % stride != 0));
outputDimensions[dimOffset + dim] = (1 + (paddedLength - kernelLength) / args.strides[dim]);
outputDimensions[dimOffset + dim] = outputLength;
}
return outputDimensions;
@ -355,6 +385,8 @@ namespace OperatorHelper
std::fill(args.outputPadding, args.outputPadding + spatialDimensionCount, 0);
}
args.useCeilingOutputShape = kernelInfo.GetOptionalAttribute<bool>(AttrName::CeilMode, 0);
return args;
}
@ -407,6 +439,33 @@ namespace OperatorHelper
args.endPadding[dim] = padding - args.startPadding[dim];
}
}
void MatMulShapeMapping(
std::vector<DimensionType>& inputShape0,
std::vector<DimensionType>& inputShape1,
std::vector<DimensionType>& outputShape)
{
// Get the padded input shapes and undo the effect of padding removal from the output shape
if (inputShape1.size() == 1)
{
inputShape1.push_back(1);
outputShape.push_back(1);
}
if (inputShape0.size() == 1)
{
inputShape0.insert(inputShape0.begin(), 1);
outputShape.insert(outputShape.end() - 1, 1);
}
// Remove the batch dimensions from each input, then re-add the broadcasted batch dimensions
// based on the output shape
inputShape0.erase(inputShape0.begin(), inputShape0.end() - 2);
inputShape1.erase(inputShape1.begin(), inputShape1.end() - 2);
inputShape0.insert(inputShape0.begin(), outputShape.begin(), outputShape.end() - 2);
inputShape1.insert(inputShape1.begin(), outputShape.begin(), outputShape.end() - 2);
}
std::vector<EdgeShapes> GetOutputShapeAsInputShapeHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
{
@ -550,15 +609,13 @@ namespace OperatorHelper
return edgeShapes;
}
std::vector<EdgeShapes> SliceHelperBase::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
std::vector<EdgeShapes> SliceHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
{
return { m_outputDimensions };
}
void PaddingHelper::Initialize(const MLOperatorAttributes& operatorAttributes)
void PaddingHelper::Initialize(const MLOperatorAttributes& operatorAttributes, gsl::span<int32_t> padding, uint32_t opsetVersion)
{
// Convert padding.
std::vector<int> padding = operatorAttributes.GetOptionalAttributeVectorInt32(AttrName::Pads);
ML_CHECK_VALID_ARGUMENT(padding.size() % 2 == 0, "Padding must be even count, including begin/end pairs.");
uint32_t dimCount = gsl::narrow_cast<uint32_t>(padding.size() / 2);
@ -770,7 +827,7 @@ namespace OperatorHelper
}
}
std::vector<EdgeShapes> MatMulHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
std::vector<EdgeShapes> MatMulHelperBase::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
{
ML_CHECK_VALID_ARGUMENT(shapeInfo.GetInputCount() >= 2);
@ -782,8 +839,8 @@ namespace OperatorHelper
// * If the first argument is 1 - D, it is promoted to a matrix by prepending a 1 to its dimensions. After matrix multiplication the prepended 1 is removed.
// * If the second argument is 1 - D, it is promoted to a matrix by appending a 1 to its dimensions. After matrix multiplication the appended 1 is removed.
auto inputShape0 = shapeInfo.GetInputTensorShape(0);
auto inputShape1 = shapeInfo.GetInputTensorShape(1);
auto inputShape0 = shapeInfo.GetInputTensorShape(m_aTensorIndex);
auto inputShape1 = shapeInfo.GetInputTensorShape(m_bTensorIndex);
ML_CHECK_VALID_ARGUMENT(inputShape0.size() >= 1);
ML_CHECK_VALID_ARGUMENT(inputShape1.size() >= 1);
@ -1286,48 +1343,40 @@ namespace OperatorHelper
}
void ResizeHelper::Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<const DimensionType> inputDimensions
)
{
m_inputDimensions.assign(inputDimensions.begin(), inputDimensions.end());
m_scales = operatorAttributes.GetOptionalAttribute<std::vector<float>>(AttrName::Scales, std::vector<float>());
ML_CHECK_VALID_ARGUMENT(inputDimensions.size() == m_scales.size(), "Input dimensions and scales must have same rank.");
InitializeOutputDimensions(m_scales, inputDimensions);
}
void ResizeHelper::Initialize(
const MLOperatorTensor& scalesTensor,
gsl::span<const DimensionType> inputDimensions
)
{
m_inputDimensions.assign(inputDimensions.begin(), inputDimensions.end());
// Read the input shape and scale factors.
const std::vector<uint32_t> scalesTensorDimensions = scalesTensor.GetShape();
ML_CHECK_VALID_ARGUMENT(scalesTensorDimensions.size() == 1, "Resize's scales tensor must be 1D.");
size_t dimCount = scalesTensorDimensions[0];
ML_CHECK_VALID_ARGUMENT(inputDimensions.size() == dimCount, "Input dimensions and scales must have same rank.");
ML_CHECK_VALID_ARGUMENT(scalesTensor.IsCpuData(), "Resize's scales tensor must be CPU Tensor.");
const float* scalesData = scalesTensor.GetData<float>();
m_scales.assign(scalesData, scalesData + dimCount);
InitializeOutputDimensions(m_scales, inputDimensions);
}
void ResizeHelper::InitializeOutputDimensions(
gsl::span<const float> scales,
gsl::span<const DimensionType> inputDimensions
gsl::span<const int32_t> outputSizes
)
{
assert(m_outputDimensions.empty());
ML_CHECK_VALID_ARGUMENT(m_scales.empty() || outputSizes.empty(), "scales and roi cannot both be present.");
for (size_t i = 0, rank = scales.size(); i < rank; ++i)
const size_t rank = m_inputDimensions.size();
if (outputSizes.empty())
{
float scale = m_scales[i];
ML_CHECK_VALID_ARGUMENT(scale > FLT_EPSILON, "Scale values should be positive.");
m_outputDimensions.push_back(gsl::narrow_cast<uint32_t>(floor(inputDimensions[i] * scale)));
// Compute output size from scales and normalized region of interest (each axis 0 to 1).
ML_CHECK_VALID_ARGUMENT(m_scales.size() == rank, "The 'scales' parameter must have same rank as input dimensions.");
ML_CHECK_VALID_ARGUMENT(m_regionOfInterest.empty() || m_regionOfInterest.size() == rank * 2, "The 'roi' parameter must have two values for each input dimension.");
for (size_t i = 0; i < rank; ++i)
{
float scale = m_scales[i];
ML_CHECK_VALID_ARGUMENT(scale > FLT_EPSILON, "Scale values should be positive.");
float roiRange = m_regionOfInterest.empty() ? 1.0f : m_regionOfInterest[i + rank] - m_regionOfInterest[i];
m_outputDimensions.push_back(gsl::narrow_cast<uint32_t>(floor(m_inputDimensions[i] * roiRange * scale)));
}
}
else
{
// Determine scales from output / input ratio.
ML_CHECK_VALID_ARGUMENT(outputSizes.size() == rank, "Input dimensions and 'sizes' must have same rank.");
m_scales.resize(rank);
for (size_t i = 0; i < rank; ++i)
{
float scale = float(outputSizes[i]) / std::max(m_inputDimensions[i], 1u);
m_scales[i] = scale;
m_outputDimensions.push_back(gsl::narrow_cast<uint32_t>(outputSizes[i]));
}
}
}

View file

@ -100,6 +100,7 @@ int64_t ReadScalarTensorCastToInt64(const MLOperatorTensor& tensor);
double ReadScalarTensorCastToFloat64(const MLOperatorTensor& tensor);
void ReadCpuLocalTensorIntoInt32(const MLOperatorTensor& tensor, std::vector<int32_t>& result);
void ReadCpuLocalTensorIntoFloat32(const MLOperatorTensor& tensor, std::vector<float>& result);
class EdgeShapes {
public:
@ -128,9 +129,17 @@ struct KernelArgs {
uint32_t endPadding[NcdhwSpatialDimensionCount];
uint32_t outputPadding[NcdhwSpatialDimensionCount];
KernelArgs(uint32_t spatialDimensionCount) : autoPad(false),
autoPadSameUpper(false),
spatialDimensionCount(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 = false;
bool autoPadSameUpper = false;
bool useCeilingOutputShape = false;
uint32_t spatialDimensionCount = 0;
KernelArgs(uint32_t spatialDimensionCount) : spatialDimensionCount(spatialDimensionCount)
{
ML_CHECK_VALID_ARGUMENT(spatialDimensionCount <= NcdhwSpatialDimensionCount);
}
@ -165,14 +174,6 @@ struct KernelArgs {
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;
};
std::vector<DimensionType> InitializeKernelOutputDimensions(
@ -194,6 +195,11 @@ void ResolveAutoPadding(
KernelArgs& args,
gsl::span<const DimensionType> inputDimensions);
void MatMulShapeMapping(
std::vector<DimensionType>& inputShape0,
std::vector<DimensionType>& inputShape1,
std::vector<DimensionType>& outputShape);
class GetOutputShapeAsInputShapeHelper {
public:
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
@ -320,14 +326,15 @@ class ConvolutionHelperBase
{
public:
enum FilterDims { K };
enum InputTensor { X, Filter};
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<typename Info_t, typename Shape_t>
ConvolutionHelperBase(const Info_t& info, const Shape_t& shape, bool transpose, bool hasDynamicPads) :
m_kernel(InitializeKernel(info, shape.GetInputTensorDimensionCount(0), shape.GetInputTensorShape(1)))
ConvolutionHelperBase(const Info_t& info, const Shape_t& shape, bool transpose, bool hasDynamicPads, uint32_t inputTensorIndex, uint32_t filterTensorIndex) :
m_kernel(InitializeKernel(info, shape.GetInputTensorDimensionCount(inputTensorIndex), shape.GetInputTensorShape(filterTensorIndex))),
m_inputTensorIndex(inputTensorIndex),
m_filterTensorIndex(filterTensorIndex)
{
m_groupCount = info.GetOptionalAttribute<uint32_t>(AttrName::Group, 1);
@ -350,8 +357,8 @@ public:
template <typename Shape_t>
void InitializeKernelAndShapes(const Shape_t& shapeInfo) {
const std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(0);
const std::vector<DimensionType> filterDims = shapeInfo.GetInputTensorShape(1);
const std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(m_inputTensorIndex);
const std::vector<DimensionType> filterDims = shapeInfo.GetInputTensorShape(m_filterTensorIndex);
ML_CHECK_VALID_ARGUMENT(
inputDimensions.size() >= 3 && inputDimensions.size() <= 5,
@ -378,8 +385,8 @@ public:
);
}
const std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(0);
const std::vector<DimensionType> filterDims = shapeInfo.GetInputTensorShape(1);
const std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(m_inputTensorIndex);
const std::vector<DimensionType> filterDims = shapeInfo.GetInputTensorShape(m_filterTensorIndex);
ML_CHECK_VALID_ARGUMENT(inputDimensions.size() > NonspatialDimensionCount, "Input dimensions must be >= 3");
@ -453,6 +460,8 @@ public:
protected:
uint32_t m_groupCount;
uint32_t m_inputTensorIndex;
uint32_t m_filterTensorIndex;
KernelArgs m_kernel;
std::vector<EdgeShapes> m_outputShapes;
};
@ -461,21 +470,28 @@ class ConvHelper : public ConvolutionHelperBase
{
public:
template<typename Info_t, typename Shape_t>
ConvHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, false, false) {}
ConvHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, false, false, 0, 1) {}
};
class ConvTransposeHelper : public ConvolutionHelperBase
{
public:
template<typename Info_t, typename Shape_t>
ConvTransposeHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, true, false) {}
ConvTransposeHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, true, false, 0, 1) {}
};
class ConvTransposeWithDynamicPadsHelper : public ConvolutionHelperBase
{
public:
template<typename Info_t, typename Shape_t>
ConvTransposeWithDynamicPadsHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, true, true) {}
ConvTransposeWithDynamicPadsHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, true, true, 0, 1) {}
};
class QLinearConvHelper : public ConvolutionHelperBase
{
public:
template<typename Info_t, typename Shape_t>
QLinearConvHelper(const Info_t& info, const Shape_t& shape) : ConvolutionHelperBase(info, shape, false, false, 0, 3) {}
};
class GemmHelper
@ -547,7 +563,7 @@ class SplitHelper {
std::vector<int> m_split;
};
class SliceHelperBase
class SliceHelper
{
public:
template<typename Info_t>
@ -657,7 +673,7 @@ 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<typename Info_t, typename Shape_t>
SliceHelperBase(const Info_t& info, const Shape_t& shape, uint32_t opsetVersion)
SliceHelper(const Info_t& info, const Shape_t& shape, uint32_t opsetVersion)
{
Initialize(info, shape.GetInputTensorShape(0), opsetVersion);
}
@ -671,31 +687,27 @@ public:
std::vector<int32_t> m_strides;
};
class SliceHelper : public SliceHelperBase
{
public:
template<typename Info_t, typename Shape_t>
SliceHelper(const Info_t& info, const Shape_t& shape) : SliceHelperBase(info, shape, 7) {}
};
class Slice10Helper : public SliceHelperBase
{
public:
template<typename Info_t, typename Shape_t>
Slice10Helper(const Info_t& info, const Shape_t& shape) : SliceHelperBase(info, shape, 10) {}
};
class PaddingHelper
{
public:
void Initialize(const MLOperatorAttributes& operatorAttributes);
void Initialize(const MLOperatorAttributes& operatorAttributes, gsl::span<int32_t> padding, uint32_t opsetVersion);
// 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 <typename Info_t, typename Shape_t>
PaddingHelper(const Info_t& info, const Shape_t& shape) {
Initialize(info);
PaddingHelper(const Info_t& info, const Shape_t& shape, uint32_t opsetVersion) {
std::vector<int32_t> padding;
if (opsetVersion >= 11)
{
MLOperatorTensor padsTensor = info.GetConstantInputTensor(1);
ReadCpuLocalTensorIntoInt32(padsTensor, /*out*/ padding);
}
else
{
padding = info.GetOptionalAttributeVectorInt32(AttrName::Pads);
}
Initialize(info, padding, opsetVersion);
}
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
@ -705,6 +717,14 @@ public:
std::vector<uint32_t> m_endPadding;
};
template <typename OpsetHelper, uint32_t OpsetVersion>
class VersionedOpsetHelper : public OpsetHelper
{
public:
template<typename Info_t, typename Shape_t>
VersionedOpsetHelper(const Info_t& info, const Shape_t& shape) : OpsetHelper(info, shape, OpsetVersion) {}
};
class ReduceHelperBase {
public:
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
@ -748,39 +768,63 @@ class ReduceHelper : public ReduceHelperBase {
ReduceHelper(const Info_t& info, const Shape_t& shape) : ReduceHelperBase(info, shape, true) {}
};
class MatMulHelper {
class MatMulHelperBase {
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 <typename Info_t, typename Shape_t>
MatMulHelper(const Info_t& info, const Shape_t& shape) {}
MatMulHelperBase(const Info_t& info, const Shape_t& shape, uint32_t aTensorIndex, uint32_t bTensorIndex) :
m_aTensorIndex(aTensorIndex),
m_bTensorIndex(bTensorIndex)
{}
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
protected:
uint32_t m_aTensorIndex = 0;
uint32_t m_bTensorIndex = 1;
};
class MatMulHelper : public MatMulHelperBase
{
public:
template<typename Info_t, typename Shape_t>
MatMulHelper(const Info_t& info, const Shape_t& shape) : MatMulHelperBase(info, shape, 0, 1) {}
};
class QLinearMatMulHelper : public MatMulHelperBase
{
public:
template<typename Info_t, typename Shape_t>
QLinearMatMulHelper(const Info_t& info, const Shape_t& shape) : MatMulHelperBase(info, shape, 0, 3) {}
};
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 <typename Info_t, typename Shape_t>
TopKHelper(const Info_t& info, const Shape_t& shape) {
m_k = info.GetOptionalAttribute<int32_t>(AttrName::K, -1);
ML_CHECK_VALID_ARGUMENT(m_k >= 0, "Attribute k is missing.");
m_axis = info.GetOptionalAttribute<int32_t>(AttrName::Axis, -1);
auto inputShape = shape.GetInputTensorShape(0);
if (m_axis < 0) {
m_axis = m_axis + gsl::narrow_cast<uint32_t>(inputShape.size());
TopKHelper(const Info_t& info, const Shape_t& shape, uint32_t opsetVersion) {
int32_t k;
if (opsetVersion >= 10) {
MLOperatorTensor kTensor = info.GetConstantInputTensor(1);
k = gsl::narrow_cast<int32_t>(ReadScalarTensorCastToInt64(kTensor));
} else {
k = info.GetOptionalAttribute<int32_t>(AttrName::K, -1);
}
ML_CHECK_VALID_ARGUMENT(m_axis >= 0 && m_axis < gsl::narrow_cast<int32_t>(inputShape.size()));
ML_CHECK_VALID_ARGUMENT(k >= 0, "Attribute k is missing or negative.");
m_k = k;
auto inputShape = shape.GetInputTensorShape(0);
int32_t axis = info.GetOptionalAttribute<int32_t>(AttrName::Axis, -1);
m_axis = HandleNegativeAxis(axis, gsl::narrow_cast<uint32_t>(inputShape.size()));
}
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
protected:
int32_t m_k;
int32_t m_axis;
uint32_t m_k;
uint32_t m_axis;
};
class RecurrentHelper {
@ -1081,22 +1125,11 @@ class ReshapeHelper {
ML_CHECK_VALID_ARGUMENT(info.GetInputCount() >= 2);
ML_CHECK_VALID_ARGUMENT(info.GetOutputCount() >= 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<uint32_t> 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<int64_t>();
// 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<int>(shapeData[i]));
}
MLOperatorTensor shapeTensor = info.GetConstantInputTensor(1);
ReadCpuLocalTensorIntoInt32(shapeTensor, /*out*/ m_shapeDims);
}
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
@ -1169,35 +1202,51 @@ class ResizeHelper {
// 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 <typename Info_t, typename Shape_t>
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.
{
Initialize(info, shape.GetInputTensorShape(0));
ResizeHelper(const Info_t& info, const Shape_t& shape, uint32_t opsetVersion) {
m_inputDimensions = shape.GetInputTensorShape(0);
std::vector<int32_t> outputSizes;
if (opsetVersion >= 11) {
if (info.IsInputValid(1))
{
MLOperatorTensor regionOfInterestTensor = info.GetConstantInputTensor(1);
ReadCpuLocalTensorIntoFloat32(regionOfInterestTensor, /*out*/ m_regionOfInterest);
}
if (info.IsInputValid(2))
{
MLOperatorTensor scalesTensor = info.GetConstantInputTensor(2);
ReadCpuLocalTensorIntoFloat32(scalesTensor, /*out*/ m_scales);
}
if (info.IsInputValid(3))
{
MLOperatorTensor outputSizesTensor = info.GetConstantInputTensor(3);
ReadCpuLocalTensorIntoInt32(outputSizesTensor, /*out*/ outputSizes);
}
}
else if (opsetVersion >= 9) {
// Read the scales from the 2nd tensor.
// Compatible with Upsample-9/Upsample-10 and Resize-10.
MLOperatorTensor scalesTensor = info.GetConstantInputTensor(1);
ReadCpuLocalTensorIntoFloat32(scalesTensor, /*out*/ m_scales);
} else
{
// From attribute, compatible with Upsample-7.
m_scales = info.GetOptionalAttribute<std::vector<float>>(AttrName::Scales, std::vector<float>());
}
Initialize(outputSizes);
}
void Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<const DimensionType> inputDimensions);
void Initialize(
const MLOperatorTensor& scalesTensor,
gsl::span<const DimensionType> inputDimensions);
void InitializeOutputDimensions(
gsl::span<const float> scales,
gsl::span<const DimensionType> inputDimensions);
void Initialize(gsl::span<const int32_t> outputSizes);
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
protected:
std::vector<DimensionType> m_inputDimensions;
std::vector<DimensionType> m_outputDimensions;
std::vector<float> m_scales; // Cached scales to check for updates/invalidate operator.
std::vector<float> m_scales;
std::vector<float> m_regionOfInterest; // Stored as [start1, ..., startN, end1, ..., endN], where N is the input rank.
};
class RangeHelper {
@ -1251,11 +1300,7 @@ class OneHotHelper {
// 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 = CastToInt64(shapeTensor.GetTensorDataType(), tensorData);
const int64_t depth64 = ReadScalarTensorCastToInt64(shapeTensor);
ML_CHECK_VALID_ARGUMENT(depth64 > 0, "Negative or zero 'depth' values for OneHot are illegal.");
const uint32_t depth = gsl::narrow_cast<uint32_t>(depth64);
m_outputDimensions.assign(indicesShape.begin(), indicesShape.end());
@ -1274,6 +1319,8 @@ class OneHotHelper {
using ShapeInferenceHelper_Conv = ConvHelper;
using ShapeInferenceHelper_ConvTranspose = ConvTransposeHelper;
using ShapeInferenceHelper_ConvTransposeWithDynamicPads = ConvTransposeWithDynamicPadsHelper;
using ShapeInferenceHelper_ConvInteger = ConvHelper;
using ShapeInferenceHelper_QLinearConv = QLinearConvHelper;
using ShapeInferenceHelper_AveragePool = PoolingHelper;
using ShapeInferenceHelper_GlobalAveragePool = GlobalPoolingHelper;
using ShapeInferenceHelper_MaxPool = PoolingHelper;
@ -1304,10 +1351,12 @@ using ShapeInferenceHelper_Flatten = FlattenHelper;
using ShapeInferenceHelper_Split = SplitHelper;
using ShapeInferenceHelper_Transpose = TransposeHelper;
using ShapeInferenceHelper_Concat = ConcatHelper;
using ShapeInferenceHelper_Slice7 = SliceHelper;
using ShapeInferenceHelper_Slice10 = Slice10Helper;
using ShapeInferenceHelper_Slice11 = Slice10Helper; // 11 and 10 are identical - no functional change.
using ShapeInferenceHelper_Pad = PaddingHelper;
using ShapeInferenceHelper_Slice7 = VersionedOpsetHelper<SliceHelper, 7>;
using ShapeInferenceHelper_Slice10 = VersionedOpsetHelper<SliceHelper, 10>;
using ShapeInferenceHelper_Slice11 = VersionedOpsetHelper<SliceHelper, 11>; // Note 11 and 10 are identical - no functional change.
using ShapeInferenceHelper_Pad7 = VersionedOpsetHelper<PaddingHelper, 7>;
using ShapeInferenceHelper_Pad11 = VersionedOpsetHelper<PaddingHelper, 11>;
using ShapeInferenceHelper_SpaceToDepth = SpaceToDepthHelper;
using ShapeInferenceHelper_DepthToSpace = DepthToSpaceHelper;
using ShapeInferenceHelper_Squeeze = SqueezeHelper;
@ -1318,7 +1367,8 @@ using ShapeInferenceHelper_Expand = ExpandHelper;
using ShapeInferenceHelper_Reshape = ReshapeHelper;
using ShapeInferenceHelper_ConstantOfShape = ConstantOfShapeHelper;
using ShapeInferenceHelper_Tile = TileHelper;
using ShapeInferenceHelper_Resize = ResizeHelper;
using ShapeInferenceHelper_Resize10 = VersionedOpsetHelper<ResizeHelper, 10>;
using ShapeInferenceHelper_Resize11 = VersionedOpsetHelper<ResizeHelper, 11>;
using ShapeInferenceHelper_OneHot = OneHotHelper;
using ShapeInferenceHelper_Sqrt = GetOutputShapeAsInputShapeHelper;
@ -1386,7 +1436,9 @@ using ShapeInferenceHelper_Neg = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_Crop = CropHelper;
using ShapeInferenceHelper_ImageScaler = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_Upsample = ResizeHelper;
using ShapeInferenceHelper_Upsample7 = VersionedOpsetHelper<ResizeHelper, 7>;
using ShapeInferenceHelper_Upsample9 = VersionedOpsetHelper<ResizeHelper, 9>;
using ShapeInferenceHelper_Upsample10 = VersionedOpsetHelper<ResizeHelper, 10>;
using ShapeInferenceHelper_Sigmoid = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_HardSigmoid = GetOutputShapeAsInputShapeHelper;
@ -1409,10 +1461,15 @@ using ShapeInferenceHelper_Shrink = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_Identity = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_MatMul = MatMulHelper;
using ShapeInferenceHelper_MatMulInteger = MatMulHelper;
using ShapeInferenceHelper_QLinearMatMul = QLinearMatMulHelper;
using ShapeInferenceHelper_Cast = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_MemcpyFromHost = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_MemcpyToHost = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_TopK = TopKHelper;
using ShapeInferenceHelper_TopK7 = VersionedOpsetHelper<TopKHelper, 7>;
using ShapeInferenceHelper_TopK10 = VersionedOpsetHelper<TopKHelper, 10>;
using ShapeInferenceHelper_TopK11 = VersionedOpsetHelper<TopKHelper, 11>;
using ShapeInferenceHelper_RandomUniform = RandomUniformHelper;
using ShapeInferenceHelper_RandomUniformLike = GetOutputShapeAsInputShapeHelper;

View file

@ -172,6 +172,7 @@ namespace OperatorHelper
namespace OnnxOperatorSet10
{
static const int sc_sinceVer_Crop = 10; // Removed in this version.
static const int sc_sinceVer_Resize = 10;
static const int sc_sinceVer_MaxPool = 10;
static const int sc_sinceVer_QuantizeLinear = 10;
@ -186,6 +187,11 @@ namespace OperatorHelper
static const int sc_sinceVer_RoiAlign = 10;
static const int sc_sinceVer_TopK = 10;
static const int sc_sinceVer_ReverseSequence = 10;
static const int sc_sinceVer_AveragePool = 10;
static const int sc_sinceVer_ConvInteger = 10;
static const int sc_sinceVer_MatMulInteger = 10;
static const int sc_sinceVer_QLinearConv = 10;
static const int sc_sinceVer_QLinearMatMul = 10;
} // namespace OnnxOperatorSet10
namespace OnnxOperatorSet11
@ -197,6 +203,8 @@ namespace OperatorHelper
static const int sc_sinceVer_Clip = 11;
static const int sc_sinceVer_Compress = 11;
static const int sc_sinceVer_Concat = 11;
static const int sc_sinceVer_Conv = 11;
static const int sc_sinceVer_ConvTranspose = 11;
static const int sc_sinceVer_CumSum = 11;
static const int sc_sinceVer_DepthToSpace = 11;
static const int sc_sinceVer_Equal = 11;
@ -207,6 +215,7 @@ namespace OperatorHelper
static const int sc_sinceVer_Gemm = 11;
static const int sc_sinceVer_Hardmax = 11;
static const int sc_sinceVer_LogSoftmax = 11;
static const int sc_sinceVer_LpPool = 11;
static const int sc_sinceVer_MaxPool = 11;
static const int sc_sinceVer_MaxUnpool = 11;
static const int sc_sinceVer_OneHot = 11;

View file

@ -66,7 +66,7 @@ OverrideSchemaInferenceFunction<OperatorHelper::ShapeInferenceHelper_##opName>(
#opName, OperatorHelper::OnnxOperatorSet##version##::sc_sinceVer_##opName, isLatest, gsl::span<uint32_t>());
#pragma push_macro("OVERRIDE_SCHEMA_EX")
#define OVERRIDE_SCHEMA_EX(version, isLatest, opName, shapeInferenceName, ...) \
#define OVERRIDE_SCHEMA_EX(version, isLatest, opName, shapeInferenceName, /*CPU constant tensor indices*/ ...) \
OverrideSchemaInferenceFunction<OperatorHelper::ShapeInferenceHelper_##shapeInferenceName>( \
#opName, OperatorHelper::OnnxOperatorSet##version##::sc_sinceVer_##opName, isLatest, std::vector<uint32_t>({##__VA_ARGS__}));
@ -78,15 +78,16 @@ OverrideSchemaInferenceFunction<OperatorHelper::ShapeInferenceHelper_##shapeInfe
OVERRIDE_SCHEMA( 7, false, MaxPool);
OVERRIDE_SCHEMA( 7, true, LpPool);
OVERRIDE_SCHEMA( 7, true, Crop);
OVERRIDE_SCHEMA( 7, false, Upsample);
OVERRIDE_SCHEMA_EX( 9, true, Upsample, Resize, 1); // Upsample v9 uses Resize's shape inference function.
OVERRIDE_SCHEMA_EX( 7, false, Upsample, Upsample7);
OVERRIDE_SCHEMA_EX( 9, true, Upsample, Upsample9, 1);
OVERRIDE_SCHEMA_EX( 7, true, Slice, Slice7);
OVERRIDE_SCHEMA( 7, true, Split);
OVERRIDE_SCHEMA_EX( 7, true, Tile, Tile, 1);
OVERRIDE_SCHEMA_EX( 8, true, Expand, Expand, 1);
OVERRIDE_SCHEMA( 8, true, MaxPool);
OVERRIDE_SCHEMA_EX( 9, true, OneHot, OneHot, 1);
OVERRIDE_SCHEMA_EX( 10, true, Resize, Resize, 1);
OVERRIDE_SCHEMA_EX( 10, false, Resize, Resize10, 1);
}
#pragma pop_macro("OVERRIDE_SCHEMA_EX")
#pragma pop_macro("REGISTER_FUSED_OP_SCHEMA")