| // |
| // Copyright © 2017 Arm Ltd. All rights reserved. |
| // SPDX-License-Identifier: MIT |
| // |
| |
| #include <backendsCommon/TensorHandle.hpp> |
| #include <backendsCommon/WorkloadData.hpp> |
| #include <armnnUtils/DataLayoutIndexed.hpp> |
| #include <armnnUtils/TensorUtils.hpp> |
| #include <armnn/utility/NumericCast.hpp> |
| #include <armnn/Logging.hpp> |
| |
| #include <algorithm> |
| #include <iomanip> |
| #include <string> |
| #include <sstream> |
| |
| #include <fmt/format.h> |
| |
| using namespace armnnUtils; |
| |
| namespace armnn |
| { |
| |
| //--------------------------------------------------------------- |
| DataType GetBiasDataType(DataType inputDataType) |
| { |
| switch (inputDataType) |
| { |
| case DataType::Float16: |
| return DataType::Float16; |
| case DataType::BFloat16: |
| case DataType::Float32: |
| return DataType::Float32; |
| case DataType::QAsymmS8: |
| return DataType::Signed32; |
| case DataType::QAsymmU8: |
| return DataType::Signed32; |
| case DataType::QSymmS8: |
| return DataType::Signed32; |
| case DataType::QSymmS16: |
| return DataType::Signed32; |
| default: |
| ARMNN_ASSERT_MSG(false, "Invalid input data type"); |
| return DataType::Float32; |
| } |
| } |
| |
| namespace |
| { |
| |
| //--------------------------------------------------------------- |
| //android ndk does not support std::to_string function. |
| template <typename T> |
| std::string to_string(T value) |
| { |
| std::ostringstream os; |
| os << value; |
| return os.str(); |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidatePointer(const void* ptr, std::string const& descName, std::string const& paramName) |
| { |
| if (!ptr) |
| { |
| throw InvalidArgumentException(descName + ": Invalid null pointer. The " + |
| paramName + " parameter must be set."); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorShapesMatch(const TensorInfo& first, |
| const TensorInfo& second, |
| std::string const& descName, |
| std::string const& firstName, |
| std::string const& secondName) |
| { |
| if (first.GetShape() != second.GetShape()) |
| { |
| throw InvalidArgumentException(descName + ": " |
| + firstName + " & " + secondName + " must have identical shapes"); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateNumInputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize) |
| { |
| if (workloadInfo.m_InputTensorInfos.size() != expectedSize) |
| { |
| throw InvalidArgumentException(descName + |
| ": Requires exactly " + to_string(expectedSize) + "input(s). " + |
| to_string(workloadInfo.m_InputTensorInfos.size()) + " have been provided."); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateNumOutputs(const WorkloadInfo& workloadInfo, std::string const& descName, const unsigned int expectedSize) |
| { |
| if (workloadInfo.m_OutputTensorInfos.size() != expectedSize) |
| { |
| throw InvalidArgumentException(descName + |
| ": Requires exactly " + to_string(expectedSize) + " output(s). " + |
| to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided."); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorNumDimensions(const TensorInfo& tensor, |
| std::string const& descName, |
| unsigned int numDimensions, |
| std::string const& tensorName) |
| { |
| if (tensor.GetNumDimensions() != numDimensions) |
| { |
| throw InvalidArgumentException(descName + ": Expected " + to_string(numDimensions) + " but got " + |
| to_string(tensor.GetNumDimensions()) + " dimensions for " + |
| tensorName + " tensor."); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorNumElements(const TensorInfo& tensor, |
| std::string const& descName, |
| unsigned int numElements, |
| std::string const& tensorName) |
| { |
| if (tensor.GetNumElements() != numElements) |
| { |
| throw InvalidArgumentException(descName + ": Expected " + to_string(numElements) + " but got " + |
| to_string(tensor.GetNumElements()) + " elements for " + |
| tensorName + " tensor."); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorNumDimNumElem(const TensorInfo& tensorInfo, |
| unsigned int numDimension, |
| unsigned int numElements, |
| std::string const& tensorName) |
| { |
| const std::string functionName{"ValidateTensorNumDimNumElem"}; |
| ValidateTensorNumDimensions(tensorInfo, functionName, numDimension, tensorName); |
| ValidateTensorNumElements(tensorInfo, functionName, numElements, tensorName); |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorDataType(const TensorInfo& tensor, DataType dataType, |
| const std::string& descName, std::string const& tensorName) |
| { |
| if (tensor.GetDataType() != dataType) |
| { |
| throw InvalidArgumentException(descName + ": Expected data type " + GetDataTypeName(dataType) + " but got " + |
| GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor."); |
| } |
| } |
| |
| void ValidPerAxisQuantizedDataType(const TensorInfo& tensor, const std::string& descName, const std::string& tensorName) |
| { |
| ARMNN_NO_DEPRECATE_WARN_BEGIN |
| if (tensor.GetDataType() != DataType::QSymmS8 && |
| tensor.GetDataType() != DataType::QuantizedSymm8PerAxis) |
| { |
| throw InvalidArgumentException(descName + |
| ": Expected data type which supports per-axis quantization scheme but got " + |
| GetDataTypeName(tensor.GetDataType()) + " for " + tensorName + " tensor."); |
| } |
| ARMNN_NO_DEPRECATE_WARN_END |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorQuantizationSpace(const TensorInfo& first, |
| const TensorInfo& second, |
| const std::string& descName, |
| std::string const& firstName, |
| std::string const& secondName) |
| { |
| if (!first.IsQuantized() || |
| !second.IsQuantized()) |
| { |
| // Not a quantized type, ignore the validation |
| return; |
| } |
| |
| DataType firstDataType = first.GetDataType(); |
| DataType secondDataType = second.GetDataType(); |
| |
| if (firstDataType != secondDataType) |
| { |
| throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName + |
| " must be of the same quantized type, " + |
| firstName + " is " + GetDataTypeName(firstDataType) + ", " + |
| secondName + " is " + GetDataTypeName(secondDataType)); |
| } |
| |
| if (!first.IsTypeSpaceMatch(second)) |
| { |
| throw InvalidArgumentException(descName + ": " + firstName + " and " + secondName + |
| " must have the same quantization space, " + |
| firstName + " has offset " + to_string(first.GetQuantizationOffset()) + |
| " and scale " + to_string(first.GetQuantizationScale()) + ", " + |
| secondName + " has offset " + to_string(second.GetQuantizationOffset()) + |
| " and scale " + to_string(second.GetQuantizationScale())); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateBiasTensorQuantization(const TensorInfo& biasTensor, |
| const TensorInfo& inputTensorInfo, |
| const TensorInfo& weightsTensorInfo, |
| const std::string& descName) |
| { |
| // Helper lambda function to validate a single bias quantization scale value |
| auto VerifyBiasQuantizationScale = [&descName](float biasScale, float expectedScale) -> void |
| { |
| constexpr float tolerance = 0.0001f; |
| if (std::abs(biasScale - expectedScale) > tolerance) |
| { |
| // Print the float values with extra precision to see very small differences |
| ARMNN_LOG(warning) << std::setprecision(6) << descName << ": Expected " << expectedScale << |
| " for bias quantization scale (product of input and weight scales), but got " << |
| biasScale << ". Using scale provided."; |
| } |
| }; |
| |
| if (biasTensor.GetQuantizationOffset() != 0) |
| { |
| throw InvalidArgumentException(descName + ": Expected zero quantization offset for bias tensor but got " + |
| to_string(biasTensor.GetQuantizationOffset())); |
| } |
| |
| if (biasTensor.HasMultipleQuantizationScales() || weightsTensorInfo.HasMultipleQuantizationScales()) |
| { |
| // Validate per-axis quantization scales |
| const std::vector<float>& weightScales = weightsTensorInfo.GetQuantizationScales(); |
| const std::vector<float>& biasScales = biasTensor.GetQuantizationScales(); |
| |
| if (weightScales.size() != biasScales.size()) |
| { |
| std::stringstream msg; |
| msg << descName << ": Expected matching number of per-axis quantization scales for weights and bias, " |
| << "but got different values. This is currently unsupported: weights=" << weightScales.size() |
| << ", biases=" << biasScales.size(); |
| throw InvalidArgumentException(msg.str(), CHECK_LOCATION()); |
| } |
| |
| for (size_t i = 0ul; i < biasScales.size(); ++i) |
| { |
| const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightScales[i]; |
| VerifyBiasQuantizationScale(biasScales[i], expectedScale); |
| } |
| } |
| else |
| { |
| // Validate per-tensor quantization scale |
| const float expectedScale = inputTensorInfo.GetQuantizationScale() * weightsTensorInfo.GetQuantizationScale(); |
| VerifyBiasQuantizationScale(biasTensor.GetQuantizationScale(), expectedScale); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensors(const std::vector<ITensorHandle*>& vec, |
| unsigned int numExpected, |
| const std::string& descName, |
| const std::string& varName) |
| { |
| if (vec.empty() && numExpected > 0) |
| { |
| throw InvalidArgumentException(descName + ": Invalid empty " + varName + " array."); |
| } |
| |
| for (unsigned int i = 0; i < numExpected; ++i) |
| { |
| if (!vec[i]) |
| { |
| throw InvalidArgumentException(descName + ": Invalid NULL for " + varName + to_string(i)); |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateBroadcastTensorShapesMatch(const TensorInfo& first, |
| const TensorInfo& second, |
| const TensorInfo& output, |
| std::string const& descName, |
| std::string const& firstName, |
| std::string const& secondName) |
| { |
| // Tensors must have the same number of dimensions in order to be explicit about which dimensions will get |
| // broadcasted. |
| if (first.GetNumDimensions() != second.GetNumDimensions()) |
| { |
| throw InvalidArgumentException(descName + ": Tensors " |
| + firstName + " & " + secondName |
| + " must have the same number of dimensions in order to be broadcasted"); |
| } |
| uint32_t numDims = first.GetNumDimensions(); |
| std::vector<uint32_t> outputDims(numDims, 0u); |
| for (uint32_t i = 0; i < numDims; i++) |
| { |
| const bool dimsNotEqual = first.GetShape()[i] != second.GetShape()[i]; |
| const bool dimsNotOne = (first.GetShape()[i] != 1) && (second.GetShape()[i] != 1); |
| if (dimsNotEqual && dimsNotOne) |
| { |
| throw InvalidArgumentException("Broadcasting is not possible for incompatible shapes"); |
| } |
| outputDims[i] = std::max(first.GetShape()[i], second.GetShape()[i]); |
| } |
| TensorShape broadcastShape = TensorShape(armnn::numeric_cast<unsigned int>(outputDims.size()), outputDims.data()); |
| if (broadcastShape != output.GetShape()) |
| { |
| throw InvalidArgumentException(descName + ": The tensor shape resulting from adding " |
| + firstName + " & " + secondName |
| + " does not match the output shape"); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateDataTypes(const TensorInfo& info, |
| const std::vector<armnn::DataType>& supportedTypes, |
| std::string const& descName) |
| { |
| auto iterator = std::find(supportedTypes.begin(), supportedTypes.end(), info.GetDataType()); |
| if (iterator == supportedTypes.end()) |
| { |
| throw InvalidArgumentException(descName + ": " + " Tensor type is not supported."); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorDataTypesMatch(const TensorInfo& first, |
| const TensorInfo& second, |
| std::string const& descName, |
| std::string const& firstName, |
| std::string const& secondName) |
| { |
| if (first.GetDataType() != second.GetDataType()) |
| { |
| throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName + |
| " must have identical data types."); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ValidateTensorNumElementsMatch(const TensorInfo& first, |
| const TensorInfo& second, |
| std::string const& descName, |
| std::string const& firstName, |
| std::string const& secondName) |
| { |
| if (first.GetNumElements() != second.GetNumElements()) |
| { |
| throw InvalidArgumentException(descName + ": " + firstName + " & " + secondName + |
| " must have the same number of elements."); |
| } |
| } |
| |
| void ValidateWeightDataType(const TensorInfo& inputInfo, |
| const TensorInfo& weightInfo, |
| const std::string& descName) |
| { |
| const DataType inputType = inputInfo.GetDataType(); |
| if (IsQuantized8BitType(inputType)) |
| { |
| ARMNN_NO_DEPRECATE_WARN_BEGIN |
| const std::vector<DataType> validTypes = |
| { |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS8, |
| DataType::QuantizedSymm8PerAxis // deprecated |
| }; |
| ARMNN_NO_DEPRECATE_WARN_END |
| |
| ValidateDataTypes(weightInfo, validTypes, descName); |
| } |
| else |
| { |
| ValidateTensorDataTypesMatch(inputInfo, weightInfo, descName, "input", "weight"); |
| } |
| } |
| |
| void ValidatePerAxisQuantizationDimension(const TensorInfo& tensorInfo, |
| const std::string& descName, |
| const std::string& tensorName) |
| { |
| const Optional<unsigned int>& quantizationDim = tensorInfo.GetQuantizationDim(); |
| if (!quantizationDim.has_value()) |
| { |
| throw InvalidArgumentException(fmt::format("{0}: Quantization dimension for per-axis quantization " |
| "not set on tensor {1}.", descName, tensorName)); |
| } |
| |
| if (quantizationDim.value() != 0) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "{0}: Quantization dimension for per-axis quantization expected to be 0 on tensor {1}, " |
| "but got: {2}", descName, tensorName, quantizationDim.value())); |
| } |
| } |
| |
| void ValidatePerAxisQuantizationOffset(const TensorInfo& tensorInfo, |
| const std::string& descName, |
| const std::string& tensorName) |
| { |
| int32_t quantizationOffset = tensorInfo.GetQuantizationOffset(); |
| if (quantizationOffset != 0) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "{0}: Quantization offset for per-axis quantization expected to be 0 on tensor {1}, but got: {2}", |
| descName, tensorName, quantizationOffset)); |
| } |
| } |
| |
| void ValidatePerAxisQuantization(const TensorInfo& inputInfo, |
| const TensorInfo& outputInfo, |
| const TensorInfo& weightInfo, |
| const Optional<TensorInfo>& optionalBiasInfo, |
| const std::string& descName) |
| { |
| if (weightInfo.HasPerAxisQuantization()) |
| { |
| const DataType inputDataType = inputInfo.GetDataType(); |
| const DataType outputDataType = outputInfo.GetDataType(); |
| |
| const bool canHavePerAxisQuantization = (IsQuantized8BitType(inputDataType)) && inputDataType == outputDataType; |
| |
| if (!canHavePerAxisQuantization) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "{0}: Per-axis quantization parameters set on tensor {1}, but data type does not support " |
| "per-axis quantization.", descName, "weight")); |
| } |
| |
| |
| ValidPerAxisQuantizedDataType(weightInfo, descName, "weight"); |
| ValidatePerAxisQuantizationDimension(weightInfo, descName, "weight"); |
| ValidatePerAxisQuantizationOffset(weightInfo, descName, "weight"); |
| |
| if (optionalBiasInfo.has_value()) |
| { |
| const TensorInfo& biasInfo = optionalBiasInfo.value(); |
| if (!biasInfo.HasPerAxisQuantization()) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "{}: Per-axis quantization parameters not set on bias tensor, " |
| "despite being set on weight tensor.", descName)); |
| } |
| |
| ValidateTensorDataType(biasInfo, DataType::Signed32, descName, "bias"); |
| ValidatePerAxisQuantizationDimension(biasInfo, descName, "bias"); |
| ValidatePerAxisQuantizationOffset(biasInfo, descName, "bias"); |
| } |
| } |
| } |
| |
| } // anonymous namespace |
| |
| void QueueDescriptor::ValidateInputsOutputs(const std::string& descName, |
| unsigned int numExpectedIn, unsigned int numExpectedOut) const |
| { |
| ValidateTensors(m_Inputs, numExpectedIn, descName, "input"); |
| ValidateTensors(m_Outputs, numExpectedOut, descName, "output"); |
| } |
| |
| //--------------------------------------------------------------- |
| void MapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"MapQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 0); |
| |
| for (unsigned int i = 0; i < m_Inputs.size(); ++i) |
| { |
| if (!m_Inputs[i]) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i))); |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void UnmapQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"UnmapQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 0); |
| |
| for (unsigned int i = 0; i < m_Inputs.size(); ++i) |
| { |
| if (!m_Inputs[i]) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: Invalid NULL input {}.", descriptorName, static_cast<int>(i))); |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void MemCopyQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"MemCopyQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName , 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| if (m_Inputs.size() != m_Outputs.size()) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "{0}: Number of inputs ({1}) does not match the number of outputs ({2}).", |
| descriptorName, m_Inputs.size(), m_Outputs.size())); |
| } |
| |
| for (unsigned int i = 0; i < m_Inputs.size(); ++i) |
| { |
| if (!m_Inputs[i]) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "{0}: Invalid NULL input {1}.", descriptorName, i)); |
| } |
| |
| if (!m_Outputs[i]) |
| { |
| throw InvalidArgumentException(fmt::format("{0}: Invalid NULL output {1}", descriptorName, i)); |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void MemImportQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| ValidateNumInputs(workloadInfo, "MemImportQueueDescriptor", 1); |
| ValidateNumOutputs(workloadInfo, "MemImportQueueDescriptor" , 1); |
| |
| if (workloadInfo.m_InputTensorInfos.size() != 1) |
| { |
| throw InvalidArgumentException(fmt::format("Number of input infos ({}) is not 1.", |
| workloadInfo.m_InputTensorInfos.size())); |
| |
| } |
| |
| if (workloadInfo.m_InputTensorInfos.size() != workloadInfo.m_OutputTensorInfos.size()) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "Number of input infos ({0}) does not match the number of output infos ({1})", |
| workloadInfo.m_InputTensorInfos.size(), workloadInfo.m_OutputTensorInfos.size())); |
| } |
| |
| for (std::size_t i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i) |
| { |
| if (workloadInfo.m_InputTensorInfos[i].GetNumElements() != |
| workloadInfo.m_OutputTensorInfos[i].GetNumElements()) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "Number of elements for tensor input and output {} does not match", i )); |
| } |
| } |
| |
| if (m_Inputs.size() != 1) |
| { |
| throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size())); |
| } |
| |
| if (m_Inputs.size() != m_Outputs.size()) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "Number of inputs ({0}) does not match the number of outputs ({1})", |
| m_Inputs.size(), m_Outputs.size())); |
| } |
| |
| for (unsigned int i = 0; i < m_Inputs.size(); ++i) |
| { |
| if (!m_Inputs[i]) |
| { |
| throw InvalidArgumentException(fmt::format("Invalid null input {}", i)); |
| } |
| |
| if (!m_Outputs[i]) |
| { |
| throw InvalidArgumentException(fmt::format("Invalid null output {}", i)); |
| } |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void MemSyncQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| ValidateNumInputs(workloadInfo, "MemSyncQueueDescriptor", 1); |
| ValidateNumOutputs(workloadInfo, "MemSyncQueueDescriptor" , 1); |
| |
| if (m_Inputs.size() != 1) |
| { |
| throw InvalidArgumentException(fmt::format("Number of inputs ({}) is not 1.", m_Inputs.size())); |
| } |
| |
| if (m_Outputs.size() != 0) |
| { |
| throw InvalidArgumentException(fmt::format("Number of outputs ({}) is not 0.", m_Outputs.size())); |
| } |
| |
| if (!m_Inputs[0]) |
| { |
| throw InvalidArgumentException(fmt::format("Invalid null input 0")); |
| } |
| } |
| |
| //--------------------------------------------------------------- |
| void ActivationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ActivationQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void ArgMinMaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ArgMinMaxQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (outputTensorInfo.GetDataType() != DataType::Signed32 && |
| outputTensorInfo.GetDataType() != DataType::Signed64) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output of ArgMinMax layer must be Int32 or Int64."); |
| } |
| |
| std::vector<DataType> supportedInputTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32, |
| DataType::Signed64 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedInputTypes, descriptorName); |
| |
| auto inputShape = inputTensorInfo.GetShape(); |
| auto outputShape = outputTensorInfo.GetShape(); |
| |
| auto inputNumDimensions = inputShape.GetNumDimensions(); |
| auto unsignedAxis = armnnUtils::GetUnsignedAxis(inputNumDimensions, m_Parameters.m_Axis); |
| |
| const std::string outputShapeError{": Output tensor shape does not match shape inferred from input tensor."}; |
| |
| // 1D input shape results in scalar output shape |
| if (inputShape.GetNumDimensions() == 1) |
| { |
| if (outputShape.GetNumDimensions() != 1 && outputShape[0] != 1) |
| { |
| throw InvalidArgumentException(descriptorName + outputShapeError); |
| } |
| } |
| else |
| { |
| for (unsigned int i = 0; i < unsignedAxis; ++i) |
| { |
| if (outputShape[i] != inputShape[i]) |
| { |
| throw InvalidArgumentException(descriptorName + outputShapeError); |
| } |
| } |
| |
| for (auto i = unsignedAxis + 1; i < inputNumDimensions; ++i) |
| { |
| if (outputShape[i - 1] != inputShape[i]) |
| { |
| throw InvalidArgumentException(descriptorName + outputShapeError); |
| } |
| } |
| } |
| } |
| |
| void CastQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"CastQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS8, |
| DataType::QSymmS16, |
| DataType::Signed32, |
| DataType::Signed64 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void SoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"SoftmaxQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void SplitterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"SplitterQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::Boolean, |
| DataType::Signed32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| for (unsigned long i = 0ul; i < workloadInfo.m_OutputTensorInfos.size(); ++i) |
| { |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[i]; |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| const std::string outputName = "output_" + std::to_string(i); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", outputName); |
| } |
| |
| if (workloadInfo.m_OutputTensorInfos.size() <= 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided."); |
| } |
| |
| if (workloadInfo.m_OutputTensorInfos.size() != m_ViewOrigins.size()) |
| { |
| throw InvalidArgumentException( |
| descriptorName + ": Number of split windows " |
| "has to match number of workloadInfo.m_OutputTensorInfos. " |
| "Number of windows: " + |
| to_string(m_ViewOrigins.size()) + |
| ". Number of workloadInfo.m_OutputTensorInfos: " + to_string(workloadInfo.m_OutputTensorInfos.size())); |
| } |
| |
| //The dimensionality of all the windows has to match the dimensionality (not shape) of the input. |
| std::size_t inputDims = workloadInfo.m_InputTensorInfos[0].GetNumDimensions(); |
| for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w ) |
| { |
| //Checks that the dimensionality of input is same as the split windows. |
| ViewOrigin const& e = m_ViewOrigins[w]; |
| if (e.m_Origin.size() != inputDims) |
| { |
| throw InvalidArgumentException(descriptorName + ": Window origin have to " |
| "have the same dimensionality as the input tensor. " |
| "Window origin (index: " + |
| to_string(w) + ") has " + to_string(e.m_Origin.size()) + |
| " dimensions, the input " |
| "tensor has " + |
| to_string(inputDims) + " dimensions."); |
| } |
| for (unsigned int i = 0; i < e.m_Origin.size(); ++i) |
| { |
| if (e.m_Origin[i] + workloadInfo.m_OutputTensorInfos[w].GetShape()[i] > |
| workloadInfo.m_InputTensorInfos[0].GetShape()[i]) |
| { |
| throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to " |
| "be smaller or equal than the size of the input in that coord."); |
| } |
| } |
| } |
| } |
| |
| void ConcatQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ConcatQueueDescriptor"}; |
| |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| if (m_Inputs.size() <= 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": At least one input needs to be provided."); |
| } |
| if (m_Outputs.size() <= 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": At least one output needs to be provided."); |
| } |
| |
| if (workloadInfo.m_InputTensorInfos.size() <= 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": At least one TensorInfo input needs to be provided."); |
| } |
| if (workloadInfo.m_OutputTensorInfos.size() <= 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": At least one TensorInfo output needs to be provided."); |
| } |
| |
| if(m_Parameters.GetConcatAxis() > workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions()) |
| { |
| throw InvalidArgumentException(descriptorName + ": Invalid concatenation axis provided."); |
| } |
| |
| if (workloadInfo.m_InputTensorInfos[0].GetShape().GetNumDimensions() - m_Parameters.GetConcatAxis() == 1) |
| { |
| return; |
| } |
| |
| if (workloadInfo.m_InputTensorInfos.size() != m_ViewOrigins.size()) |
| { |
| throw InvalidArgumentException( |
| descriptorName + ": Number of split windows " |
| "has to match number of workloadInfo.m_InputTensorInfos. " |
| "Number of windows: " + |
| to_string(m_ViewOrigins.size()) + |
| ". Number of workloadInfo.m_InputTensorInfos: " + to_string(workloadInfo.m_InputTensorInfos.size())); |
| } |
| |
| //The dimensionality of all the windows has to match the dimensionality (not shape) of the output. |
| std::size_t outputDims = workloadInfo.m_OutputTensorInfos[0].GetNumDimensions(); |
| for(unsigned int w = 0; w < m_ViewOrigins.size(); ++w ) |
| { |
| //Checks that the dimensionality of output is same as the split windows. |
| ViewOrigin const& e = m_ViewOrigins[w]; |
| if (e.m_Origin.size() != outputDims) |
| { |
| throw InvalidArgumentException(descriptorName + ": Window origin have to " |
| "have the same dimensionality as the output tensor. " |
| "Window origin (index: " + |
| to_string(w) + ") has " + to_string(e.m_Origin.size()) + |
| " dimensions, the output " |
| "tensor has " + |
| to_string(outputDims) + " dimensions."); |
| } |
| //Checks that the merge windows are within the output tensor. |
| for (unsigned int i = 0; i < e.m_Origin.size(); ++i) |
| { |
| if (e.m_Origin[i] + workloadInfo.m_InputTensorInfos[w].GetShape()[i] |
| > workloadInfo.m_OutputTensorInfos[0].GetShape()[i]) |
| { |
| throw InvalidArgumentException(descriptorName + ": Window extent coordinates have to " |
| "be smaller or equal than the size of the output in that coord."); |
| } |
| } |
| } |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::Boolean, |
| DataType::Signed32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| for (unsigned long i = 0ul; i < workloadInfo.m_InputTensorInfos.size(); ++i) |
| { |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[i]; |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| |
| const std::string inputName = "input_" + std::to_string(i); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, inputName, "output"); |
| } |
| } |
| |
| void StackQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"StackQueueDescriptor"}; |
| |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| if (m_Parameters.m_NumInputs != workloadInfo.m_InputTensorInfos.size()) |
| { |
| throw InvalidArgumentException(descriptorName + ": Must have the defined number of input tensors."); |
| } |
| |
| // All inputs must have the same shape, which is defined in parameters |
| const TensorShape& inputShape = m_Parameters.m_InputShape; |
| for (unsigned int i = 0; i < workloadInfo.m_InputTensorInfos.size(); ++i) |
| { |
| if (workloadInfo.m_InputTensorInfos[i].GetShape() != inputShape) |
| { |
| throw InvalidArgumentException(descriptorName + ": All input tensor shapes must match the defined shape."); |
| } |
| } |
| |
| if (inputShape.GetNumDimensions() > 4) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor may have up to 4 dimensions."); |
| } |
| |
| // m_Axis is 0-based and may take values from 0 to the number of input dimensions (inclusive), |
| // since the output tensor has an additional dimension. |
| if (m_Parameters.m_Axis > inputShape.GetNumDimensions()) |
| { |
| throw InvalidArgumentException(descriptorName + ": Axis may not be greater " |
| "than the number of input dimensions."); |
| } |
| |
| // Output shape must be as inferred from the input shape |
| const TensorShape& outputShape = workloadInfo.m_OutputTensorInfos[0].GetShape(); |
| for (unsigned int i = 0; i < m_Parameters.m_Axis; ++i) |
| { |
| if (outputShape[i] != inputShape[i]) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor must " |
| "match shape inferred from input tensor."); |
| } |
| } |
| |
| if (outputShape[m_Parameters.m_Axis] != m_Parameters.m_NumInputs) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor must " |
| "match shape inferred from input tensor."); |
| } |
| |
| for (unsigned int i = m_Parameters.m_Axis + 1; i < inputShape.GetNumDimensions() + 1; ++i) |
| { |
| if (outputShape[i] != inputShape[i-1]) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor must " |
| "match shape inferred from input tensor."); |
| } |
| } |
| |
| if (outputShape.GetNumDimensions() > 5) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor may have up to 5 dimensions."); |
| } |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::Boolean, |
| DataType::Signed32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName); |
| |
| for (unsigned int i = 1ul; i < workloadInfo.m_InputTensorInfos.size(); ++i) |
| { |
| ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0], |
| workloadInfo.m_InputTensorInfos[i], |
| descriptorName, |
| "input_0", |
| "input_" + std::to_string(i)); |
| } |
| |
| ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0], |
| workloadInfo.m_OutputTensorInfos[0], |
| descriptorName, |
| "input_0", |
| "output"); |
| } |
| |
| void FillQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"FillQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 1, "input"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| } |
| |
| void FullyConnectedQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"FullyConnectedQueueDescriptor"}; |
| |
| uint32_t numInputs = 1; |
| if (!m_Parameters.m_ConstantWeights) |
| { |
| numInputs = 2; |
| if (m_Parameters.m_BiasEnabled) |
| { |
| numInputs = 3; |
| } |
| } |
| ValidateNumInputs(workloadInfo, descriptorName, numInputs); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output"); |
| |
| if (!(inputTensorInfo.GetNumDimensions() == 2 || inputTensorInfo.GetNumDimensions() == 4)) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor must have 2 or 4 dimensions."); |
| } |
| |
| TensorInfo weightTensorInfo; |
| if (m_Parameters.m_ConstantWeights) |
| { |
| ValidatePointer(m_Weight, descriptorName, "weight"); |
| weightTensorInfo = m_Weight->GetTensorInfo(); |
| } |
| else |
| { |
| weightTensorInfo = workloadInfo.m_InputTensorInfos[1]; |
| } |
| ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 2, "weight"); |
| |
| if (m_Parameters.m_BiasEnabled) |
| { |
| TensorInfo biasTensorInfo; |
| if (m_Parameters.m_ConstantWeights) |
| { |
| ValidatePointer(m_Bias, descriptorName, "bias"); |
| biasTensorInfo = m_Bias->GetTensorInfo(); |
| } |
| else |
| { |
| biasTensorInfo = workloadInfo.m_InputTensorInfos[2]; |
| } |
| // Validates type and quantization values. |
| ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName); |
| ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias"); |
| ValidateTensorNumDimensions(biasTensorInfo, descriptorName, 1, "bias"); |
| } |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| |
| // For FullyConnected, we allow to have BFloat16 input with Float32 output for optimization. |
| if (inputTensorInfo.GetDataType() == DataType::BFloat16) |
| { |
| if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32) |
| { |
| throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 " |
| "for BFloat16 input."); |
| } |
| } |
| else |
| { |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| } |
| |
| void NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"NormalizationQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void AdditionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"AdditionQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1"); |
| ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output"); |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| } |
| |
| void MultiplicationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"MultiplicationQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1"); |
| ValidateTensorDataTypesMatch(inputTensorInfo1, outputTensorInfo, descriptorName, "input_1", "output"); |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| } |
| |
| void BatchNormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"BatchNormalizationQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| ValidatePointer(m_Mean, descriptorName, "mean"); |
| ValidatePointer(m_Variance, descriptorName, "variance"); |
| ValidatePointer(m_Beta, descriptorName, "beta"); |
| ValidatePointer(m_Gamma, descriptorName, "gamma"); |
| |
| const TensorInfo& mean = m_Mean->GetTensorInfo(); |
| const TensorInfo& variance = m_Variance->GetTensorInfo(); |
| const TensorInfo& beta = m_Beta->GetTensorInfo(); |
| const TensorInfo& gamma = m_Gamma->GetTensorInfo(); |
| |
| ValidateTensorNumDimensions(mean, descriptorName, 1, "mean"); |
| ValidateTensorNumDimensions(variance, descriptorName, 1, "variance"); |
| ValidateTensorNumDimensions(beta, descriptorName, 1, "beta"); |
| ValidateTensorNumDimensions(gamma, descriptorName, 1, "gamma"); |
| |
| ValidateTensorShapesMatch(mean, variance, descriptorName, "mean", "variance"); |
| ValidateTensorShapesMatch(mean, beta, descriptorName, "mean", "beta"); |
| ValidateTensorShapesMatch(mean, gamma, descriptorName, "mean", "gamma"); |
| } |
| |
| void Convolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"Convolution2dQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| ValidatePointer(m_Weight, descriptorName, "weight"); |
| |
| const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo(); |
| ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight"); |
| |
| ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName); |
| |
| Optional<TensorInfo> optionalBiasTensorInfo; |
| if (m_Parameters.m_BiasEnabled) |
| { |
| ValidatePointer(m_Bias, descriptorName, "bias"); |
| |
| optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo()); |
| const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value(); |
| |
| ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias"); |
| ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName); |
| } |
| |
| if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 ) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: strideX (provided {}) and strideY (provided {}) " |
| "cannot be either negative or 0.", |
| descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY)); |
| } |
| |
| ValidatePerAxisQuantization(inputTensorInfo, |
| outputTensorInfo, |
| weightTensorInfo, |
| optionalBiasTensorInfo, |
| descriptorName); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::QSymmS8 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| |
| // For Convolution2d, we allow to have BFloat16 input with Float32 output for optimization. |
| if (inputTensorInfo.GetDataType() == DataType::BFloat16) |
| { |
| if (outputTensorInfo.GetDataType() != DataType::BFloat16 && outputTensorInfo.GetDataType() != DataType::Float32) |
| { |
| throw InvalidArgumentException(descriptorName + ": " + " Output tensor type must be BFloat16 or Float32 " |
| "for BFloat16 input."); |
| } |
| } |
| else |
| { |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| } |
| |
| void DepthwiseConvolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"DepthwiseConvolution2dQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| ValidatePointer(m_Weight, descriptorName, "weight"); |
| |
| const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo(); |
| ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight"); |
| |
| if (m_Parameters.m_DilationX < 1 || m_Parameters.m_DilationY < 1 ) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: dilationX (provided {}) and dilationY (provided {}) " |
| "cannot be smaller than 1.", |
| descriptorName, m_Parameters.m_DilationX, m_Parameters.m_DilationX)); |
| } |
| |
| if (m_Parameters.m_StrideX <= 0 || m_Parameters.m_StrideY <= 0 ) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: strideX (provided {}) and strideY (provided {}) " |
| "cannot be either negative or 0.", |
| descriptorName, m_Parameters.m_StrideX, m_Parameters.m_StrideY)); |
| } |
| |
| const unsigned int channelIndex = (m_Parameters.m_DataLayout == DataLayout::NCHW) ? 1 : 3; |
| |
| // Expected weight shape: [ M, I, H, W ] - This shape does NOT depend on the data layout |
| // inputChannels * channelMultiplier should be equal to outputChannels. |
| const unsigned int numWeightChannelMultiplier = weightTensorInfo.GetShape()[0]; |
| const unsigned int numWeightInputChannels = weightTensorInfo.GetShape()[1]; |
| const unsigned int numWeightOutputChannels = outputTensorInfo.GetShape()[channelIndex]; |
| if (numWeightChannelMultiplier * numWeightInputChannels != numWeightOutputChannels) |
| { |
| throw InvalidArgumentException(fmt::format( |
| "{0}: output_channels (provided {1}) should be equal to input_channels (provided {2}) " |
| "multiplied by channel_multiplier (provided {3}).", |
| descriptorName, numWeightOutputChannels, numWeightInputChannels, numWeightChannelMultiplier)); |
| } |
| |
| ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName); |
| |
| Optional<TensorInfo> optionalBiasTensorInfo; |
| if (m_Parameters.m_BiasEnabled) |
| { |
| ValidatePointer(m_Bias, descriptorName, "bias"); |
| |
| optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo()); |
| const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value(); |
| |
| ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName); |
| ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias"); |
| } |
| ValidatePerAxisQuantization(inputTensorInfo, |
| outputTensorInfo, |
| weightTensorInfo, |
| optionalBiasTensorInfo, |
| descriptorName); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void PermuteQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"PermuteQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const PermutationVector& mapping = m_Parameters.m_DimMappings; |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output"); |
| |
| for (unsigned int i = 0u; i < mapping.GetSize(); ++i) |
| { |
| if (inputTensorInfo.GetShape()[i] != outputTensorInfo.GetShape()[mapping[i]]) |
| { |
| throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(i) + |
| " (=" + to_string(inputTensorInfo.GetShape()[i]) + ") " + |
| "must match dst dimension " + to_string(mapping[i]) + |
| " (=" + to_string(outputTensorInfo.GetShape()[mapping[i]]) + ")"); |
| } |
| } |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void Pooling2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"Pooling2dQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void ResizeBilinearQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ResizeBilinearQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| // ResizeBilinear only changes width and height: batch and channel count must match. |
| const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0]; |
| const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0]; |
| if (inputBatchSize != outputBatchSize) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: Input batch size ({}) does not match output batch size ({})", |
| descriptorName, inputBatchSize, outputBatchSize)); |
| } |
| |
| DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout); |
| const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()]; |
| const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()]; |
| if (inputChannelCount != outputChannelCount) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: Input channel count ({}) does not match output channel count ({})", |
| descriptorName, inputChannelCount, outputChannelCount)); |
| } |
| } |
| |
| void ResizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ResizeQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| // Resize only changes width and height: batch and channel count must match. |
| const unsigned int inputBatchSize = inputTensorInfo.GetShape()[0]; |
| const unsigned int outputBatchSize = outputTensorInfo.GetShape()[0]; |
| if (inputBatchSize != outputBatchSize) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: Input batch size ({}) does not match output batch size ({})", |
| descriptorName, inputBatchSize, outputBatchSize)); |
| } |
| |
| DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout); |
| const unsigned int inputChannelCount = inputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()]; |
| const unsigned int outputChannelCount = outputTensorInfo.GetShape()[dimensionIndices.GetChannelsIndex()]; |
| if (inputChannelCount != outputChannelCount) |
| { |
| throw InvalidArgumentException( |
| fmt::format("{}: Input channel count ({}) does not match output channel count ({})", |
| descriptorName, inputChannelCount, outputChannelCount)); |
| } |
| } |
| |
| void FakeQuantizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"FakeQuantizationQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 2, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 2, "output"); |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| if (m_Parameters.m_Min > m_Parameters.m_Max) |
| { |
| throw InvalidArgumentException(descriptorName + ": min cannot be greater than max"); |
| } |
| } |
| |
| void InstanceNormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"InstanceNormalizationQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (inputTensorInfo.GetNumDimensions() > 4) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported."); |
| } |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void L2NormalizationQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"L2NormalizationQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (inputTensorInfo.GetNumDimensions() > 4) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported."); |
| } |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void LogSoftmaxQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"LogSoftmaxQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void ConstantQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ConstantQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 0); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| if (!m_LayerOutput) |
| { |
| throw InvalidArgumentException(descriptorName + ": No const input specified."); |
| } |
| |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| ValidateTensorShapesMatch(m_LayerOutput->GetTensorInfo(), outputTensorInfo, descriptorName, "constant", "output"); |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| } |
| |
| void ReshapeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ReshapeQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| // Check the supported data types |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32, |
| DataType::Boolean |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void SpaceToBatchNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"SpaceToBatchNdQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| if (m_Parameters.m_BlockShape.size() != 2) |
| { |
| throw InvalidArgumentException(descriptorName + ": Block Shape must contain 2 spatial dimensions."); |
| } |
| |
| if (m_Parameters.m_BlockShape.size() != m_Parameters.m_PadList.size()) |
| { |
| throw InvalidArgumentException(descriptorName + ": Pad List must contain the same number of " |
| "dimensions as Block Shape."); |
| } |
| |
| const TensorShape& inputShape = inputTensorInfo.GetShape(); |
| |
| std::pair<unsigned int, unsigned int> heightPad = m_Parameters.m_PadList[0]; |
| std::pair<unsigned int, unsigned int> widthPad = m_Parameters.m_PadList[1]; |
| |
| DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout); |
| |
| const unsigned int inputWidth = inputShape[dimensionIndices.GetWidthIndex()] + |
| widthPad.first + widthPad.second; |
| const unsigned int inputHeight = inputShape[dimensionIndices.GetHeightIndex()] + |
| heightPad.first + heightPad.second; |
| |
| const unsigned int numInputElements = inputShape[0] * inputHeight * inputWidth * |
| inputShape[dimensionIndices.GetChannelsIndex()]; |
| const unsigned int numOutputElements = outputTensorInfo.GetNumElements(); |
| |
| if (numOutputElements != numInputElements) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor has " + |
| to_string(numInputElements) + " after padding but output tensor has " + |
| to_string(numOutputElements) + " elements."); |
| } |
| |
| if (inputHeight % m_Parameters.m_BlockShape[0] != 0 || inputWidth % m_Parameters.m_BlockShape[1] != 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input shape after padding must be " |
| "divisible by Block Shape in all spatial dimensions"); |
| } |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void SpaceToDepthQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"SpaceToDepthQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorNumElementsMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| if (m_Parameters.m_BlockSize == 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": Block size cannot be 0."); |
| } |
| |
| DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout); |
| const unsigned int wIndex = dimensionIndices.GetWidthIndex(); |
| const unsigned int hIndex = dimensionIndices.GetHeightIndex(); |
| const unsigned int cIndex = dimensionIndices.GetChannelsIndex(); |
| |
| const TensorShape& inputShape = inputTensorInfo.GetShape(); |
| if (inputShape[hIndex] % m_Parameters.m_BlockSize != 0 || inputShape[wIndex] % m_Parameters.m_BlockSize != 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input shape must be divisible " |
| "by block size in all spatial dimensions"); |
| } |
| |
| const TensorShape& outputShape = outputTensorInfo.GetShape(); |
| if (outputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": The depth of the output tensor" |
| "must be divisible by the square of block size." ); |
| } |
| } |
| |
| void FloorQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"FloorQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| |
| if (inputTensorInfo != outputTensorInfo) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input and output tensor infos do not match."); |
| } |
| } |
| |
| void LstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| // ported from android/ml/nn/common/operations/LSTM.cpp CheckInputTensorDimensions() |
| |
| const std::string descriptorName{"LstmQueueDescriptor"}; |
| |
| // check dimensions of all inputs and outputs |
| if (workloadInfo.m_InputTensorInfos.size() != 3) |
| { |
| throw InvalidArgumentException(descriptorName + ": Invalid number of inputs."); |
| } |
| if (workloadInfo.m_OutputTensorInfos.size() != 4) |
| { |
| throw InvalidArgumentException(descriptorName + ": Invalid number of outputs."); |
| } |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QSymmS16 |
| }; |
| |
| // check for supported type of one input and match them with all the other input and output |
| ValidateDataTypes(workloadInfo.m_InputTensorInfos[0], supportedTypes, descriptorName); |
| |
| // type matches all other inputs |
| for (uint32_t i = 1u; i < workloadInfo.m_InputTensorInfos.size(); ++i) |
| { |
| ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0], |
| workloadInfo.m_InputTensorInfos[i], |
| descriptorName, |
| "input_0", |
| "input_" + std::to_string(i)); |
| } |
| // type matches all other outputs |
| for (uint32_t i = 0u; i < workloadInfo.m_OutputTensorInfos.size(); ++i) |
| { |
| ValidateTensorDataTypesMatch(workloadInfo.m_InputTensorInfos[0], |
| workloadInfo.m_OutputTensorInfos[i], |
| "LstmQueueDescriptor", |
| "input_0", |
| "output_" + std::to_string(i)); |
| } |
| |
| // Making sure clipping parameters have valid values. |
| // == 0 means no clipping |
| // > 0 means clipping |
| if (m_Parameters.m_ClippingThresCell < 0.0f) |
| { |
| throw InvalidArgumentException(descriptorName + ": negative cell clipping threshold is invalid"); |
| } |
| if (m_Parameters.m_ClippingThresProj < 0.0f) |
| { |
| throw InvalidArgumentException(descriptorName + ": negative projection clipping threshold is invalid"); |
| } |
| |
| |
| // Inferring batch size, number of outputs and number of cells from the inputs. |
| const uint32_t n_input = workloadInfo.m_InputTensorInfos[0].GetShape()[1]; |
| const uint32_t n_batch = workloadInfo.m_InputTensorInfos[0].GetShape()[0]; |
| ValidatePointer(m_InputToOutputWeights, "Null pointer check", "InputToOutputWeights"); |
| const uint32_t n_cell = m_InputToOutputWeights->GetShape()[0]; |
| ValidatePointer(m_RecurrentToOutputWeights, "Null pointer check", "RecurrentToOutputWeights"); |
| const uint32_t n_output = m_RecurrentToOutputWeights->GetShape()[1]; |
| |
| // input tensor |
| ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[0], 2, (n_batch * n_input), |
| descriptorName + " input_0"); |
| // outputStateInTensor |
| ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[1], 2, (n_batch * n_output), |
| descriptorName + " input_1"); |
| // outputStateInTensor |
| ValidateTensorNumDimNumElem(workloadInfo.m_InputTensorInfos[2], 2, (n_batch * n_cell), |
| descriptorName + " input_2"); |
| // scratchBufferTensor |
| unsigned int scratchBufferSize = m_Parameters.m_CifgEnabled ? n_cell * 3 : n_cell * 4; |
| ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[0], 2, (n_batch * scratchBufferSize), |
| descriptorName + " output_0"); |
| // outputStateOutTensor |
| ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[1], 2, (n_batch * n_output), |
| descriptorName + " output_1"); |
| // cellStateOutTensor |
| ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[2], 2, (n_batch * n_cell), |
| descriptorName + " output_2"); |
| // outputTensor |
| ValidateTensorNumDimNumElem(workloadInfo.m_OutputTensorInfos[3], 2, (n_batch * n_output), |
| descriptorName + " output_3"); |
| |
| |
| // check that dimensions of inputs/outputs and QueueDescriptor data match with each other |
| if ( m_InputToInputWeights ) |
| { |
| ValidateTensorNumDimNumElem(m_InputToInputWeights->GetTensorInfo(), 2, |
| (n_cell * n_input), "InputLayerNormWeights"); |
| } |
| |
| ValidatePointer(m_InputToForgetWeights, "Null pointer check", "InputToForgetWeights"); |
| ValidateTensorNumDimNumElem(m_InputToForgetWeights->GetTensorInfo(), 2, |
| (n_cell * n_input), "InputToForgetWeights"); |
| |
| ValidatePointer(m_InputToCellWeights, "Null pointer check", "InputToCellWeights"); |
| ValidateTensorNumDimNumElem(m_InputToCellWeights->GetTensorInfo(), 2, |
| (n_cell * n_input), "InputToCellWeights"); |
| |
| if ( m_RecurrentToInputWeights ) |
| { |
| ValidateTensorNumDimNumElem(m_RecurrentToInputWeights->GetTensorInfo(), 2, |
| (n_cell * n_output), "RecurrentToInputWeights"); |
| } |
| |
| ValidatePointer(m_RecurrentToForgetWeights, "Null pointer check", "RecurrentToForgetWeights"); |
| ValidateTensorNumDimNumElem(m_RecurrentToForgetWeights->GetTensorInfo(), 2, |
| (n_cell * n_output), "RecurrentToForgetWeights"); |
| |
| ValidatePointer(m_RecurrentToCellWeights, "Null pointer check", "RecurrentToCellWeights"); |
| ValidateTensorNumDimNumElem(m_RecurrentToCellWeights->GetTensorInfo(), 2, |
| (n_cell * n_output), "RecurrentToCellWeights"); |
| |
| // Make sure the input-gate's parameters are either both present (regular |
| // LSTM) or not at all (CIFG-LSTM). And CifgEnable is set accordingly. |
| bool cifg_weights_all_or_none = ((m_InputToInputWeights && m_RecurrentToInputWeights && |
| !m_Parameters.m_CifgEnabled) || |
| (!m_InputToInputWeights && !m_RecurrentToInputWeights && |
| m_Parameters.m_CifgEnabled)); |
| if (!cifg_weights_all_or_none) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input-Gate's parameters InputToInputWeights and " |
| "RecurrentToInputWeights must either both be present (regular LSTM) " |
| "or both not present (CIFG-LSTM). In addition CifgEnable must be set " |
| "accordingly."); |
| } |
| |
| if ( m_CellToInputWeights ) |
| { |
| ValidateTensorNumDimNumElem(m_CellToInputWeights->GetTensorInfo(), 1, |
| n_cell, "CellToInputWeights"); |
| } |
| if ( m_CellToForgetWeights ) |
| { |
| ValidateTensorNumDimNumElem(m_CellToForgetWeights->GetTensorInfo(), 1, |
| n_cell, "CellToForgetWeights"); |
| } |
| if ( m_CellToOutputWeights ) |
| { |
| ValidateTensorNumDimNumElem(m_CellToOutputWeights->GetTensorInfo(), 1, |
| n_cell, "CellToOutputWeights"); |
| } |
| |
| // Making sure the peephole weights are there all or none. And PeepholeEnable is set accordingly. |
| bool peephole_weights_all_or_none = |
| (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights |
| && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled) |
| || ( !m_CellToInputWeights && !m_CellToForgetWeights |
| && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled)); |
| if (!peephole_weights_all_or_none) |
| { |
| throw InvalidArgumentException(descriptorName + ": Invalid combination of peephole parameters."); |
| } |
| |
| // Make sure the input gate bias is present only when not a CIFG-LSTM. |
| if (m_Parameters.m_CifgEnabled) |
| { |
| if (m_InputGateBias) |
| { |
| throw InvalidArgumentException(descriptorName + ": InputGateBias is present and CIFG-LSTM is enabled."); |
| } |
| } |
| else |
| { |
| if (!m_InputGateBias) |
| { |
| throw InvalidArgumentException(descriptorName + ": If CIFG-LSTM is disabled InputGateBias " |
| "must be present."); |
| } |
| ValidateTensorNumDimNumElem(m_InputGateBias->GetTensorInfo(), 1, |
| n_cell, "InputGateBias"); |
| } |
| |
| ValidatePointer(m_ForgetGateBias, "Null pointer check", "ForgetGateBias"); |
| ValidateTensorNumDimNumElem(m_ForgetGateBias->GetTensorInfo(), 1, n_cell, "ForgetGateBias"); |
| |
| ValidatePointer(m_CellBias, "Null pointer check", "CellBias"); |
| ValidateTensorNumDimNumElem(m_CellBias->GetTensorInfo(), 1, n_cell, "CellBias"); |
| |
| ValidatePointer(m_OutputGateBias, "Null pointer check", "OutputGateBias"); |
| ValidateTensorNumDimNumElem(m_OutputGateBias->GetTensorInfo(), 1, n_cell, "OutputGateBias"); |
| |
| if (m_ProjectionWeights) |
| { |
| ValidateTensorNumDimNumElem(m_ProjectionWeights->GetTensorInfo(), 2, |
| (n_cell * n_output), "ProjectionWeights"); |
| } |
| if (m_ProjectionBias) |
| { |
| ValidateTensorNumDimNumElem(m_ProjectionBias->GetTensorInfo(), 1, n_output, "ProjectionBias"); |
| } |
| |
| // Making sure the projection tensors are consistent: |
| // 1) If projection weight is not present, then projection bias should not be |
| // present. |
| // 2) If projection weight is present, then projection bias is optional. |
| bool projecton_tensors_consistent = ((!m_ProjectionWeights && !m_ProjectionBias && |
| !m_Parameters.m_ProjectionEnabled) |
| || (m_ProjectionWeights && !m_ProjectionBias && |
| m_Parameters.m_ProjectionEnabled) |
| || (m_ProjectionWeights && m_ProjectionBias && |
| m_Parameters.m_ProjectionEnabled)); |
| if (!projecton_tensors_consistent) |
| { |
| throw InvalidArgumentException(descriptorName + ": Projection tensors are inconsistent."); |
| } |
| |
| // The four layer normalization weights either all have values or none of them have values. Additionally, if |
| // CIFG is used, input layer normalization weights tensor is omitted and the other layer normalization weights |
| // either all have values or none of them have values. Layer normalization is used when the values of all the |
| // layer normalization weights are present |
| if (m_InputLayerNormWeights) |
| { |
| ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), 1, n_cell, "InputLayerNormWeights"); |
| } |
| if (m_ForgetLayerNormWeights) |
| { |
| ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights"); |
| } |
| if (m_CellLayerNormWeights) |
| { |
| ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights"); |
| } |
| if (m_OutputLayerNormWeights) |
| { |
| ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights"); |
| } |
| |
| if (m_Parameters.m_LayerNormEnabled) |
| { |
| if (!m_Parameters.m_CifgEnabled) |
| { |
| if (!m_InputLayerNormWeights) |
| { |
| throw InvalidArgumentException(descriptorName + ": Layer normalisation is enabled and CIFG-LSTM is " |
| "disabled but InputLayerNormWeights are not present"); |
| } |
| ValidateTensorNumDimNumElem(m_InputLayerNormWeights->GetTensorInfo(), |
| 1, n_cell, "InputLayerNormWeights"); |
| } |
| else if (m_InputLayerNormWeights) |
| { |
| throw InvalidArgumentException(descriptorName + ":InputLayerNormWeights are present while CIFG is " |
| "enabled"); |
| } |
| |
| ValidatePointer(m_ForgetLayerNormWeights, "Null pointer check layer normalisation enabled", |
| "ForgetLayerNormWeights"); |
| ValidateTensorNumDimNumElem(m_ForgetLayerNormWeights->GetTensorInfo(), 1, n_cell, "ForgetLayerNormWeights"); |
| |
| ValidatePointer(m_OutputLayerNormWeights, "Null pointer check layer normalisation enabled", |
| "OutputLayerNormWeights"); |
| ValidateTensorNumDimNumElem(m_OutputLayerNormWeights->GetTensorInfo(), 1, n_cell, "OutputLayerNormWeights"); |
| |
| ValidatePointer(m_CellLayerNormWeights, "Null pointer check layer normalisation enabled", |
| "CellLayerNormWeights"); |
| ValidateTensorNumDimNumElem(m_CellLayerNormWeights->GetTensorInfo(), 1, n_cell, "CellLayerNormWeights"); |
| } |
| else if (m_InputLayerNormWeights || m_ForgetLayerNormWeights || m_OutputLayerNormWeights || m_CellLayerNormWeights) |
| { |
| throw InvalidArgumentException(descriptorName + ": Layer normalisation is disabled but one or more layer " |
| "normalisation weights are present."); |
| } |
| } |
| |
| void ConvertBf16ToFp32QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ConvertBf16ToFp32QueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (inputTensorInfo.GetDataType() != DataType::BFloat16) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor type must be BFloat16."); |
| } |
| |
| if (outputTensorInfo.GetDataType() != DataType::Float32) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32."); |
| } |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void ConvertFp32ToBf16QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ConvertFp32ToBf16QueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (inputTensorInfo.GetDataType() != DataType::Float32) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32."); |
| } |
| |
| if (outputTensorInfo.GetDataType() != DataType::BFloat16) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be BFloat16."); |
| } |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void ConvertFp32ToFp16QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ConvertFp32ToFp16QueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (inputTensorInfo.GetDataType() != DataType::Float32) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float32."); |
| } |
| |
| if (outputTensorInfo.GetDataType() != DataType::Float16) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float16."); |
| } |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void ConvertFp16ToFp32QueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ConvertFp16ToFp32QueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (inputTensorInfo.GetDataType() != DataType::Float16) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor type must be Float16."); |
| } |
| |
| if (outputTensorInfo.GetDataType() != DataType::Float32) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be Float32."); |
| } |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void DivisionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"DivisionQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| } |
| |
| void SubtractionQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"SubtractionQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32, |
| }; |
| |
| ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| } |
| |
| void MaximumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"MaximumQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| } |
| |
| void MeanQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"MeanQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| // First check if input tensor data type is supported, then |
| // check if this data type matches the output tensor data type |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| if (m_Parameters.m_KeepDims) |
| { |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output"); |
| } |
| else if (m_Parameters.m_Axis.empty()) |
| { |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output"); |
| } |
| else |
| { |
| unsigned int outputDim = |
| inputTensorInfo.GetNumDimensions() - armnn::numeric_cast<unsigned int>(m_Parameters.m_Axis.size()); |
| ValidateTensorNumDimensions(outputTensorInfo, |
| descriptorName, |
| outputDim > 0 ? outputDim : 1, |
| "output"); |
| } |
| } |
| |
| void PadQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"PadQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| // input and output should have the same number of dimensions |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, inputTensorInfo.GetNumDimensions(), "output"); |
| |
| // there should be entry in the pad list for each dimension in the input tensor |
| if (m_Parameters.m_PadList.size() != inputTensorInfo.GetNumDimensions()) { |
| throw InvalidArgumentException(descriptorName + ":Pad List should contain the same number of entries " |
| "as there are dimensions in the input tensor that is " + |
| std::to_string(inputTensorInfo.GetNumDimensions()) + " entries " + |
| " not " + std::to_string(m_Parameters.m_PadList.size()) + " entries."); |
| } |
| } |
| |
| void QuantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"QuantizeQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QSymmS8, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| |
| if (!IsQuantizedType(outputTensorInfo.GetDataType())) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output of quantized layer must be quantized type."); |
| } |
| } |
| |
| void BatchToSpaceNdQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"BatchToSpaceNdQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void StridedSliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"StridedSliceQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| ValidateTensorQuantizationSpace(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| const uint32_t rank = inputTensorInfo.GetNumDimensions(); |
| if (rank > 4) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported."); |
| } |
| |
| // Begin, End & Stride length must be of rank(input0) |
| if (m_Parameters.m_Begin.size() != rank) |
| { |
| throw InvalidArgumentException(descriptorName + ": Begin length must be of rank " + std::to_string(rank)); |
| } |
| |
| if (m_Parameters.m_End.size() != rank) |
| { |
| throw InvalidArgumentException(descriptorName + ": End length must be of rank " + std::to_string(rank)); |
| } |
| |
| if (m_Parameters.m_Stride.size() != rank) |
| { |
| throw InvalidArgumentException(descriptorName + ": Stride length must be of rank " + std::to_string(rank)); |
| } |
| |
| // Stride entries must be non-zero |
| for (auto& stride : m_Parameters.m_Stride) |
| { |
| if (stride == 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": Stride entries must be non-zero."); |
| } |
| } |
| } |
| |
| void MinimumQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"MinimumQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| } |
| |
| void DebugQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"DebugQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| } |
| |
| void EqualQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"EqualQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| |
| if (outputTensorInfo.GetDataType() != DataType::Boolean) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean."); |
| } |
| } |
| |
| void GreaterQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"GreaterQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| |
| if (outputTensorInfo.GetDataType() != DataType::Boolean) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean."); |
| } |
| } |
| |
| void RsqrtQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"RsqrtQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void GatherQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"GatherQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& indicesTensorInfo = workloadInfo.m_InputTensorInfos[1]; |
| if (indicesTensorInfo.GetDataType() != DataType::Signed32) |
| { |
| throw InvalidArgumentException(descriptorName + ": Indices tensor type must be Int32."); |
| } |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32, |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| unsigned int outputDim = inputTensorInfo.GetNumDimensions() + indicesTensorInfo.GetNumDimensions() - 1; |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, outputDim, "output"); |
| } |
| |
| void DetectionPostProcessQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string& descriptorName{"DetectionPostProcessQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| |
| if (workloadInfo.m_OutputTensorInfos.size() != 4) |
| { |
| throw InvalidArgumentException(descriptorName + ": Requires exactly four outputs. " + |
| to_string(workloadInfo.m_OutputTensorInfos.size()) + " has been provided."); |
| } |
| |
| if (m_Anchors == nullptr) |
| { |
| throw InvalidArgumentException(descriptorName + ": Anchors tensor descriptor is missing."); |
| } |
| |
| const TensorInfo& boxEncodingsInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& scoresInfo = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& anchorsInfo = m_Anchors->GetTensorInfo(); |
| |
| const TensorInfo& detectionBoxesInfo = workloadInfo.m_OutputTensorInfos[0]; |
| const TensorInfo& detectionClassesInfo = workloadInfo.m_OutputTensorInfos[1]; |
| const TensorInfo& detectionScoresInfo = workloadInfo.m_OutputTensorInfos[2]; |
| const TensorInfo& numDetectionsInfo = workloadInfo.m_OutputTensorInfos[3]; |
| |
| ValidateTensorNumDimensions(boxEncodingsInfo, descriptorName, 3, "box encodings"); |
| ValidateTensorNumDimensions(scoresInfo, descriptorName, 3, "scores"); |
| ValidateTensorNumDimensions(anchorsInfo, descriptorName, 2, "anchors"); |
| |
| const std::vector<DataType> supportedInputTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(boxEncodingsInfo, supportedInputTypes, descriptorName); |
| ValidateDataTypes(scoresInfo, supportedInputTypes, descriptorName); |
| ValidateDataTypes(anchorsInfo, supportedInputTypes, descriptorName); |
| |
| ValidateTensorNumDimensions(detectionBoxesInfo, descriptorName, 3, "detection boxes"); |
| ValidateTensorNumDimensions(detectionScoresInfo, descriptorName, 2, "detection scores"); |
| ValidateTensorNumDimensions(detectionClassesInfo, descriptorName, 2, "detection classes"); |
| ValidateTensorNumDimensions(numDetectionsInfo, descriptorName, 1, "num detections"); |
| |
| // NOTE: Output is always Float32 regardless of input type |
| ValidateTensorDataType(detectionBoxesInfo, DataType::Float32, descriptorName, "detection boxes"); |
| ValidateTensorDataType(detectionScoresInfo, DataType::Float32, descriptorName, "detection scores"); |
| ValidateTensorDataType(detectionClassesInfo, DataType::Float32, descriptorName, "detection classes"); |
| ValidateTensorDataType(numDetectionsInfo, DataType::Float32, descriptorName, "num detections"); |
| |
| if (m_Parameters.m_NmsIouThreshold <= 0.0f || m_Parameters.m_NmsIouThreshold > 1.0f) |
| { |
| throw InvalidArgumentException(descriptorName + ": Intersection over union threshold " |
| "must be positive and less than or equal to 1."); |
| } |
| |
| if (scoresInfo.GetShape()[2] != m_Parameters.m_NumClasses + 1) |
| { |
| throw InvalidArgumentException(descriptorName + ": Number of classes with background " |
| "should be equal to number of classes + 1."); |
| } |
| } |
| |
| void DequantizeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string& descriptorName{"DequantizeQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| if (!IsQuantizedType(inputTensorInfo.GetDataType())) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input to dequantize layer must be quantized type."); |
| } |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16 |
| }; |
| |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| } |
| |
| void MergeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string& descriptorName{"MergeQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorShapesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1"); |
| ValidateTensorShapesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output"); |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo0, inputTensorInfo1, descriptorName, "input_0", "input_1"); |
| ValidateTensorDataTypesMatch(inputTensorInfo0, outputTensorInfo, descriptorName, "input_0", "output"); |
| } |
| |
| void SwitchQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string& descriptorName{"SwitchQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 2); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| |
| const TensorInfo& outputTensorInfo0 = workloadInfo.m_OutputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo1 = workloadInfo.m_OutputTensorInfos[1]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(inputTensorInfo1, supportedTypes, descriptorName); |
| |
| ValidateDataTypes(outputTensorInfo0, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo1, supportedTypes, descriptorName); |
| |
| ValidateTensorShapesMatch(inputTensorInfo0, |
| outputTensorInfo0, |
| descriptorName, |
| "input_0", |
| "output_0"); |
| |
| ValidateTensorShapesMatch(inputTensorInfo0, |
| outputTensorInfo1, |
| descriptorName, |
| "input_0", |
| "output_1"); |
| } |
| |
| void PreCompiledQueueDescriptor::Validate(const WorkloadInfo& /*workloadInfo*/) const |
| { |
| // This is internally generated so it should not need validation. |
| } |
| |
| void PreluQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string& descriptorName{"PreluQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& alphaTensorInfo = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateDataTypes(alphaTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateDataTypes(outputTensorInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, alphaTensorInfo, descriptorName, "input", "alpha"); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "ouptut"); |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo, |
| alphaTensorInfo, |
| outputTensorInfo, |
| descriptorName, |
| "input", |
| "alpha"); |
| } |
| |
| void TransposeConvolution2dQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"TransposeConvolution2dQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output"); |
| |
| ValidatePointer(m_Weight, descriptorName, "weight"); |
| |
| const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo(); |
| ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight"); |
| |
| ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName); |
| |
| Optional<TensorInfo> optionalBiasTensorInfo; |
| if (m_Parameters.m_BiasEnabled) |
| { |
| ValidatePointer(m_Bias, descriptorName, "bias"); |
| |
| optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo()); |
| const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value(); |
| |
| ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias"); |
| ValidateBiasTensorQuantization(biasTensorInfo, inputTensorInfo, weightTensorInfo, descriptorName); |
| } |
| |
| ValidatePerAxisQuantization(inputTensorInfo, |
| outputTensorInfo, |
| weightTensorInfo, |
| optionalBiasTensorInfo, |
| descriptorName); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void TransposeQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"TransposeQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const PermutationVector& mapping = m_Parameters.m_DimMappings; |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputTensorInfo, descriptorName, mapping.GetSize(), "input"); |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, mapping.GetSize(), "output"); |
| |
| for (unsigned int i = 0u; i < mapping.GetSize(); ++i) |
| { |
| if (inputTensorInfo.GetShape()[mapping[i]] != outputTensorInfo.GetShape()[i]) |
| { |
| throw InvalidArgumentException(descriptorName + ": src dimension " + to_string(mapping[i]) + |
| " (=" + to_string(inputTensorInfo.GetShape()[mapping[i]]) + ") " + |
| "must match dst dimension " + to_string(i) + |
| " (=" + to_string(outputTensorInfo.GetShape()[i]) + ")"); |
| } |
| } |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void QLstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"QLstmQueueDescriptor"}; |
| |
| // Validate number of inputs/outputs |
| ValidateNumInputs(workloadInfo, descriptorName, 3); |
| ValidateNumOutputs(workloadInfo, descriptorName, 3); |
| |
| // Input/output tensor info |
| auto inputInfo = workloadInfo.m_InputTensorInfos[0]; |
| auto outputStateInInfo = workloadInfo.m_InputTensorInfos[1]; |
| auto cellStateInInfo = workloadInfo.m_InputTensorInfos[2]; |
| |
| auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[0]; |
| auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[1]; |
| auto outputInfo = workloadInfo.m_OutputTensorInfos[2]; |
| |
| // Supported types for various tensors in QLSTM |
| std::vector<DataType> inputOutputSupportedTypes = |
| { |
| DataType::QAsymmS8 |
| }; |
| |
| std::vector<DataType> cellStateSupportedTypes = |
| { |
| DataType::QSymmS16 |
| }; |
| |
| std::vector<DataType> weightsSupportedTypes = |
| { |
| DataType::QSymmS8 |
| }; |
| |
| std::vector<DataType> layerNormPeepholeWeightsSupportedTypes = |
| { |
| DataType::QSymmS16 |
| }; |
| |
| std::vector<DataType> biasSupportedTypes = |
| { |
| DataType::Signed32 |
| }; |
| |
| // Validate types of input/output tensors |
| ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName); |
| ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName); |
| ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName); |
| |
| ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName); |
| ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName); |
| ValidateDataTypes(outputInfo, inputOutputSupportedTypes, descriptorName); |
| |
| // Validate matching types of input/output tensors |
| ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn"); |
| ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName, |
| "outputStateIn", "outputStateOut"); |
| ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut"); |
| |
| // Infer number of batches, number of units, input size and output size from tensor dimensions |
| const uint32_t numBatches = inputInfo.GetShape()[0]; |
| const uint32_t inputSize = inputInfo.GetShape()[1]; |
| const uint32_t outputSize = outputStateInInfo.GetShape()[1]; |
| const uint32_t numUnits = cellStateInInfo.GetShape()[1]; |
| |
| // Validate number of dimensions and number of elements for input/output tensors |
| ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input"); |
| ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn"); |
| ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * numUnits), descriptorName + " cellStateIn"); |
| |
| ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut"); |
| ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * numUnits), descriptorName + " cellStateOut"); |
| ValidateTensorNumDimNumElem(outputInfo, 2, (numBatches * outputSize), descriptorName + " output"); |
| |
| // Validate number of dimensions and number of elements for MANDATORY weight tensors |
| ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights"); |
| auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (numUnits * inputSize), " InputToForgetWeights"); |
| |
| ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights"); |
| auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (numUnits * inputSize), " InputToCellWeights"); |
| |
| ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights"); |
| auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (numUnits * inputSize), " InputToOutputWeights"); |
| |
| ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights"); |
| auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (numUnits * outputSize), |
| " RecurrentToForgetWeights"); |
| |
| ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights"); |
| auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights"); |
| |
| ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights"); |
| auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (numUnits * outputSize), " RecurrentToCellWeights"); |
| |
| // Validate data types for MANDATORY weights tensors (all should match each other) |
| ValidateDataTypes(inputToForgetWeightsInfo, weightsSupportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToCellWeightsInfo, descriptorName, |
| "inputToForgetWeights", "inputToCellWeights"); |
| ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToOutputWeightsInfo, descriptorName, |
| "inputToForgetWeights", "inputToOutputWeights"); |
| |
| ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToForgetWeightsInfo, descriptorName, |
| "inputToForgetWeights", "recurrentToForgeteights"); |
| ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToCellWeightsInfo, descriptorName, |
| "inputToForgetWeights", "recurrentToCellWeights"); |
| ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToOutputWeightsInfo, descriptorName, |
| "inputToForgetWeights", "recurrentToOutputWeights"); |
| |
| // Validate number of dimensions and number of elements for MANDATORY bias tensors |
| ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias"); |
| auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, numUnits, " ForgetGateBias"); |
| |
| ValidatePointer(m_CellBias, descriptorName, "CellBias"); |
| auto cellBiasInfo = m_CellBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(cellBiasInfo, 1, numUnits, " CellBias"); |
| |
| ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias"); |
| auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, numUnits, " OutputGateBias"); |
| |
| // Validate data types for MANDATORY bias tensors |
| ValidateDataTypes(forgetGateBiasInfo, biasSupportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(forgetGateBiasInfo, cellBiasInfo, descriptorName, |
| "forgetGateBias", "cellBias"); |
| ValidateTensorDataTypesMatch(forgetGateBiasInfo, outputGateBiasInfo, descriptorName, |
| "forgetGateBias", "outputGateBias"); |
| |
| // Validate OPTIONAL params: CIFG (inputToInputWeights, recurrentToInputWeights, inputGateBias) |
| const bool allCifgParamsPresentOrNot = ((m_InputToInputWeights && m_RecurrentToInputWeights && m_InputGateBias && |
| !m_Parameters.m_CifgEnabled) || |
| (!m_InputToInputWeights && !m_RecurrentToInputWeights && |
| !m_InputGateBias && m_Parameters.m_CifgEnabled)); |
| |
| if (!allCifgParamsPresentOrNot) |
| { |
| throw InvalidArgumentException(descriptorName + |
| ": InputToInputWeights, RecurrentToInputWeights and InputGateBias must either all be present " |
| "(CIFG disabled) or not be present at all (CIFG enabled). m_Parameters.m_CifgEnabled should be " |
| "set appropriately."); |
| } |
| |
| if (!m_Parameters.m_CifgEnabled) |
| { |
| // Validate number of dimensions and number of elements |
| auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (numUnits * inputSize), " InputToInputWeights"); |
| |
| auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (numUnits * outputSize), |
| " RecurrentToInputWeights"); |
| |
| auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, numUnits, " InputGateBias"); |
| |
| // Validate data types |
| ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, inputToInputWeightsInfo, descriptorName, |
| "inputToForgetWeights", "inputToInputWeights"); |
| ValidateTensorDataTypesMatch(inputToForgetWeightsInfo, recurrentToInputWeightsInfo, descriptorName, |
| "inputToForgetWeights", "recurrentToInputWeights"); |
| ValidateTensorDataTypesMatch(forgetGateBiasInfo, inputGateBiasInfo, descriptorName, |
| "forgetGateBias", "inputGateBias"); |
| } |
| |
| // Validate OPTIONAL params: Peephole (cellToInputWeights, cellToForgetWeights, cellToOutputWeights) |
| bool allPeepholeWeightsPresentOrNot = |
| (((m_CellToInputWeights || m_Parameters.m_CifgEnabled) && m_CellToForgetWeights |
| && m_CellToOutputWeights && m_Parameters.m_PeepholeEnabled) |
| || (!m_CellToInputWeights && !m_CellToForgetWeights |
| && !m_CellToOutputWeights && !m_Parameters.m_PeepholeEnabled)); |
| |
| if (!allPeepholeWeightsPresentOrNot) |
| { |
| throw InvalidArgumentException(descriptorName + |
| ": CellToInputWeights, CellToForgetWeights and CellToOutputWeights should all be present (Peephole " |
| "enabled) or not be present at all (Peephole disabled). CellToInputWeights should only be present " |
| "when Peephole is enabled and CIFG is disabled. m_Parameters.m_PeepholeEnabled should be set " |
| "appropriately."); |
| } |
| |
| if (m_Parameters.m_PeepholeEnabled) |
| { |
| auto cellToForgetWeightsInfo = m_CellToForgetWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(cellToForgetWeightsInfo, 1, numUnits, " cellToForgetWeights"); |
| ValidateDataTypes(cellToForgetWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName); |
| |
| auto cellToOutputWeightsInfo = m_CellToOutputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(cellToOutputWeightsInfo, 1, numUnits, " cellToOutputWeights"); |
| ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToOutputWeightsInfo, descriptorName, |
| "cellToForgetWeight", "cellToOutputWeights"); |
| |
| if (!m_Parameters.m_CifgEnabled) |
| { |
| auto cellToInputWeightsInfo = m_CellToInputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(cellToInputWeightsInfo, 1, numUnits, " cellToInputWeights"); |
| ValidateTensorDataTypesMatch(cellToForgetWeightsInfo, cellToInputWeightsInfo, descriptorName, |
| "cellToForgetWeights", "cellToInputWeights"); |
| } |
| } |
| |
| // Validate OPTIONAL params: Layer Norm Weights |
| bool allLayerNormWeightsPresentOrNot = |
| (((m_InputLayerNormWeights || m_Parameters.m_CifgEnabled) && m_ForgetLayerNormWeights |
| && m_CellLayerNormWeights && m_OutputLayerNormWeights && m_Parameters.m_LayerNormEnabled) |
| || (!m_InputLayerNormWeights && !m_ForgetLayerNormWeights && !m_CellLayerNormWeights |
| && !m_OutputLayerNormWeights && !m_Parameters.m_LayerNormEnabled)); |
| |
| if (!allLayerNormWeightsPresentOrNot) |
| { |
| throw InvalidArgumentException(descriptorName + |
| ": InputLayerNormWeights, ForgetLayerNormWeights, m_OutputLayerNormWeights " |
| "and CellLayerNormWeights should all be present (Layer Norm enabled) or not " |
| "be present at all (Layer Norm disabled). InputLayerNormWeights should " |
| "only be present when Layer Norm is enabled and CIFG is disabled. " |
| "m_Parameters.m_LayerNormEnabled should be set appropriately."); |
| } |
| |
| if (m_Parameters.m_LayerNormEnabled) |
| { |
| auto forgetLayerNormWeightsInfo = m_ForgetLayerNormWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(forgetLayerNormWeightsInfo, 1, numUnits, " forgetLayerNormWeights"); |
| ValidateDataTypes(forgetLayerNormWeightsInfo, layerNormPeepholeWeightsSupportedTypes, descriptorName); |
| |
| auto cellLayerNormWeightsInfo = m_CellLayerNormWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(cellLayerNormWeightsInfo, 1, numUnits, " cellLayerNormWeights"); |
| ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, cellLayerNormWeightsInfo, descriptorName, |
| "forgetLayerNormWeights", "cellLayerNormWeights"); |
| |
| auto outputLayerNormWeightsInfo = m_OutputLayerNormWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(outputLayerNormWeightsInfo, 1, numUnits, " outputLayerNormWeights"); |
| ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, outputLayerNormWeightsInfo, descriptorName, |
| "forgetLayerNormWeights", "outputLayerNormWeights"); |
| |
| if (!m_Parameters.m_CifgEnabled) |
| { |
| auto inputLayerNormWeightsInfo = m_InputLayerNormWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputLayerNormWeightsInfo, 1, numUnits, " inputLayerNormWeights"); |
| ValidateTensorDataTypesMatch(forgetLayerNormWeightsInfo, inputLayerNormWeightsInfo, descriptorName, |
| "forgetLayerNormWeights", "inputLayerNormWeights"); |
| } |
| } |
| |
| // Validate OPTIONAL params: Projection (projectionWeights, projectionBias) |
| bool correctProjectionTensorsPresent = |
| ((!m_ProjectionWeights && !m_ProjectionBias && !m_Parameters.m_ProjectionEnabled) || |
| (m_ProjectionWeights && !m_ProjectionBias && m_Parameters.m_ProjectionEnabled) || |
| (m_ProjectionWeights && m_ProjectionBias && m_Parameters.m_ProjectionEnabled)); |
| |
| if (!correctProjectionTensorsPresent) |
| { |
| throw InvalidArgumentException(descriptorName + |
| ": If projection is enabled, ProjectionWeights should be present and " |
| "ProjectionBias is optional. If projection is disabled, neither " |
| "ProjectionWeights nor ProjectionBias should be present."); |
| } |
| |
| if (m_Parameters.m_ProjectionEnabled) |
| { |
| auto projectionWeightsInfo = m_ProjectionWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(projectionWeightsInfo, 2, (numUnits * outputSize), "ProjectionWeights"); |
| ValidateDataTypes(projectionWeightsInfo, weightsSupportedTypes, descriptorName); |
| |
| if (m_ProjectionBias) |
| { |
| auto projectionBiasInfo = m_ProjectionBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(projectionBiasInfo, 1, outputSize, "ProjectionBias"); |
| ValidateDataTypes(projectionBiasInfo, biasSupportedTypes, descriptorName); |
| } |
| |
| } |
| else if ((outputInfo.GetQuantizationScale() != m_Parameters.m_HiddenStateScale) && |
| outputInfo.GetQuantizationOffset() != m_Parameters.m_HiddenStateZeroPoint) { |
| throw InvalidArgumentException(descriptorName + |
| ": If projection is disabled, output quantization info (scale, offset) " |
| "should match HiddenStateScale and HiddenStateZeroPoint."); |
| } |
| |
| } |
| |
| void QuantizedLstmQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"QuantizedLstmQueueDescriptor"}; |
| |
| // Validate number of inputs/outputs |
| ValidateNumInputs(workloadInfo, descriptorName, 3); |
| ValidateNumOutputs(workloadInfo, descriptorName, 2); |
| |
| // Input/output tensor infos |
| auto inputInfo = workloadInfo.m_InputTensorInfos[0]; |
| auto cellStateInInfo = workloadInfo.m_InputTensorInfos[1]; |
| auto outputStateInInfo = workloadInfo.m_InputTensorInfos[2]; |
| |
| auto cellStateOutInfo = workloadInfo.m_OutputTensorInfos[0]; |
| auto outputStateOutInfo = workloadInfo.m_OutputTensorInfos[1]; |
| |
| std::vector<DataType> inputOutputSupportedTypes = |
| { |
| DataType::QAsymmU8 |
| }; |
| |
| std::vector<DataType> cellStateSupportedTypes = |
| { |
| DataType::QSymmS16 |
| }; |
| |
| std::vector<DataType> weightsSupportedTypes = |
| { |
| DataType::QAsymmU8 |
| }; |
| |
| std::vector<DataType> biasSupportedTypes = |
| { |
| DataType::Signed32 |
| }; |
| |
| // Validate types of input/output tensors |
| ValidateDataTypes(inputInfo, inputOutputSupportedTypes, descriptorName); |
| ValidateDataTypes(cellStateInInfo, cellStateSupportedTypes, descriptorName); |
| ValidateDataTypes(outputStateInInfo, inputOutputSupportedTypes, descriptorName); |
| |
| ValidateDataTypes(cellStateOutInfo, cellStateSupportedTypes, descriptorName); |
| ValidateDataTypes(outputStateOutInfo, inputOutputSupportedTypes, descriptorName); |
| |
| // Validate matching types of input/output tensors |
| ValidateTensorDataTypesMatch(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn"); |
| ValidateTensorDataTypesMatch(outputStateInInfo, outputStateOutInfo, descriptorName, |
| "outputStateIn", "outputStateOut"); |
| ValidateTensorDataTypesMatch(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut"); |
| |
| // Validate matching quantization info for input/output tensors |
| ValidateTensorQuantizationSpace(inputInfo, outputStateInInfo, descriptorName, "input", "outputStateIn"); |
| ValidateTensorQuantizationSpace(inputInfo, outputStateOutInfo, descriptorName, "input", "outputStateOut"); |
| ValidateTensorQuantizationSpace(cellStateInInfo, cellStateOutInfo, descriptorName, "cellStateIn", "cellStateOut"); |
| |
| // Infer number of batches, input size and output size from tensor dimensions |
| const uint32_t numBatches = inputInfo.GetShape()[0]; |
| const uint32_t inputSize = inputInfo.GetShape()[1]; |
| const uint32_t outputSize = cellStateInInfo.GetShape()[1]; |
| |
| // Validate number of dimensions and number of elements for input/output tensors |
| ValidateTensorNumDimNumElem(inputInfo, 2, (numBatches * inputSize), descriptorName + " input"); |
| ValidateTensorNumDimNumElem(cellStateInInfo, 2, (numBatches * outputSize), descriptorName + " cellStateIn"); |
| ValidateTensorNumDimNumElem(outputStateInInfo, 2, (numBatches * outputSize), descriptorName + " outputStateIn"); |
| ValidateTensorNumDimNumElem(cellStateOutInfo, 2, (numBatches * outputSize), descriptorName + " cellStateOut"); |
| ValidateTensorNumDimNumElem(outputStateOutInfo, 2, (numBatches * outputSize), descriptorName + " outputStateOut"); |
| |
| // Validate number of dimensions and number of elements for weights tensors |
| ValidatePointer(m_InputToInputWeights, descriptorName, "InputToInputWeights"); |
| auto inputToInputWeightsInfo = m_InputToInputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToInputWeightsInfo, 2, (outputSize * inputSize), " InputToInputWeights"); |
| |
| ValidatePointer(m_InputToForgetWeights, descriptorName, "InputToForgetWeights"); |
| auto inputToForgetWeightsInfo = m_InputToForgetWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToForgetWeightsInfo, 2, (outputSize * inputSize), " InputToForgetWeights"); |
| |
| ValidatePointer(m_InputToCellWeights, descriptorName, "InputToCellWeights"); |
| auto inputToCellWeightsInfo = m_InputToCellWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToCellWeightsInfo, 2, (outputSize * inputSize), " InputToCellWeights"); |
| |
| ValidatePointer(m_InputToOutputWeights, descriptorName, "InputToOutputWeights"); |
| auto inputToOutputWeightsInfo = m_InputToOutputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputToOutputWeightsInfo, 2, (outputSize * inputSize), " InputToOutputWeights"); |
| |
| ValidatePointer(m_RecurrentToInputWeights, descriptorName, "RecurrentToInputWeights"); |
| auto recurrentToInputWeightsInfo = m_RecurrentToInputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToInputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToInputWeights"); |
| |
| ValidatePointer(m_RecurrentToForgetWeights, descriptorName, "RecurrentToForgetWeights"); |
| auto recurrentToForgetWeightsInfo = m_RecurrentToForgetWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToForgetWeightsInfo, 2, (outputSize * outputSize), |
| " RecurrentToForgetWeights"); |
| |
| ValidatePointer(m_RecurrentToCellWeights, descriptorName, "RecurrentToCellWeights"); |
| auto recurrentToCellWeightsInfo = m_RecurrentToCellWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToCellWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights"); |
| |
| ValidatePointer(m_RecurrentToOutputWeights, descriptorName, "RecurrentToOutputWeights"); |
| auto recurrentToOutputWeightsInfo = m_RecurrentToOutputWeights->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(recurrentToOutputWeightsInfo, 2, (outputSize * outputSize), " RecurrentToCellWeights"); |
| |
| // Validate data types for weights tensors (all should match each other) |
| ValidateDataTypes(inputToInputWeightsInfo, weightsSupportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToForgetWeightsInfo, descriptorName, |
| "inputToInputWeights", "inputToForgetWeights"); |
| ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToCellWeightsInfo, descriptorName, |
| "inputToInputWeights", "inputToCellWeights"); |
| ValidateTensorDataTypesMatch(inputToInputWeightsInfo, inputToOutputWeightsInfo, descriptorName, |
| "inputToInputWeights", "inputToOutputWeights"); |
| |
| ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToInputWeightsInfo, descriptorName, |
| "inputToInputWeights", "recurrentToInputWeights"); |
| ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToForgetWeightsInfo, descriptorName, |
| "inputToInputWeights", "recurrentToForgeteights"); |
| ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToCellWeightsInfo, descriptorName, |
| "inputToInputWeights", "recurrentToCellWeights"); |
| ValidateTensorDataTypesMatch(inputToInputWeightsInfo, recurrentToOutputWeightsInfo, descriptorName, |
| "inputToInputWeights", "recurrentToOutputWeights"); |
| |
| // Validate matching quantization info for weight tensors (all should match each other) |
| ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToForgetWeightsInfo, |
| descriptorName, "inputToInputWeights", "inputToForgetWeights"); |
| ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToCellWeightsInfo, |
| descriptorName, "inputToInputWeights", "inputToCellWeights"); |
| ValidateTensorQuantizationSpace(inputToInputWeightsInfo, inputToOutputWeightsInfo, |
| descriptorName, "inputToInputWeights", "inputToOutputWeights"); |
| |
| ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToInputWeightsInfo, |
| descriptorName, "inputToInputWeights", "recurrentToInputWeights"); |
| ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToForgetWeightsInfo, |
| descriptorName, "inputToInputWeights", "recurrentToForgetWeights"); |
| ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToCellWeightsInfo, |
| descriptorName, "inputToInputWeights", "recurrentToCellWeights"); |
| ValidateTensorQuantizationSpace(inputToInputWeightsInfo, recurrentToOutputWeightsInfo, |
| descriptorName, "inputToInputWeights", "recurrentToOutputWeights"); |
| |
| // Validate number of dimensions and number of elements in bias tensors |
| ValidatePointer(m_InputGateBias, descriptorName, "InputGateBias"); |
| auto inputGateBiasInfo = m_InputGateBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(inputGateBiasInfo, 1, outputSize, " InputGateBias"); |
| |
| ValidatePointer(m_ForgetGateBias, descriptorName, "ForgetGateBias"); |
| auto forgetGateBiasInfo = m_ForgetGateBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(forgetGateBiasInfo, 1, outputSize, " ForgetGateBias"); |
| |
| ValidatePointer(m_CellBias, descriptorName, "CellBias"); |
| auto cellBiasInfo = m_CellBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(cellBiasInfo, 1, outputSize, " CellBias"); |
| |
| ValidatePointer(m_OutputGateBias, descriptorName, "OutputGateBias"); |
| auto outputGateBiasInfo = m_OutputGateBias->GetTensorInfo(); |
| ValidateTensorNumDimNumElem(outputGateBiasInfo, 1, outputSize, " OutputGateBias"); |
| |
| // Validate data types for bias tensors (all should match each other) |
| ValidateDataTypes(inputGateBiasInfo, biasSupportedTypes, descriptorName); |
| |
| ValidateTensorDataTypesMatch(inputGateBiasInfo, forgetGateBiasInfo, descriptorName, |
| "inputGateBias", "forgetGateBias"); |
| ValidateTensorDataTypesMatch(inputGateBiasInfo, cellBiasInfo, descriptorName, |
| "inputGateBias", "cellBias"); |
| ValidateTensorDataTypesMatch(inputGateBiasInfo, outputGateBiasInfo, descriptorName, |
| "inputGateBias", "outputGateBias"); |
| |
| // Validate bias tensor quantization info |
| ValidateBiasTensorQuantization(inputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName); |
| ValidateBiasTensorQuantization(forgetGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName); |
| ValidateBiasTensorQuantization(cellBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName); |
| ValidateBiasTensorQuantization(outputGateBiasInfo, inputInfo, inputToInputWeightsInfo, descriptorName); |
| } |
| |
| void AbsQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"AbsQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void SliceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"SliceQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| const unsigned int rank = inputTensorInfo.GetNumDimensions(); |
| if (rank > 4) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensors with rank greater than 4 are not supported."); |
| } |
| |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, rank, "output"); |
| |
| // Check if m_Begin and m_Size have the expected length |
| if (m_Parameters.m_Begin.size() != rank) |
| { |
| throw InvalidArgumentException(descriptorName + |
| ": Length of begin offset descriptor must equal rank " + std::to_string(rank)); |
| } |
| if (m_Parameters.m_Size.size() != rank) |
| { |
| throw InvalidArgumentException(descriptorName + |
| ": Length of size descriptor must equal rank " + std::to_string(rank)); |
| } |
| |
| // Check if the shape of the output tensor matches m_Size |
| const TensorShape& outputShape = outputTensorInfo.GetShape(); |
| for (unsigned int i = 0u; i < rank; ++i) |
| { |
| if (m_Parameters.m_Size[i] != outputShape[i]) |
| { |
| throw InvalidArgumentException(descriptorName + ": Size descriptor does not match output tensor."); |
| } |
| } |
| |
| // Check if the sum of begin offset and size in a given dimension |
| // does not exceed the size of corresponding input |
| const TensorShape& inputShape = inputTensorInfo.GetShape(); |
| for(unsigned int i = 0u; i < rank; ++i) |
| { |
| if (m_Parameters.m_Begin[i] + m_Parameters.m_Size[i] > inputShape[i]) |
| { |
| throw InvalidArgumentException(descriptorName + ": Sum of begin offset and size for dimension " + |
| std::to_string(i) + " exceeds input size."); |
| } |
| } |
| } |
| |
| void DepthToSpaceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"DepthToSpaceQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(inputInfo, descriptorName, 4, "input"); |
| ValidateTensorNumDimensions(outputInfo, descriptorName, 4, "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float32, |
| DataType::Float16, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16 |
| }; |
| |
| ValidateDataTypes(inputInfo, supportedTypes, descriptorName); |
| ValidateDataTypes(outputInfo, supportedTypes, descriptorName); |
| |
| ValidateTensorNumElementsMatch(inputInfo, outputInfo, descriptorName, "input", "output"); |
| |
| if (m_Parameters.m_BlockSize == 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": Block size cannot be 0."); |
| } |
| |
| DataLayoutIndexed dimensionIndices(m_Parameters.m_DataLayout); |
| const unsigned int wIndex = dimensionIndices.GetWidthIndex(); |
| const unsigned int hIndex = dimensionIndices.GetHeightIndex(); |
| const unsigned int cIndex = dimensionIndices.GetChannelsIndex(); |
| |
| const TensorShape& outputShape = outputInfo.GetShape(); |
| if (outputShape[hIndex] % m_Parameters.m_BlockSize != 0 || outputShape[wIndex] % m_Parameters.m_BlockSize != 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output width and height shape" |
| "must be divisible by block size."); |
| } |
| |
| const TensorShape& inputShape = inputInfo.GetShape(); |
| if (inputShape[cIndex] % (m_Parameters.m_BlockSize * m_Parameters.m_BlockSize) != 0) |
| { |
| throw InvalidArgumentException(descriptorName + ": The depth of the input tensor" |
| "must be divisible by the square of block size." ); |
| } |
| } |
| |
| void ComparisonQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ComparisonQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| |
| if (outputTensorInfo.GetDataType() != DataType::Boolean) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean."); |
| } |
| } |
| |
| void ElementwiseUnaryQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ElementwiseUnaryQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorShapesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| std::vector<DataType> logicalSupportedTypes = |
| { |
| DataType::Boolean |
| }; |
| |
| if (m_Parameters.m_Operation == UnaryOperation::LogicalNot) |
| { |
| ValidateDataTypes(inputTensorInfo, logicalSupportedTypes, descriptorName); |
| } |
| else |
| { |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| } |
| |
| |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| void RankQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"RankQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 1, "output"); |
| ValidateTensorNumElements(outputTensorInfo, descriptorName, 1, "output"); |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateDataTypes(outputTensorInfo, { DataType::Signed32 }, descriptorName); |
| } |
| |
| void LogicalBinaryQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"LogicalBinaryQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 2); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo0 = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& inputTensorInfo1 = workloadInfo.m_InputTensorInfos[1]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| ValidateBroadcastTensorShapesMatch(inputTensorInfo0, |
| inputTensorInfo1, |
| outputTensorInfo, |
| descriptorName, |
| "input_0", |
| "input_1"); |
| |
| if (inputTensorInfo0.GetDataType() != DataType::Boolean) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor 0 type must be Boolean."); |
| } |
| |
| if (inputTensorInfo1.GetDataType() != DataType::Boolean) |
| { |
| throw InvalidArgumentException(descriptorName + ": Input tensor 1 type must be Boolean."); |
| } |
| |
| if (outputTensorInfo.GetDataType() != DataType::Boolean) |
| { |
| throw InvalidArgumentException(descriptorName + ": Output tensor type must be Boolean."); |
| } |
| } |
| |
| void ReduceQueueDescriptor::Validate(const WorkloadInfo& workloadInfo) const |
| { |
| const std::string descriptorName{"ReduceQueueDescriptor"}; |
| |
| ValidateNumInputs(workloadInfo, descriptorName, 1); |
| ValidateNumOutputs(workloadInfo, descriptorName, 1); |
| |
| const TensorInfo& inputTensorInfo = workloadInfo.m_InputTensorInfos[0]; |
| const TensorInfo& outputTensorInfo = workloadInfo.m_OutputTensorInfos[0]; |
| |
| std::vector<DataType> supportedTypes = |
| { |
| DataType::BFloat16, |
| DataType::Float16, |
| DataType::Float32, |
| DataType::QAsymmS8, |
| DataType::QAsymmU8, |
| DataType::QSymmS16, |
| DataType::Signed32 |
| }; |
| |
| ValidateDataTypes(inputTensorInfo, supportedTypes, descriptorName); |
| ValidateTensorDataTypesMatch(inputTensorInfo, outputTensorInfo, descriptorName, "input", "output"); |
| } |
| |
| } // namespace armnn |