Fix Range.

This commit is contained in:
Dwayne Robinson 2020-03-24 00:03:08 -07:00
parent f6211217d8
commit 1df264f4b3
7 changed files with 355 additions and 133 deletions

View file

@ -49,7 +49,7 @@ enum class MLOperatorAttributeType : uint32_t
//! \brief Specifies the data type of a tensor.
//! Each data type numerically matches corresponding ONNX types.
enum class MLOperatorTensorDataType : uint32_t
{
{
//! Undefined (unused).
Undefined = 0,

View file

@ -181,7 +181,7 @@ namespace Dml
// CPU Allocator used to create buffers for the MemcpyFromHost operator.
m_cpuInputAllocator = std::make_shared<CPUAllocator>(OrtMemType::OrtMemTypeCPUInput);
m_cpuOutputAllocator = std::make_shared<CPUAllocator>(OrtMemType::OrtMemTypeCPUOutput);
CreateDmlKernelRegistry(&m_kernelRegistry, &m_internalRegInfoMap);
}

View file

@ -29,13 +29,10 @@ public:
int32_t onnxAxis = 0;
if (kernelCreationContext.IsInputValid(1))
{
uint64_t rawAxisBytes;
MLOperatorTensor axisTensor = kernelCreationContext.GetConstantInputTensor(1);
const uint32_t axisElementCount = ComputeElementCountFromDimensions(axisTensor.GetShape());
ML_CHECK_VALID_ARGUMENT(axisTensor.IsCpuData(), "CumSum's 'axis' tensor must be a CPU Tensor.");
ML_CHECK_VALID_ARGUMENT(axisElementCount == 1, "CumSum's 'axis' tensor must have one element.");
const void* tensorData = axisTensor.GetByteData();
onnxAxis = static_cast<int32_t>(ReadAsInt64(axisTensor.GetTensorDataType(), tensorData));
ReadScalarTensorData(axisTensor, /*out*/ &rawAxisBytes, sizeof(rawAxisBytes));
onnxAxis = gsl::narrow_cast<int32_t>(ReadAsInt64(axisTensor.GetTensorDataType(), /*out*/ &rawAxisBytes));
}
uint32_t dmlAxis = GetDmlAdjustedAxis(onnxAxis, kernelCreationContext, m_inputTensorDescs.front().GetDimensionCount());

View file

@ -23,53 +23,16 @@ public:
std::vector<std::optional<uint32_t>> inputIndices = {}; // All tensors are CPU bound.
std::vector<std::optional<uint32_t>> outputIndices = { 0 };
DmlOperator::Initialize(kernelCreationContext, inputIndices, outputIndices);
//-- // Unsqueeze the indices tensor by inserting a flat dimension of size 1,
//-- // and compute the output tensor by expanding along the active axis.
//-- // This way they are both size-compatible and directly consumable by DirectML.
//-- std::vector<uint32_t> indicesDimensions;
//-- indicesDimensions = kernelCreationContext.GetTensorShapeDescription().GetInputTensorShape(0);
//-- indicesDimensions.insert(indicesDimensions.begin() + m_absoluteAxis, 1u);
//--
//-- // Update the tensor descriptions with new sizes.
//-- m_inputTensorDescs[0] =
//-- TensorDesc(
//-- m_inputTensorDescs[0].GetMlOperatorDataType(),
//-- gsl::make_span(indicesDimensions),
//-- gsl::make_span(indicesDimensions),
//-- TensorAxis::DoNotCoerce,
//-- TensorAxis::W,
//-- TensorAxis::RightAligned,
//-- NchwDimensionCount, // minDimensionCount
//-- 0
//-- );
//--
//-- m_outputTensorDescs[0] =
//-- TensorDesc(
//-- m_outputTensorDescs[0].GetMlOperatorDataType(),
//-- gsl::make_span(m_outputDimensions),
//-- gsl::make_span(m_outputDimensions),
//-- TensorAxis::DoNotCoerce,
//-- TensorAxis::W,
//-- TensorAxis::RightAligned,
//-- NchwDimensionCount, // minDimensionCount
//-- 0
//-- );
//--
//-- // Adjust the axis so it's in DML's terms rather than the original ONNX indexing.
//-- uint32_t dmlAxis = GetDmlAdjustedAxis(
//-- m_absoluteAxis,
//-- gsl::narrow_cast<uint32_t>(indicesDimensions.size()),
//-- m_inputTensorDescs.front().GetDimensionCount()
//-- );
std::vector<DML_TENSOR_DESC> inputDescs = GetDmlInputDescs();
std::vector<DML_TENSOR_DESC> outputDescs = GetDmlOutputDescs();
DML_FILL_VALUE_SEQUENCE_OPERATOR_DESC operatorDesc = {};
operatorDesc.ValueDataType = m_outputTensorDescs[0].GetDmlDataType();;
operatorDesc.ValueStart.Float32 = 1; // todo:::
operatorDesc.ValueDelta.Float32 = 1;
static_assert(sizeof(operatorDesc.ValueStart) == sizeof(m_valueStart));
static_assert(sizeof(operatorDesc.ValueDelta) == sizeof(m_valueDelta));
memcpy(&operatorDesc.ValueStart, &m_valueStart, sizeof(m_valueStart));
memcpy(&operatorDesc.ValueDelta, &m_valueDelta, sizeof(m_valueDelta));
operatorDesc.OutputTensor = outputDescs.data();
DML_OPERATOR_DESC opDesc = { DML_OPERATOR_FILL_VALUE_SEQUENCE, &operatorDesc };

View file

@ -230,7 +230,7 @@ const static char* const typeNameListLogicalComparison[2] = { "T", "T1" };
const static char* const typeNameListT1T2[2] = { "T1", "T2" };
const static char* const typeNameListConstantOfShape[2] = { "T1", "T2" };
const static char* const typeNameListScatterGather[2] = { "T", "Tind" };
const static char* const typeNameListScatterGatherND[2] = { "T" }; // Tind is curiously missing, only allowing 64-bit.
const static char* const typeNameListScatterGatherND[1] = { "T" }; // Tind is curiously missing, only allowing 64-bit.
const static char* const typeNameListQuantize[2] = { "T1", "T2" };
const static char* const typeNameListWhere[2] = { "B", "T" };
const static char* const typeNameListOneHot[3] = { "T1", "T2", "T3" };
@ -246,7 +246,7 @@ const static SupportedTensorDataTypes supportedTypeListTopK[2] = {SupportedTenso
const static SupportedTensorDataTypes supportedTypeListIndices[1] = { SupportedTensorDataTypes::Int32|SupportedTensorDataTypes::Int64 };
const static SupportedTensorDataTypes supportedTypeListCast[2] = { SupportedTensorDataTypes::AllScalars, SupportedTensorDataTypes::Scalars8to32 };
const static SupportedTensorDataTypes supportedTypeListScatterGather[2] = { SupportedTensorDataTypes::NumericDefault, SupportedTensorDataTypes::Int32 | SupportedTensorDataTypes::Int64 };
const static SupportedTensorDataTypes supportedTypeListScatterGatherND[2] = { SupportedTensorDataTypes::NumericDefault };
const static SupportedTensorDataTypes supportedTypeListScatterGatherND[1] = { SupportedTensorDataTypes::NumericDefault };
const static SupportedTensorDataTypes supportedTypeListQuantizeLinear[2] = { SupportedTensorDataTypes::Float32 | SupportedTensorDataTypes::Int32, SupportedTensorDataTypes::UInt8 | SupportedTensorDataTypes::Int8 };
const static SupportedTensorDataTypes supportedTypeListDequantizeLinear[2] = { SupportedTensorDataTypes::Float32, SupportedTensorDataTypes::UInt8 | SupportedTensorDataTypes::Int8 | SupportedTensorDataTypes::Int32 };
const static SupportedTensorDataTypes supportedTypeListQuantize[2] = { SupportedTensorDataTypes::Float32, SupportedTensorDataTypes::UInt8 };
@ -511,15 +511,16 @@ const static OperatorRegistrationInformation operatorRegistrationInformationTabl
{REG_INFO( 11, Round, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
{REG_INFO( 10, ReverseSequence, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)}, // TODO::: data types, why not registered??
{REG_INFO( 11, CumSum, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})},
{REG_INFO( 11, Range, typeNameListDefault, supportedTypeListRange, DmGraphSupport::Supported), {0,1,2}},
{REG_INFO( 11, Range, typeNameListDefault, supportedTypeListRange, DmGraphSupport::Supported, {0,1,2})},
{REG_INFO( 11, Gather, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
{REG_INFO( 11, GatherElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
{REG_INFO( 11, GatherND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)},
{REG_INFO( 11, ScatterElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
{REG_INFO( 11, ScatterND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)},
#if 0
{REG_INFO( 9, MaxUnpool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {2})},
{REG_INFO( 11, Gather, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
-{REG_INFO( 11, GatherElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
-{REG_INFO( 11, GatherND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)},
{REG_INFO( 9, MaxUnpool, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {2})},
{REG_INFO( 11, Resize, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported, {1})},
-{REG_INFO( 11, ScatterElements, typeNameListScatterGather, supportedTypeListScatterGather, DmGraphSupport::Supported)},
-{REG_INFO( 11, ScatterND, typeNameListScatterGatherND, supportedTypeListScatterGatherND, DmGraphSupport::Supported)},
{REG_INFO( 11, QLinearConv, typeNameListDefault, supportedTypeListFloat16to32, DmGraphSupport::Supported)},
// T1 : tensor(int8), tensor(uint8)

View file

@ -6,36 +6,36 @@
namespace OperatorHelper
{
bool ContainsEmptyDimensions(gsl::span<const DimensionType> dimensions)
{
return std::find(dimensions.begin(), dimensions.end(), 0) != dimensions.end();
}
// Convert any negative axis into an absolute axis relative to the back end.
// So given 3 dimensions, a -1 refers to axis 2, and -3 to axis 0.
uint32_t HandleNegativeAxis(int32_t signedOnnxAxis, uint32_t dimCount)
{
if (signedOnnxAxis < 0)
bool ContainsEmptyDimensions(gsl::span<const DimensionType> dimensions)
{
signedOnnxAxis += dimCount;
return std::find(dimensions.begin(), dimensions.end(), 0) != dimensions.end();
}
uint32_t absoluteAxis = gsl::narrow_cast<uint32_t>(signedOnnxAxis);
ML_CHECK_VALID_ARGUMENT(absoluteAxis < dimCount);
return absoluteAxis;
}
void HandleNegativeAxes(gsl::span<int32_t> onnxAxes, uint32_t dimCount)
{
for (int32_t& axis : onnxAxes)
// Convert any negative axis into an absolute axis relative to the back end.
// So given 3 dimensions, a -1 refers to axis 2, and -3 to axis 0.
uint32_t HandleNegativeAxis(int32_t signedOnnxAxis, uint32_t dimCount)
{
axis = HandleNegativeAxis(axis, dimCount);
if (signedOnnxAxis < 0)
{
signedOnnxAxis += dimCount;
}
uint32_t absoluteAxis = gsl::narrow_cast<uint32_t>(signedOnnxAxis);
ML_CHECK_VALID_ARGUMENT(absoluteAxis < dimCount);
return absoluteAxis;
}
}
int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p)
{
switch (tensorDataType)
void HandleNegativeAxes(gsl::span<int32_t> onnxAxes, uint32_t dimCount)
{
for (int32_t& axis : onnxAxes)
{
axis = HandleNegativeAxis(axis, dimCount);
}
}
int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p)
{
switch (tensorDataType)
{
case MLOperatorTensorDataType::Float: return static_cast<int64_t>(*reinterpret_cast<const float*>(p));
case MLOperatorTensorDataType::UInt8: return static_cast<int64_t>(*reinterpret_cast<const uint8_t*>(p));
case MLOperatorTensorDataType::Int8: return static_cast<int64_t>(*reinterpret_cast<const int8_t*>(p));
@ -56,6 +56,57 @@ int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p)
};
}
double ReadAsFloat64(MLOperatorTensorDataType tensorDataType, const void* p)
{
switch (tensorDataType)
{
case MLOperatorTensorDataType::Float: return static_cast<double>(*reinterpret_cast<const float*>(p));
case MLOperatorTensorDataType::UInt8: return static_cast<double>(*reinterpret_cast<const uint8_t*>(p));
case MLOperatorTensorDataType::Int8: return static_cast<double>(*reinterpret_cast<const int8_t*>(p));
case MLOperatorTensorDataType::UInt16: return static_cast<double>(*reinterpret_cast<const uint16_t*>(p));
case MLOperatorTensorDataType::Int16: return static_cast<double>(*reinterpret_cast<const int16_t*>(p));
case MLOperatorTensorDataType::Int32: return static_cast<double>(*reinterpret_cast<const int32_t*>(p));
case MLOperatorTensorDataType::Int64: return static_cast<double>(*reinterpret_cast<const int64_t*>(p));
case MLOperatorTensorDataType::String: ML_INVALID_ARGUMENT("MLOperatorTensorDataType::String type is unsupported for reading as an integer.");
case MLOperatorTensorDataType::Bool: return static_cast<double>(*reinterpret_cast<const uint8_t*>(p));
case MLOperatorTensorDataType::Float16: ML_INVALID_ARGUMENT("MLOperatorTensorDataType::Float16 type is unsupported for reading as an integer.");
case MLOperatorTensorDataType::Double: return static_cast<double>(*reinterpret_cast<const double*>(p));
case MLOperatorTensorDataType::UInt32: return static_cast<double>(*reinterpret_cast<const uint32_t*>(p));
case MLOperatorTensorDataType::UInt64: return static_cast<double>(*reinterpret_cast<const uint64_t*>(p));
case MLOperatorTensorDataType::Complex64: return static_cast<double>(*reinterpret_cast<const float*>(p)); // Read the real component.
case MLOperatorTensorDataType::Complex128: return static_cast<double>(*reinterpret_cast<const double*>(p)); // Read the real component.
case MLOperatorTensorDataType::Undefined:
default: ML_INVALID_ARGUMENT("Unknown MLOperatorTensorDataType.");
};
}
int64_t IsFloatDataType(MLOperatorTensorDataType tensorDataType)
{
switch (tensorDataType)
{
case MLOperatorTensorDataType::Float:
case MLOperatorTensorDataType::Float16:
case MLOperatorTensorDataType::Double:
case MLOperatorTensorDataType::Complex64:
case MLOperatorTensorDataType::Complex128:
return true;
};
return false;
}
void ReadScalarTensorData(const MLOperatorTensor& tensor, /*out*/ void* data, size_t dataByteSize)
{
// Read the tensor bytes of a scalar value into the output data,
// validating dimensions and byte size.
const uint32_t elementCount = ComputeElementCountFromDimensions(tensor.GetShape());
const size_t elementByteSize = GetByteSizeFromMlDataType(tensor.GetTensorDataType());
ML_CHECK_VALID_ARGUMENT(tensor.IsCpuData(), "Tensor must be a CPU Tensor.");
ML_CHECK_VALID_ARGUMENT(elementCount == 1, "Scalar tensors must have exactly 1 element.");
ML_CHECK_VALID_ARGUMENT(dataByteSize >= elementByteSize, "Scalar tensor element byte size is too large.");
memcpy(data, tensor.GetByteData(), elementByteSize);
}
// Calculates the spatial dimensions from input dimensions and a kernel. The non-spatial (leading)
// dimensions will be initialized to match the input dimensions. This assumes the spatial dimensions
// are ordered such that they are at the end (e.g. NCHW or NCDHW).
@ -526,6 +577,106 @@ int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p)
return { EdgeShapes(std::move(outputDimensions)) };
}
// TODO:::
void GatherNDHelper::Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<const DimensionType> inputDimensions
)
{
int32_t signedOnnxAxis = operatorAttributes.GetOptionalAttribute<int>(AttrName::Axis, 0);
uint32_t inputRank = gsl::narrow_cast<int>(inputDimensions.size());
m_axis = HandleNegativeAxis(signedOnnxAxis, inputRank);
}
std::vector<EdgeShapes> GatherNDHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
{
std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(0);
std::vector<DimensionType> indicesDimensions = shapeInfo.GetInputTensorShape(1);
ML_CHECK_VALID_ARGUMENT(inputDimensions.size() >= 1);
ML_CHECK_VALID_ARGUMENT(indicesDimensions.size() >= 0);
int outDimCount = gsl::narrow_cast<int>(inputDimensions.size() + indicesDimensions.size() - 1);
ML_CHECK_VALID_ARGUMENT(outDimCount > 0 && outDimCount <= NchwDimensionCount);
std::vector<DimensionType> outputDimensions(outDimCount, 1);
// The input dimensions following the gather axis determine the final output dimensions.
int outputDim = outDimCount - 1;
int inputDim = gsl::narrow_cast<int>(inputDimensions.size() - 1);
for (; inputDim > m_axis; --outputDim, --inputDim)
{
outputDimensions[outputDim] = inputDimensions[inputDim];
}
// The shape of the index tensor is reflected in the middle dimensions of the output tensor.
int indexDim = gsl::narrow_cast<int>(indicesDimensions.size() - 1);
for (; indexDim >= 0; --outputDim, --indexDim)
{
outputDimensions[outputDim] = indicesDimensions[indexDim];
}
// The gather dimension is skipped for the purposes of sizing because the index values choose slices
// across it. Preceding input dimensions determine the shape of the output's leading dimensions.
inputDim = m_axis - 1;
for (; outputDim >= 0 && inputDim >= 0; --outputDim, --inputDim)
{
outputDimensions[outputDim] = inputDimensions[inputDim];
}
return { EdgeShapes(std::move(outputDimensions)) };
}
// TODO:::
void ScatterNDHelper::Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<const DimensionType> inputDimensions
)
{
int32_t signedOnnxAxis = operatorAttributes.GetOptionalAttribute<int>(AttrName::Axis, 0);
uint32_t inputRank = gsl::narrow_cast<int>(inputDimensions.size());
m_axis = HandleNegativeAxis(signedOnnxAxis, inputRank);
}
std::vector<EdgeShapes> ScatterNDHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
{
std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(0);
std::vector<DimensionType> indicesDimensions = shapeInfo.GetInputTensorShape(1);
ML_CHECK_VALID_ARGUMENT(inputDimensions.size() >= 1);
ML_CHECK_VALID_ARGUMENT(indicesDimensions.size() >= 0);
int outDimCount = gsl::narrow_cast<int>(inputDimensions.size() + indicesDimensions.size() - 1);
ML_CHECK_VALID_ARGUMENT(outDimCount > 0 && outDimCount <= NchwDimensionCount);
std::vector<DimensionType> outputDimensions(outDimCount, 1);
// The input dimensions following the gather axis determine the final output dimensions.
int outputDim = outDimCount - 1;
int inputDim = gsl::narrow_cast<int>(inputDimensions.size() - 1);
for (; inputDim > m_axis; --outputDim, --inputDim)
{
outputDimensions[outputDim] = inputDimensions[inputDim];
}
// The shape of the index tensor is reflected in the middle dimensions of the output tensor.
int indexDim = gsl::narrow_cast<int>(indicesDimensions.size() - 1);
for (; indexDim >= 0; --outputDim, --indexDim)
{
outputDimensions[outputDim] = indicesDimensions[indexDim];
}
// The gather dimension is skipped for the purposes of sizing because the index values choose slices
// across it. Preceding input dimensions determine the shape of the output's leading dimensions.
inputDim = m_axis - 1;
for (; outputDim >= 0 && inputDim >= 0; --outputDim, --inputDim)
{
outputDimensions[outputDim] = inputDimensions[inputDim];
}
return { EdgeShapes(std::move(outputDimensions)) };
}
void TransposeHelper::Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<const DimensionType> inputDimensions
@ -1139,6 +1290,46 @@ int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p)
return { m_outputDimensions };
}
void RangeHelper::Initialize(
const MLOperatorTensor& startTensor,
const MLOperatorTensor& limitTensor,
const MLOperatorTensor& deltaTensor
)
{
ReadScalarTensorData(startTensor, &m_valueStart, sizeof(m_valueStart));
ReadScalarTensorData(limitTensor, &m_valueLimit, sizeof(m_valueLimit));
ReadScalarTensorData(deltaTensor, &m_valueDelta, sizeof(m_valueDelta));
m_tensorDataType = startTensor.GetTensorDataType();
// The output size is a 1D tensor ranging from start up to limit,
// where:
//
// number_of_elements = max(ceil((limit - start) / delta), 0)
//
uint32_t totalElementCount = 0;
if (IsFloatDataType(m_tensorDataType))
{
double start = ReadAsFloat64(m_tensorDataType, &m_valueStart);
double limit = ReadAsFloat64(m_tensorDataType, &m_valueLimit);
double delta = ReadAsFloat64(m_tensorDataType, &m_valueDelta);
totalElementCount = gsl::narrow_cast<uint32_t>(ceil((limit - start) / delta));
}
else
{
int64_t start = ReadAsInt64(m_tensorDataType, &m_valueStart);
int64_t limit = ReadAsInt64(m_tensorDataType, &m_valueLimit);
int64_t delta = ReadAsInt64(m_tensorDataType, &m_valueDelta);
int64_t range = limit - start;
totalElementCount = gsl::narrow_cast<uint32_t>((range / delta) + (range % delta != 0));
}
m_outputDimensions.push_back(totalElementCount);
}
std::vector<EdgeShapes> RangeHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
{
return { m_outputDimensions };
}
std::vector<EdgeShapes> OneHotHelper::GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const
{
return { std::move(EdgeShapes(m_outputDimensions)) };

View file

@ -76,6 +76,8 @@ void RemoveValuesByIndex(gsl::span<const uint32_t> indices, bool keepOneValue, /
}
int64_t ReadAsInt64(MLOperatorTensorDataType tensorDataType, const void* p);
double ReadAsFloat64(MLOperatorTensorDataType tensorDataType, const void* p);
void ReadScalarTensorData(const MLOperatorTensor& tensor, void* data, size_t dataByteSize);
class EdgeShapes {
public:
@ -174,13 +176,38 @@ class GetOutputShapeAsInputShapeHelper {
public:
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
// Shape_t is used to obtain input shape which will be used for adjusting attribute value.
// Default to first input tensor.
template <typename Info_t, typename Shape_t>
GetOutputShapeAsInputShapeHelper(const Info_t& info, const Shape_t& shape){
ORT_UNUSED_PARAMETER(info);
ORT_UNUSED_PARAMETER(shape);
};
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
// Shape_t is used to obtain input shape which will be used for adjusting attribute value.
// Pass specific tensor index.
template <typename Info_t, typename Shape_t>
GetOutputShapeAsInputShapeHelper(const Info_t& info, const Shape_t& shape, uint32_t inputTensorIndex)
: m_inputTensorIndex(inputTensorIndex)
{
ORT_UNUSED_PARAMETER(info);
ORT_UNUSED_PARAMETER(shape);
};
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
uint32_t m_inputTensorIndex = 0;
};
template <uint32_t InputTensorIndex>
class GetOutputShapeAsSpecificInputShapeHelper : public GetOutputShapeAsInputShapeHelper {
public:
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
// Shape_t is used to obtain input shape which will be used for adjusting attribute value.
template <typename Info_t, typename Shape_t>
GetOutputShapeAsSpecificInputShapeHelper(const Info_t& info, const Shape_t& shape)
: GetOutputShapeAsInputShapeHelper(info, shape, InputTensorIndex)
{}
};
class GetBroadcastedOutputShapeHelper {
@ -329,10 +356,10 @@ public:
);
}
const std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(0);
const std::vector<DimensionType> filterDims = shapeInfo.GetInputTensorShape(1);
const std::vector<DimensionType> inputDimensions = shapeInfo.GetInputTensorShape(0);
const std::vector<DimensionType> filterDims = shapeInfo.GetInputTensorShape(1);
ML_CHECK_VALID_ARGUMENT(inputDimensions.size() > NonspatialDimensionCount, "Input dimensions must be >= 3");
ML_CHECK_VALID_ARGUMENT(inputDimensions.size() > NonspatialDimensionCount, "Input dimensions must be >= 3");
if (hasDynamicPads)
{
@ -367,39 +394,39 @@ public:
assert(m_outputShapes[0].GetShape().size() > C);
m_outputShapes[0].GetShape()[C] = filterDims[C] * m_groupCount;
if (!outputShape.empty()) {
// Start padding, end padding, and output padding are all ignored if output shape is set.
std::fill(m_kernel.outputPadding, m_kernel.outputPadding + m_kernel.spatialDimensionCount, 0);
if (!outputShape.empty()) {
// Start padding, end padding, and output padding are all ignored if output shape is set.
std::fill(m_kernel.outputPadding, m_kernel.outputPadding + m_kernel.spatialDimensionCount, 0);
if (outputShape.size() > 2) {
ML_CHECK_VALID_ARGUMENT(outputShape[outputShape.size() - 3] == gsl::narrow_cast<int>(m_outputShapes[0].GetShape()[C]), "Output channel must be equivalent to filter channel.");
}
if (outputShape.size() > 2) {
ML_CHECK_VALID_ARGUMENT(outputShape[outputShape.size() - 3] == gsl::narrow_cast<int>(m_outputShapes[0].GetShape()[C]), "Output channel must be equivalent to filter channel.");
}
for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) {
size_t outputIndex = outputShape.size() - m_kernel.spatialDimensionCount + i;
ML_CHECK_VALID_ARGUMENT(outputShape[outputIndex] >= gsl::narrow_cast<int>(inputDimensions[H + i]), "Output dimension cannot be smaller than input dimension.");
m_outputShapes[0].GetShape()[H + i] = outputShape[outputIndex];
}
for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) {
size_t outputIndex = outputShape.size() - m_kernel.spatialDimensionCount + i;
ML_CHECK_VALID_ARGUMENT(outputShape[outputIndex] >= gsl::narrow_cast<int>(inputDimensions[H + i]), "Output dimension cannot be smaller than input dimension.");
m_outputShapes[0].GetShape()[H + i] = outputShape[outputIndex];
}
const int dimOffset = gsl::narrow_cast<int>(inputDimensions.size() - m_kernel.spatialDimensionCount);
const int dimOffset = gsl::narrow_cast<int>(inputDimensions.size() - m_kernel.spatialDimensionCount);
for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) {
int stride = m_kernel.strides[i];
int windowSize = m_kernel.windowSize[i];
for (size_t i = 0; i < m_kernel.spatialDimensionCount; ++i) {
int stride = m_kernel.strides[i];
int windowSize = m_kernel.windowSize[i];
// Compute padding such that in reverse order, the logical input (m_outputShapes below) is fully defined
// for a convolution over the logical output region (inputDimensions below).
//
// The padding required is the first windowSize element (for the first logical output element),
// plus (logicalOutput - 1) steps of stride (the distance between each windowed set of logical
// input elements), minus the actual logical input size.
int paddings = gsl::narrow_cast<int>((inputDimensions[i + dimOffset] - 1) * stride + windowSize - m_outputShapes[0].GetShape()[i + dimOffset]);
paddings = std::max<int>(0, paddings);
// Compute padding such that in reverse order, the logical input (m_outputShapes below) is fully defined
// for a convolution over the logical output region (inputDimensions below).
//
// The padding required is the first windowSize element (for the first logical output element),
// plus (logicalOutput - 1) steps of stride (the distance between each windowed set of logical
// input elements), minus the actual logical input size.
int paddings = gsl::narrow_cast<int>((inputDimensions[i + dimOffset] - 1) * stride + windowSize - m_outputShapes[0].GetShape()[i + dimOffset]);
paddings = std::max<int>(0, paddings);
m_kernel.startPadding[i] = m_kernel.autoPadSameUpper ? (paddings + 1) / 2 : paddings / 2;
m_kernel.endPadding[i] = paddings - m_kernel.startPadding[i];
}
}
m_kernel.startPadding[i] = m_kernel.autoPadSameUpper ? (paddings + 1) / 2 : paddings / 2;
m_kernel.endPadding[i] = paddings - m_kernel.startPadding[i];
}
}
}
protected:
@ -898,6 +925,46 @@ class GatherHelper {
int m_axis = 0;
};
class GatherNDHelper {
public:
void Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<const DimensionType> dataDimensions
);
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
// Shape_t is used to obtain input shape which will be used for adjusting attribute value.
template <typename Info_t, typename Shape_t>
GatherNDHelper(const Info_t& info, const Shape_t& shape) {
Initialize(info, shape.GetInputTensorShape(0));
}
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
protected:
int m_axis = 0;
};
class ScatterNDHelper {
public:
void Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<const DimensionType> dataDimensions
);
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
// Shape_t is used to obtain input shape which will be used for adjusting attribute value.
template <typename Info_t, typename Shape_t>
ScatterNDHelper(const Info_t& info, const Shape_t& shape) {
Initialize(info, shape.GetInputTensorShape(0));
}
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
protected:
int m_axis = 0;
};
class PoolingHelperBase {
public:
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
@ -1127,38 +1194,36 @@ class ResizeHelper {
std::vector<float> m_scales; // Cached scales to check for updates/invalidate operator.
};
//TODO:::
class RangeHelper {
public:
// Info_t is used to obtain attributes which will be used for calculating the output shape later.
// Shape_t is used to obtain input shape which will be used for adjusting attribute value.
template <typename Info_t, typename Shape_t>
RangeHelper(const Info_t& info, const Shape_t& shape) {
// Read the scales from the 2nd tensor.
if (info.GetInputCount() > 1) {
MLOperatorTensor scalesTensor = info.GetConstantInputTensor(1);
Initialize(scalesTensor, shape.GetInputTensorShape(0));
} else // From attribute.
{
Initialize(info, shape.GetInputTensorShape(0));
}
RangeHelper(const Info_t& info, const Shape_t& shape)
{
auto startTensor = info.GetConstantInputTensor(0);
auto limitTensor = info.GetConstantInputTensor(1);
auto deltaTensor = info.GetConstantInputTensor(2);
Initialize(startTensor, limitTensor, deltaTensor);
}
void Initialize(
const MLOperatorAttributes& operatorAttributes,
gsl::span<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);
const MLOperatorTensor& startTensor,
const MLOperatorTensor& limitTensor,
const MLOperatorTensor& deltaTensor
);
std::vector<EdgeShapes> GetOutputShapes(const MLShapeInferenceContext& shapeInfo) const;
protected:
std::vector<DimensionType> m_outputDimensions;
MLOperatorTensorDataType m_tensorDataType = MLOperatorTensorDataType::Undefined;
using TensorScalarData = typename std::aligned_storage<sizeof(double), alignof(double)>::type;
TensorScalarData m_valueStart;
TensorScalarData m_valueLimit;
TensorScalarData m_valueDelta;
};
class OneHotHelper {
@ -1220,7 +1285,13 @@ using ShapeInferenceHelper_LpNormalization = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_RNN = RecurrentHelper;
using ShapeInferenceHelper_GRU = RecurrentHelper;
using ShapeInferenceHelper_LSTM = RecurrentHelper;
using ShapeInferenceHelper_Gather = GatherHelper;
using ShapeInferenceHelper_GatherElements = GetOutputShapeAsSpecificInputShapeHelper<1>;
using ShapeInferenceHelper_ScatterElements = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_Scatter = ShapeInferenceHelper_ScatterElements;
using ShapeInferenceHelper_GatherND = GatherNDHelper;
using ShapeInferenceHelper_ScatterND = ScatterNDHelper;
using ShapeInferenceHelper_Flatten = FlattenHelper;
using ShapeInferenceHelper_Split = SplitHelper;
@ -1276,7 +1347,6 @@ using ShapeInferenceHelper_Atan = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_Affine = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_QuantizeLinear = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_DequantizeLinear = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_Scatter = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_Sign = GetBroadcastedOutputShapeHelper;
using ShapeInferenceHelper_IsNan = GetBroadcastedOutputShapeHelper;
using ShapeInferenceHelper_Erf = GetBroadcastedOutputShapeHelper;
@ -1344,7 +1414,7 @@ using ShapeInferenceHelper_Multinomial = MultinomialHelper;
using ShapeInferenceHelper_ReverseSequence = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_CumSum = GetOutputShapeAsInputShapeHelper;
using ShapeInferenceHelper_ShapeInferenceHelper_Range = RangeHelper;
using ShapeInferenceHelper_Range = RangeHelper;
using ShapeInferenceHelper_FusedConv = ConvHelper;
using ShapeInferenceHelper_FusedConvTranspose = ConvTransposeHelper;