mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-18 21:21:17 +00:00
[DML EP] Register pad18 (#15985)
### Description <!-- Describe your changes. --> Pad18 adds the `axes` input, which is used to indicate what axes the padding values should be applied to. Add logic to manipulate paddings into DML padding operator inputs. ### Motivation and Context <!-- - Why is this change required? What problem does it solve? - If it fixes an open issue, please link to the issue here. --> --------- Co-authored-by: Linnea May <linneamay@microsoft.com>
This commit is contained in:
parent
bcd8b73343
commit
954ea6604a
7 changed files with 73 additions and 32 deletions
|
|
@ -1044,7 +1044,8 @@ Do not modify directly.*
|
|||
|PRelu|*in* X:**T**<br> *in* slope:**T**<br> *out* Y:**T**|16+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8)|
|
||||
|||9+|**T** = tensor(float), tensor(float16), tensor(int16), tensor(int32), tensor(int8)|
|
||||
|||7+|**T** = tensor(float), tensor(float16)|
|
||||
|Pad|*in* data:**T**<br> *in* pads:**tensor(int64)**<br> *in* constant_value:**T**<br> *in* axes:**Tind**<br> *out* output:**T**<br><br>or<br><br>*in* data:**T**<br> *in* pads:**tensor(int64)**<br> *in* constant_value:**T**<br> *out* output:**T**<br><br>or<br><br>*in* data:**T**<br> *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)|
|
||||
|Pad|*in* data:**T**<br> *in* pads:**tensor(int64)**<br> *in* constant_value:**T**<br> *in* axes:**Tind**<br> *out* output:**T**<br><br>or<br><br>*in* data:**T**<br> *in* pads:**tensor(int64)**<br> *in* constant_value:**T**<br> *out* output:**T**<br><br>or<br><br>*in* data:**T**<br> *out* output:**T**|18+|**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)|
|
||||
|||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)|
|
||||
|||2+|**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)|
|
||||
|ParametricSoftplus|*in* X:**T**<br> *out* Y:**T**|1+|**T** = tensor(float), tensor(float16)|
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ public:
|
|||
{
|
||||
const uint32_t inputCount = kernelInfo.GetInputCount();
|
||||
ML_CHECK_VALID_ARGUMENT((opsetVersion >= 2 && opsetVersion < 11 && inputCount == 1)
|
||||
|| (opsetVersion >= 11 && inputCount >= 2 && inputCount <= 3));
|
||||
|| (opsetVersion >= 11 && inputCount >= 2 && inputCount <= 4));
|
||||
ML_CHECK_VALID_ARGUMENT(kernelInfo.GetOutputCount() == 1);
|
||||
|
||||
std::vector<std::optional<uint32_t>> kernelInputIndices = { 0 }; // Only bind GPU to first 'data' tensor.
|
||||
|
|
@ -68,12 +68,12 @@ public:
|
|||
paddingDesc.EndPadding = m_endPadding.data();
|
||||
// PaddingValueDataType will always be equal to inputDataTensorDataType
|
||||
// Assigning paddingValueDataType to inputDataTensorDataType because this field
|
||||
// has to be assigned even if program does not go through below conditional
|
||||
// has to be assigned even if program does not go through below conditional
|
||||
// logic for some corner test case (like opsetVersion >= 11, but no validInput at index 2)
|
||||
// Same applies to paddingValue.
|
||||
paddingDesc.PaddingValueDataType = this->m_inputTensorDescs[0].GetDmlDataType();
|
||||
CastToClampedScalarUnion<float>(paddingDesc.PaddingValueDataType, 0.0f, /*out*/&paddingDesc.PaddingValue);
|
||||
|
||||
|
||||
// Read the constant value which can come from an attribute or tensor.
|
||||
if (opsetVersion >= 11)
|
||||
{
|
||||
|
|
@ -107,7 +107,7 @@ void CALLBACK QueryPad(IMLOperatorSupportQueryContextPrivate* context, /*out*/ b
|
|||
*isSupported = true;
|
||||
|
||||
MLOperatorAttributes attributes(context);
|
||||
|
||||
|
||||
std::vector<int32_t> padding = attributes.GetOptionalAttributeVectorInt32(AttrName::Pads);
|
||||
*isSupported = std::none_of(padding.begin(), padding.end(), [](int32_t padCount) {return padCount < 0; });
|
||||
}
|
||||
|
|
@ -115,5 +115,6 @@ void CALLBACK QueryPad(IMLOperatorSupportQueryContextPrivate* context, /*out*/ b
|
|||
DML_OP_DEFINE_CREATION_FUNCTION(Pad7, VersionedKernel<DmlOperatorPadding, 7>);
|
||||
DML_OP_DEFINE_CREATION_FUNCTION(Pad11, VersionedKernel<DmlOperatorPadding, 11>);
|
||||
DML_OP_DEFINE_CREATION_FUNCTION(Pad13, VersionedKernel<DmlOperatorPadding, 13>);
|
||||
DML_OP_DEFINE_CREATION_FUNCTION(Pad18, VersionedKernel<DmlOperatorPadding, 18>);
|
||||
|
||||
} // namespace Dml
|
||||
|
|
|
|||
|
|
@ -292,6 +292,7 @@ DML_OP_EXTERN_CREATION_FUNCTION(Slice13);
|
|||
DML_OP_EXTERN_CREATION_FUNCTION(Pad7);
|
||||
DML_OP_EXTERN_CREATION_FUNCTION(Pad11);
|
||||
DML_OP_EXTERN_CREATION_FUNCTION(Pad13);
|
||||
DML_OP_EXTERN_CREATION_FUNCTION(Pad18);
|
||||
DML_OP_EXTERN_CREATION_FUNCTION(SpaceToDepth);
|
||||
DML_OP_EXTERN_CREATION_FUNCTION(DepthToSpace);
|
||||
DML_OP_EXTERN_CREATION_FUNCTION(Sqrt);
|
||||
|
|
@ -650,6 +651,7 @@ constexpr static OperatorRegistrationInformation operatorRegistrationInformation
|
|||
{REG_INFO_VER( 7, Pad, typeNameListDefault, supportedTypeListAllScalars, DmlGraphSupport::Supported, requiredConstantCpuInputs(), std::nullopt, QueryPad)},
|
||||
{REG_INFO_VER( 11, Pad, typeNameListDefault, supportedTypeListAllScalars, DmlGraphSupport::Supported, requiredConstantCpuInputs(1, 2) /*pads, value*/)}, // https://microsoft.visualstudio.com/OS/_workitems/edit/26007728
|
||||
{REG_INFO_VER( 13, Pad, typeNameListDefault, supportedTypeListAllScalars, DmlGraphSupport::Supported, requiredConstantCpuInputs(1, 2) /*pads, value*/)}, // https://microsoft.visualstudio.com/OS/_workitems/edit/26007728
|
||||
{REG_INFO_VER( 18, Pad, typeNameListDefault, supportedTypeListAllScalars, DmlGraphSupport::Supported, requiredConstantCpuInputs(1, 2, 3) /*pads, value, axes*/)},
|
||||
{REG_INFO( 7, SpaceToDepth, typeNameListDefault, supportedTypeListAllScalars, DmlGraphSupport::Supported)},
|
||||
{REG_INFO( 13, SpaceToDepth, typeNameListDefault, supportedTypeListAllScalars, DmlGraphSupport::Supported)},
|
||||
{REG_INFO( 7, DepthToSpace, typeNameListDefault, supportedTypeListAllScalars, DmlGraphSupport::Supported)},
|
||||
|
|
|
|||
|
|
@ -41,6 +41,21 @@ namespace OperatorHelper
|
|||
}
|
||||
}
|
||||
|
||||
void HandleEmptyAxes(
|
||||
/*inout*/std::vector<int32_t>& axes,
|
||||
gsl::span<const uint32_t> inputShape,
|
||||
bool treatEmptyAsNop
|
||||
)
|
||||
{
|
||||
// If axes is not specified, reduce over all the dimensions.
|
||||
// If empty axes should be treated as a nop, then just leave them as-is.
|
||||
if (axes.empty() && !treatEmptyAsNop)
|
||||
{
|
||||
axes.resize(inputShape.size());
|
||||
std::iota(axes.begin(), axes.end(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
float CastFloat16ToFloat32(uint16_t input)
|
||||
{
|
||||
// Promote float16m10e5s1 to float32m23e8s1.
|
||||
|
|
@ -1122,12 +1137,36 @@ namespace OperatorHelper
|
|||
}
|
||||
|
||||
ML_CHECK_VALID_ARGUMENT(padding.size() % 2 == 0, "Padding must be even count, including begin/end pairs.");
|
||||
std::vector<uint32_t> inputShape = shapeInformation.GetInputTensorShape(0);
|
||||
uint32_t dimCount = gsl::narrow_cast<uint32_t>(inputShape.size());
|
||||
m_startPadding.resize(dimCount, 0);
|
||||
m_endPadding.resize(dimCount, 0);
|
||||
std::vector<int32_t> axes;
|
||||
|
||||
uint32_t dimCount = gsl::narrow_cast<uint32_t>(padding.size() / 2);
|
||||
m_startPadding.resize(dimCount);
|
||||
m_endPadding.resize(dimCount);
|
||||
std::copy(padding.begin(), padding.begin() + dimCount, m_startPadding.begin());
|
||||
std::copy(padding.begin() + dimCount, padding.begin() + dimCount * 2, m_endPadding.begin());
|
||||
// Handle possible axes input
|
||||
if (opsetVersion >= 18)
|
||||
{
|
||||
if (kernelInformation.IsInputValid(3))
|
||||
{
|
||||
ReadCpuLocalTensorIntoInt32(kernelInformation.GetConstantInputTensor(3), /*out*/ axes);
|
||||
}
|
||||
HandleEmptyAxes(axes, inputShape, false);
|
||||
ML_CHECK_VALID_ARGUMENT(axes.size() * 2 == padding.size(), "The number of elements in padding should be 2 times the number of axes.");
|
||||
HandleNegativeAxes(axes, dimCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleEmptyAxes(axes, inputShape, false);
|
||||
}
|
||||
|
||||
uint32_t numAxes = gsl::narrow_cast<uint32_t>(axes.size());
|
||||
for (int32_t i = 0; i < axes.size(); i++)
|
||||
{
|
||||
auto xi_begin = padding[i];
|
||||
auto xi_end = padding[i+axes.size()];
|
||||
m_startPadding[axes[i]] = xi_begin;
|
||||
m_endPadding[axes[i]] = xi_end;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<EdgeShapes> PaddingHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
|
||||
|
|
@ -1360,21 +1399,6 @@ namespace OperatorHelper
|
|||
}
|
||||
}
|
||||
|
||||
void ReduceHelperBase::HandleEmptyAxes(
|
||||
/*inout*/std::vector<int32_t>& axes,
|
||||
gsl::span<const uint32_t> inputShape,
|
||||
bool treatEmptyAsNop
|
||||
)
|
||||
{
|
||||
// If axes is not specified, reduce over all the dimensions.
|
||||
// If empty axes should be treated as a nop, then just leave them as-is.
|
||||
if (axes.empty() && !treatEmptyAsNop)
|
||||
{
|
||||
axes.resize(inputShape.size());
|
||||
std::iota(axes.begin(), axes.end(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void EinSumHelper::Initialize()
|
||||
{
|
||||
ParseEquationComponents();
|
||||
|
|
|
|||
|
|
@ -687,13 +687,6 @@ public:
|
|||
|
||||
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
|
||||
|
||||
private:
|
||||
static void HandleEmptyAxes(
|
||||
/*inout*/std::vector<int32_t>& onnxAxes,
|
||||
gsl::span<const uint32_t> inputShape,
|
||||
bool treatEmptyAsNop
|
||||
);
|
||||
|
||||
protected:
|
||||
std::vector<int32_t> m_axes;
|
||||
int m_keepDims = 0; // Keep the dimensions rather than removing size 1 dimensions.
|
||||
|
|
@ -1526,6 +1519,7 @@ using ShapeInferenceHelper_Slice13 = VersionedOpsetHelper<SliceHelper, 13>; // N
|
|||
using ShapeInferenceHelper_Pad7 = VersionedOpsetHelper<PaddingHelper, 7>;
|
||||
using ShapeInferenceHelper_Pad11 = VersionedOpsetHelper<PaddingHelper, 11>;
|
||||
using ShapeInferenceHelper_Pad13 = VersionedOpsetHelper<PaddingHelper, 13>;
|
||||
using ShapeInferenceHelper_Pad18 = VersionedOpsetHelper<PaddingHelper, 18>;
|
||||
|
||||
using ShapeInferenceHelper_SpaceToDepth = SpaceToDepthHelper;
|
||||
using ShapeInferenceHelper_DepthToSpace = DepthToSpaceHelper;
|
||||
|
|
|
|||
|
|
@ -404,6 +404,7 @@ namespace OperatorHelper
|
|||
static const int sc_sinceVer_BitwiseOr = 18;
|
||||
static const int sc_sinceVer_BitwiseXor = 18;
|
||||
static const int sc_sinceVer_BitwiseNot = 18;
|
||||
static const int sc_sinceVer_Pad = 18;
|
||||
static const int sc_sinceVer_Split = 18;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1011,6 +1011,24 @@ TEST(PadOpTest, ConstantPadAxesTest3) {
|
|||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kNnapiExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(PadOpTest, ConstantPadAxesTest4) {
|
||||
OpTester test("Pad", 18);
|
||||
test.AddAttribute("mode", "constant");
|
||||
test.AddInput<float>("data", {1, 2, 2, 2},
|
||||
{1.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 1.0f,
|
||||
1.0f, 1.0f});
|
||||
test.AddInput<int64_t>("pads", {8}, {0, 0, 0, 1, 0, 0, 0, 1}, true /* pads_is_initializer */);
|
||||
test.AddInput<float>("value", {1}, {0.0f}, true /* value_is_initializer */);
|
||||
test.AddOutput<float>("output", {1, 2, 2, 4},
|
||||
{0.0f, 1.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f, 0.0f,
|
||||
0.0f, 1.0f, 1.0f, 0.0f});
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kTensorrtExecutionProvider, kNnapiExecutionProvider});
|
||||
}
|
||||
|
||||
TEST(PadOpTest, ConstantPadAxesOutOfOrder) {
|
||||
// Specified out of order axes values
|
||||
OpTester test("Pad", 18);
|
||||
|
|
|
|||
Loading…
Reference in a new issue