diff --git a/docs/OperatorKernels.md b/docs/OperatorKernels.md
index 481d36f3f6..414dfaab8d 100644
--- a/docs/OperatorKernels.md
+++ b/docs/OperatorKernels.md
@@ -984,7 +984,8 @@ Do not modify directly.*
|Crop|*in* input:**T**
*out* output:**T**|1+|**T** = tensor(float), tensor(float16)|
|CumSum|*in* x:**T**
*in* axis:**T2**
*out* y:**T**|14+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)|
|||11+|**T** = tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)|
-|DFT|*in* input:**T1**
*in* dft_length:**T2**
*in* axis:**tensor(int64)**
*out* output:**T1**
or
*in* input:**T1**
*in* dft_length:**T2**
*out* output:**T1**|17+|**T1** = tensor(float), tensor(float16)
**T2** = tensor(int64)|
+|DFT|*in* input:**T1**
*in* dft_length:**T2**
*in* axis:**tensor(int64)**
*out* output:**T1**
or
*in* input:**T1**
*in* dft_length:**T2**
*out* output:**T1**|20+|**T1** = tensor(double), tensor(float), tensor(float16)
**T2** = tensor(int32), tensor(int64)|
+|||17+|**T1** = tensor(double), tensor(float), tensor(float16)
**T2** = tensor(int32), tensor(int64)|
|DepthToSpace|*in* input:**T**
*out* output:**T**|13+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
|||11+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
|||1+|**T** = tensor(bool), tensor(double), tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int64), tensor(int8), tensor(uint16), tensor(uint32), tensor(uint64), tensor(uint8)|
diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h
index a99d8bf655..1de88a61a0 100644
--- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h
+++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/DmlDFT.h
@@ -208,7 +208,7 @@ public:
PrepareBluesteinZChirp(dataType);
}
- GpuDFTOperator(IMLOperatorKernelCreationContext* context)
+ GpuDFTOperator(IMLOperatorKernelCreationContext* context, int32_t version)
{
ComPtr executionObject;
context->GetExecutionInterface(executionObject.GetAddressOf());
@@ -218,8 +218,6 @@ public:
ORT_THROW_IF_FAILED(commandList->GetDevice(IID_ID3D12Device, &m_device));
- ORT_THROW_IF_FAILED(context->GetAttribute("axis", MLOperatorAttributeType::Int, 1, sizeof(int64_t), reinterpret_cast(&m_axis)));
-
int64_t isInverseInt;
ORT_THROW_IF_FAILED(context->GetAttribute("inverse", MLOperatorAttributeType::Int, 1, sizeof(int64_t), reinterpret_cast(&isInverseInt)));
m_isInverse = static_cast(isInverseInt);
@@ -232,6 +230,15 @@ public:
ORT_THROW_IF_FAILED(context->GetInputEdgeDescription(0, &edgeDesc));
assert(edgeDesc.edgeType == MLOperatorEdgeType::Tensor);
+ if (version == 17)
+ {
+ ORT_THROW_IF_FAILED(context->GetAttribute("axis", MLOperatorAttributeType::Int, 1, sizeof(int64_t), reinterpret_cast(&m_axis)));
+ }
+ else
+ {
+ m_axis = -2; //-2 is the default axis value for DFT-20 if the optional axis input is not provided
+ }
+
PrepareStockhamFFT(edgeDesc.tensorDataType);
PrepareBluesteinZChirp(edgeDesc.tensorDataType);
}
@@ -398,7 +405,15 @@ public:
// Get the input and output shape sizes
auto inputDims = GetTensorDimensions(inputTensor.Get());
- ML_CHECK_VALID_ARGUMENT(static_cast(m_axis) < inputDims.size())
+ auto rank = static_cast(inputDims.size());
+ ComPtr axisTensor;
+ if (SUCCEEDED(context->GetInputTensor(2, &axisTensor)) && axisTensor != nullptr)
+ {
+ MLOperatorTensor tensor(axisTensor.Get());
+ m_axis = OperatorHelper::ReadScalarTensorCastToInt64(tensor);
+ }
+ m_axis = OperatorHelper::HandleNegativeAxis(static_cast(m_axis), rank);
+ ML_CHECK_VALID_ARGUMENT(m_axis >= 0 && m_axis < rank);
auto outputDims = GetTensorDimensions(outputTensor.Get());
ORT_THROW_HR_IF(E_FAIL, inputDims.size() != outputDims.size());
@@ -977,8 +992,6 @@ struct DFTShapeInferrer : public WRL::Base
{
try
{
- int64_t axis;
- ORT_THROW_IF_FAILED(context->GetAttribute("axis", MLOperatorAttributeType::Int, 1, sizeof(int64_t), reinterpret_cast(&axis)));
int64_t isInverseInt;
ORT_THROW_IF_FAILED(context->GetAttribute("inverse", MLOperatorAttributeType::Int, 1, sizeof(int64_t), reinterpret_cast(&isInverseInt)));
int64_t isOnesidedInt;
@@ -999,7 +1012,25 @@ struct DFTShapeInferrer : public WRL::Base
throw;
}
- auto axisIdx = OperatorHelper::HandleNegativeAxis(static_cast(axis), rank);
+ int64_t axisValue = -2; //Set default axis value to -2 for DFT-20 (last signal axis)
+ bool isDft17 = !context->IsInputValid(2); //Check if axis is provided as an input - if yes then it is DFT-20
+
+ if (isDft17)
+ {
+ axisValue = 1; //Default axis value for DFT-17 should be 1 if axis attribute is not provided
+ ORT_THROW_IF_FAILED(context->GetAttribute("axis", MLOperatorAttributeType::Int, 1, sizeof(int64_t), reinterpret_cast(&axisValue)));
+ }
+ else
+ {
+ ComPtr contextPrivate;
+ ORT_THROW_IF_FAILED(context->QueryInterface(IID_PPV_ARGS(&contextPrivate)));
+ ComPtr axisTensor;
+ ORT_THROW_IF_FAILED(contextPrivate->GetConstantInputTensor(2, &axisTensor));
+ MLOperatorTensor tensor(axisTensor.Get());
+ axisValue = OperatorHelper::ReadScalarTensorCastToInt64(tensor);
+ }
+
+ auto axisIdx = OperatorHelper::HandleNegativeAxis(static_cast(axisValue), rank);
// In general the output shape will match the input shape exactly
// So initialize the output shape with the input shape
@@ -1010,6 +1041,8 @@ struct DFTShapeInferrer : public WRL::Base
// It corresponds to the real and imaginary parts of the DFT output.
outputDims.back() = 2;
+ auto dftLength = inputDims[axisIdx];
+
if (context->IsInputValid(1))
{
// If dft_length is specified, then we should honor the shape.
@@ -1019,10 +1052,11 @@ struct DFTShapeInferrer : public WRL::Base
ComPtr dftLengthTensor;
ORT_THROW_IF_FAILED(contextPrivate->GetConstantInputTensor(1, &dftLengthTensor));
MLOperatorTensor tensor(dftLengthTensor.Get());
- auto dftLength = onnxruntime::narrow(OperatorHelper::ReadScalarTensorCastToInt64(tensor));
- outputDims[axisIdx] = dftLength;
+ dftLength = onnxruntime::narrow(OperatorHelper::ReadScalarTensorCastToInt64(tensor));
}
+ outputDims[axisIdx] = dftLength;
+
// When DFT is onesided, the output shape is half the size of the input shape
// along the specified axis.
if (isOnesided)
@@ -1056,7 +1090,14 @@ public:
{
try
{
- auto dftOperator = wil::MakeOrThrow(context);
+ //If the axis value is provided as an input use DFT-20, otherwise use DFT-17
+ int32_t version = 17;
+ if (context->IsInputValid(2))
+ {
+ version = 20;
+ }
+
+ auto dftOperator = wil::MakeOrThrow(context, version);
dftOperator.CopyTo(kernel);
return S_OK;
}
@@ -1066,12 +1107,12 @@ public:
}
}
- static void RegisterDFTKernel(IMLOperatorRegistry* registry)
+ static void RegisterDFTKernel(IMLOperatorRegistry* registry, int32_t version)
{
MLOperatorKernelDescription kernelDescription = {};
kernelDescription.domain = "";
kernelDescription.name = "DFT";
- kernelDescription.minimumOperatorSetVersion = 17;
+ kernelDescription.minimumOperatorSetVersion = version;
kernelDescription.executionType = MLOperatorExecutionType::D3D12;
// T1: tensor(float16), tensor(float), tensor(double), tensor(bfloat16)
@@ -1081,7 +1122,7 @@ public:
{
MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Float16 },
MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Float },
- //MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Double },
+ MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Double },
};
t1Constraint.allowedTypes = t1AllowedEdges.data();
t1Constraint.allowedTypeCount = static_cast(t1AllowedEdges.size());
@@ -1091,7 +1132,7 @@ public:
t2Constraint.typeLabel = "T2";
std::vector t2AllowedEdges
{
- // MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Int32 },
+ MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Int32 },
MLOperatorEdgeDescription { MLOperatorEdgeType::Tensor, (uint64_t)MLOperatorTensorDataType::Int64 },
};
t2Constraint.allowedTypes = t2AllowedEdges.data();
@@ -1101,13 +1142,6 @@ public:
kernelDescription.typeConstraints = typeConstraints.data();
kernelDescription.typeConstraintCount = static_cast(typeConstraints.size());
- MLOperatorAttributeNameValue axisAttributeValue;
- axisAttributeValue.name = "axis";
- axisAttributeValue.type = MLOperatorAttributeType::Int;
- axisAttributeValue.valueCount = 1;
- static const int64_t axis[] = { 1 };
- axisAttributeValue.ints = axis;
-
MLOperatorAttributeNameValue inverseAttributeValue;
inverseAttributeValue.name = "inverse";
inverseAttributeValue.type = MLOperatorAttributeType::Int;
@@ -1123,11 +1157,21 @@ public:
onesidedAttributeValue.ints = onesided;
std::vector attributeDefaultValues{
- axisAttributeValue,
inverseAttributeValue,
onesidedAttributeValue
};
+ if (version == 17)
+ {
+ MLOperatorAttributeNameValue axisAttributeValue;
+ axisAttributeValue.name = "axis";
+ axisAttributeValue.type = MLOperatorAttributeType::Int;
+ axisAttributeValue.valueCount = 1;
+ static const int64_t axis[] = { 1 };
+ axisAttributeValue.ints = axis;
+ attributeDefaultValues.push_back(axisAttributeValue);
+ }
+
kernelDescription.defaultAttributes = attributeDefaultValues.data();
kernelDescription.defaultAttributeCount = static_cast(attributeDefaultValues.size());
kernelDescription.options = MLOperatorKernelOptions::None;
@@ -1136,7 +1180,7 @@ public:
auto shareInferrer = wil::MakeOrThrow();
auto factory = wil::MakeOrThrow();
- std::array requiredConstantCpuInputs = { 1 };
+ std::array requiredConstantCpuInputs = { 1, 2 };
ComPtr registryPrivate;
ORT_THROW_IF_FAILED(registry->QueryInterface(IID_PPV_ARGS(®istryPrivate)));
diff --git a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp
index 96949e777f..27605a6ad8 100644
--- a/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp
+++ b/onnxruntime/core/providers/dml/DmlExecutionProvider/src/Operators/OperatorRegistration.cpp
@@ -1314,7 +1314,8 @@ void RegisterDmlOperators(IMLOperatorRegistry* registry)
));
}
- GpuDFTOperatorFactory::RegisterDFTKernel(registry);
+ GpuDFTOperatorFactory::RegisterDFTKernel(registry, 17);
+ GpuDFTOperatorFactory::RegisterDFTKernel(registry, 20);
DmlSTFTOperatorFactory::RegisterSTFTKernel(registry);
DmlGridSampleOperatorFactory::RegisterGridSampleKernel(registry);
}
diff --git a/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc b/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc
index 54d725defe..9b44b5aa4c 100644
--- a/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc
+++ b/onnxruntime/test/providers/cpu/signal/signal_ops_test.cc
@@ -33,6 +33,10 @@ static void TestNaiveDFTFloat(bool onesided, int since_version) {
expected_output.resize(6);
}
test.AddInput("input", shape, input);
+ if (since_version == 20) {
+ test.AddInput("dft_length", {}, {5});
+ test.AddInput("axis", {}, {-2});
+ }
test.AddAttribute("onesided", static_cast(onesided));
test.AddOutput("output", output_shape, expected_output);
test.Run();
@@ -53,6 +57,10 @@ static void TestRadix2DFTFloat(bool onesided, int since_version) {
expected_output.resize(10);
}
test.AddInput("input", shape, input);
+ if (since_version == 20) {
+ test.AddInput("dft_length", {}, {8});
+ test.AddInput("axis", {}, {1});
+ }
test.AddAttribute("onesided", static_cast(onesided));
test.AddOutput("output", output_shape, expected_output);
test.Run();
@@ -67,6 +75,10 @@ static void TestInverseFloat(int since_version) {
vector expected_output = {1.000f, 0.000f, 2.000f, 0.000f, 3.000f, 0.000f, 4.000f, 0.000f, 5.000f, 0.000f};
test.AddInput("input", shape, input);
+ if (since_version == 20) {
+ test.AddInput("dft_length", {}, {5});
+ test.AddInput("axis", {}, {1});
+ }
test.AddAttribute("inverse", static_cast(true));
test.AddOutput("output", shape, expected_output);
test.Run();