7 #include <half/half.hpp>
14 using Half = half_float::half;
23 switch (operation.type)
25 case OperationType::ABS:
26 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Abs);
27 case OperationType::ADD:
28 return ConvertAdd(operation, model, data);
29 case OperationType::ARGMAX:
30 return ConvertArgMinMax(operation, model, data, ArgMinMaxFunction::Max);
31 case OperationType::ARGMIN:
32 return ConvertArgMinMax(operation, model, data, ArgMinMaxFunction::Min);
33 case OperationType::AVERAGE_POOL_2D:
34 return ConvertAveragePool2d(operation, model, data);
35 case OperationType::BATCH_MATMUL:
36 return ConvertBatchMatMul(operation, model, data);
37 case OperationType::BATCH_TO_SPACE_ND:
38 return ConvertBatchToSpaceNd(operation, model, data);
39 case OperationType::CAST:
40 return ConvertCast(operation, model, data);
41 case OperationType::CONCATENATION:
42 return ConvertConcatenation(operation, model, data);
43 case OperationType::CONV_2D:
44 return ConvertConv2d(operation, model, data);
45 case OperationType::DEPTH_TO_SPACE:
46 return ConvertDepthToSpace(operation, model, data);
47 case OperationType::DEPTHWISE_CONV_2D:
48 return ConvertDepthwiseConv2d(operation, model, data);
49 case OperationType::DEQUANTIZE:
50 return ConvertDequantize(operation, model, data);
51 case OperationType::DIV:
52 return ConvertDiv(operation, model, data);
53 case OperationType::ELU:
54 return ConvertElu(operation, model, data);
55 case OperationType::EQUAL:
56 return ConvertComparison(operation, model, data, ComparisonOperation::Equal);
57 case OperationType::EXP:
58 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Exp);
59 case OperationType::EXPAND_DIMS:
60 return ConvertExpandDims(operation, model, data);
61 case OperationType::FILL:
62 return ConvertFill(operation, model, data);
63 case OperationType::FLOOR:
64 return ConvertFloor(operation, model, data);
65 case OperationType::FULLY_CONNECTED:
66 return ConvertFullyConnected(operation, model, data);
67 case OperationType::GATHER:
68 return ConvertGather(operation, model, data);
69 case OperationType::GREATER:
70 return ConvertComparison(operation, model, data, ComparisonOperation::Greater);
71 case OperationType::GREATER_EQUAL:
72 return ConvertComparison(operation, model, data, ComparisonOperation::GreaterOrEqual);
73 case OperationType::GROUPED_CONV_2D:
74 return ConvertGroupedConv2d(operation, model, data);
75 case OperationType::HARD_SWISH:
76 return ConvertHardSwish(operation, model, data);
77 case OperationType::INSTANCE_NORMALIZATION:
78 return ConvertInstanceNormalization(operation, model, data);
79 case OperationType::L2_NORMALIZATION:
80 return ConvertL2Normalization(operation, model, data);
81 case OperationType::L2_POOL_2D:
82 return ConvertL2Pool2d(operation, model, data);
83 case OperationType::LESS:
84 return ConvertComparison(operation, model, data, ComparisonOperation::Less);
85 case OperationType::LESS_EQUAL:
86 return ConvertComparison(operation, model, data, ComparisonOperation::LessOrEqual);
87 case OperationType::LOCAL_RESPONSE_NORMALIZATION:
88 return ConvertLocalResponseNormalization(operation, model, data);
89 case OperationType::LOG:
90 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Log);
91 case OperationType::LOGICAL_AND:
92 return ConvertLogicalBinary(operation, model, data, LogicalBinaryOperation::LogicalAnd);
93 case OperationType::LOGICAL_NOT:
94 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::LogicalNot);
95 case OperationType::LOGICAL_OR:
96 return ConvertLogicalBinary(operation, model, data, LogicalBinaryOperation::LogicalOr);
97 case OperationType::LOGISTIC:
98 return ConvertLogistic(operation, model, data);
99 case OperationType::LOG_SOFTMAX:
100 return ConvertLogSoftmax(operation, model, data);
101 case OperationType::LSTM:
102 return ConvertLstm(operation, model, data);
103 case OperationType::MAX_POOL_2D:
104 return ConvertMaxPool2d(operation, model, data);
105 case OperationType::MAXIMUM:
106 return ConvertMaximum(operation, model, data);
107 case OperationType::MEAN:
108 return ConvertMean(operation, model, data);
109 case OperationType::MINIMUM:
110 return ConvertMinimum(operation, model, data);
111 case OperationType::MUL:
112 return ConvertMul(operation, model, data);
113 case OperationType::NEG:
114 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Neg);
115 case OperationType::NOT_EQUAL:
116 return ConvertComparison(operation, model, data, ComparisonOperation::NotEqual);
117 case OperationType::PAD:
118 return ConvertPad(operation, model, data);
119 case OperationType::PAD_V2:
120 return ConvertPadV2(operation, model, data);
121 case OperationType::PRELU:
122 return ConvertPrelu(operation, model, data);
123 case OperationType::QUANTIZE:
124 return ConvertQuantize(operation, model, data);
125 case OperationType::QUANTIZED_LSTM:
126 return ConvertQuantizedLstm(operation, model, data);
127 case OperationType::QUANTIZED_16BIT_LSTM:
128 return ConvertQuantized16BitLstm(operation, model, data);
129 case OperationType::RANK:
130 return ConvertRank(operation, model, data);
131 case OperationType::REDUCE_MAX:
133 case OperationType::REDUCE_MIN:
135 case OperationType::REDUCE_SUM:
137 case OperationType::RELU:
138 return ConvertReLu(operation, model, data);
139 case OperationType::RELU1:
140 return ConvertReLu1(operation, model, data);
141 case OperationType::RELU6:
142 return ConvertReLu6(operation, model, data);
143 case OperationType::RESHAPE:
144 return ConvertReshape(operation, model, data);
145 case OperationType::RESIZE_BILINEAR:
146 return ConvertResize(operation, model, data, ResizeMethod::Bilinear);
147 case OperationType::RESIZE_NEAREST_NEIGHBOR:
148 return ConvertResize(operation, model, data, ResizeMethod::NearestNeighbor);
149 case OperationType::RSQRT:
150 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Rsqrt);
151 case OperationType::SIN:
152 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Sin);
153 case OperationType::SOFTMAX:
154 return ConvertSoftmax(operation, model, data);
155 case OperationType::SPACE_TO_BATCH_ND :
156 return ConvertSpaceToBatchNd(operation, model, data);
157 case OperationType::SPACE_TO_DEPTH:
158 return ConvertSpaceToDepth(operation, model, data);
159 case OperationType::SQRT:
160 return ConvertSqrt(operation, model, data);
161 case OperationType::SQUEEZE:
162 return ConvertSqueeze(operation, model, data);
163 case OperationType::STRIDED_SLICE:
164 return ConvertStridedSlice(operation, model, data);
165 case OperationType::SUB:
166 return ConvertSub(operation, model, data);
167 case OperationType::TRANSPOSE:
168 return ConvertTranspose(operation, model, data);
169 case OperationType::TRANSPOSE_CONV_2D:
170 return ConvertTransposeConv2d(operation, model, data);
171 case OperationType::TANH:
172 return ConvertTanH(operation, model, data);
174 VLOG(DRIVER) <<
"Operation type: " << operation.type <<
"is not supported in ArmnnDriver";
181 VLOG(DRIVER) <<
"Converter::ConvertAdd()";
187 return Fail(
"%s: Operation has invalid inputs", __func__);
191 ActivationFn activationFunction;
194 return Fail(
"%s: Operation has invalid inputs", __func__);
208 bool isSupported =
false;
226 validateFunc(outputInfo, isSupported);
241 startLayer->SetBackendId(setBackend);
243 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
244 if (!isReshapeSupported)
250 data,
nullptr, validateFunc, activationFunction);
253 bool Converter::ConvertArgMinMax(
const Operation& operation,
258 VLOG(DRIVER) <<
"Converter::ConvertArgMinMax()";
265 return Fail(
"%s: Operation has invalid inputs", __func__);
269 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
271 return Fail(
"%s: Operation has invalid inputs. Failed to read axis.", __func__);
277 if (((axis < -rank) && (axis < 0)) || ((axis >= rank) && (axis > 0)))
282 return Fail(
"%s: Axis must be in range [-n, n)", __func__);
288 return Fail(
"%s: Could not read output 0", __func__);
299 bool isSupported =
false;
304 IsArgMinMaxSupported,
319 validateFunc(outputInfo, isSupported);
329 assert(layer !=
nullptr);
338 VLOG(DRIVER) <<
"Converter::ConvertAveragePool2d()";
339 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Average, model, data);
344 VLOG(DRIVER) <<
"Converter::ConvertBatchMatMul()";
350 return Fail(
"%s: Operation has invalid inputs", __func__);
357 if (rankInput0 > 4 || rankInput0 < 2)
359 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
363 if (rankInput1 > 4 || rankInput1 < 2)
365 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
372 return Fail(
"%s: Operation has invalid inputs", __func__);
379 return Fail(
"%s: Operation has invalid inputs", __func__);
382 if (input0Type != input1Type)
384 return Fail(
"%s: Operation has invalid inputs (Inputs must have same OperandCode)", __func__);
390 return Fail(
"%s: Could not read output 0", __func__);
402 bool isSupported =
false;
407 IsBatchMatMulSupported,
419 validateFunc(outputInfo, isSupported);
434 assert(layer !=
nullptr);
443 VLOG(DRIVER) <<
"Converter::ConvertBatchToSpaceNd()";
447 return Fail(
"%s: Operation has invalid inputs", __func__);
453 return Fail(
"%s: Could not read output 0", __func__);
461 return Fail(
"%s: Could not read input 1", __func__);
465 std::vector<int32_t> block;
468 return Fail(
"%s: Input 1 has invalid values", __func__);
476 Fail(
"%s: Only inputs with rank equal to 4 are supported", __func__);
479 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
481 return Fail(
"%s: Block sizes for each spatial dimension of the input tensor must be"
482 " greater than or equal to 1", __func__);
486 batchToSpaceNdDesc.
m_BlockShape.assign(block.cbegin(), block.cend());
489 if (Is12OrLaterOperand(*output))
494 batchToSpaceNdDesc.
m_Crops = {{0, 0}, {0, 0}};
496 bool isSupported =
false;
512 validateFunc(outputInfo, isSupported);
527 assert(layer !=
nullptr);
535 VLOG(DRIVER) <<
"Converter::ConvertCast()";
541 return Fail(
"%s: Operation has invalid inputs", __func__);
547 return Fail(
"%s: Could not read output 0", __func__);
553 bool isSupported =
false;
568 validateFunc(outputInfo, isSupported);
582 assert(layer !=
nullptr);
588 bool Converter::ConvertComparison(
const Operation& operation,
593 VLOG(DRIVER) <<
"Converter::ConvertComparison()";
601 return Fail(
"%s: Operation has invalid inputs", __func__);
607 return Fail(
"%s: Could not read output 0", __func__);
616 bool isSupported =
false;
621 IsComparisonSupported,
633 validateFunc(outputInfo, isSupported);
647 assert(layer !=
nullptr);
649 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
650 if (!isReshapeSupported)
667 VLOG(DRIVER) <<
"Converter::ConvertConcatenation()";
670 if (operation.inputs.size() <= 1)
672 return Fail(
"%s: Operation has insufficient arguments", __func__);
676 const std::size_t numInputTensors = operation.inputs.size() - 1;
679 if (!
GetInputScalar(operation, numInputTensors, OperandType::INT32, concatDim, model, data))
681 return Fail(
"%s: Operation has invalid inputs", __func__);
687 return Fail(
"%s: Operation has no outputs", __func__);
703 if (concatDim >=
static_cast<int32_t
>(outputShape.
GetNumDimensions()) || concatDim < 0)
705 return Fail(
"%s: Operation has invalid concat axis: %d", __func__, concatDim);
708 std::vector<LayerInputHandle> inputHandles;
709 std::vector<armnn::TensorShape> inputShapes;
711 inputHandles.reserve(numInputTensors);
712 inputShapes.reserve(numInputTensors);
714 bool inputsHaveBeenReshaped =
false;
715 unsigned int tensorDimensionsAdded = 0;
716 for (uint32_t i = 0; i < numInputTensors; ++i)
721 return Fail(
"%s: Operation has invalid inputs", __func__);
725 if (!operandInputHandle.
IsValid())
727 return Fail(
"%s: Operation has invalid inputs", __func__);
733 return Fail(
"%s: Operands with rank 0 are not supported", __func__);
736 if (RequiresReshape(operandShape))
738 inputsHaveBeenReshaped =
true;
746 tensorDimensionsAdded = 1;
751 tensorDimensionsAdded = 2;
757 bool isSupported =
false;
776 operandShape = reshapeInfo.
GetShape();
780 inputShapes.emplace_back(operandShape);
781 inputHandles.emplace_back(operandInputHandle);
783 if (!inputHandles.back().IsValid())
785 return Fail(
"%s: Operation has invalid inputs", __func__);
789 ARMNN_ASSERT(inputShapes.size() == inputHandles.size());
791 if (inputsHaveBeenReshaped)
794 concatDim += tensorDimensionsAdded;
797 if (tensorDimensionsAdded == 1)
808 else if (tensorDimensionsAdded == 2)
823 std::pair<armnn::PermutationVector, armnn::PermutationVector> permutationPair =
824 std::make_pair(IdentityPermutation4D, IdentityPermutation4D);
825 bool needPermute = CreateConcatPermutationParameters(inputShapes[0].GetNumDimensions(),
830 if (!isDynamicTensor)
841 if (!TransposeInputTensors(data, inputHandles, inputShapes, permutationPair.first))
856 }
catch (std::exception& error)
858 return Fail(
"%s: Error preparing concat descriptor. %s", __func__,
error.what());
863 if (!isDynamicTensor)
865 if (!ValidateConcatOutputShape(inputShapes, outputShape, concatDim))
867 return Fail(
"%s: Error validating the output shape for concat", __func__);
871 std::vector<const armnn::TensorInfo*> inputTensorInfos;
872 std::transform(inputHandles.begin(), inputHandles.end(), std::back_inserter(inputTensorInfos),
875 bool isSupported =
false;
888 if (!isDynamicTensor)
890 validateFunc(outputInfo, isSupported);
904 assert(layer !=
nullptr);
908 assert(
static_cast<std::size_t
>(numInputSlots) == inputHandles.size());
909 for (
int i = 0; i < numInputSlots; ++i)
916 auto transposeOutputShape = [&](){
921 permutationPair.second);
925 IsTransposeSupported,
938 permutationPair.second);
940 layer = &deswizzleLayer;
945 if (needPermute && !isDynamicTensor)
947 transposeOutputShape();
950 if (inputsHaveBeenReshaped)
956 if (!ValidateConcatOutputShape(inputShapes,
960 return Fail(
"%s: Error validating the output shape for concat", __func__);
962 transposeOutputShape();
967 if (tensorDimensionsAdded == 1)
972 else if (tensorDimensionsAdded == 2)
983 auto validateReshapeFunc = [&](
const armnn::TensorInfo& afterConcatInfo,
bool& isSupported){
996 validateReshapeFunc(afterConcatInfo, isSupported);
1015 validateReshapeFunc);
1023 VLOG(DRIVER) <<
"Converter::ConvertConv2d()";
1028 return Fail(
"%s: Operation has invalid inputs", __func__);
1034 return Fail(
"%s: Could not read output 0", __func__);
1044 bool implicitPadding = operation.inputs.size() == 7
1045 || (operation.inputs.size() >= 8
1048 if (implicitPadding)
1052 else if (operation.inputs.size() >= 10)
1066 return Fail(
"%s: Operation has unsupported weights OperandLifeTime", __func__);
1075 return Fail(
"%s: Operation has invalid inputs", __func__);
1081 return Fail(
"%s: Operation has invalid inputs", __func__);
1088 ActivationFn activation;
1089 if (implicitPadding)
1091 ::android::nn::PaddingScheme paddingScheme;
1098 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1102 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1103 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1104 const uint32_t kernelX = weightsInfo.
GetShape()[widthIndex];
1105 const uint32_t kernelY = weightsInfo.
GetShape()[heightIndex];
1106 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1107 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1113 else if (operation.inputs.size() >= 10)
1125 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1130 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1136 bool requiresValidation =
true;
1145 requiresValidation =
false;
1146 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Weights and Biases are as INPUTS.";
1150 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1163 if (requiresValidation)
1165 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Requires Validation!";
1166 bool isSupported =
false;
1169 validateFunc(outputInfo, isSupported);
1187 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
1199 VLOG(DRIVER) <<
"Converter::ConvertDepthToSpace()";
1204 return Fail(
"%s: Operation has invalid inputs", __func__);
1211 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
1217 return Fail(
"%s: Could not read output 0", __func__);
1227 return Fail(
"%s: Block size must be at least 1 in all dimensions");
1231 if (Is12OrLaterOperand(*output))
1236 bool isSupported =
false;
1241 IsDepthToSpaceSupported,
1252 validateFunc(outputInfo, isSupported);
1266 assert(layer !=
nullptr);
1274 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d()";
1280 return Fail(
"%s: Operation has invalid inputs", __func__);
1287 return Fail(
"%s: Could not read output 0", __func__);
1297 if (!weightsOperand)
1299 return Fail(
"%s: Could not read weights", __func__);
1304 if (weightsOperand->dimensions[0] != 1)
1306 return Fail(
"%s: Filter operand dimension 0 is invalid, should be 1", __func__);
1313 bool implicitPadding = operation.inputs.size() == 8
1314 || (operation.inputs.size() >= 9
1318 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
1322 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1323 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1328 return Fail(
"%s: Operation has invalid inputs", __func__);
1334 return Fail(
"%s: Could not read bias", __func__);
1340 return Fail(
"%s: Operation has invalid inputs", __func__);
1347 ActivationFn activation;
1348 if (implicitPadding)
1350 ::android::nn::PaddingScheme paddingScheme;
1357 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1360 const uint32_t kernelX = weightsInfo.
GetShape()[2];
1361 const uint32_t kernelY = weightsInfo.
GetShape()[1];
1362 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1363 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1368 else if (operation.inputs.size() >= 11)
1380 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1385 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1391 bool requiresValidation =
true;
1397 requiresValidation =
false;
1398 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Weights and Biases are as INPUTS.";
1402 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1415 if (requiresValidation)
1417 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Requires Validation!";
1418 bool isSupported =
false;
1421 validateFunc(outputInfo, isSupported);
1439 return Fail(
"%s: AddDepthwiseConvolution2dLayer failed", __func__);
1453 VLOG(DRIVER) <<
"Converter::ConvertDequantize()";
1458 return Fail(
"%s: Operation has invalid input", __func__);
1465 return Fail(
"%s: Operation has quantization dimension different than 0", __func__);
1471 return Fail(
"%s: Operation has invalid outputs", __func__);
1476 bool isSupported =
false;
1495 validateFunc(outputInfo, isSupported);
1505 assert(layer !=
nullptr);
1513 VLOG(DRIVER) <<
"Converter::ConvertDiv()";
1520 return Fail(
"%s: Operation has invalid inputs", __func__);
1525 ActivationFn activationFunction;
1528 return Fail(
"%s: Operation has invalid inputs", __func__);
1534 return Fail(
"%s: Could not read output 0", __func__);
1539 bool isSupported =
false;
1557 validateFunc(outputInfo, isSupported);
1572 startLayer->SetBackendId(setBackend);
1574 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
1575 if (!isReshapeSupported)
1581 data,
nullptr, validateFunc, activationFunction);
1584 bool Converter::ConvertElementwiseUnary(
const Operation& operation,
1589 VLOG(DRIVER) <<
"Converter::ConvertElementwiseUnary()";
1596 return Fail(
"%s: Operation has invalid input", __func__);
1602 return Fail(
"%s: Could not read output 0", __func__);
1610 bool isSupported =
false;
1615 IsElementwiseUnarySupported,
1626 validateFunc(outputInfo, isSupported);
1640 assert(layer !=
nullptr);
1648 VLOG(DRIVER) <<
"Converter::ConvertElu()";
1653 return Fail(
"%s: Operation has invalid inputs", __func__);
1660 return Fail(
"%s: Operation has invalid inputs", __func__);
1667 if (inputType == OperandType::TENSOR_FLOAT16)
1671 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, alpha, model, data))
1673 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
1676 desc.
m_A =
static_cast<float>(alpha);
1678 else if (inputType == OperandType::TENSOR_FLOAT32)
1682 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
1687 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
1695 VLOG(DRIVER) <<
"Converter::ConvertExpandDims()";
1701 return Fail(
"%s: Operation has invalid input", __func__);
1707 return Fail(
"%s: Operation has invalid output", __func__);
1713 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
1715 return Fail(
"%s: failed to get axis input value", __func__);
1724 catch (
const std::exception& e)
1726 return Fail(
"%s: %s", __func__, e.what());
1732 bool isSupported =
false;
1748 if (targetShape != outputInfo.
GetShape())
1750 return Fail(
"%s: Shape of the output operand does not match the resolved expanded shape", __func__);
1752 validateFunc(outputInfo, isSupported);
1766 assert(layer !=
nullptr);
1774 VLOG(DRIVER) <<
"Converter::ConvertFill()";
1778 return Fail(
"%s: Operation has invalid inputs", __func__);
1784 return Fail(
"%s: Could not read output", __func__);
1791 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
1798 if (outputType == OperandType::TENSOR_FLOAT16)
1802 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
1804 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1807 descriptor.
m_Value =
static_cast<float>(value);
1809 else if (outputType == OperandType::TENSOR_FLOAT32)
1813 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1816 else if (outputType == OperandType::TENSOR_INT32)
1820 if (!
GetInputScalar(operation, 1, OperandType::INT32, value, model, data))
1822 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1825 descriptor.
m_Value =
static_cast<float>(value);
1829 return Fail(
"%s: Unsupported input tensor type: %d", __func__, outputType);
1832 bool isSupported =
false;
1849 assert(layer !=
nullptr);
1857 VLOG(DRIVER) <<
"Converter::ConvertFloor()";
1861 return Fail(
"%s: Operation has invalid inputs", __func__);
1867 return Fail(
"%s: Operation has invalid outputs", __func__);
1872 bool isSupported =
false;
1887 validateFunc(outputInfo, isSupported);
1901 assert(layer !=
nullptr);
1909 VLOG(DRIVER) <<
"Converter::ConvertFullyConnected()";
1913 return Fail(
"%s: Operation has invalid inputs", __func__);
1919 return Fail(
"%s: Could not read output 0", __func__);
1927 if (!weightsOperand)
1929 return Fail(
"%s: Could not read weights", __func__);
1937 return Fail(
"%s: Operation has invalid inputs", __func__);
1944 return Fail(
"%s: Could not read bias", __func__);
1952 return Fail(
"%s: Operation has invalid inputs", __func__);
1961 catch (
const std::exception& e)
1963 return Fail(
"%s: %s", __func__, e.what());
1968 SanitizeBiasQuantizationScale(biasInfo, weightsInfo, reshapedInfo);
1970 ActivationFn activationFunction;
1973 return Fail(
"%s: Operation has invalid inputs", __func__);
1981 bool isSupported =
false;
1985 if (!VerifyFullyConnectedShapes(reshapedInfo.
GetShape(),
1990 isSupported =
false;
1991 Fail(
"%s: Expected outputShape does not match actual outputShape", __func__);
2009 validateFunc(outputInfo, isSupported);
2031 assert(reshapeLayer !=
nullptr);
2046 data,
nullptr, validateFunc, activationFunction);
2051 VLOG(DRIVER) <<
"Converter::ConvertGather()";
2056 return Fail(
"%s: Operation has invalid input", __func__);
2063 return Fail(
"%s: Operation has invalid indices", __func__);
2070 return Fail(
"%s: Operation has invalid output", __func__);
2074 if (outputDimensions != inputDimensions + indicesDimensions - 1)
2076 return Fail(
"%s: Operation has invalid output dimensions: %d. Output must be an (%d + %d - 1)-D tensor",
2077 __func__, outputDimensions, inputDimensions, indicesDimensions);
2081 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
2083 return Fail(
"%s: Operation has invalid or unsupported axis operand", __func__);
2085 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
2087 return Fail(
"%s: Operation has invalid axis: %d. It is out of bounds [-%d, %d))", __func__, axis,
2088 inputDimensions, inputDimensions);
2094 bool isSupported =
false;
2111 validateFunc(outputInfo, isSupported);
2125 assert(layer !=
nullptr);
2134 VLOG(DRIVER) <<
"Converter::ConvertGroupedConv2d()";
2141 return Fail(
"%s: Operation has invalid inputs", __func__);
2148 return Fail(
"%s: Could not read output 0", __func__);
2154 if (operation.inputs.size() == 12)
2168 const ConstTensorPin weightsPin = (dataLayout == DataLayout::NCHW) ?
2170 model, data, ohwiToOihw) :
2176 return Fail(
"%s: Operation has invalid inputs", __func__);
2181 SanitizeBiasQuantizationScale(biases.
GetInfo(), weights.
GetInfo(), inputInfo);
2189 const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
2190 const unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
2191 const unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
2198 ActivationFn activation;
2200 if (operation.inputs.size() == 12)
2208 !
GetInputScalar(operation, 9, OperandType::INT32, numGroups, model, data) ||
2211 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
2215 else if (operation.inputs.size() == 9)
2217 ::android::nn::PaddingScheme paddingScheme;
2221 !
GetInputScalar(operation, 6, OperandType::INT32, numGroups, model, data) ||
2224 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
2227 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
2228 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
2230 const uint32_t kernelX = weightsShape[widthIndex];
2231 const uint32_t kernelY = weightsShape[heightIndex];
2238 return Fail(
"%s: Unsupported number of operation inputs", __func__);
2242 const unsigned int outputChannels = weightsShape[0];
2244 const unsigned int channelsPerGroup = weightsShape[channelsIndex];
2245 const unsigned int channelMultiplier = outputChannels / numGroups;
2252 return Fail(
"%s: Number of groups must be greater than 0. Got: %d", __func__, numGroups);
2255 if (outputChannels % numGroups != 0u)
2257 return Fail(
"%s: Output channels must be divisible by the number of groups", __func__);
2263 unsigned int splitterDimSizes[4] = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
2264 splitterDimSizes[channelsIndex] /= numGroups;
2272 std::vector<std::reference_wrapper<TensorInfo>> splitterOutputInfos(numGroups, std::ref(splitterOutputInfo));
2275 for (
unsigned int group = 0u; group < numGroups; ++group)
2277 splitterDesc.SetViewOriginCoord(group, channelsIndex, splitterDimSizes[channelsIndex] * group);
2278 for (
unsigned int dimIdx = 0u; dimIdx < 4u; dimIdx++)
2280 splitterDesc.SetViewSize(group, dimIdx, splitterDimSizes[dimIdx]);
2284 bool isSupported =
false;
2292 splitterOutputInfos,
2303 return Fail(
"%s: Failed to add SplitterLayer", __func__);
2307 for (
unsigned int group = 0u; group < splitterLayer->
GetNumOutputSlots(); ++group)
2318 groupInputShape[channelsIndex] = channelsPerGroup;
2321 groupWeightsShape[0] /= channelMultiplier * numGroups;
2327 groupInputInfo.SetShape(groupInputShape);
2331 groupWeightsInfo.SetShape(groupWeightsShape);
2335 groupBiasesInfo.SetShape(groupBiasesShape);
2343 groupOutputShape[channelsIndex] = 1;
2345 groupOutputInfo.SetShape(groupOutputShape);
2347 const unsigned int weightsDataTypeSize =
GetDataTypeSize(groupWeightsInfo.GetDataType());
2348 const unsigned int biasesDataTypeSize =
GetDataTypeSize(groupBiasesInfo.GetDataType());
2350 std::vector<IConnectableLayer*> convLayers(numGroups * channelMultiplier,
nullptr);
2351 for (
unsigned int group = 0u; group < numGroups; ++group)
2353 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2355 auto index = group * channelMultiplier + m;
2357 const unsigned int weightsDataOffset = groupWeightsShape.GetNumElements() * index * weightsDataTypeSize;
2358 const unsigned int biasesDataOffset = groupBiasesShape.GetNumElements() * index * biasesDataTypeSize;
2364 groupWeightsInfo.SetQuantizationScales(
2365 std::vector<float>(weightsQuantScales.begin() + index,
2366 weightsQuantScales.begin() + index + groupWeightsShape[0]));
2370 groupBiasesInfo.SetQuantizationScales(
2371 std::vector<float>(biasesQuantScales.begin() + index,
2372 biasesQuantScales.begin() + index + groupWeightsShape[0]));
2377 static_cast<const void *
>(
reinterpret_cast<const char *
>(weights.
GetMemoryArea()) +
2378 weightsDataOffset));
2380 static_cast<const void *
>(
reinterpret_cast<const char *
>(biases.
GetMemoryArea()) +
2383 isSupported =
false;
2401 validateFunc(groupOutputInfo, isSupported);
2421 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
2446 convLayers[index] = convLayer;
2456 for (
unsigned int group = 0u; group < numGroups; ++group)
2458 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2460 auto index = group * channelMultiplier + m;
2466 isSupported =
false;
2473 std::vector<const TensorInfo*>(numGroups * channelMultiplier, &groupOutputInfo),
2486 return Fail(
"%s: AddConcatLayer failed", __func__);
2489 for (
unsigned int group = 0u; group < numGroups; ++group)
2491 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2493 auto index = group * channelMultiplier + m;
2494 convLayers[index]->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(index));
2500 data,
nullptr,
nullptr, activation);
2505 VLOG(DRIVER) <<
"Converter::ConvertHardSwish()";
2507 desc.
m_Function = ActivationFunction::HardSwish;
2514 VLOG(DRIVER) <<
"Converter::ConvertInstanceNormalization()";
2519 return Fail(
"%s: Operation has an invalid input 0", __func__);
2525 return Fail(
"%s: Operation has an invalid output", __func__);
2534 return Fail(
"%s: Operation has invalid inputs", __func__);
2540 if (inputType == OperandType::TENSOR_FLOAT16)
2546 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Gamma, model, data) ||
2547 !
GetInputScalar(operation, 2, OperandType::FLOAT16, fp16Beta, model, data) ||
2548 !
GetInputScalar(operation, 3, OperandType::FLOAT16, fp16Epsilon, model, data))
2550 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
2553 desc.
m_Gamma =
static_cast<float>(fp16Gamma);
2554 desc.
m_Beta =
static_cast<float>(fp16Beta);
2555 desc.
m_Eps =
static_cast<float>(fp16Epsilon);
2557 else if (inputType == OperandType::TENSOR_FLOAT32)
2563 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
2568 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2573 bool isSupported =
false;
2578 IsInstanceNormalizationSupported,
2593 validateFunc(outputInfo, isSupported);
2610 VLOG(DRIVER) <<
"Converter::ConvertL2Normalization()";
2612 if (operation.inputs.size() != 1)
2614 return Fail(
"%s: Optional inputs are not supported", __func__);
2620 return Fail(
"%s: Operation has invalid inputs", __func__);
2626 return Fail(
"%s: Could not read output 0", __func__);
2634 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2640 bool isSupported =
false;
2656 validateFunc(outputInfo, isSupported);
2670 assert(layer !=
nullptr);
2678 VLOG(DRIVER) <<
"Converter::ConvertL2Pool2d()";
2679 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::L2, model, data);
2682 bool Converter::ConvertLocalResponseNormalization(
const Operation& operation,
2686 VLOG(DRIVER) <<
"Converter::ConvertLocalResponseNormalization()";
2688 if (operation.inputs.size() != 5)
2690 return Fail(
"%s: Optional inputs are not supported", __func__);
2696 return Fail(
"%s: Operation has invalid inputs", __func__);
2702 return Fail(
"%s: Could not read output 0", __func__);
2710 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2724 return Fail(
"%s: Operation has invalid inputs", __func__);
2731 bool isSupported =
false;
2747 validateFunc(outputInfo, isSupported);
2762 assert(layer !=
nullptr);
2768 bool Converter::ConvertLogicalBinary(
const Operation& operation,
2773 VLOG(DRIVER) <<
"Converter::ConvertLogicalBinary()";
2774 VLOG(DRIVER) <<
"ConvertLogicalBinary()";
2782 return Fail(
"%s: Operation has invalid inputs", __func__);
2788 return Fail(
"%s: Could not read output 0", __func__);
2797 bool isSupported =
false;
2802 IsLogicalBinarySupported,
2814 validateFunc(outputInfo, isSupported);
2828 assert(layer !=
nullptr);
2830 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
2831 if (!isReshapeSupported)
2841 VLOG(DRIVER) <<
"Converter::ConvertLogistic()";
2850 VLOG(DRIVER) <<
"Converter::ConvertLogSoftmax()";
2855 return Fail(
"%s: Failed to read input 0", __func__);
2861 return Fail(
"%s: Failed to read output", __func__);
2870 return Fail(
"%s: Operation has invalid inputs", __func__);
2876 if (inputType == OperandType::TENSOR_FLOAT16)
2879 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Beta, model, data))
2881 return Fail(
"%s: Failed to read input 1 (FLOAT16)", __func__);
2884 descriptor.
m_Beta =
static_cast<float>(fp16Beta);
2886 else if (inputType == OperandType::TENSOR_FLOAT32)
2890 return Fail(
"%s: Failed to read input 1 (FLOAT32)", __func__);
2895 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2901 return Fail(
"%s: Failed to read input 2", __func__);
2904 bool isSupported =
false;
2909 IsLogSoftmaxSupported,
2924 validateFunc(outputInfo, isSupported);
2936 return Fail(
"%s: AddLogSoftmaxLayer() returned nullptr", __func__);
2946 VLOG(DRIVER) <<
"Converter::ConvertLstm()";
2954 return Fail(
"%s: Could not read input 0: input", __func__);
2960 return Fail(
"%s: Could not read input 18: outputStateIn", __func__);
2966 return Fail(
"%s: Could not read input 19: cellStateIn", __func__);
3004 if (!inputToForgetWeightsPin.
IsValid() ||
3005 !inputToCellWeightsPin.
IsValid() ||
3006 !inputToOutputWeightsPin.
IsValid() ||
3007 !recurrentToForgetWeightsPin.
IsValid() ||
3008 !recurrentToCellWeightsPin.
IsValid() ||
3009 !recurrentToOutputWeightsPin.
IsValid() ||
3010 !forgetGateBiasPin.
IsValid() ||
3014 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3060 if ((!inputToInputWeightsPin.
IsValid() && !inputToInputWeightsPin.
IsOptional()) ||
3061 (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional()) ||
3069 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3079 ActivationFn activation = ActivationFn::kActivationNone;
3083 !
GetInputScalar(operation, 21, OperandType::FLOAT32, cellClip, model, data) ||
3084 !
GetInputScalar(operation, 22, OperandType::FLOAT32, projClip, model, data))
3086 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
3134 return Fail(
"%s: Could not read output 0: scratchBuffer", __func__);
3138 if (!outputStateOut)
3140 return Fail(
"%s: Could not read output 1: outputStateOut", __func__);
3146 return Fail(
"%s: Could not read output 2: cellStateOut", __func__);
3153 return Fail(
"%s: Could not read output 3: output", __func__);
3202 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
3203 " and input gate bias must be provided", __func__);
3208 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
3216 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
3217 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
3226 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
3227 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
3292 bool isSupported =
false;
3312 bool isDynamic =
false;
3318 validateFunc(outputInfo, isSupported);
3354 operation, 3, *layer, 3, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
3361 VLOG(DRIVER) <<
"Converter::ConvertMaxPool2d()";
3362 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Max, model, data);
3367 VLOG(DRIVER) <<
"Converter::ConvertMaximum()";
3374 return Fail(
"%s: Operation has invalid inputs", __func__);
3380 return Fail(
"%s: Could not read output", __func__);
3385 bool isSupported =
false;
3407 validateFunc(outInfo, isSupported);
3418 layer->SetBackendId(setBackend);
3419 assert(layer !=
nullptr);
3420 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
3421 if (!isReshapeSupported)
3431 VLOG(DRIVER) <<
"Converter::ConvertMean()";
3436 return Fail(
"%s: Operation has invalid inputs", __func__);
3442 return Fail(
"%s: Could not read output 0", __func__);
3450 return Fail(
"%s: Could not read input 1", __func__);
3453 std::vector<int32_t> axis;
3456 return Fail(
"%s: Input 1 has invalid values", __func__);
3463 std::set<unsigned int> uniqueAxis;
3464 std::transform(axis.begin(), axis.end(),
3465 std::inserter(uniqueAxis, uniqueAxis.begin()),
3466 [rank](
int i) ->
unsigned int { return (i + rank) % rank; });
3469 int32_t keepDims = 0;
3472 return Fail(
"%s: Could not read input 2", __func__);
3476 descriptor.
m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
3479 bool isSupported =
false;
3495 validateFunc(outputInfo, isSupported);
3509 assert(layer !=
nullptr);
3517 VLOG(DRIVER) <<
"Converter::ConvertMinimum()";
3524 return Fail(
"%s: Operation has invalid inputs", __func__);
3530 return Fail(
"%s: Could not read output 0", __func__);
3535 bool isSupported =
false;
3557 validateFunc(outputInfo, isSupported);
3568 layer->SetBackendId(setBackend);
3569 assert(layer !=
nullptr);
3570 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
3571 if (!isReshapeSupported)
3581 VLOG(DRIVER) <<
"Converter::ConvertMul()";
3588 return Fail(
"%s: Operation has invalid inputs", __func__);
3593 ActivationFn activationFunction;
3596 return Fail(
"%s: Operation has invalid inputs", __func__);
3601 if (outputOperand ==
nullptr)
3608 bool isSupported =
false;
3626 validateFunc(outputInfo, isSupported);
3641 startLayer->SetBackendId(setBackend);
3643 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
3644 if (!isReshapeSupported)
3650 data,
nullptr, validateFunc, activationFunction);
3655 VLOG(DRIVER) <<
"Converter::ConvertPad()";
3660 return Fail(
"%s: Operation has invalid inputs", __func__);
3669 return Fail(
"%s: Could not convert paddings", __func__);
3685 return Fail(
"%s: Could not read output", __func__);
3690 bool isSupported =
false;
3706 validateFunc(outputInfo, isSupported);
3720 assert(layer !=
nullptr);
3728 VLOG(DRIVER) <<
"Converter::ConvertPadV2()";
3733 return Fail(
"%s: Could not read input 0", __func__);
3739 return Fail(
"%s: Could not read output", __func__);
3748 return Fail(
"%s: Could not convert paddings", __func__);
3760 return Fail(
"%s: Operation has invalid inputs", __func__);
3764 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
3767 if (!
GetInputScalar(operation, 2, operandType2, f16PadValue, model, data))
3769 return Fail(
"%s: Could not read input 2 (FLOAT16)", __func__);
3774 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
3778 return Fail(
"%s: Could not read input 2 (FLOAT32)", __func__);
3783 int32_t intPadValue = 0;
3786 return Fail(
"%s: Could not read input 2 (INT32)", __func__);
3792 return Fail(
"%s: Operation has invalid inputs: type mismatch", __func__);
3795 bool isSupported =
false;
3815 validateFunc(outputInfo, isSupported);
3825 assert(layer !=
nullptr);
3833 VLOG(DRIVER) <<
"Converter::ConvertPrelu()";
3840 return Fail(
"%s: Operation has invalid inputs", __func__);
3847 return Fail(
"%s: Could not read output", __func__);
3854 bool isSupported =
false;
3874 validateFunc(outputInfo, isSupported);
3887 return Fail(
"%s: AddPreluLayer failed", __func__);
3890 bool isReshapeSupported = BroadcastTensor(input, alpha, layer, data);
3891 if (!isReshapeSupported)
3901 VLOG(DRIVER) <<
"Converter::ConvertQuantize()";
3906 return Fail(
"%s: Operation has invalid input", __func__);
3912 return Fail(
"%s: Operation has invalid outputs", __func__);
3917 bool isSupported =
false;
3922 IsQuantizeSupported,
3936 validateFunc(outputInfo, isSupported);
3946 assert(layer !=
nullptr);
3954 VLOG(DRIVER) <<
"Converter::ConvertQuantizedLstm()";
3956 VLOG(DRIVER) <<
"ConvertQuantizedLstm()";
3964 return Fail(
"%s: Could not read input 0: input", __func__);
3969 if (!outputStatePrevTimeStep.
IsValid())
3971 return Fail(
"%s: Could not read input 18: outputStatePrevTimeStep", __func__);
3976 if (!cellStatePrevTimeStep.
IsValid())
3978 return Fail(
"%s: Could not read input 19: cellStatePrevTimeStep", __func__);
4025 if (!inputToForgetWeightsPin.
IsValid() ||
4026 !inputToCellWeightsPin.
IsValid() ||
4027 !inputToOutputWeightsPin.
IsValid() ||
4028 !recurrentToForgetWeightsPin.
IsValid() ||
4029 !recurrentToCellWeightsPin.
IsValid() ||
4030 !recurrentToOutputWeightsPin.
IsValid() ||
4031 !forgetGateBiasPin.
IsValid() ||
4035 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4128 || (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional())
4136 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4186 if ((!inputLayerNormWeightsPin.
IsValid() && !inputLayerNormWeightsPin.
IsOptional())
4187 || (!forgetLayerNormWeightsPin.
IsValid() && !forgetLayerNormWeightsPin.
IsOptional())
4188 || (!cellLayerNormWeightsPin.
IsValid() && !cellLayerNormWeightsPin.
IsOptional())
4189 || (!outputLayerNormWeightsPin.
IsValid() && !outputLayerNormWeightsPin.
IsOptional()))
4191 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4205 float cellClip, projClip, matMulInputGate, matMulForgetGate, matMulCellGate, matMulOutputGate, projInputScale;
4206 int projInputZeroPoint;
4208 if (!
GetInputScalar(operation, 24, OperandType::FLOAT32, cellClip, model, data,
true) ||
4209 !
GetInputScalar(operation, 25, OperandType::FLOAT32, projClip, model, data,
true) ||
4210 !
GetInputScalar(operation, 26, OperandType::FLOAT32, matMulInputGate, model, data) ||
4211 !
GetInputScalar(operation, 27, OperandType::FLOAT32, matMulForgetGate, model, data) ||
4212 !
GetInputScalar(operation, 28, OperandType::FLOAT32, matMulCellGate, model, data) ||
4213 !
GetInputScalar(operation, 29, OperandType::FLOAT32, matMulOutputGate, model, data) ||
4214 !
GetInputScalar(operation, 30, OperandType::INT32, projInputZeroPoint, model, data) ||
4215 !
GetInputScalar(operation, 31, OperandType::FLOAT32, projInputScale, model, data))
4217 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
4224 if (!outputStateOut)
4226 return Fail(
"%s: Could not read output 0: outputStateOut", __func__);
4233 return Fail(
"%s: Could not read output 1: cellStateOut", __func__);
4241 return Fail(
"%s: Could not read output 2: output", __func__);
4295 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
4296 " and input gate bias must be provided", __func__);
4301 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
4309 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
4310 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
4319 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
4320 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
4376 const TensorInfo constOutputStateOutInfo(outputStateOutInfo);
4377 const TensorInfo constOutputInfo(outputInfo);
4397 bool isSupported =
false;
4399 auto validateFunc = [&](
const armnn::TensorInfo& cellStateOutInfo,
bool& isSupported)
4407 outputStatePrevTimeStepInfo,
4408 cellStatePrevTimeStepInfo,
4409 constOutputStateOutInfo,
4416 bool isDynamic =
false;
4421 validateFunc(outputInfo, isSupported);
4445 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4452 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4454 operation, 1, *layer, 1, model, data,
nullptr, validateFunc,
4455 ActivationFn::kActivationNone,
true) &&
4462 VLOG(DRIVER) <<
"Converter::ConvertQuantized16BitLstm()";
4463 VLOG(DRIVER) <<
"Policy::ConvertQuantized16BitLstm()";
4471 return Fail(
"%s: Could not read input 0: input", __func__);
4478 if (!previousCellStateIn.
IsValid())
4480 return Fail(
"%s: Could not read input 13: previousCellStateIn", __func__);
4487 if (!previousOutputIn.
IsValid())
4489 return Fail(
"%s: Could not read input 14: previousOutputIn", __func__);
4565 if (!inputToInputWeightsPin.
IsValid() ||
4566 !inputToForgetWeightsPin.
IsValid() ||
4567 !inputToCellWeightsPin.
IsValid() ||
4568 !inputToOutputWeightsPin.
IsValid() ||
4569 !recurrentToInputWeightsPin.
IsValid() ||
4570 !recurrentToForgetWeightsPin.
IsValid() ||
4571 !recurrentToCellWeightsPin.
IsValid() ||
4572 !recurrentToOutputWeightsPin.
IsValid() ||
4573 !inputGateBiasPin.
IsValid() ||
4574 !forgetGateBiasPin.
IsValid() ||
4578 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4588 return Fail(
"%s: Could not read output 0: cellStateOut", __func__);
4596 return Fail(
"%s: Could not read output 1: output", __func__);
4611 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4643 bool isSupported =
false;
4653 previousCellStateInInfo,
4654 previousOutputInInfo,
4660 bool isDynamic =
false;
4664 validateFunc(outputInfo, isSupported);
4692 operation, 1, *layer, 1, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
4699 VLOG(DRIVER) <<
"Converter::ConvertRank()";
4704 if (inputOperand ==
nullptr || outputOperand ==
nullptr)
4706 return Fail(
"%s: Operation has invalid inputs", __func__);
4709 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4710 const Shape outputOperandShape = GetOperandShape(*outputOperand);
4715 return Fail(
"%s: Could not read input 0", __func__);
4721 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4724 bool isSupported =
false;
4740 assert(layer !=
nullptr);
4748 VLOG(DRIVER) <<
"Converter::ConvertReLu()";
4756 return Fail(
"%s: Input 0 is invalid",
"operationName");
4767 bool isSupported =
false;
4787 validateFunc(outInfo, isSupported);
4805 VLOG(DRIVER) <<
"Converter::ConvertReLu1()";
4816 VLOG(DRIVER) <<
"Converter::ConvertReLu6()";
4826 VLOG(DRIVER) <<
"Converter::ConvertReshape()";
4832 if (inputOperand ==
nullptr
4833 || requestedShapeOperand ==
nullptr
4834 || outputOperand ==
nullptr)
4836 return Fail(
"%s: Operation has invalid inputs", __func__);
4839 if (requestedShapeOperand->dimensions.size() != 1)
4841 return Fail(
"%s: Input 1 expected to be one-dimensional (found %i dimensions)",
4842 __func__, requestedShapeOperand->dimensions.size());
4845 std::vector<int32_t> targetDimensions;
4848 return Fail(
"%s: Could not read values of input 1", __func__);
4851 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4853 Shape requestedShape;
4856 if (!reshapePrepare(inputOperandShape, targetDimensions.data(), targetDimensions.size(), &requestedShape))
4858 return Fail(
"%s: Failed to resolve the requested shape", __func__);
4864 return Fail(
"%s: Could not read input 0", __func__);
4869 requestedShape.dimensions.data());
4873 bool isSupported =
false;
4889 validateFunc(outputInfo, isSupported);
4903 assert(layer !=
nullptr);
4909 bool Converter::ConvertResize(
const Operation& operation,
4914 VLOG(DRIVER) <<
"Converter::ConvertResize()";
4920 return Fail(
"%s: Could not read input 0", __func__);
4926 return Fail(
"%s: Could not read output 0", __func__);
4933 descriptor.
m_Method = resizeMethod;
4942 return Fail(
"%s: Operation has invalid inputs", __func__);
4945 if (operandType1 != operandType2)
4947 return Fail(
"%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
4950 if (operandType1 == OperandType::INT32)
4953 int32_t targetWidth = 0;
4954 int32_t targetHeight = 0;
4956 if (!
GetInputInt32(operation, 1, targetWidth, model, data) ||
4959 return Fail(
"%s: Operation has invalid inputs for resizing by shape", __func__);
4962 if (targetWidth < 0 || targetHeight < 0)
4964 return Fail(
"%s: Operation has invalid inputs for resizing by shape. "
4965 "Target width/height cannot be < 0", __func__);
4968 descriptor.
m_TargetWidth =
static_cast<uint32_t
>(targetWidth);
4971 else if (operandType1 == OperandType::FLOAT32)
4974 float widthScale = 1.0f;
4975 float heightScale = 1.0f;
4980 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
4986 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
4987 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
4992 else if (operandType1 == OperandType::FLOAT16)
4997 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, widthScale, model, data) ||
4998 !
GetInputScalar(operation, 2, OperandType::FLOAT16, heightScale, model, data))
5000 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
5006 Half width =
static_cast<Half>(inputShape[dataLayoutIndexed.GetWidthIndex()]);
5007 Half height =
static_cast<Half>(inputShape[dataLayoutIndexed.GetHeightIndex()]);
5014 return Fail(
"%s: Operand has invalid data type for resizing by scale", __func__);
5020 bool isSupported =
false;
5040 validateFunc(outputInfo, isSupported);
5050 assert(layer !=
nullptr);
5058 VLOG(DRIVER) <<
"Converter::ConvertSpaceToBatchNd()";
5063 return Fail(
"%s: Operation has invalid inputs", __func__);
5068 unsigned int spatialDim = rank - 2;
5072 Fail(
"%s: Only inputs with rank 4 are supported", __func__);
5078 return Fail(
"%s: Could not read output 0", __func__);
5086 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
5089 return Fail(
"%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
5092 std::vector<int32_t> blockShape;
5095 return Fail(
"%s: Operation has an invalid or unsupported block size operand", __func__);
5097 if(std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i)
5100 return Fail(
"%s: Block shape must be at least 1 in all dimensions.", __func__);
5103 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
5106 return Fail(
"%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
5109 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
5110 std::vector<int32_t> paddings;
5113 return Fail(
"%s: Operation has an invalid or unsupported paddings operand", __func__);
5115 for (
unsigned int i = 0; i < paddings.size() - 1; i += 2)
5117 int paddingBeforeInput = paddings[i];
5118 int paddingAfterInput = paddings[i + 1];
5119 if(paddingBeforeInput < 0 || paddingAfterInput < 0)
5121 return Fail(
"%s: Operation has invalid paddings operand, invalid padding values.", __func__);
5124 paddingList.emplace_back((
unsigned int) paddingBeforeInput, (
unsigned int) paddingAfterInput);
5129 descriptor.
m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
5130 descriptor.
m_PadList.assign(paddingList.cbegin(), paddingList.cend());
5132 if(Is12OrLaterOperand(*output))
5137 bool isSupported =
false;
5156 validateFunc(outputInfo, isSupported);
5166 assert(layer !=
nullptr);
5174 VLOG(DRIVER) <<
"Converter::ConvertSpaceToDepth()";
5179 return Fail(
"%s: Operation has invalid inputs", __func__);
5186 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
5192 return Fail(
"%s: Could not read output 0", __func__);
5203 return Fail(
"%s: Block size must be at least 1 in all dimensions");
5208 bool isSupported =
false;
5228 validateFunc(outputInfo, isSupported);
5238 assert(layer !=
nullptr);
5246 VLOG(DRIVER) <<
"Converter::ConvertSoftmax()";
5251 return Fail(
"%s: Operation has invalid inputs", __func__);
5257 return Fail(
"%s: Operation has no outputs", __func__);
5266 if (outputType == OperandType::TENSOR_FLOAT16)
5270 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
5272 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5275 desc.
m_Beta =
static_cast<float>(value);
5281 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5292 return Fail(
"%s: Operation has invalid inputs", __func__);
5295 bool isSupported =
false;
5315 validateFunc(outputInfo, isSupported);
5325 assert(layer !=
nullptr);
5333 VLOG(DRIVER) <<
"Converter::ConvertSub()";
5340 return Fail(
"%s: Operation has invalid inputs", __func__);
5345 ActivationFn activationFunction;
5348 return Fail(
"%s: Operation has invalid inputs", __func__);
5354 return Fail(
"%s: Could not read output 0", __func__);
5359 bool isSupported =
false;
5381 validateFunc(outputInfo, isSupported);
5392 startLayer->SetBackendId(setBackend);
5394 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
5395 if (!isReshapeSupported)
5400 data,
nullptr, validateFunc, activationFunction);
5405 VLOG(DRIVER) <<
"Converter::ConvertTanH()";
5417 VLOG(DRIVER) <<
"Converter::ConvertTransposeConv2d()";
5423 return Fail(
"%s: Operation has invalid inputs", __func__);
5430 return Fail(
"%s: Could not read output 0", __func__);
5440 if (weightsOperand ==
nullptr)
5442 return Fail(
"%s: Operand is invalid", __func__);
5448 bool implicitPadding = operation.inputs.size() == 9;
5450 if (implicitPadding )
5460 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
5461 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
5469 model, data, OHWIToOIHW) :
5478 return Fail(
"%s: Operation has invalid weights", __func__);
5483 return Fail(
"%s: Operation has invalid biases", __func__);
5488 SanitizeBiasQuantizationScale(bias.
GetInfo(), weights.
GetInfo(), inputInfo);
5490 ActivationFn activation;
5492 if (implicitPadding)
5497 int32_t padRight{0};
5499 int32_t padBottom{0};
5501 ::android::nn::PaddingScheme paddingScheme;
5503 !
GetInputScalar(operation, 5, OperandType::INT32, strideX, model, data) ||
5504 !
GetInputScalar(operation, 6, OperandType::INT32, strideY, model, data) ||
5507 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
5510 const uint32_t kernelX = weights.
GetShape()[widthIndex];
5511 const uint32_t kernelY = weights.
GetShape()[heightIndex];
5515 std::vector<int32_t> outputShape;
5516 if ((outputShapeOperand) && (
GetTensorInt32Values(*outputShapeOperand, outputShape, model, data)))
5519 for (
int dimension : outputShape)
5521 desc.
m_OutputShape.push_back(
static_cast<unsigned int>(dimension));
5531 if (outputShape.size() == 0)
5533 return Fail(
"%s: Padding sizes cannot be inferred", __func__);
5536 outputX = outputShape[widthIndex];
5537 outputY = outputShape[heightIndex];
5541 outputX = outputInfo.
GetShape()[widthIndex];
5542 outputY = outputInfo.
GetShape()[heightIndex];
5545 CalcPaddingTransposeConv(outputX, kernelX, strideX, padLeft, padRight, paddingScheme);
5546 CalcPaddingTransposeConv(outputY, kernelY, strideY, padTop, padBottom, paddingScheme);
5550 if (padLeft < 0 || padRight < 0 || padTop < 0 || padBottom < 0)
5552 return Fail(
"%s: Negative padding values are not supported", __func__);
5555 desc.
m_StrideX = armnn::numeric_cast<uint32_t>(strideX);
5556 desc.
m_StrideY = armnn::numeric_cast<uint32_t>(strideY);
5557 desc.
m_PadLeft = armnn::numeric_cast<uint32_t>(padLeft);
5558 desc.
m_PadRight = armnn::numeric_cast<uint32_t>(padRight);
5559 desc.
m_PadTop = armnn::numeric_cast<uint32_t>(padTop);
5560 desc.
m_PadBottom = armnn::numeric_cast<uint32_t>(padBottom);
5562 else if (operation.inputs.size() == 11)
5573 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
5578 return Fail(
"%s: Unsupported number of operation inputs", __func__);
5584 bool isSupported =
false;
5606 validateFunc(outputInfo, isSupported);
5618 return Fail(
"%s: AddTransposeConvolution2dLayer failed", __func__);
5624 data,
nullptr, validateFunc, activation);
5629 VLOG(DRIVER) <<
"Converter::ConvertSqrt()";
5638 VLOG(DRIVER) <<
"Converter::ConvertSqueeze()";
5643 return Fail(
"%s: Operation has invalid inputs", __func__);
5650 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5656 return Fail(
"%s: Could not read output 0", __func__);
5661 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
5668 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
5670 std::vector<int32_t> axis;
5673 axis.assign(dimensionSequence,
5674 dimensionSequence + rank);
5678 return Fail(
"%s: Operation has an invalid or unsupported axis operand", __func__);
5681 std::vector<uint32_t> outputDims;
5682 for (
unsigned int i = 0; i < rank; i++)
5684 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
5685 auto currentDimension = inputInfo.
GetShape()[i];
5686 if (skipSqueeze || currentDimension != 1)
5688 outputDims.push_back(currentDimension);
5700 bool isSupported =
false;
5718 assert(layer !=
nullptr);
5726 VLOG(DRIVER) <<
"Converter::ConvertStridedSlice()";
5731 return Fail(
"%s: Operation has invalid inputs", __func__);
5738 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5744 return Fail(
"%s: Could not read output 0", __func__);
5753 std::vector<int32_t> beginValues;
5754 std::vector<int32_t> endValues;
5755 std::vector<int32_t> stridesValues;
5758 auto ValidateInputOperands = [&] (
const Operand& operand, std::vector<int32_t>& operandValues)
5765 if (operandValues.size() != rank)
5773 if (!ValidateInputOperands(*beginOperand, beginValues)
5774 || !ValidateInputOperands(*endOperand, endValues)
5775 || !ValidateInputOperands(*stridesOperand, stridesValues))
5777 return Fail(
"%s: Operation has invalid input operand", __func__);
5781 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
5783 return Fail(
"%s: Stride must be non-zero value.", __func__);
5787 descriptor.
m_Begin.assign(beginValues.cbegin(), beginValues.cend());
5788 descriptor.
m_End.assign(endValues.cbegin(), endValues.cend());
5789 descriptor.
m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
5797 return Fail(
"%s: Operation has invalid inputs", __func__);
5800 bool isSupported =
false;
5820 validateFunc(outputInfo, isSupported);
5832 int stride = descriptor.
m_Stride[i];
5838 if (((descriptor.
m_Begin[i] - descriptor.
m_End[i]) > 1)
5839 || ((descriptor.
m_Begin[i] - descriptor.
m_End[i]) < -1))
5841 return Fail(
"%s: StridedSlice: Output will not be large enough to hold the slice", __func__);
5846 return Fail(
"%s: StridedSlice: Stride can not be negative while ShrinkAxisMask is set.", __func__);
5853 assert(layer !=
nullptr);
5861 VLOG(DRIVER) <<
"Converter::ConvertTranspose()";
5866 return Fail(
"%s: Operation has invalid inputs", __func__);
5873 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5880 std::vector<int32_t> perm(rank);
5881 if (!permOperand || (permOperand->lifetime == OperandLifeTime::NO_VALUE))
5883 for (
unsigned int i = rank; i > 0; i--)
5885 perm[rank - i] = armnn::numeric_cast<int> (i - 1);
5890 return Fail(
"%s: Operation has an invalid or unsupported permutation operand", __func__);
5893 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
5901 return Fail(
"%s: Could not read output 0", __func__);
5906 bool isSupported =
false;
5911 IsTransposeSupported,
5926 validateFunc(outputInfo, isSupported);
5936 assert(layer !=
nullptr);