7 #include <half/half.hpp>
15 using Half = half_float::half;
24 switch (operation.type)
26 case OperationType::ABS:
27 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Abs);
28 case OperationType::ADD:
30 case OperationType::ARGMAX:
31 return ConvertArgMinMax(operation, model, data, ArgMinMaxFunction::Max);
32 case OperationType::ARGMIN:
33 return ConvertArgMinMax(operation, model, data, ArgMinMaxFunction::Min);
34 case OperationType::AVERAGE_POOL_2D:
35 return ConvertAveragePool2d(operation, model, data);
36 case OperationType::BATCH_MATMUL:
37 return ConvertBatchMatMul(operation, model, data);
38 case OperationType::BATCH_TO_SPACE_ND:
39 return ConvertBatchToSpaceNd(operation, model, data);
40 case OperationType::CAST:
41 return ConvertCast(operation, model, data);
42 case OperationType::CONCATENATION:
43 return ConvertConcatenation(operation, model, data);
44 case OperationType::CONV_2D:
45 return ConvertConv2d(operation, model, data);
46 case OperationType::DEPTH_TO_SPACE:
47 return ConvertDepthToSpace(operation, model, data);
48 case OperationType::DEPTHWISE_CONV_2D:
49 return ConvertDepthwiseConv2d(operation, model, data);
50 case OperationType::DEQUANTIZE:
51 return ConvertDequantize(operation, model, data);
52 case OperationType::DIV:
54 case OperationType::ELU:
55 return ConvertElu(operation, model, data);
56 case OperationType::EQUAL:
57 return ConvertComparison(operation, model, data, ComparisonOperation::Equal);
58 case OperationType::EXP:
59 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Exp);
60 case OperationType::EXPAND_DIMS:
61 return ConvertExpandDims(operation, model, data);
62 case OperationType::FILL:
63 return ConvertFill(operation, model, data);
64 case OperationType::FLOOR:
65 return ConvertFloor(operation, model, data);
66 case OperationType::FULLY_CONNECTED:
67 return ConvertFullyConnected(operation, model, data);
68 case OperationType::GATHER:
69 return ConvertGather(operation, model, data);
70 case OperationType::GREATER:
71 return ConvertComparison(operation, model, data, ComparisonOperation::Greater);
72 case OperationType::GREATER_EQUAL:
73 return ConvertComparison(operation, model, data, ComparisonOperation::GreaterOrEqual);
74 case OperationType::GROUPED_CONV_2D:
75 return ConvertGroupedConv2d(operation, model, data);
76 case OperationType::HARD_SWISH:
77 return ConvertHardSwish(operation, model, data);
78 case OperationType::INSTANCE_NORMALIZATION:
79 return ConvertInstanceNormalization(operation, model, data);
80 case OperationType::L2_NORMALIZATION:
81 return ConvertL2Normalization(operation, model, data);
82 case OperationType::L2_POOL_2D:
83 return ConvertL2Pool2d(operation, model, data);
84 case OperationType::LESS:
85 return ConvertComparison(operation, model, data, ComparisonOperation::Less);
86 case OperationType::LESS_EQUAL:
87 return ConvertComparison(operation, model, data, ComparisonOperation::LessOrEqual);
88 case OperationType::LOCAL_RESPONSE_NORMALIZATION:
89 return ConvertLocalResponseNormalization(operation, model, data);
90 case OperationType::LOG:
91 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Log);
92 case OperationType::LOGICAL_AND:
93 return ConvertLogicalBinary(operation, model, data, LogicalBinaryOperation::LogicalAnd);
94 case OperationType::LOGICAL_NOT:
95 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::LogicalNot);
96 case OperationType::LOGICAL_OR:
97 return ConvertLogicalBinary(operation, model, data, LogicalBinaryOperation::LogicalOr);
98 case OperationType::LOGISTIC:
99 return ConvertLogistic(operation, model, data);
100 case OperationType::LOG_SOFTMAX:
101 return ConvertLogSoftmax(operation, model, data);
102 case OperationType::LSTM:
103 return ConvertLstm(operation, model, data);
104 case OperationType::MAX_POOL_2D:
105 return ConvertMaxPool2d(operation, model, data);
106 case OperationType::MAXIMUM:
108 case OperationType::MEAN:
109 return ConvertMean(operation, model, data);
110 case OperationType::MINIMUM:
112 case OperationType::MUL:
114 case OperationType::NEG:
115 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Neg);
116 case OperationType::NOT_EQUAL:
117 return ConvertComparison(operation, model, data, ComparisonOperation::NotEqual);
118 case OperationType::PAD:
119 return ConvertPad(operation, model, data);
120 case OperationType::PAD_V2:
121 return ConvertPadV2(operation, model, data);
122 case OperationType::PRELU:
123 return ConvertPrelu(operation, model, data);
124 case OperationType::POW:
125 return ConvertElementwiseBinary(operation, model, data, BinaryOperation::Power);
126 case OperationType::QUANTIZE:
127 return ConvertQuantize(operation, model, data);
128 case OperationType::QUANTIZED_LSTM:
129 return ConvertQuantizedLstm(operation, model, data);
130 case OperationType::QUANTIZED_16BIT_LSTM:
131 return ConvertQuantized16BitLstm(operation, model, data);
132 case OperationType::RANK:
133 return ConvertRank(operation, model, data);
134 case OperationType::REDUCE_MAX:
136 case OperationType::REDUCE_MIN:
138 case OperationType::REDUCE_PROD:
140 case OperationType::REDUCE_SUM:
142 case OperationType::RELU:
143 return ConvertReLu(operation, model, data);
144 case OperationType::RELU1:
145 return ConvertReLu1(operation, model, data);
146 case OperationType::RELU6:
147 return ConvertReLu6(operation, model, data);
148 case OperationType::RESHAPE:
149 return ConvertReshape(operation, model, data);
150 case OperationType::RESIZE_BILINEAR:
151 return ConvertResize(operation, model, data, ResizeMethod::Bilinear);
152 case OperationType::RESIZE_NEAREST_NEIGHBOR:
153 return ConvertResize(operation, model, data, ResizeMethod::NearestNeighbor);
154 case OperationType::REVERSE:
155 return ConvertReverseV2(operation, model, data);
156 case OperationType::RSQRT:
157 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Rsqrt);
158 case OperationType::SIN:
159 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Sin);
160 case OperationType::SOFTMAX:
161 return ConvertSoftmax(operation, model, data);
162 case OperationType::SPACE_TO_BATCH_ND :
163 return ConvertSpaceToBatchNd(operation, model, data);
164 case OperationType::SPACE_TO_DEPTH:
165 return ConvertSpaceToDepth(operation, model, data);
166 case OperationType::SQRT:
167 return ConvertSqrt(operation, model, data);
168 case OperationType::SQUEEZE:
169 return ConvertSqueeze(operation, model, data);
170 case OperationType::STRIDED_SLICE:
171 return ConvertStridedSlice(operation, model, data);
172 case OperationType::SUB:
173 return ConvertElementwiseBinary(operation, model, data, BinaryOperation::Sub);
174 case OperationType::TILE:
175 return ConvertTile(operation, model, data);
176 case OperationType::TRANSPOSE:
177 return ConvertTranspose(operation, model, data);
178 case OperationType::TRANSPOSE_CONV_2D:
179 return ConvertTransposeConv2d(operation, model, data);
180 case OperationType::TANH:
181 return ConvertTanH(operation, model, data);
183 VLOG(DRIVER) <<
"Operation type: " << operation.type <<
"is not supported in ArmnnDriver";
188 bool Converter::ConvertArgMinMax(
const Operation& operation,
193 VLOG(DRIVER) <<
"Converter::ConvertArgMinMax()";
200 return Fail(
"%s: Operation has invalid inputs", __func__);
204 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
206 return Fail(
"%s: Operation has invalid inputs. Failed to read axis.", __func__);
212 if (((axis < -rank) && (axis < 0)) || ((axis >= rank) && (axis > 0)))
217 return Fail(
"%s: Axis must be in range [-n, n)", __func__);
223 return Fail(
"%s: Could not read output 0", __func__);
234 bool isSupported =
false;
239 IsArgMinMaxSupported,
254 validateFunc(outputInfo, isSupported);
264 assert(layer !=
nullptr);
273 VLOG(DRIVER) <<
"Converter::ConvertAveragePool2d()";
274 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Average, model, data);
279 VLOG(DRIVER) <<
"Converter::ConvertBatchMatMul()";
285 return Fail(
"%s: Operation has invalid inputs", __func__);
292 if (rankInput0 > 4 || rankInput0 < 2)
294 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
298 if (rankInput1 > 4 || rankInput1 < 2)
300 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
307 return Fail(
"%s: Operation has invalid inputs", __func__);
314 return Fail(
"%s: Operation has invalid inputs", __func__);
317 if (input0Type != input1Type)
319 return Fail(
"%s: Operation has invalid inputs (Inputs must have same OperandCode)", __func__);
325 return Fail(
"%s: Could not read output 0", __func__);
337 bool isSupported =
false;
342 IsBatchMatMulSupported,
354 validateFunc(outputInfo, isSupported);
369 assert(layer !=
nullptr);
378 VLOG(DRIVER) <<
"Converter::ConvertBatchToSpaceNd()";
382 return Fail(
"%s: Operation has invalid inputs", __func__);
388 return Fail(
"%s: Could not read output 0", __func__);
396 return Fail(
"%s: Could not read input 1", __func__);
400 std::vector<int32_t> block;
403 return Fail(
"%s: Input 1 has invalid values", __func__);
411 Fail(
"%s: Only inputs with rank equal to 4 are supported", __func__);
414 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
416 return Fail(
"%s: Block sizes for each spatial dimension of the input tensor must be"
417 " greater than or equal to 1", __func__);
421 batchToSpaceNdDesc.
m_BlockShape.assign(block.cbegin(), block.cend());
424 if (Is12OrLaterOperand(*output))
429 batchToSpaceNdDesc.
m_Crops = {{0, 0}, {0, 0}};
431 bool isSupported =
false;
436 IsBatchToSpaceNdSupported,
447 validateFunc(outputInfo, isSupported);
462 assert(layer !=
nullptr);
470 VLOG(DRIVER) <<
"Converter::ConvertCast()";
476 return Fail(
"%s: Operation has invalid inputs", __func__);
482 return Fail(
"%s: Could not read output 0", __func__);
488 bool isSupported =
false;
503 validateFunc(outputInfo, isSupported);
517 assert(layer !=
nullptr);
523 bool Converter::ConvertComparison(
const Operation& operation,
528 VLOG(DRIVER) <<
"Converter::ConvertComparison()";
536 return Fail(
"%s: Operation has invalid inputs", __func__);
542 return Fail(
"%s: Could not read output 0", __func__);
551 bool isSupported =
false;
556 IsComparisonSupported,
568 validateFunc(outputInfo, isSupported);
582 assert(layer !=
nullptr);
584 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
585 if (!isReshapeSupported)
602 VLOG(DRIVER) <<
"Converter::ConvertConcatenation()";
605 if (operation.inputs.size() <= 1)
607 return Fail(
"%s: Operation has insufficient arguments", __func__);
611 const std::size_t numInputTensors = operation.inputs.size() - 1;
614 if (!
GetInputScalar(operation, numInputTensors, OperandType::INT32, concatDim, model, data))
616 return Fail(
"%s: Operation has invalid inputs", __func__);
622 return Fail(
"%s: Operation has no outputs", __func__);
638 if (concatDim >=
static_cast<int32_t
>(outputShape.
GetNumDimensions()) || concatDim < 0)
640 return Fail(
"%s: Operation has invalid concat axis: %d", __func__, concatDim);
643 std::vector<LayerInputHandle> inputHandles;
644 std::vector<armnn::TensorShape> inputShapes;
646 inputHandles.reserve(numInputTensors);
647 inputShapes.reserve(numInputTensors);
649 bool inputsHaveBeenReshaped =
false;
650 unsigned int tensorDimensionsAdded = 0;
651 for (uint32_t i = 0; i < numInputTensors; ++i)
656 return Fail(
"%s: Operation has invalid inputs", __func__);
660 if (!operandInputHandle.
IsValid())
662 return Fail(
"%s: Operation has invalid inputs", __func__);
668 return Fail(
"%s: Operands with rank 0 are not supported", __func__);
671 if (RequiresReshape(operandShape))
673 inputsHaveBeenReshaped =
true;
681 tensorDimensionsAdded = 1;
686 tensorDimensionsAdded = 2;
692 bool isSupported =
false;
711 operandShape = reshapeInfo.
GetShape();
715 inputShapes.emplace_back(operandShape);
716 inputHandles.emplace_back(operandInputHandle);
718 if (!inputHandles.back().IsValid())
720 return Fail(
"%s: Operation has invalid inputs", __func__);
724 if (inputShapes.size() != inputHandles.size())
726 return Fail(
"%s: invalid model input shapes size doesn't match input handles size: %i != %i", __func__,
727 inputShapes.size(), inputHandles.size());
730 if (inputsHaveBeenReshaped)
733 concatDim += tensorDimensionsAdded;
736 if (tensorDimensionsAdded == 1)
747 else if (tensorDimensionsAdded == 2)
762 std::pair<armnn::PermutationVector, armnn::PermutationVector> permutationPair =
763 std::make_pair(IdentityPermutation4D, IdentityPermutation4D);
764 bool needPermute = CreateConcatPermutationParameters(inputShapes[0].GetNumDimensions(),
769 if (!isDynamicTensor)
780 if (!TransposeInputTensors(data, inputHandles, inputShapes, permutationPair.first))
795 }
catch (std::exception& error)
797 return Fail(
"%s: Error preparing concat descriptor. %s", __func__,
error.what());
802 if (!isDynamicTensor)
804 if (!ValidateConcatOutputShape(inputShapes, outputShape, concatDim))
806 return Fail(
"%s: Error validating the output shape for concat", __func__);
810 std::vector<const armnn::TensorInfo*> inputTensorInfos;
811 std::transform(inputHandles.begin(), inputHandles.end(), std::back_inserter(inputTensorInfos),
814 bool isSupported =
false;
827 if (!isDynamicTensor)
829 validateFunc(outputInfo, isSupported);
843 assert(layer !=
nullptr);
847 assert(
static_cast<std::size_t
>(numInputSlots) == inputHandles.size());
848 for (
int i = 0; i < numInputSlots; ++i)
855 auto transposeOutputShape = [&](){
860 permutationPair.second);
864 IsTransposeSupported,
877 permutationPair.second);
879 layer = &deswizzleLayer;
884 if (needPermute && !isDynamicTensor)
886 transposeOutputShape();
889 if (inputsHaveBeenReshaped)
897 "tensor info is not set on output slot, cannot process dynamic tensor after input reshape");
899 if (!ValidateConcatOutputShape(inputShapes,
903 return Fail(
"%s: Error validating the output shape for concat", __func__);
905 transposeOutputShape();
910 if (tensorDimensionsAdded == 1)
915 else if (tensorDimensionsAdded == 2)
926 auto validateReshapeFunc = [&](
const armnn::TensorInfo& afterConcatInfo,
bool& isSupported){
939 validateReshapeFunc(afterConcatInfo, isSupported);
958 validateReshapeFunc);
966 VLOG(DRIVER) <<
"Converter::ConvertConv2d()";
971 return Fail(
"%s: Operation has invalid inputs", __func__);
977 return Fail(
"%s: Could not read output 0", __func__);
987 bool implicitPadding = operation.inputs.size() == 7
988 || (operation.inputs.size() >= 8
995 else if (operation.inputs.size() >= 10)
1009 return Fail(
"%s: Operation has unsupported weights OperandLifeTime", __func__);
1018 return Fail(
"%s: Operation has invalid inputs", __func__);
1024 return Fail(
"%s: Operation has invalid inputs", __func__);
1031 ActivationFn activation;
1032 if (implicitPadding)
1034 ::android::nn::PaddingScheme paddingScheme;
1041 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1045 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1046 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1047 const uint32_t kernelX = weightsInfo.
GetShape()[widthIndex];
1048 const uint32_t kernelY = weightsInfo.
GetShape()[heightIndex];
1049 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1050 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1056 else if (operation.inputs.size() >= 10)
1068 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1073 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1079 bool requiresValidation =
true;
1088 requiresValidation =
false;
1089 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Weights and Biases are as INPUTS.";
1093 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1095 IsConvolution2dSupported,
1106 if (requiresValidation)
1108 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Requires Validation!";
1109 bool isSupported =
false;
1112 validateFunc(outputInfo, isSupported);
1130 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
1142 VLOG(DRIVER) <<
"Converter::ConvertDepthToSpace()";
1147 return Fail(
"%s: Operation has invalid inputs", __func__);
1154 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
1160 return Fail(
"%s: Could not read output 0", __func__);
1170 return Fail(
"%s: Block size must be at least 1 in all dimensions", __func__);
1174 if (Is12OrLaterOperand(*output))
1179 bool isSupported =
false;
1184 IsDepthToSpaceSupported,
1195 validateFunc(outputInfo, isSupported);
1209 assert(layer !=
nullptr);
1217 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d()";
1223 return Fail(
"%s: Operation has invalid inputs", __func__);
1230 return Fail(
"%s: Could not read output 0", __func__);
1239 return Fail(
"%s: This Operation has unsupported weights OperandLifeTime", __func__);
1248 if (weightsOperand->dimensions[0] != 1)
1250 return Fail(
"%s: Filter operand dimension 0 is invalid, should be 1", __func__);
1257 bool implicitPadding = operation.inputs.size() == 8
1258 || (operation.inputs.size() >= 9
1262 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
1266 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1267 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1272 return Fail(
"%s: Operation has invalid inputs", __func__);
1278 return Fail(
"%s: Could not read bias", __func__);
1284 return Fail(
"%s: Operation has invalid inputs", __func__);
1291 ActivationFn activation;
1292 if (implicitPadding)
1294 ::android::nn::PaddingScheme paddingScheme;
1301 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1304 const uint32_t kernelX = weightsInfo.
GetShape()[2];
1305 const uint32_t kernelY = weightsInfo.
GetShape()[1];
1306 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1307 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1312 else if (operation.inputs.size() >= 11)
1324 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1329 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1335 bool requiresValidation =
true;
1341 requiresValidation =
false;
1342 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Weights and Biases are as INPUTS.";
1346 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1348 IsDepthwiseConvolutionSupported,
1359 if (requiresValidation)
1361 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Requires Validation!";
1362 bool isSupported =
false;
1365 validateFunc(outputInfo, isSupported);
1383 return Fail(
"%s: AddDepthwiseConvolution2dLayer failed", __func__);
1397 VLOG(DRIVER) <<
"Converter::ConvertDequantize()";
1402 return Fail(
"%s: Operation has invalid input", __func__);
1409 return Fail(
"%s: Operation has quantization dimension different than 0", __func__);
1415 return Fail(
"%s: Operation has invalid outputs", __func__);
1420 bool isSupported =
false;
1425 IsDequantizeSupported,
1439 validateFunc(outputInfo, isSupported);
1449 assert(layer !=
nullptr);
1455 bool Converter::ConvertElementwiseBinary(
const Operation& operation,
1460 VLOG(DRIVER) <<
"Converter::ConvertElementwiseBinary()";
1468 return Fail(
"%s: Operation has invalid inputs", __func__);
1472 ActivationFn activationFunction;
1475 return Fail(
"%s: Operation has invalid optional input: activation function", __func__);
1481 return Fail(
"%s: Could not read output", __func__);
1488 bool isSupported =
false;
1492 IsElementwiseBinarySupported,
1504 validateFunc(outputInfo, isSupported);
1519 return Fail(
"%s: Could not add the ElementwiseBinaryLayer", __func__);
1521 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
1522 if (!isReshapeSupported)
1528 data,
nullptr, validateFunc, activationFunction);
1531 bool Converter::ConvertElementwiseUnary(
const Operation& operation,
1536 VLOG(DRIVER) <<
"Converter::ConvertElementwiseUnary()";
1543 return Fail(
"%s: Operation has invalid input", __func__);
1549 return Fail(
"%s: Could not read output 0", __func__);
1557 bool isSupported =
false;
1562 IsElementwiseUnarySupported,
1573 validateFunc(outputInfo, isSupported);
1587 assert(layer !=
nullptr);
1595 VLOG(DRIVER) <<
"Converter::ConvertElu()";
1600 return Fail(
"%s: Operation has invalid inputs", __func__);
1607 return Fail(
"%s: Operation has invalid inputs", __func__);
1614 if (inputType == OperandType::TENSOR_FLOAT16)
1618 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, alpha, model, data))
1620 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
1623 desc.
m_A =
static_cast<float>(alpha);
1625 else if (inputType == OperandType::TENSOR_FLOAT32)
1629 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
1634 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
1642 VLOG(DRIVER) <<
"Converter::ConvertExpandDims()";
1648 return Fail(
"%s: Operation has invalid input", __func__);
1654 return Fail(
"%s: Operation has invalid output", __func__);
1660 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
1662 return Fail(
"%s: failed to get axis input value", __func__);
1671 catch (
const std::exception& e)
1673 return Fail(
"%s: %s", __func__, e.what());
1679 bool isSupported =
false;
1695 if (targetShape != outputInfo.
GetShape())
1697 return Fail(
"%s: Shape of the output operand does not match the resolved expanded shape", __func__);
1699 validateFunc(outputInfo, isSupported);
1713 assert(layer !=
nullptr);
1721 VLOG(DRIVER) <<
"Converter::ConvertFill()";
1725 return Fail(
"%s: Operation has invalid inputs", __func__);
1731 return Fail(
"%s: Could not read output", __func__);
1738 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
1745 if (outputType == OperandType::TENSOR_FLOAT16)
1749 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
1751 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1754 descriptor.
m_Value =
static_cast<float>(value);
1756 else if (outputType == OperandType::TENSOR_FLOAT32)
1760 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1763 else if (outputType == OperandType::TENSOR_INT32)
1767 if (!
GetInputScalar(operation, 1, OperandType::INT32, value, model, data))
1769 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1772 descriptor.
m_Value =
static_cast<float>(value);
1776 return Fail(
"%s: Unsupported input tensor type: %d", __func__, outputType);
1779 bool isSupported =
false;
1796 assert(layer !=
nullptr);
1804 VLOG(DRIVER) <<
"Converter::ConvertFloor()";
1808 return Fail(
"%s: Operation has invalid inputs", __func__);
1814 return Fail(
"%s: Operation has invalid outputs", __func__);
1819 bool isSupported =
false;
1834 validateFunc(outputInfo, isSupported);
1848 assert(layer !=
nullptr);
1856 VLOG(DRIVER) <<
"Converter::ConvertFullyConnected()";
1860 return Fail(
"%s: Operation has invalid inputs", __func__);
1866 return Fail(
"%s: Could not read output 0", __func__);
1874 if (!weightsOperand)
1876 return Fail(
"%s: Could not read weights", __func__);
1884 return Fail(
"%s: Operation has invalid inputs", __func__);
1891 return Fail(
"%s: Could not read bias", __func__);
1899 return Fail(
"%s: Operation has invalid inputs", __func__);
1908 catch (
const std::exception& e)
1910 return Fail(
"%s: %s", __func__, e.what());
1915 SanitizeBiasQuantizationScale(biasInfo, weightsInfo, reshapedInfo);
1917 ActivationFn activationFunction;
1920 return Fail(
"%s: Operation has invalid inputs", __func__);
1928 bool isSupported =
false;
1932 if (!VerifyFullyConnectedShapes(reshapedInfo.
GetShape(),
1937 isSupported =
false;
1938 Fail(
"%s: Expected outputShape does not match actual outputShape", __func__);
1943 IsFullyConnectedSupported,
1956 validateFunc(outputInfo, isSupported);
1978 assert(reshapeLayer !=
nullptr);
1993 data,
nullptr, validateFunc, activationFunction);
1998 VLOG(DRIVER) <<
"Converter::ConvertGather()";
2003 return Fail(
"%s: Operation has invalid input", __func__);
2010 return Fail(
"%s: Operation has invalid indices", __func__);
2017 return Fail(
"%s: Operation has invalid output", __func__);
2021 if (outputDimensions != inputDimensions + indicesDimensions - 1)
2023 return Fail(
"%s: Operation has invalid output dimensions: %d. Output must be an (%d + %d - 1)-D tensor",
2024 __func__, outputDimensions, inputDimensions, indicesDimensions);
2028 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
2030 return Fail(
"%s: Operation has invalid or unsupported axis operand", __func__);
2032 int32_t inputDimensions_int =
static_cast<int32_t
>(inputDimensions);
2033 if ((axis < -inputDimensions_int) || (inputDimensions_int <= axis))
2035 return Fail(
"%s: Operation has invalid axis: %d. It is out of bounds [-%d, %d))", __func__, axis,
2036 inputDimensions, inputDimensions);
2042 bool isSupported =
false;
2059 validateFunc(outputInfo, isSupported);
2073 assert(layer !=
nullptr);
2082 VLOG(DRIVER) <<
"Converter::ConvertGroupedConv2d()";
2089 return Fail(
"%s: Operation has invalid inputs", __func__);
2096 return Fail(
"%s: Could not read output 0", __func__);
2102 if (operation.inputs.size() == 12)
2116 const ConstTensorPin weightsPin = (dataLayout == DataLayout::NCHW) ?
2118 model, data, ohwiToOihw) :
2124 return Fail(
"%s: Operation has invalid inputs", __func__);
2129 SanitizeBiasQuantizationScale(biases.
GetInfo(), weights.
GetInfo(), inputInfo);
2137 const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
2138 const unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
2139 const unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
2146 ActivationFn activation;
2148 if (operation.inputs.size() == 12)
2156 !
GetInputScalar(operation, 9, OperandType::INT32, numGroups, model, data) ||
2159 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
2163 else if (operation.inputs.size() == 9)
2165 ::android::nn::PaddingScheme paddingScheme;
2169 !
GetInputScalar(operation, 6, OperandType::INT32, numGroups, model, data) ||
2172 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
2175 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
2176 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
2178 const uint32_t kernelX = weightsShape[widthIndex];
2179 const uint32_t kernelY = weightsShape[heightIndex];
2186 return Fail(
"%s: Unsupported number of operation inputs", __func__);
2190 const unsigned int outputChannels = weightsShape[0];
2192 const unsigned int channelsPerGroup = weightsShape[channelsIndex];
2193 const unsigned int channelMultiplier = outputChannels / numGroups;
2200 return Fail(
"%s: Number of groups must be greater than 0. Got: %d", __func__, numGroups);
2203 if (outputChannels % numGroups != 0u)
2205 return Fail(
"%s: Output channels must be divisible by the number of groups", __func__);
2211 unsigned int splitterDimSizes[4] = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
2212 splitterDimSizes[channelsIndex] /= numGroups;
2220 std::vector<std::reference_wrapper<TensorInfo>> splitterOutputInfos(numGroups, std::ref(splitterOutputInfo));
2223 for (
unsigned int group = 0u; group < numGroups; ++group)
2225 splitterDesc.SetViewOriginCoord(group, channelsIndex, splitterDimSizes[channelsIndex] * group);
2226 for (
unsigned int dimIdx = 0u; dimIdx < 4u; dimIdx++)
2228 splitterDesc.SetViewSize(group, dimIdx, splitterDimSizes[dimIdx]);
2232 bool isSupported =
false;
2235 IsSplitterSupported,
2240 splitterOutputInfos,
2251 return Fail(
"%s: Failed to add SplitterLayer", __func__);
2255 for (
unsigned int group = 0u; group < splitterLayer->
GetNumOutputSlots(); ++group)
2266 groupInputShape[channelsIndex] = channelsPerGroup;
2269 groupWeightsShape[0] /= channelMultiplier * numGroups;
2275 groupInputInfo.SetShape(groupInputShape);
2279 groupWeightsInfo.SetShape(groupWeightsShape);
2283 groupBiasesInfo.SetShape(groupBiasesShape);
2291 groupOutputShape[channelsIndex] = 1;
2293 groupOutputInfo.SetShape(groupOutputShape);
2295 const unsigned int weightsDataTypeSize =
GetDataTypeSize(groupWeightsInfo.GetDataType());
2296 const unsigned int biasesDataTypeSize =
GetDataTypeSize(groupBiasesInfo.GetDataType());
2298 std::vector<IConnectableLayer*> convLayers(numGroups * channelMultiplier,
nullptr);
2299 for (
unsigned int group = 0u; group < numGroups; ++group)
2301 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2303 auto index = group * channelMultiplier + m;
2305 const unsigned int weightsDataOffset = groupWeightsShape.GetNumElements() * index * weightsDataTypeSize;
2306 const unsigned int biasesDataOffset = groupBiasesShape.GetNumElements() * index * biasesDataTypeSize;
2312 groupWeightsInfo.SetQuantizationScales(
2313 std::vector<float>(weightsQuantScales.begin() + index,
2314 weightsQuantScales.begin() + index + groupWeightsShape[0]));
2318 groupBiasesInfo.SetQuantizationScales(
2319 std::vector<float>(biasesQuantScales.begin() + index,
2320 biasesQuantScales.begin() + index + groupWeightsShape[0]));
2325 static_cast<const void *
>(
reinterpret_cast<const char *
>(weights.
GetMemoryArea()) +
2326 weightsDataOffset));
2328 static_cast<const void *
>(
reinterpret_cast<const char *
>(biases.
GetMemoryArea()) +
2331 isSupported =
false;
2336 IsConvolution2dSupported,
2349 validateFunc(groupOutputInfo, isSupported);
2369 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
2394 convLayers[index] = convLayer;
2404 for (
unsigned int group = 0u; group < numGroups; ++group)
2406 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2408 auto index = group * channelMultiplier + m;
2414 isSupported =
false;
2421 std::vector<const TensorInfo*>(numGroups * channelMultiplier, &groupOutputInfo),
2434 return Fail(
"%s: AddConcatLayer failed", __func__);
2437 for (
unsigned int group = 0u; group < numGroups; ++group)
2439 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2441 auto index = group * channelMultiplier + m;
2442 convLayers[index]->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(index));
2448 data,
nullptr,
nullptr, activation);
2453 VLOG(DRIVER) <<
"Converter::ConvertHardSwish()";
2455 desc.
m_Function = ActivationFunction::HardSwish;
2462 VLOG(DRIVER) <<
"Converter::ConvertInstanceNormalization()";
2467 return Fail(
"%s: Operation has an invalid input 0", __func__);
2473 return Fail(
"%s: Operation has an invalid output", __func__);
2482 return Fail(
"%s: Operation has invalid inputs", __func__);
2488 if (inputType == OperandType::TENSOR_FLOAT16)
2494 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Gamma, model, data) ||
2495 !
GetInputScalar(operation, 2, OperandType::FLOAT16, fp16Beta, model, data) ||
2496 !
GetInputScalar(operation, 3, OperandType::FLOAT16, fp16Epsilon, model, data))
2498 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
2501 desc.
m_Gamma =
static_cast<float>(fp16Gamma);
2502 desc.
m_Beta =
static_cast<float>(fp16Beta);
2503 desc.
m_Eps =
static_cast<float>(fp16Epsilon);
2505 else if (inputType == OperandType::TENSOR_FLOAT32)
2511 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
2516 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2521 bool isSupported =
false;
2526 IsInstanceNormalizationSupported,
2541 validateFunc(outputInfo, isSupported);
2558 VLOG(DRIVER) <<
"Converter::ConvertL2Normalization()";
2560 if (operation.inputs.size() != 1)
2562 return Fail(
"%s: Optional inputs are not supported", __func__);
2568 return Fail(
"%s: Operation has invalid inputs", __func__);
2574 return Fail(
"%s: Could not read output 0", __func__);
2582 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2588 bool isSupported =
false;
2593 IsL2NormalizationSupported,
2604 validateFunc(outputInfo, isSupported);
2618 assert(layer !=
nullptr);
2626 VLOG(DRIVER) <<
"Converter::ConvertL2Pool2d()";
2627 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::L2, model, data);
2630 bool Converter::ConvertLocalResponseNormalization(
const Operation& operation,
2634 VLOG(DRIVER) <<
"Converter::ConvertLocalResponseNormalization()";
2636 if (operation.inputs.size() != 5)
2638 return Fail(
"%s: Optional inputs are not supported", __func__);
2644 return Fail(
"%s: Operation has invalid inputs", __func__);
2650 return Fail(
"%s: Could not read output 0", __func__);
2658 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2672 return Fail(
"%s: Operation has invalid inputs", __func__);
2679 bool isSupported =
false;
2684 IsNormalizationSupported,
2695 validateFunc(outputInfo, isSupported);
2710 assert(layer !=
nullptr);
2716 bool Converter::ConvertLogicalBinary(
const Operation& operation,
2721 VLOG(DRIVER) <<
"Converter::ConvertLogicalBinary()";
2722 VLOG(DRIVER) <<
"ConvertLogicalBinary()";
2730 return Fail(
"%s: Operation has invalid inputs", __func__);
2736 return Fail(
"%s: Could not read output 0", __func__);
2745 bool isSupported =
false;
2750 IsLogicalBinarySupported,
2762 validateFunc(outputInfo, isSupported);
2776 assert(layer !=
nullptr);
2778 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
2779 if (!isReshapeSupported)
2789 VLOG(DRIVER) <<
"Converter::ConvertLogistic()";
2798 VLOG(DRIVER) <<
"Converter::ConvertLogSoftmax()";
2803 return Fail(
"%s: Failed to read input 0", __func__);
2809 return Fail(
"%s: Failed to read output", __func__);
2818 return Fail(
"%s: Operation has invalid inputs", __func__);
2824 if (inputType == OperandType::TENSOR_FLOAT16)
2827 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Beta, model, data))
2829 return Fail(
"%s: Failed to read input 1 (FLOAT16)", __func__);
2832 descriptor.
m_Beta =
static_cast<float>(fp16Beta);
2834 else if (inputType == OperandType::TENSOR_FLOAT32)
2838 return Fail(
"%s: Failed to read input 1 (FLOAT32)", __func__);
2843 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2849 return Fail(
"%s: Failed to read input 2", __func__);
2852 bool isSupported =
false;
2857 IsLogSoftmaxSupported,
2872 validateFunc(outputInfo, isSupported);
2884 return Fail(
"%s: AddLogSoftmaxLayer() returned nullptr", __func__);
2894 VLOG(DRIVER) <<
"Converter::ConvertLstm()";
2902 return Fail(
"%s: Could not read input 0: input", __func__);
2908 return Fail(
"%s: Could not read input 18: outputStateIn", __func__);
2914 return Fail(
"%s: Could not read input 19: cellStateIn", __func__);
2952 if (!inputToForgetWeightsPin.
IsValid() ||
2953 !inputToCellWeightsPin.
IsValid() ||
2954 !inputToOutputWeightsPin.
IsValid() ||
2955 !recurrentToForgetWeightsPin.
IsValid() ||
2956 !recurrentToCellWeightsPin.
IsValid() ||
2957 !recurrentToOutputWeightsPin.
IsValid() ||
2958 !forgetGateBiasPin.
IsValid() ||
2962 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3008 if ((!inputToInputWeightsPin.
IsValid() && !inputToInputWeightsPin.
IsOptional()) ||
3009 (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional()) ||
3017 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3027 ActivationFn activation = ActivationFn::kActivationNone;
3031 !
GetInputScalar(operation, 21, OperandType::FLOAT32, cellClip, model, data) ||
3032 !
GetInputScalar(operation, 22, OperandType::FLOAT32, projClip, model, data))
3034 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
3082 return Fail(
"%s: Could not read output 0: scratchBuffer", __func__);
3086 if (!outputStateOut)
3088 return Fail(
"%s: Could not read output 1: outputStateOut", __func__);
3094 return Fail(
"%s: Could not read output 2: cellStateOut", __func__);
3101 return Fail(
"%s: Could not read output 3: output", __func__);
3150 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
3151 " and input gate bias must be provided", __func__);
3156 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
3164 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
3165 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
3174 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
3175 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
3240 bool isSupported =
false;
3260 bool isDynamic =
false;
3266 validateFunc(outputInfo, isSupported);
3302 operation, 3, *layer, 3, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
3309 VLOG(DRIVER) <<
"Converter::ConvertMaxPool2d()";
3310 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Max, model, data);
3315 VLOG(DRIVER) <<
"Converter::ConvertMean()";
3320 return Fail(
"%s: Operation has invalid inputs", __func__);
3326 return Fail(
"%s: Could not read output 0", __func__);
3334 return Fail(
"%s: Could not read input 1", __func__);
3337 std::vector<int32_t> axis;
3340 return Fail(
"%s: Input 1 has invalid values", __func__);
3347 std::set<unsigned int> uniqueAxis;
3348 std::transform(axis.begin(), axis.end(),
3349 std::inserter(uniqueAxis, uniqueAxis.begin()),
3350 [rank](
int i) ->
unsigned int { return (i + rank) % rank; });
3353 int32_t keepDims = 0;
3356 return Fail(
"%s: Could not read input 2", __func__);
3360 descriptor.
m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
3363 bool isSupported =
false;
3379 validateFunc(outputInfo, isSupported);
3393 assert(layer !=
nullptr);
3401 VLOG(DRIVER) <<
"Converter::ConvertPad()";
3406 return Fail(
"%s: Operation has invalid inputs", __func__);
3415 return Fail(
"%s: Could not convert paddings", __func__);
3431 return Fail(
"%s: Could not read output", __func__);
3436 bool isSupported =
false;
3452 validateFunc(outputInfo, isSupported);
3466 assert(layer !=
nullptr);
3474 VLOG(DRIVER) <<
"Converter::ConvertPadV2()";
3479 return Fail(
"%s: Could not read input 0", __func__);
3485 return Fail(
"%s: Could not read output", __func__);
3494 return Fail(
"%s: Could not convert paddings", __func__);
3506 return Fail(
"%s: Operation has invalid inputs", __func__);
3510 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
3513 if (!
GetInputScalar(operation, 2, operandType2, f16PadValue, model, data))
3515 return Fail(
"%s: Could not read input 2 (FLOAT16)", __func__);
3520 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
3524 return Fail(
"%s: Could not read input 2 (FLOAT32)", __func__);
3529 int32_t intPadValue = 0;
3532 return Fail(
"%s: Could not read input 2 (INT32)", __func__);
3538 return Fail(
"%s: Operation has invalid inputs: type mismatch", __func__);
3541 bool isSupported =
false;
3561 validateFunc(outputInfo, isSupported);
3571 assert(layer !=
nullptr);
3579 VLOG(DRIVER) <<
"Converter::ConvertPrelu()";
3586 return Fail(
"%s: Operation has invalid inputs", __func__);
3593 return Fail(
"%s: Could not read output", __func__);
3600 bool isSupported =
false;
3620 validateFunc(outputInfo, isSupported);
3633 return Fail(
"%s: AddPreluLayer failed", __func__);
3636 bool isReshapeSupported = BroadcastTensor(input, alpha, layer, data);
3637 if (!isReshapeSupported)
3647 VLOG(DRIVER) <<
"Converter::ConvertQuantize()";
3652 return Fail(
"%s: Operation has invalid input", __func__);
3658 return Fail(
"%s: Operation has invalid outputs", __func__);
3663 bool isSupported =
false;
3668 IsQuantizeSupported,
3682 validateFunc(outputInfo, isSupported);
3692 assert(layer !=
nullptr);
3700 VLOG(DRIVER) <<
"Converter::ConvertQuantizedLstm()";
3702 VLOG(DRIVER) <<
"ConvertQuantizedLstm()";
3710 return Fail(
"%s: Could not read input 0: input", __func__);
3715 if (!outputStatePrevTimeStep.
IsValid())
3717 return Fail(
"%s: Could not read input 18: outputStatePrevTimeStep", __func__);
3722 if (!cellStatePrevTimeStep.
IsValid())
3724 return Fail(
"%s: Could not read input 19: cellStatePrevTimeStep", __func__);
3771 if (!inputToForgetWeightsPin.
IsValid() ||
3772 !inputToCellWeightsPin.
IsValid() ||
3773 !inputToOutputWeightsPin.
IsValid() ||
3774 !recurrentToForgetWeightsPin.
IsValid() ||
3775 !recurrentToCellWeightsPin.
IsValid() ||
3776 !recurrentToOutputWeightsPin.
IsValid() ||
3777 !forgetGateBiasPin.
IsValid() ||
3781 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3874 || (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional())
3882 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3932 if ((!inputLayerNormWeightsPin.
IsValid() && !inputLayerNormWeightsPin.
IsOptional())
3933 || (!forgetLayerNormWeightsPin.
IsValid() && !forgetLayerNormWeightsPin.
IsOptional())
3934 || (!cellLayerNormWeightsPin.
IsValid() && !cellLayerNormWeightsPin.
IsOptional())
3935 || (!outputLayerNormWeightsPin.
IsValid() && !outputLayerNormWeightsPin.
IsOptional()))
3937 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3951 float cellClip, projClip, matMulInputGate, matMulForgetGate, matMulCellGate, matMulOutputGate, projInputScale;
3952 int projInputZeroPoint;
3954 if (!
GetInputScalar(operation, 24, OperandType::FLOAT32, cellClip, model, data,
true) ||
3955 !
GetInputScalar(operation, 25, OperandType::FLOAT32, projClip, model, data,
true) ||
3956 !
GetInputScalar(operation, 26, OperandType::FLOAT32, matMulInputGate, model, data) ||
3957 !
GetInputScalar(operation, 27, OperandType::FLOAT32, matMulForgetGate, model, data) ||
3958 !
GetInputScalar(operation, 28, OperandType::FLOAT32, matMulCellGate, model, data) ||
3959 !
GetInputScalar(operation, 29, OperandType::FLOAT32, matMulOutputGate, model, data) ||
3960 !
GetInputScalar(operation, 30, OperandType::INT32, projInputZeroPoint, model, data) ||
3961 !
GetInputScalar(operation, 31, OperandType::FLOAT32, projInputScale, model, data))
3963 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
3970 if (!outputStateOut)
3972 return Fail(
"%s: Could not read output 0: outputStateOut", __func__);
3979 return Fail(
"%s: Could not read output 1: cellStateOut", __func__);
3987 return Fail(
"%s: Could not read output 2: output", __func__);
4041 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
4042 " and input gate bias must be provided", __func__);
4047 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
4055 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
4056 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
4065 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
4066 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
4122 const TensorInfo constOutputStateOutInfo(outputStateOutInfo);
4123 const TensorInfo constOutputInfo(outputInfo);
4143 bool isSupported =
false;
4145 auto validateFunc = [&](
const armnn::TensorInfo& cellStateOutInfo,
bool& isSupported)
4153 outputStatePrevTimeStepInfo,
4154 cellStatePrevTimeStepInfo,
4155 constOutputStateOutInfo,
4162 bool isDynamic =
false;
4167 validateFunc(outputInfo, isSupported);
4191 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4198 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4200 operation, 1, *layer, 1, model, data,
nullptr, validateFunc,
4201 ActivationFn::kActivationNone,
true) &&
4208 VLOG(DRIVER) <<
"Converter::ConvertQuantized16BitLstm()";
4209 VLOG(DRIVER) <<
"Policy::ConvertQuantized16BitLstm()";
4217 return Fail(
"%s: Could not read input 0: input", __func__);
4224 if (!previousCellStateIn.
IsValid())
4226 return Fail(
"%s: Could not read input 13: previousCellStateIn", __func__);
4233 if (!previousOutputIn.
IsValid())
4235 return Fail(
"%s: Could not read input 14: previousOutputIn", __func__);
4311 if (!inputToInputWeightsPin.
IsValid() ||
4312 !inputToForgetWeightsPin.
IsValid() ||
4313 !inputToCellWeightsPin.
IsValid() ||
4314 !inputToOutputWeightsPin.
IsValid() ||
4315 !recurrentToInputWeightsPin.
IsValid() ||
4316 !recurrentToForgetWeightsPin.
IsValid() ||
4317 !recurrentToCellWeightsPin.
IsValid() ||
4318 !recurrentToOutputWeightsPin.
IsValid() ||
4319 !inputGateBiasPin.
IsValid() ||
4320 !forgetGateBiasPin.
IsValid() ||
4324 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4334 return Fail(
"%s: Could not read output 0: cellStateOut", __func__);
4342 return Fail(
"%s: Could not read output 1: output", __func__);
4357 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4389 bool isSupported =
false;
4394 IsQuantizedLstmSupported,
4399 previousCellStateInInfo,
4400 previousOutputInInfo,
4406 bool isDynamic =
false;
4410 validateFunc(outputInfo, isSupported);
4438 operation, 1, *layer, 1, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
4445 VLOG(DRIVER) <<
"Converter::ConvertRank()";
4450 if (inputOperand ==
nullptr || outputOperand ==
nullptr)
4452 return Fail(
"%s: Operation has invalid inputs", __func__);
4455 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4456 const Shape outputOperandShape = GetOperandShape(*outputOperand);
4461 return Fail(
"%s: Could not read input 0", __func__);
4467 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4470 bool isSupported =
false;
4486 assert(layer !=
nullptr);
4494 VLOG(DRIVER) <<
"Converter::ConvertReLu()";
4502 return Fail(
"%s: Input 0 is invalid",
"operationName", __func__);
4513 bool isSupported =
false;
4518 IsActivationSupported,
4533 validateFunc(outInfo, isSupported);
4542 if (layer ==
nullptr)
4554 VLOG(DRIVER) <<
"Converter::ConvertReLu1()";
4565 VLOG(DRIVER) <<
"Converter::ConvertReLu6()";
4575 VLOG(DRIVER) <<
"Converter::ConvertReshape()";
4581 if (inputOperand ==
nullptr
4582 || requestedShapeOperand ==
nullptr
4583 || outputOperand ==
nullptr)
4585 return Fail(
"%s: Operation has invalid inputs", __func__);
4588 if (requestedShapeOperand->dimensions.size() != 1)
4590 return Fail(
"%s: Input 1 expected to be one-dimensional (found %i dimensions)",
4591 __func__, requestedShapeOperand->dimensions.size());
4594 std::vector<int32_t> targetDimensions;
4597 return Fail(
"%s: Could not read values of input 1", __func__);
4600 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4602 Shape requestedShape;
4605 if (!reshapePrepare(inputOperandShape, targetDimensions.data(), targetDimensions.size(), &requestedShape))
4607 return Fail(
"%s: Failed to resolve the requested shape", __func__);
4613 return Fail(
"%s: Could not read input 0", __func__);
4618 requestedShape.dimensions.data());
4622 bool isSupported =
false;
4638 validateFunc(outputInfo, isSupported);
4652 assert(layer !=
nullptr);
4658 bool Converter::ConvertResize(
const Operation& operation,
4663 VLOG(DRIVER) <<
"Converter::ConvertResize()";
4669 return Fail(
"%s: Could not read input 0", __func__);
4675 return Fail(
"%s: Could not read output 0", __func__);
4682 descriptor.
m_Method = resizeMethod;
4691 return Fail(
"%s: Operation has invalid inputs", __func__);
4694 if (operandType1 != operandType2)
4696 return Fail(
"%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
4699 if (operandType1 == OperandType::INT32)
4702 int32_t targetWidth = 0;
4703 int32_t targetHeight = 0;
4705 if (!
GetInputInt32(operation, 1, targetWidth, model, data) ||
4708 return Fail(
"%s: Operation has invalid inputs for resizing by shape", __func__);
4711 if (targetWidth < 0 || targetHeight < 0)
4713 return Fail(
"%s: Operation has invalid inputs for resizing by shape. "
4714 "Target width/height cannot be < 0", __func__);
4717 descriptor.
m_TargetWidth =
static_cast<uint32_t
>(targetWidth);
4720 else if (operandType1 == OperandType::FLOAT32)
4723 float widthScale = 1.0f;
4724 float heightScale = 1.0f;
4729 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
4735 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
4736 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
4741 else if (operandType1 == OperandType::FLOAT16)
4746 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, widthScale, model, data) ||
4747 !
GetInputScalar(operation, 2, OperandType::FLOAT16, heightScale, model, data))
4749 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
4755 Half width =
static_cast<Half>(inputShape[dataLayoutIndexed.GetWidthIndex()]);
4756 Half height =
static_cast<Half>(inputShape[dataLayoutIndexed.GetHeightIndex()]);
4763 return Fail(
"%s: Operand has invalid data type for resizing by scale", __func__);
4769 bool isSupported =
false;
4789 validateFunc(outputInfo, isSupported);
4799 assert(layer !=
nullptr);
4807 VLOG(DRIVER) <<
"Converter::ConvertReverseV2()";
4813 return Fail(
"%s: Operation has invalid inputs", __func__);
4821 return Fail(
"%s: Could not read output 0", __func__);
4825 bool isSupported =
false;
4830 IsReverseV2Supported,
4841 validateFunc(outputInfo, isSupported);
4855 assert(layer !=
nullptr);
4864 VLOG(DRIVER) <<
"Converter::ConvertSpaceToBatchNd()";
4869 return Fail(
"%s: Operation has invalid inputs", __func__);
4874 unsigned int spatialDim = rank - 2;
4878 Fail(
"%s: Only inputs with rank 4 are supported", __func__);
4884 return Fail(
"%s: Could not read output 0", __func__);
4892 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
4895 return Fail(
"%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
4898 std::vector<int32_t> blockShape;
4901 return Fail(
"%s: Operation has an invalid or unsupported block size operand", __func__);
4903 if(std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i)
4906 return Fail(
"%s: Block shape must be at least 1 in all dimensions.", __func__);
4909 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
4912 return Fail(
"%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
4915 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
4916 std::vector<int32_t> paddings;
4919 return Fail(
"%s: Operation has an invalid or unsupported paddings operand", __func__);
4921 for (
unsigned int i = 0; i < paddings.size() - 1; i += 2)
4923 int paddingBeforeInput = paddings[i];
4924 int paddingAfterInput = paddings[i + 1];
4925 if(paddingBeforeInput < 0 || paddingAfterInput < 0)
4927 return Fail(
"%s: Operation has invalid paddings operand, invalid padding values.", __func__);
4930 paddingList.emplace_back((
unsigned int) paddingBeforeInput, (
unsigned int) paddingAfterInput);
4935 descriptor.
m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
4936 descriptor.
m_PadList.assign(paddingList.cbegin(), paddingList.cend());
4938 if(Is12OrLaterOperand(*output))
4943 bool isSupported =
false;
4948 IsSpaceToBatchNdSupported,
4962 validateFunc(outputInfo, isSupported);
4972 assert(layer !=
nullptr);
4980 VLOG(DRIVER) <<
"Converter::ConvertSpaceToDepth()";
4985 return Fail(
"%s: Operation has invalid inputs", __func__);
4992 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
4998 return Fail(
"%s: Could not read output 0", __func__);
5009 return Fail(
"%s: Block size must be at least 1 in all dimensions", __func__);
5014 bool isSupported =
false;
5019 IsSpaceToDepthSupported,
5034 validateFunc(outputInfo, isSupported);
5044 assert(layer !=
nullptr);
5052 VLOG(DRIVER) <<
"Converter::ConvertSoftmax()";
5057 return Fail(
"%s: Operation has invalid inputs", __func__);
5063 return Fail(
"%s: Operation has no outputs", __func__);
5072 if (outputType == OperandType::TENSOR_FLOAT16)
5076 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
5078 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5081 desc.
m_Beta =
static_cast<float>(value);
5087 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5098 return Fail(
"%s: Operation has invalid inputs", __func__);
5101 bool isSupported =
false;
5121 validateFunc(outputInfo, isSupported);
5131 assert(layer !=
nullptr);
5139 VLOG(DRIVER) <<
"Converter::ConvertTanH()";
5151 VLOG(DRIVER) <<
"Converter::ConvertTile()";
5156 return Fail(
"%s: Operation has invalid inputs", __func__);
5163 return Fail(
"%s: Operation has no outputs", __func__);
5168 if (!multiplesOperand)
5170 return Fail(
"%s: Could not read input 1", __func__);
5172 std::vector<int32_t> multiples;
5175 return Fail(
"%s: Input 1 has invalid values", __func__);
5179 descriptor.
m_Multiples.assign(multiples.begin(), multiples.end());
5181 bool isSupported =
false;
5201 validateFunc(outputInfo, isSupported);
5211 assert(layer !=
nullptr);
5219 VLOG(DRIVER) <<
"Converter::ConvertTransposeConv2d()";
5225 return Fail(
"%s: Operation has invalid inputs", __func__);
5232 return Fail(
"%s: Could not read output 0", __func__);
5242 if (weightsOperand ==
nullptr)
5244 return Fail(
"%s: Operand is invalid", __func__);
5250 bool implicitPadding = operation.inputs.size() == 9;
5252 if (implicitPadding )
5262 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
5263 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
5271 model, data, OHWIToOIHW) :
5280 return Fail(
"%s: Operation has invalid weights", __func__);
5285 return Fail(
"%s: Operation has invalid biases", __func__);
5290 SanitizeBiasQuantizationScale(bias.
GetInfo(), weights.
GetInfo(), inputInfo);
5292 ActivationFn activation;
5294 if (implicitPadding)
5299 int32_t padRight{0};
5301 int32_t padBottom{0};
5303 ::android::nn::PaddingScheme paddingScheme;
5305 !
GetInputScalar(operation, 5, OperandType::INT32, strideX, model, data) ||
5306 !
GetInputScalar(operation, 6, OperandType::INT32, strideY, model, data) ||
5309 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
5312 const uint32_t kernelX = weights.
GetShape()[widthIndex];
5313 const uint32_t kernelY = weights.
GetShape()[heightIndex];
5317 std::vector<int32_t> outputShape;
5318 if ((outputShapeOperand) && (
GetTensorInt32Values(*outputShapeOperand, outputShape, model, data)))
5321 for (
int dimension : outputShape)
5323 desc.
m_OutputShape.push_back(
static_cast<unsigned int>(dimension));
5333 if (outputShape.size() == 0)
5335 return Fail(
"%s: Padding sizes cannot be inferred", __func__);
5338 outputX = outputShape[widthIndex];
5339 outputY = outputShape[heightIndex];
5343 outputX = outputInfo.
GetShape()[widthIndex];
5344 outputY = outputInfo.
GetShape()[heightIndex];
5347 CalcPaddingTransposeConv(outputX, kernelX, strideX, padLeft, padRight, paddingScheme);
5348 CalcPaddingTransposeConv(outputY, kernelY, strideY, padTop, padBottom, paddingScheme);
5352 if (padLeft < 0 || padRight < 0 || padTop < 0 || padBottom < 0)
5354 return Fail(
"%s: Negative padding values are not supported", __func__);
5357 desc.
m_StrideX = armnn::numeric_cast<uint32_t>(strideX);
5358 desc.
m_StrideY = armnn::numeric_cast<uint32_t>(strideY);
5359 desc.
m_PadLeft = armnn::numeric_cast<uint32_t>(padLeft);
5360 desc.
m_PadRight = armnn::numeric_cast<uint32_t>(padRight);
5361 desc.
m_PadTop = armnn::numeric_cast<uint32_t>(padTop);
5362 desc.
m_PadBottom = armnn::numeric_cast<uint32_t>(padBottom);
5364 else if (operation.inputs.size() == 11)
5375 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
5380 return Fail(
"%s: Unsupported number of operation inputs", __func__);
5386 bool isSupported =
false;
5391 IsTransposeConvolution2dSupported,
5408 validateFunc(outputInfo, isSupported);
5420 return Fail(
"%s: AddTransposeConvolution2dLayer failed", __func__);
5426 data,
nullptr, validateFunc, activation);
5431 VLOG(DRIVER) <<
"Converter::ConvertSqrt()";
5440 VLOG(DRIVER) <<
"Converter::ConvertSqueeze()";
5445 return Fail(
"%s: Operation has invalid inputs", __func__);
5452 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5458 return Fail(
"%s: Could not read output 0", __func__);
5463 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
5470 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
5472 std::vector<int32_t> axis;
5475 axis.assign(dimensionSequence,
5476 dimensionSequence + rank);
5480 return Fail(
"%s: Operation has an invalid or unsupported axis operand", __func__);
5483 std::vector<uint32_t> outputDims;
5484 for (
unsigned int i = 0; i < rank; i++)
5486 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
5487 auto currentDimension = inputInfo.
GetShape()[i];
5488 if (skipSqueeze || currentDimension != 1)
5490 outputDims.push_back(currentDimension);
5502 bool isSupported =
false;
5520 assert(layer !=
nullptr);
5528 VLOG(DRIVER) <<
"Converter::ConvertStridedSlice()";
5533 return Fail(
"%s: Operation has invalid inputs", __func__);
5540 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5546 return Fail(
"%s: Could not read output 0", __func__);
5555 std::vector<int32_t> beginValues;
5556 std::vector<int32_t> endValues;
5557 std::vector<int32_t> stridesValues;
5560 auto ValidateInputOperands = [&] (
const Operand& operand, std::vector<int32_t>& operandValues)
5567 if (operandValues.size() != rank)
5575 if (!ValidateInputOperands(*beginOperand, beginValues)
5576 || !ValidateInputOperands(*endOperand, endValues)
5577 || !ValidateInputOperands(*stridesOperand, stridesValues))
5579 return Fail(
"%s: Operation has invalid input operand", __func__);
5583 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
5585 return Fail(
"%s: Stride must be non-zero value.", __func__);
5589 descriptor.
m_Begin.assign(beginValues.cbegin(), beginValues.cend());
5590 descriptor.
m_End.assign(endValues.cbegin(), endValues.cend());
5591 descriptor.
m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
5599 return Fail(
"%s: Operation has invalid inputs", __func__);
5602 bool isSupported =
false;
5607 IsStridedSliceSupported,
5622 validateFunc(outputInfo, isSupported);
5634 int stride = descriptor.
m_Stride[i];
5640 if (((descriptor.
m_Begin[i] - descriptor.
m_End[i]) > 1)
5641 || ((descriptor.
m_Begin[i] - descriptor.
m_End[i]) < -1))
5643 return Fail(
"%s: StridedSlice: Output will not be large enough to hold the slice", __func__);
5648 return Fail(
"%s: StridedSlice: Stride can not be negative while ShrinkAxisMask is set.", __func__);
5655 assert(layer !=
nullptr);
5663 VLOG(DRIVER) <<
"Converter::ConvertTranspose()";
5668 return Fail(
"%s: Operation has invalid inputs", __func__);
5675 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5682 std::vector<int32_t> perm(rank);
5683 if (!permOperand || (permOperand->lifetime == OperandLifeTime::NO_VALUE))
5685 for (
unsigned int i = rank; i > 0; i--)
5687 perm[rank - i] = armnn::numeric_cast<int> (i - 1);
5692 return Fail(
"%s: Operation has an invalid or unsupported permutation operand", __func__);
5695 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
5703 return Fail(
"%s: Could not read output 0", __func__);
5708 bool isSupported =
false;
5713 IsTransposeSupported,
5728 validateFunc(outputInfo, isSupported);
5738 assert(layer !=
nullptr);