19 #include <ActivationFunctor.h> 20 #include <CpuExecutor.h> 21 #include <OperationsUtils.h> 37 #include <nnapi/OperandTypes.h> 38 #include <nnapi/Result.h> 39 #include <nnapi/TypeUtils.h> 40 #include <nnapi/Types.h> 41 #include <nnapi/Validation.h> 107 bool IsValid()
const;
108 bool IsOptional()
const;
119 std::vector<uint8_t> m_SwizzledTensorData;
144 template<
class... Args>
145 static bool Fail(
const char* formatStr, Args&&... args)
147 ALOGD(formatStr, std::forward<Args>(args)...);
153 #define FORWARD_LAYER_SUPPORT_FUNC(funcName, func, backends, supported, ...) \ 156 for (auto&& backendId : backends) \ 158 auto layerSupportObject = armnn::GetILayerSupportByBackendId(backendId); \ 159 if (layerSupportObject.IsBackendRegistered()) \ 161 std::string reasonIfUnsupported; \ 163 layerSupportObject.func(__VA_ARGS__, armnn::Optional<std::string&>(reasonIfUnsupported)); \ 170 if (reasonIfUnsupported.size() > 0) \ 172 VLOG(DRIVER) << funcName << ": not supported by armnn: " << reasonIfUnsupported.c_str(); \ 176 VLOG(DRIVER) << funcName << ": not supported by armnn"; \ 182 VLOG(DRIVER) << funcName << ": backend not registered: " << backendId.Get().c_str(); \ 187 VLOG(DRIVER) << funcName << ": not supported by any specified backend"; \ 190 catch (const armnn::InvalidArgumentException &e) \ 192 throw armnn::InvalidArgumentException(e, "Failed to check layer support", CHECK_LOCATION()); \ 201 inline bool IsOperandTypeSupportedForTensors(
OperandType type)
203 return type == OperandType::BOOL ||
204 type == OperandType::TENSOR_BOOL8 ||
205 type == OperandType::TENSOR_FLOAT16 ||
206 type == OperandType::TENSOR_FLOAT32 ||
207 type == OperandType::TENSOR_QUANT8_ASYMM ||
208 type == OperandType::TENSOR_QUANT8_ASYMM_SIGNED ||
209 type == OperandType::TENSOR_QUANT8_SYMM ||
210 type == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL ||
211 type == OperandType::TENSOR_QUANT16_SYMM ||
212 type == OperandType::TENSOR_INT32;
215 inline bool IsBool(
Operand operand)
217 return operand.type == OperandType::BOOL;
220 inline bool Is12OrLaterOperand(
Operand)
226 template<
typename LayerHandleType>
228 LayerHandleType& inputLayer,
241 return *reshapeLayer;
251 unsigned int inputSize = weightsShape[1];
253 unsigned int batchSize = totalInputElements / inputSize;
255 if(totalInputElements % batchSize != 0)
257 throw std::runtime_error(
"Failed to deduce tensor shape");
271 bool transposeWeightMatrix)
273 unsigned int dimIdx = transposeWeightMatrix ? 0 : 1;
274 return (inputShape[0] == outputShape[0] && weightsShape[dimIdx] == outputShape[1]);
290 if (inputDimensions0 == inputDimensions1)
302 unsigned int maxInputDimensions = std::max(inputDimensions0, inputDimensions1);
303 unsigned int sizeDifference = std::abs(armnn::numeric_cast<int>(inputDimensions0) -
304 armnn::numeric_cast<int>(inputDimensions1));
306 bool input0IsSmaller = inputDimensions0 < inputDimensions1;
311 std::vector<unsigned int> reshapedDimensions(maxInputDimensions, 1);
312 for (
unsigned int i = sizeDifference; i < maxInputDimensions; i++)
314 reshapedDimensions[i] = smallShape[i - sizeDifference];
319 reshapedDimensions.data() });
324 bool isSupported =
false;
370 void CalcPadding(uint32_t input,
373 uint32_t& outPadHead,
374 uint32_t& outPadTail,
375 PaddingScheme scheme)
379 calculateExplicitPadding(input, stride, kernel, scheme, &padHead, &padTail);
384 void CalcPadding(uint32_t input, uint32_t kernel, uint32_t stride, uint32_t dilation, uint32_t& outPadHead,
385 uint32_t& outPadTail, ::android::nn::PaddingScheme scheme)
389 calculateExplicitPadding(input, stride, dilation, kernel, scheme, &padHead, &padTail);
394 inline void CalcPaddingTransposeConv(uint32_t output, uint32_t kernel, int32_t stride, int32_t& outPadHead,
395 int32_t& outPadTail, ::android::nn::PaddingScheme scheme)
397 calculateExplicitPaddingTransposeConv(output, stride, kernel, scheme, &outPadHead, &outPadTail);
400 Shape GetOperandShape(
const Operand& operand)
404 shape.dimensions = operand.dimensions;
405 shape.scale = operand.scale;
406 shape.offset = operand.zeroPoint;
423 auto UpdateBiasScaleValue = [&inputInfo](
float biasScale) ->
float 429 std::transform(biasScales.begin(), biasScales.end(), biasScales.begin(), UpdateBiasScaleValue);
435 VLOG(DRIVER) <<
"Bias quantization params have been updated for per-axis quantization";
444 VLOG(DRIVER) <<
"Bias quantization scale has been modified to match input * weights";
460 template<
typename OSlot>
479 bool ValidateConcatOutputShape(
const std::vector<armnn::TensorShape> & inputShapes,
484 unsigned int numDimensions = inputShapes[0].GetNumDimensions();
487 return Fail(
"%s: Output shape has wrong number of dimensions", __func__);
490 unsigned int outputSizeAlongConcatenatedDimension = 0;
491 for (
unsigned int i = 0; i < inputShapes.size(); i++)
493 outputSizeAlongConcatenatedDimension += inputShapes[i][concatDim];
496 for (
unsigned int i = 0; i < numDimensions; ++i)
500 if (outputShape[i] != outputSizeAlongConcatenatedDimension)
503 "%s: Invalid output shape for dimension %d (%d != %d)",
507 outputSizeAlongConcatenatedDimension);
512 if (outputShape[i] != inputShapes[0][i])
514 return Fail(
"%s: Invalid output shape", __func__);
528 std::vector<LayerInputHandle>& inputs,
529 std::vector<armnn::TensorShape>& inputShapes,
532 if (!mapping.
IsEqual(IdentityPermutation4D))
534 size_t nInputs = inputs.size();
535 for (
size_t i=0; i<nInputs; ++i)
543 inputShapes[i] = inputs[i].GetTensorInfo().GetShape();
549 std::vector<LayerInputHandle>& inputs,
550 std::vector<armnn::TensorShape>& inputShapes,
554 if (!mapping.
IsEqual(IdentityPermutation4D) && !mapping.
IsEqual(IdentityPermutation3D))
557 size_t nInputs = inputs.size();
558 for (
size_t i=0; i<nInputs; ++i)
565 bool isSupported =
false;
567 IsTransposeSupported,
570 inputs[i].GetTensorInfo(),
579 SwizzleInputs(*data.
m_Network, inputs, inputShapes, mapping);
584 bool CreateConcatPermutationParameters(
const unsigned int numberOfDimensions,
585 int32_t & concatDimension,
586 std::pair<armnn::PermutationVector, armnn::PermutationVector> & permutationPair)
588 bool needPermute =
false;
594 if (numberOfDimensions == 4 && concatDimension == 2)
597 permutationPair = std::make_pair(SwapDim1And2, SwapDim1And2);
600 else if (numberOfDimensions == 3 && concatDimension == 1)
603 permutationPair = std::make_pair(RotateTensorLeft, RotateTensorRight);
608 else if (numberOfDimensions == 3 && concatDimension == 2)
610 permutationPair = std::make_pair(IdentityPermutation3D, IdentityPermutation3D);
628 ActivationFn activation,
636 bool failOnIndexOutOfBounds =
true)
638 if (inputIndex >= operation.inputs.size())
640 if (failOnIndexOutOfBounds)
642 Fail(
"%s: invalid input index: %i out of %i", __func__, inputIndex, operation.inputs.size());
649 return &
getMainModel(model).operands[operation.inputs[inputIndex]];
653 uint32_t outputIndex,
656 if (outputIndex >= operation.outputs.size())
658 Fail(
"%s: invalid output index: %i out of %i", __func__, outputIndex, operation.outputs.size());
665 return &
getMainModel(model).operands[operation.outputs[outputIndex]];
671 bool optional =
false);
681 return Fail(
"%s: invalid input operand at index %i", __func__, inputIndex);
684 type = operand->type;
692 return lifetime == OperandLifeTime::CONSTANT_COPY ||
693 lifetime == OperandLifeTime::CONSTANT_REFERENCE ||
694 lifetime == OperandLifeTime::POINTER ||
695 lifetime == OperandLifeTime::NO_VALUE;
705 bool optional =
false,
715 bool optional =
false)
720 Fail(
"%s: failed to get input operand: index=%u", __func__, inputIndex);
731 template <
typename OutputType>
735 OutputType& outValue,
738 bool optional =
false)
741 if (!optional && !operand)
743 return Fail(
"%s: invalid input operand at index %i", __func__, inputIndex);
746 if (!optional && operand->type != type)
748 VLOG(DRIVER) << __func__ <<
": unexpected operand type: " << operand->type <<
" should be: " << type;
752 if (!optional && operand->location.length !=
sizeof(OutputType))
754 return Fail(
"%s: incorrect operand location length: %i (should be %i)",
755 __func__, operand->location.length,
sizeof(OutputType));
759 if (!optional && !valueAddress)
761 return Fail(
"%s: failed to get address for operand", __func__);
766 outValue = *(
static_cast<const OutputType*
>(valueAddress));
778 return GetInputScalar(operation, inputIndex, OperandType::INT32, outValue, model, data);
787 return GetInputScalar(operation, inputIndex, OperandType::FLOAT32, outValue, model, data);
793 ActivationFn& outActivationFunction,
797 if (type != OperandType::INT32 && type != OperandType::TENSOR_INT32)
799 VLOG(DRIVER) << __func__ <<
": unexpected operand type: " << type
800 <<
" should be OperandType::INT32 or OperandType::TENSOR_INT32";
804 int32_t activationFunctionAsInt;
805 if (!
GetInputScalar(operation, inputIndex, type, activationFunctionAsInt, model, data))
807 return Fail(
"%s: failed to get activation input value", __func__);
809 outActivationFunction =
static_cast<ActivationFn
>(activationFunctionAsInt);
815 ActivationFn& outActivationFunction,
822 outActivationFunction,
829 ActivationFn& outActivationFunction,
837 outActivationFunction,
845 ActivationFn& activationFunction,
849 if (operation.inputs.size() <= inputIndex)
851 activationFunction = ActivationFn::kActivationNone;
857 return Fail(
"%s: Operation has invalid inputs", __func__);
863 template<
typename ConvolutionDescriptor>
865 uint32_t dilationXIndex,
866 ConvolutionDescriptor& descriptor,
871 if (operation.inputs.size() >= dilationXIndex + 2)
876 descriptor.m_DilationX,
882 descriptor.m_DilationY,
901 if (!IsBool(*operand))
912 return *(
static_cast<const bool*
>(valueAddress));
916 std::vector<int32_t>& outValues,
922 PaddingScheme& outPaddingScheme,
934 uint32_t operationOutputIndex,
936 uint32_t layerOutputIndex,
940 const std::function <
void (
const armnn::TensorInfo&,
bool&)>& validateFunc =
nullptr,
941 const ActivationFn& activationFunction = ActivationFn::kActivationNone,
942 bool inferOutputShapes =
false);
951 uint32_t outputIndex,
956 const std::function <
void (
const armnn::TensorInfo&,
bool&)>& validateFunc =
nullptr,
957 const ActivationFn& activationFunction = ActivationFn::kActivationNone)
971 const char* operationName,
987 const char* operationName,
994 return operand.type == OperandType::TENSOR_QUANT8_SYMM;
1014 size_t operandIndex,
1015 bool optional =
false);
unsigned int GetNumElements() const
Function that calculates the tensor elements by multiplying all dimension size which are Specified...
const Operand * GetOutputOperand(const Operation &operation, uint32_t outputIndex, const Model &model)
std::vector<::android::nn::RunTimePoolInfo > m_MemPools
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
bool IsQSymm8(const Operand &operand)
std::vector< armnn::IOutputSlot * > m_OutputSlotForOperand
const TensorShape & GetShape() const
A ReshapeDescriptor for the ReshapeLayer.
::android::nn::ErrorStatus ErrorStatus
const std::vector< armnn::BackendId > m_Backends
bool GetInputActivationFunction(const Operation &operation, uint32_t inputIndex, ActivationFn &outActivationFunction, const Model &model, const ConversionData &data)
bool HasPerAxisQuantization() const
bool ConvertReduce(const Operation &operation, const Model &model, ConversionData &data, armnn::ReduceOperation reduceOperation)
::android::nn::Operation Operation
bool GetOptionalBool(const Operation &operation, uint32_t inputIndex, const Model &model, const ConversionData &data)
ConstTensorPin ConvertOperandToConstTensorPin(const Operand &operand, const Model &model, const ConversionData &data, const armnn::PermutationVector &dimensionMappings, const armnn::TensorShape *overrideTensorShape, bool optional, const armnn::DataType *overrideDataType)
Main network class which provides the interface for building up a neural network. ...
bool GetOperandType(const Operation &operation, uint32_t inputIndex, const Model &model, OperandType &type)
bool GetOptionalInputActivation(const Operation &operation, uint32_t inputIndex, ActivationFn &activationFunction, const Model &model, const ConversionData &data)
std::vector< float > GetQuantizationScales() const
::android::nn::OperandType OperandType
bool GetInputActivationFunctionImpl(const Operation &operation, uint32_t inputIndex, OperandType type, ActivationFn &outActivationFunction, const Model &model, const ConversionData &data)
bool m_DynamicInputsEncountered
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
void SetShape(const TensorShape &newShape)
const armnn::PermutationVector g_DontPermute
const Operand * GetInputOperand(const Operation &operation, uint32_t inputIndex, const Model &model, bool failOnIndexOutOfBounds=true)
TensorShape m_TargetShape
Target shape value.
A PadDescriptor for the PadLayer.
bool ConvertPooling2d(const Operation &operation, const char *operationName, armnn::PoolingAlgorithm poolType, const Model &model, ConversionData &data)
ConstTensorPin ConvertOperationInputToConstTensorPin(const Operation &operation, uint32_t inputIndex, const Model &model, const ConversionData &data, const armnn::PermutationVector &dimensionMappings=g_DontPermute, const armnn::TensorShape *overrideTensorShape=nullptr, bool optional=false)
::android::nn::Model Model
Helper classes.
bool GetInputScalar(const Operation &operation, uint32_t inputIndex, OperandType type, OutputType &outValue, const Model &model, const ConversionData &data, bool optional=false)
armnn::INetworkPtr m_Network
An output connection slot for a layer.
armnn::DataLayout OptionalDataLayout(const Operation &operation, uint32_t inputIndex, const Model &model, ConversionData &data)
float GetQuantizationScale() const
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
bool ConvertPaddings(const Operation &operation, const Model &model, ConversionData &data, unsigned int rank, armnn::PadDescriptor &padDescriptor)
const void * GetOperandValueReadOnlyAddress(const Operand &operand, const Model &model, const ConversionData &data, bool optional)
void SetQuantizationScale(float scale)
#define ARMNN_ASSERT(COND)
An ActivationDescriptor for the ActivationLayer.
bool GetTensorInt32Values(const Operand &operand, std::vector< int32_t > &outValues, const Model &model, const ConversionData &data)
bool GetInputActivationFunctionFromTensor(const Operation &operation, uint32_t inputIndex, ActivationFn &outActivationFunction, const Model &model, const ConversionData &data)
ConversionData(const std::vector< armnn::BackendId > &backends)
void SetQuantizationDim(const Optional< unsigned int > &quantizationDim)
bool IsWeightsValid(const Operation &operation, uint32_t inputIndex, const Model &model)
Utility functions.
std::tuple< std::unique_ptr< float[]>, size_t, armnn::TensorInfo, DequantizeStatus > DequantizeResult
bool IsEqual(const PermutationVector &other) const
LayerInputHandle ConvertToLayerInputHandle(const Operation &operation, uint32_t inputIndex, const Model &model, ConversionData &data, const armnn::PermutationVector &dimensionMappings, const LayerInputHandle *inputHandle)
::android::nn::Operand Operand
IConnectableLayer * AddReshapeLayer(const ReshapeDescriptor &reshapeDescriptor, const char *name=nullptr)
Adds a reshape layer to the network.
bool SetupAndTrackLayerOutputSlot(const Operation &operation, uint32_t operationOutputIndex, armnn::IConnectableLayer &layer, uint32_t layerOutputIndex, const Model &model, ConversionData &data, const armnn::TensorInfo *overrideOutputInfo, const std::function< void(const armnn::TensorInfo &, bool &)> &validateFunc, const ActivationFn &activationFunction, bool inferOutputShapes)
const android::nn::Model::Subgraph & getMainModel(const android::nn::Model &model)
bool GetInputPaddingScheme(const Operation &operation, uint32_t inputIndex, PaddingScheme &outPaddingScheme, const Model &model, const ConversionData &data)
bool ConvertToActivation(const Operation &operation, const char *operationName, const armnn::ActivationDescriptor &activationDesc, const Model &model, ConversionData &data)
ConstTensorPin DequantizeAndMakeConstTensorPin(const Operation &operation, const Model &model, const ConversionData &data, size_t operandIndex, bool optional)
#define FORWARD_LAYER_SUPPORT_FUNC(funcName, func, backends, supported,...)
bool GetInputInt32(const Operation &operation, uint32_t inputIndex, int32_t &outValue, const Model &model, const ConversionData &data)
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
bool IsConnectedToDequantize(armnn::IOutputSlot *ioutputSlot)
::android::nn::Operand::LifeTime OperandLifeTime
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
armnn::IConnectableLayer * ProcessActivation(const armnn::TensorInfo &tensorInfo, ActivationFn activation, armnn::IConnectableLayer *prevLayer, ConversionData &data)
std::enable_if_t< std::is_unsigned< Source >::value &&std::is_unsigned< Dest >::value, Dest > numeric_cast(Source source)
armnn::TensorInfo GetTensorInfo(unsigned int numberOfBatches, unsigned int numberOfChannels, unsigned int height, unsigned int width, const armnn::DataLayout dataLayout, const armnn::DataType dataType)
bool IsOperandConstant(const Operand &operand)
A TransposeDescriptor for the TransposeLayer.
virtual const TensorInfo & GetTensorInfo() const =0
::android::nn::OperationType OperationType
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
DequantizeResult DequantizeIfRequired(size_t operand_index, const Operation &operation, const Model &model, const ConversionData &data)
void Connect(armnn::IConnectableLayer *from, armnn::IConnectableLayer *to, const armnn::TensorInfo &tensorInfo, unsigned int fromIndex, unsigned int toIndex)
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
armnn::TensorShape TransposeTensorShape(const armnn::TensorShape &srcShape, const armnn::PermutationVector &mappings)
bool within_percentage_tolerance(float a, float b, float tolerancePercent=1.0f)
Compare two floats and return true if their values are within a specified tolerance of each other...
virtual int Connect(IInputSlot &destination)=0
bool GetOptionalConvolutionDilationParams(const Operation &operation, uint32_t dilationXIndex, ConvolutionDescriptor &descriptor, const Model &model, const ConversionData &data)
void SetQuantizationScales(const std::vector< float > &scales)
unsigned int GetNumDimensions() const
PermutationVector m_DimMappings
Indicates how to translate tensor elements from a given source into the target destination, when source and target potentially have different memory layouts e.g.
bool GetInputFloat32(const Operation &operation, uint32_t inputIndex, float &outValue, const Model &model, const ConversionData &data)
IConnectableLayer * AddTransposeLayer(const TransposeDescriptor &transposeDescriptor, const char *name=nullptr)
Adds a transpose layer to the network.
bool IsReshapeSupported(const BackendId &backend, const TensorInfo &input, const ReshapeDescriptor &descriptor, char *reasonIfUnsupported=nullptr, size_t reasonIfUnsupportedMaxLength=1024)
Deprecated in favor of IBackend and ILayerSupport interfaces.