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;
224 validateFunc(outputInfo, isSupported);
239 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
240 if (!isReshapeSupported)
246 data,
nullptr, validateFunc, activationFunction);
249 bool Converter::ConvertArgMinMax(
const Operation& operation,
254 VLOG(DRIVER) <<
"Converter::ConvertArgMinMax()";
261 return Fail(
"%s: Operation has invalid inputs", __func__);
265 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
267 return Fail(
"%s: Operation has invalid inputs. Failed to read axis.", __func__);
273 if (((axis < -rank) && (axis < 0)) || ((axis >= rank) && (axis > 0)))
278 return Fail(
"%s: Axis must be in range [-n, n)", __func__);
284 return Fail(
"%s: Could not read output 0", __func__);
295 bool isSupported =
false;
300 IsArgMinMaxSupported,
315 validateFunc(outputInfo, isSupported);
325 assert(layer !=
nullptr);
334 VLOG(DRIVER) <<
"Converter::ConvertAveragePool2d()";
335 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Average, model, data);
340 VLOG(DRIVER) <<
"Converter::ConvertBatchMatMul()";
346 return Fail(
"%s: Operation has invalid inputs", __func__);
353 if (rankInput0 > 4 || rankInput0 < 2)
355 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
359 if (rankInput1 > 4 || rankInput1 < 2)
361 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
368 return Fail(
"%s: Operation has invalid inputs", __func__);
375 return Fail(
"%s: Operation has invalid inputs", __func__);
378 if (input0Type != input1Type)
380 return Fail(
"%s: Operation has invalid inputs (Inputs must have same OperandCode)", __func__);
386 return Fail(
"%s: Could not read output 0", __func__);
398 bool isSupported =
false;
403 IsBatchMatMulSupported,
415 validateFunc(outputInfo, isSupported);
430 assert(layer !=
nullptr);
439 VLOG(DRIVER) <<
"Converter::ConvertBatchToSpaceNd()";
443 return Fail(
"%s: Operation has invalid inputs", __func__);
449 return Fail(
"%s: Could not read output 0", __func__);
457 return Fail(
"%s: Could not read input 1", __func__);
461 std::vector<int32_t> block;
464 return Fail(
"%s: Input 1 has invalid values", __func__);
472 Fail(
"%s: Only inputs with rank equal to 4 are supported", __func__);
475 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
477 return Fail(
"%s: Block sizes for each spatial dimension of the input tensor must be"
478 " greater than or equal to 1", __func__);
482 batchToSpaceNdDesc.
m_BlockShape.assign(block.cbegin(), block.cend());
485 if (Is12OrLaterOperand(*output))
490 batchToSpaceNdDesc.
m_Crops = {{0, 0}, {0, 0}};
492 bool isSupported =
false;
508 validateFunc(outputInfo, isSupported);
523 assert(layer !=
nullptr);
531 VLOG(DRIVER) <<
"Converter::ConvertCast()";
537 return Fail(
"%s: Operation has invalid inputs", __func__);
543 return Fail(
"%s: Could not read output 0", __func__);
549 bool isSupported =
false;
564 validateFunc(outputInfo, isSupported);
578 assert(layer !=
nullptr);
584 bool Converter::ConvertComparison(
const Operation& operation,
589 VLOG(DRIVER) <<
"Converter::ConvertComparison()";
597 return Fail(
"%s: Operation has invalid inputs", __func__);
603 return Fail(
"%s: Could not read output 0", __func__);
612 bool isSupported =
false;
617 IsComparisonSupported,
629 validateFunc(outputInfo, isSupported);
643 assert(layer !=
nullptr);
645 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
646 if (!isReshapeSupported)
663 VLOG(DRIVER) <<
"Converter::ConvertConcatenation()";
666 if (operation.inputs.size() <= 1)
668 return Fail(
"%s: Operation has insufficient arguments", __func__);
672 const std::size_t numInputTensors = operation.inputs.size() - 1;
675 if (!
GetInputScalar(operation, numInputTensors, OperandType::INT32, concatDim, model, data))
677 return Fail(
"%s: Operation has invalid inputs", __func__);
683 return Fail(
"%s: Operation has no outputs", __func__);
699 if (concatDim >=
static_cast<int32_t
>(outputShape.
GetNumDimensions()) || concatDim < 0)
701 return Fail(
"%s: Operation has invalid concat axis: %d", __func__, concatDim);
704 std::vector<LayerInputHandle> inputHandles;
705 std::vector<armnn::TensorShape> inputShapes;
707 inputHandles.reserve(numInputTensors);
708 inputShapes.reserve(numInputTensors);
710 bool inputsHaveBeenReshaped =
false;
711 unsigned int tensorDimensionsAdded = 0;
712 for (uint32_t i = 0; i < numInputTensors; ++i)
717 return Fail(
"%s: Operation has invalid inputs", __func__);
721 if (!operandInputHandle.
IsValid())
723 return Fail(
"%s: Operation has invalid inputs", __func__);
729 return Fail(
"%s: Operands with rank 0 are not supported", __func__);
732 if (RequiresReshape(operandShape))
734 inputsHaveBeenReshaped =
true;
742 tensorDimensionsAdded = 1;
747 tensorDimensionsAdded = 2;
753 bool isSupported =
false;
772 operandShape = reshapeInfo.
GetShape();
776 inputShapes.emplace_back(operandShape);
777 inputHandles.emplace_back(operandInputHandle);
779 if (!inputHandles.back().IsValid())
781 return Fail(
"%s: Operation has invalid inputs", __func__);
785 ARMNN_ASSERT(inputShapes.size() == inputHandles.size());
787 if (inputsHaveBeenReshaped)
790 concatDim += tensorDimensionsAdded;
793 if (tensorDimensionsAdded == 1)
804 else if (tensorDimensionsAdded == 2)
819 std::pair<armnn::PermutationVector, armnn::PermutationVector> permutationPair =
820 std::make_pair(IdentityPermutation4D, IdentityPermutation4D);
821 bool needPermute = CreateConcatPermutationParameters(inputShapes[0].GetNumDimensions(),
826 if (!isDynamicTensor)
837 if (!TransposeInputTensors(data, inputHandles, inputShapes, permutationPair.first))
852 }
catch (std::exception& error)
854 return Fail(
"%s: Error preparing concat descriptor. %s", __func__,
error.what());
859 if (!isDynamicTensor)
861 if (!ValidateConcatOutputShape(inputShapes, outputShape, concatDim))
863 return Fail(
"%s: Error validating the output shape for concat", __func__);
867 std::vector<const armnn::TensorInfo*> inputTensorInfos;
868 std::transform(inputHandles.begin(), inputHandles.end(), std::back_inserter(inputTensorInfos),
871 bool isSupported =
false;
884 if (!isDynamicTensor)
886 validateFunc(outputInfo, isSupported);
900 assert(layer !=
nullptr);
904 assert(
static_cast<std::size_t
>(numInputSlots) == inputHandles.size());
905 for (
int i = 0; i < numInputSlots; ++i)
912 auto transposeOutputShape = [&](){
917 permutationPair.second);
921 IsTransposeSupported,
934 permutationPair.second);
936 layer = &deswizzleLayer;
941 if (needPermute && !isDynamicTensor)
943 transposeOutputShape();
946 if (inputsHaveBeenReshaped)
952 if (!ValidateConcatOutputShape(inputShapes,
956 return Fail(
"%s: Error validating the output shape for concat", __func__);
958 transposeOutputShape();
963 if (tensorDimensionsAdded == 1)
968 else if (tensorDimensionsAdded == 2)
979 auto validateReshapeFunc = [&](
const armnn::TensorInfo& afterConcatInfo,
bool& isSupported){
992 validateReshapeFunc(afterConcatInfo, isSupported);
1011 validateReshapeFunc);
1019 VLOG(DRIVER) <<
"Converter::ConvertConv2d()";
1024 return Fail(
"%s: Operation has invalid inputs", __func__);
1030 return Fail(
"%s: Could not read output 0", __func__);
1040 bool implicitPadding = operation.inputs.size() == 7
1041 || (operation.inputs.size() >= 8
1044 if (implicitPadding)
1048 else if (operation.inputs.size() >= 10)
1062 return Fail(
"%s: Operation has unsupported weights OperandLifeTime", __func__);
1071 return Fail(
"%s: Operation has invalid inputs", __func__);
1077 return Fail(
"%s: Operation has invalid inputs", __func__);
1084 ActivationFn activation;
1085 if (implicitPadding)
1087 ::android::nn::PaddingScheme paddingScheme;
1094 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1098 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1099 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1100 const uint32_t kernelX = weightsInfo.
GetShape()[widthIndex];
1101 const uint32_t kernelY = weightsInfo.
GetShape()[heightIndex];
1102 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1103 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1109 else if (operation.inputs.size() >= 10)
1121 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1126 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1132 bool requiresValidation =
true;
1141 requiresValidation =
false;
1142 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Weights and Biases are as INPUTS.";
1146 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1159 if (requiresValidation)
1161 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Requires Validation!";
1162 bool isSupported =
false;
1165 validateFunc(outputInfo, isSupported);
1183 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
1195 VLOG(DRIVER) <<
"Converter::ConvertDepthToSpace()";
1200 return Fail(
"%s: Operation has invalid inputs", __func__);
1207 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
1213 return Fail(
"%s: Could not read output 0", __func__);
1223 return Fail(
"%s: Block size must be at least 1 in all dimensions");
1227 if (Is12OrLaterOperand(*output))
1232 bool isSupported =
false;
1237 IsDepthToSpaceSupported,
1248 validateFunc(outputInfo, isSupported);
1262 assert(layer !=
nullptr);
1270 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d()";
1276 return Fail(
"%s: Operation has invalid inputs", __func__);
1283 return Fail(
"%s: Could not read output 0", __func__);
1293 if (!weightsOperand)
1295 return Fail(
"%s: Could not read weights", __func__);
1300 if (weightsOperand->dimensions[0] != 1)
1302 return Fail(
"%s: Filter operand dimension 0 is invalid, should be 1", __func__);
1309 bool implicitPadding = operation.inputs.size() == 8
1310 || (operation.inputs.size() >= 9
1314 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
1318 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1319 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1324 return Fail(
"%s: Operation has invalid inputs", __func__);
1330 return Fail(
"%s: Could not read bias", __func__);
1336 return Fail(
"%s: Operation has invalid inputs", __func__);
1343 ActivationFn activation;
1344 if (implicitPadding)
1346 ::android::nn::PaddingScheme paddingScheme;
1353 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1356 const uint32_t kernelX = weightsInfo.
GetShape()[2];
1357 const uint32_t kernelY = weightsInfo.
GetShape()[1];
1358 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1359 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1364 else if (operation.inputs.size() >= 11)
1376 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1381 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1387 bool requiresValidation =
true;
1393 requiresValidation =
false;
1394 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Weights and Biases are as INPUTS.";
1398 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1411 if (requiresValidation)
1413 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Requires Validation!";
1414 bool isSupported =
false;
1417 validateFunc(outputInfo, isSupported);
1435 return Fail(
"%s: AddDepthwiseConvolution2dLayer failed", __func__);
1449 VLOG(DRIVER) <<
"Converter::ConvertDequantize()";
1454 return Fail(
"%s: Operation has invalid input", __func__);
1461 return Fail(
"%s: Operation has quantization dimension different than 0", __func__);
1467 return Fail(
"%s: Operation has invalid outputs", __func__);
1472 bool isSupported =
false;
1491 validateFunc(outputInfo, isSupported);
1501 assert(layer !=
nullptr);
1509 VLOG(DRIVER) <<
"Converter::ConvertDiv()";
1516 return Fail(
"%s: Operation has invalid inputs", __func__);
1521 ActivationFn activationFunction;
1524 return Fail(
"%s: Operation has invalid inputs", __func__);
1530 return Fail(
"%s: Could not read output 0", __func__);
1535 bool isSupported =
false;
1551 validateFunc(outputInfo, isSupported);
1566 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
1567 if (!isReshapeSupported)
1573 data,
nullptr, validateFunc, activationFunction);
1576 bool Converter::ConvertElementwiseUnary(
const Operation& operation,
1581 VLOG(DRIVER) <<
"Converter::ConvertElementwiseUnary()";
1588 return Fail(
"%s: Operation has invalid input", __func__);
1594 return Fail(
"%s: Could not read output 0", __func__);
1602 bool isSupported =
false;
1607 IsElementwiseUnarySupported,
1618 validateFunc(outputInfo, isSupported);
1632 assert(layer !=
nullptr);
1640 VLOG(DRIVER) <<
"Converter::ConvertElu()";
1645 return Fail(
"%s: Operation has invalid inputs", __func__);
1652 return Fail(
"%s: Operation has invalid inputs", __func__);
1659 if (inputType == OperandType::TENSOR_FLOAT16)
1663 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, alpha, model, data))
1665 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
1668 desc.
m_A =
static_cast<float>(alpha);
1670 else if (inputType == OperandType::TENSOR_FLOAT32)
1674 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
1679 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
1687 VLOG(DRIVER) <<
"Converter::ConvertExpandDims()";
1693 return Fail(
"%s: Operation has invalid input", __func__);
1699 return Fail(
"%s: Operation has invalid output", __func__);
1705 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
1707 return Fail(
"%s: failed to get axis input value", __func__);
1716 catch (
const std::exception& e)
1718 return Fail(
"%s: %s", __func__, e.what());
1724 bool isSupported =
false;
1740 if (targetShape != outputInfo.
GetShape())
1742 return Fail(
"%s: Shape of the output operand does not match the resolved expanded shape", __func__);
1744 validateFunc(outputInfo, isSupported);
1758 assert(layer !=
nullptr);
1766 VLOG(DRIVER) <<
"Converter::ConvertFill()";
1770 return Fail(
"%s: Operation has invalid inputs", __func__);
1776 return Fail(
"%s: Could not read output", __func__);
1783 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
1790 if (outputType == OperandType::TENSOR_FLOAT16)
1794 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
1796 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1799 descriptor.
m_Value =
static_cast<float>(value);
1801 else if (outputType == OperandType::TENSOR_FLOAT32)
1805 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1808 else if (outputType == OperandType::TENSOR_INT32)
1812 if (!
GetInputScalar(operation, 1, OperandType::INT32, value, model, data))
1814 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1817 descriptor.
m_Value =
static_cast<float>(value);
1821 return Fail(
"%s: Unsupported input tensor type: %d", __func__, outputType);
1824 bool isSupported =
false;
1841 assert(layer !=
nullptr);
1849 VLOG(DRIVER) <<
"Converter::ConvertFloor()";
1853 return Fail(
"%s: Operation has invalid inputs", __func__);
1859 return Fail(
"%s: Operation has invalid outputs", __func__);
1864 bool isSupported =
false;
1879 validateFunc(outputInfo, isSupported);
1893 assert(layer !=
nullptr);
1901 VLOG(DRIVER) <<
"Converter::ConvertFullyConnected()";
1905 return Fail(
"%s: Operation has invalid inputs", __func__);
1911 return Fail(
"%s: Could not read output 0", __func__);
1919 if (!weightsOperand)
1921 return Fail(
"%s: Could not read weights", __func__);
1929 return Fail(
"%s: Operation has invalid inputs", __func__);
1936 return Fail(
"%s: Could not read bias", __func__);
1944 return Fail(
"%s: Operation has invalid inputs", __func__);
1953 catch (
const std::exception& e)
1955 return Fail(
"%s: %s", __func__, e.what());
1960 SanitizeBiasQuantizationScale(biasInfo, weightsInfo, reshapedInfo);
1962 ActivationFn activationFunction;
1965 return Fail(
"%s: Operation has invalid inputs", __func__);
1973 bool isSupported =
false;
1977 if (!VerifyFullyConnectedShapes(reshapedInfo.
GetShape(),
1982 isSupported =
false;
1983 Fail(
"%s: Expected outputShape does not match actual outputShape", __func__);
2001 validateFunc(outputInfo, isSupported);
2023 assert(reshapeLayer !=
nullptr);
2038 data,
nullptr, validateFunc, activationFunction);
2043 VLOG(DRIVER) <<
"Converter::ConvertGather()";
2048 return Fail(
"%s: Operation has invalid input", __func__);
2055 return Fail(
"%s: Operation has invalid indices", __func__);
2062 return Fail(
"%s: Operation has invalid output", __func__);
2066 if (outputDimensions != inputDimensions + indicesDimensions - 1)
2068 return Fail(
"%s: Operation has invalid output dimensions: %d. Output must be an (%d + %d - 1)-D tensor",
2069 __func__, outputDimensions, inputDimensions, indicesDimensions);
2073 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
2075 return Fail(
"%s: Operation has invalid or unsupported axis operand", __func__);
2077 if (((axis < -inputDimensions) && (axis < 0)) || ((axis >= inputDimensions) && (axis > 0)))
2079 return Fail(
"%s: Operation has invalid axis: %d. It is out of bounds [-%d, %d))", __func__, axis,
2080 inputDimensions, inputDimensions);
2086 bool isSupported =
false;
2103 validateFunc(outputInfo, isSupported);
2117 assert(layer !=
nullptr);
2126 VLOG(DRIVER) <<
"Converter::ConvertGroupedConv2d()";
2133 return Fail(
"%s: Operation has invalid inputs", __func__);
2140 return Fail(
"%s: Could not read output 0", __func__);
2146 if (operation.inputs.size() == 12)
2160 const ConstTensorPin weightsPin = (dataLayout == DataLayout::NCHW) ?
2162 model, data, ohwiToOihw) :
2168 return Fail(
"%s: Operation has invalid inputs", __func__);
2173 SanitizeBiasQuantizationScale(biases.
GetInfo(), weights.
GetInfo(), inputInfo);
2181 const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
2182 const unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
2183 const unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
2190 ActivationFn activation;
2192 if (operation.inputs.size() == 12)
2200 !
GetInputScalar(operation, 9, OperandType::INT32, numGroups, model, data) ||
2203 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
2207 else if (operation.inputs.size() == 9)
2209 ::android::nn::PaddingScheme paddingScheme;
2213 !
GetInputScalar(operation, 6, OperandType::INT32, numGroups, model, data) ||
2216 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
2219 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
2220 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
2222 const uint32_t kernelX = weightsShape[widthIndex];
2223 const uint32_t kernelY = weightsShape[heightIndex];
2230 return Fail(
"%s: Unsupported number of operation inputs", __func__);
2234 const unsigned int outputChannels = weightsShape[0];
2236 const unsigned int channelsPerGroup = weightsShape[channelsIndex];
2237 const unsigned int channelMultiplier = outputChannels / numGroups;
2244 return Fail(
"%s: Number of groups must be greater than 0. Got: %d", __func__, numGroups);
2247 if (outputChannels % numGroups != 0u)
2249 return Fail(
"%s: Output channels must be divisible by the number of groups", __func__);
2255 unsigned int splitterDimSizes[4] = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
2256 splitterDimSizes[channelsIndex] /= numGroups;
2264 std::vector<std::reference_wrapper<TensorInfo>> splitterOutputInfos(numGroups, std::ref(splitterOutputInfo));
2267 for (
unsigned int group = 0u; group < numGroups; ++group)
2269 splitterDesc.SetViewOriginCoord(group, channelsIndex, splitterDimSizes[channelsIndex] * group);
2270 for (
unsigned int dimIdx = 0u; dimIdx < 4u; dimIdx++)
2272 splitterDesc.SetViewSize(group, dimIdx, splitterDimSizes[dimIdx]);
2276 bool isSupported =
false;
2284 splitterOutputInfos,
2295 return Fail(
"%s: Failed to add SplitterLayer", __func__);
2299 for (
unsigned int group = 0u; group < splitterLayer->
GetNumOutputSlots(); ++group)
2310 groupInputShape[channelsIndex] = channelsPerGroup;
2313 groupWeightsShape[0] /= channelMultiplier * numGroups;
2319 groupInputInfo.SetShape(groupInputShape);
2323 groupWeightsInfo.SetShape(groupWeightsShape);
2327 groupBiasesInfo.SetShape(groupBiasesShape);
2335 groupOutputShape[channelsIndex] = 1;
2337 groupOutputInfo.SetShape(groupOutputShape);
2339 const unsigned int weightsDataTypeSize =
GetDataTypeSize(groupWeightsInfo.GetDataType());
2340 const unsigned int biasesDataTypeSize =
GetDataTypeSize(groupBiasesInfo.GetDataType());
2342 std::vector<IConnectableLayer*> convLayers(numGroups * channelMultiplier,
nullptr);
2343 for (
unsigned int group = 0u; group < numGroups; ++group)
2345 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2347 auto index = group * channelMultiplier + m;
2349 const unsigned int weightsDataOffset = groupWeightsShape.GetNumElements() * index * weightsDataTypeSize;
2350 const unsigned int biasesDataOffset = groupBiasesShape.GetNumElements() * index * biasesDataTypeSize;
2356 groupWeightsInfo.SetQuantizationScales(
2357 std::vector<float>(weightsQuantScales.begin() + index,
2358 weightsQuantScales.begin() + index + groupWeightsShape[0]));
2362 groupBiasesInfo.SetQuantizationScales(
2363 std::vector<float>(biasesQuantScales.begin() + index,
2364 biasesQuantScales.begin() + index + groupWeightsShape[0]));
2369 static_cast<const void *
>(
reinterpret_cast<const char *
>(weights.
GetMemoryArea()) +
2370 weightsDataOffset));
2372 static_cast<const void *
>(
reinterpret_cast<const char *
>(biases.
GetMemoryArea()) +
2375 isSupported =
false;
2393 validateFunc(groupOutputInfo, isSupported);
2413 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
2438 convLayers[index] = convLayer;
2448 for (
unsigned int group = 0u; group < numGroups; ++group)
2450 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2452 auto index = group * channelMultiplier + m;
2458 isSupported =
false;
2465 std::vector<const TensorInfo*>(numGroups * channelMultiplier, &groupOutputInfo),
2478 return Fail(
"%s: AddConcatLayer failed", __func__);
2481 for (
unsigned int group = 0u; group < numGroups; ++group)
2483 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2485 auto index = group * channelMultiplier + m;
2486 convLayers[index]->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(index));
2492 data,
nullptr,
nullptr, activation);
2497 VLOG(DRIVER) <<
"Converter::ConvertHardSwish()";
2499 desc.
m_Function = ActivationFunction::HardSwish;
2506 VLOG(DRIVER) <<
"Converter::ConvertInstanceNormalization()";
2511 return Fail(
"%s: Operation has an invalid input 0", __func__);
2517 return Fail(
"%s: Operation has an invalid output", __func__);
2526 return Fail(
"%s: Operation has invalid inputs", __func__);
2532 if (inputType == OperandType::TENSOR_FLOAT16)
2538 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Gamma, model, data) ||
2539 !
GetInputScalar(operation, 2, OperandType::FLOAT16, fp16Beta, model, data) ||
2540 !
GetInputScalar(operation, 3, OperandType::FLOAT16, fp16Epsilon, model, data))
2542 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
2545 desc.
m_Gamma =
static_cast<float>(fp16Gamma);
2546 desc.
m_Beta =
static_cast<float>(fp16Beta);
2547 desc.
m_Eps =
static_cast<float>(fp16Epsilon);
2549 else if (inputType == OperandType::TENSOR_FLOAT32)
2555 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
2560 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2565 bool isSupported =
false;
2570 IsInstanceNormalizationSupported,
2585 validateFunc(outputInfo, isSupported);
2602 VLOG(DRIVER) <<
"Converter::ConvertL2Normalization()";
2604 if (operation.inputs.size() != 1)
2606 return Fail(
"%s: Optional inputs are not supported", __func__);
2612 return Fail(
"%s: Operation has invalid inputs", __func__);
2618 return Fail(
"%s: Could not read output 0", __func__);
2626 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2632 bool isSupported =
false;
2648 validateFunc(outputInfo, isSupported);
2662 assert(layer !=
nullptr);
2670 VLOG(DRIVER) <<
"Converter::ConvertL2Pool2d()";
2671 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::L2, model, data);
2674 bool Converter::ConvertLocalResponseNormalization(
const Operation& operation,
2678 VLOG(DRIVER) <<
"Converter::ConvertLocalResponseNormalization()";
2680 if (operation.inputs.size() != 5)
2682 return Fail(
"%s: Optional inputs are not supported", __func__);
2688 return Fail(
"%s: Operation has invalid inputs", __func__);
2694 return Fail(
"%s: Could not read output 0", __func__);
2702 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2716 return Fail(
"%s: Operation has invalid inputs", __func__);
2723 bool isSupported =
false;
2739 validateFunc(outputInfo, isSupported);
2754 assert(layer !=
nullptr);
2760 bool Converter::ConvertLogicalBinary(
const Operation& operation,
2765 VLOG(DRIVER) <<
"Converter::ConvertLogicalBinary()";
2766 VLOG(DRIVER) <<
"ConvertLogicalBinary()";
2774 return Fail(
"%s: Operation has invalid inputs", __func__);
2780 return Fail(
"%s: Could not read output 0", __func__);
2789 bool isSupported =
false;
2794 IsLogicalBinarySupported,
2806 validateFunc(outputInfo, isSupported);
2820 assert(layer !=
nullptr);
2822 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
2823 if (!isReshapeSupported)
2833 VLOG(DRIVER) <<
"Converter::ConvertLogistic()";
2842 VLOG(DRIVER) <<
"Converter::ConvertLogSoftmax()";
2847 return Fail(
"%s: Failed to read input 0", __func__);
2853 return Fail(
"%s: Failed to read output", __func__);
2862 return Fail(
"%s: Operation has invalid inputs", __func__);
2868 if (inputType == OperandType::TENSOR_FLOAT16)
2871 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Beta, model, data))
2873 return Fail(
"%s: Failed to read input 1 (FLOAT16)", __func__);
2876 descriptor.
m_Beta =
static_cast<float>(fp16Beta);
2878 else if (inputType == OperandType::TENSOR_FLOAT32)
2882 return Fail(
"%s: Failed to read input 1 (FLOAT32)", __func__);
2887 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2893 return Fail(
"%s: Failed to read input 2", __func__);
2896 bool isSupported =
false;
2901 IsLogSoftmaxSupported,
2916 validateFunc(outputInfo, isSupported);
2928 return Fail(
"%s: AddLogSoftmaxLayer() returned nullptr", __func__);
2938 VLOG(DRIVER) <<
"Converter::ConvertLstm()";
2946 return Fail(
"%s: Could not read input 0: input", __func__);
2952 return Fail(
"%s: Could not read input 18: outputStateIn", __func__);
2958 return Fail(
"%s: Could not read input 19: cellStateIn", __func__);
2996 if (!inputToForgetWeightsPin.
IsValid() ||
2997 !inputToCellWeightsPin.
IsValid() ||
2998 !inputToOutputWeightsPin.
IsValid() ||
2999 !recurrentToForgetWeightsPin.
IsValid() ||
3000 !recurrentToCellWeightsPin.
IsValid() ||
3001 !recurrentToOutputWeightsPin.
IsValid() ||
3002 !forgetGateBiasPin.
IsValid() ||
3006 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3052 if ((!inputToInputWeightsPin.
IsValid() && !inputToInputWeightsPin.
IsOptional()) ||
3053 (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional()) ||
3061 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3071 ActivationFn activation = ActivationFn::kActivationNone;
3075 !
GetInputScalar(operation, 21, OperandType::FLOAT32, cellClip, model, data) ||
3076 !
GetInputScalar(operation, 22, OperandType::FLOAT32, projClip, model, data))
3078 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
3126 return Fail(
"%s: Could not read output 0: scratchBuffer", __func__);
3130 if (!outputStateOut)
3132 return Fail(
"%s: Could not read output 1: outputStateOut", __func__);
3138 return Fail(
"%s: Could not read output 2: cellStateOut", __func__);
3145 return Fail(
"%s: Could not read output 3: output", __func__);
3194 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
3195 " and input gate bias must be provided", __func__);
3200 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
3208 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
3209 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
3218 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
3219 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
3284 bool isSupported =
false;
3304 bool isDynamic =
false;
3310 validateFunc(outputInfo, isSupported);
3346 operation, 3, *layer, 3, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
3353 VLOG(DRIVER) <<
"Converter::ConvertMaxPool2d()";
3354 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Max, model, data);
3359 VLOG(DRIVER) <<
"Converter::ConvertMaximum()";
3366 return Fail(
"%s: Operation has invalid inputs", __func__);
3372 return Fail(
"%s: Could not read output", __func__);
3377 bool isSupported =
false;
3397 validateFunc(outInfo, isSupported);
3407 assert(layer !=
nullptr);
3408 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
3409 if (!isReshapeSupported)
3419 VLOG(DRIVER) <<
"Converter::ConvertMean()";
3424 return Fail(
"%s: Operation has invalid inputs", __func__);
3430 return Fail(
"%s: Could not read output 0", __func__);
3438 return Fail(
"%s: Could not read input 1", __func__);
3441 std::vector<int32_t> axis;
3444 return Fail(
"%s: Input 1 has invalid values", __func__);
3451 std::set<unsigned int> uniqueAxis;
3452 std::transform(axis.begin(), axis.end(),
3453 std::inserter(uniqueAxis, uniqueAxis.begin()),
3454 [rank](
int i) ->
unsigned int { return (i + rank) % rank; });
3457 int32_t keepDims = 0;
3460 return Fail(
"%s: Could not read input 2", __func__);
3464 descriptor.
m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
3467 bool isSupported =
false;
3483 validateFunc(outputInfo, isSupported);
3497 assert(layer !=
nullptr);
3505 VLOG(DRIVER) <<
"Converter::ConvertMinimum()";
3512 return Fail(
"%s: Operation has invalid inputs", __func__);
3518 return Fail(
"%s: Could not read output 0", __func__);
3523 bool isSupported =
false;
3543 validateFunc(outputInfo, isSupported);
3553 assert(layer !=
nullptr);
3554 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
3555 if (!isReshapeSupported)
3565 VLOG(DRIVER) <<
"Converter::ConvertMul()";
3572 return Fail(
"%s: Operation has invalid inputs", __func__);
3577 ActivationFn activationFunction;
3580 return Fail(
"%s: Operation has invalid inputs", __func__);
3585 if (outputOperand ==
nullptr)
3592 bool isSupported =
false;
3608 validateFunc(outputInfo, isSupported);
3623 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
3624 if (!isReshapeSupported)
3630 data,
nullptr, validateFunc, activationFunction);
3635 VLOG(DRIVER) <<
"Converter::ConvertPad()";
3640 return Fail(
"%s: Operation has invalid inputs", __func__);
3649 return Fail(
"%s: Could not convert paddings", __func__);
3665 return Fail(
"%s: Could not read output", __func__);
3670 bool isSupported =
false;
3686 validateFunc(outputInfo, isSupported);
3700 assert(layer !=
nullptr);
3708 VLOG(DRIVER) <<
"Converter::ConvertPadV2()";
3713 return Fail(
"%s: Could not read input 0", __func__);
3719 return Fail(
"%s: Could not read output", __func__);
3728 return Fail(
"%s: Could not convert paddings", __func__);
3740 return Fail(
"%s: Operation has invalid inputs", __func__);
3744 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
3747 if (!
GetInputScalar(operation, 2, operandType2, f16PadValue, model, data))
3749 return Fail(
"%s: Could not read input 2 (FLOAT16)", __func__);
3754 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
3758 return Fail(
"%s: Could not read input 2 (FLOAT32)", __func__);
3763 int32_t intPadValue = 0;
3766 return Fail(
"%s: Could not read input 2 (INT32)", __func__);
3772 return Fail(
"%s: Operation has invalid inputs: type mismatch", __func__);
3775 bool isSupported =
false;
3795 validateFunc(outputInfo, isSupported);
3805 assert(layer !=
nullptr);
3813 VLOG(DRIVER) <<
"Converter::ConvertPrelu()";
3820 return Fail(
"%s: Operation has invalid inputs", __func__);
3827 return Fail(
"%s: Could not read output", __func__);
3834 bool isSupported =
false;
3854 validateFunc(outputInfo, isSupported);
3867 return Fail(
"%s: AddPreluLayer failed", __func__);
3870 bool isReshapeSupported = BroadcastTensor(input, alpha, layer, data);
3871 if (!isReshapeSupported)
3881 VLOG(DRIVER) <<
"Converter::ConvertQuantize()";
3886 return Fail(
"%s: Operation has invalid input", __func__);
3892 return Fail(
"%s: Operation has invalid outputs", __func__);
3897 bool isSupported =
false;
3902 IsQuantizeSupported,
3916 validateFunc(outputInfo, isSupported);
3926 assert(layer !=
nullptr);
3934 VLOG(DRIVER) <<
"Converter::ConvertQuantizedLstm()";
3936 VLOG(DRIVER) <<
"ConvertQuantizedLstm()";
3944 return Fail(
"%s: Could not read input 0: input", __func__);
3949 if (!outputStatePrevTimeStep.
IsValid())
3951 return Fail(
"%s: Could not read input 18: outputStatePrevTimeStep", __func__);
3956 if (!cellStatePrevTimeStep.
IsValid())
3958 return Fail(
"%s: Could not read input 19: cellStatePrevTimeStep", __func__);
4005 if (!inputToForgetWeightsPin.
IsValid() ||
4006 !inputToCellWeightsPin.
IsValid() ||
4007 !inputToOutputWeightsPin.
IsValid() ||
4008 !recurrentToForgetWeightsPin.
IsValid() ||
4009 !recurrentToCellWeightsPin.
IsValid() ||
4010 !recurrentToOutputWeightsPin.
IsValid() ||
4011 !forgetGateBiasPin.
IsValid() ||
4015 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4108 || (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional())
4116 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4166 if ((!inputLayerNormWeightsPin.
IsValid() && !inputLayerNormWeightsPin.
IsOptional())
4167 || (!forgetLayerNormWeightsPin.
IsValid() && !forgetLayerNormWeightsPin.
IsOptional())
4168 || (!cellLayerNormWeightsPin.
IsValid() && !cellLayerNormWeightsPin.
IsOptional())
4169 || (!outputLayerNormWeightsPin.
IsValid() && !outputLayerNormWeightsPin.
IsOptional()))
4171 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4185 float cellClip, projClip, matMulInputGate, matMulForgetGate, matMulCellGate, matMulOutputGate, projInputScale;
4186 int projInputZeroPoint;
4188 if (!
GetInputScalar(operation, 24, OperandType::FLOAT32, cellClip, model, data,
true) ||
4189 !
GetInputScalar(operation, 25, OperandType::FLOAT32, projClip, model, data,
true) ||
4190 !
GetInputScalar(operation, 26, OperandType::FLOAT32, matMulInputGate, model, data) ||
4191 !
GetInputScalar(operation, 27, OperandType::FLOAT32, matMulForgetGate, model, data) ||
4192 !
GetInputScalar(operation, 28, OperandType::FLOAT32, matMulCellGate, model, data) ||
4193 !
GetInputScalar(operation, 29, OperandType::FLOAT32, matMulOutputGate, model, data) ||
4194 !
GetInputScalar(operation, 30, OperandType::INT32, projInputZeroPoint, model, data) ||
4195 !
GetInputScalar(operation, 31, OperandType::FLOAT32, projInputScale, model, data))
4197 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
4204 if (!outputStateOut)
4206 return Fail(
"%s: Could not read output 0: outputStateOut", __func__);
4213 return Fail(
"%s: Could not read output 1: cellStateOut", __func__);
4221 return Fail(
"%s: Could not read output 2: output", __func__);
4275 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
4276 " and input gate bias must be provided", __func__);
4281 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
4289 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
4290 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
4299 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
4300 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
4356 const TensorInfo constOutputStateOutInfo(outputStateOutInfo);
4357 const TensorInfo constOutputInfo(outputInfo);
4377 bool isSupported =
false;
4379 auto validateFunc = [&](
const armnn::TensorInfo& cellStateOutInfo,
bool& isSupported)
4387 outputStatePrevTimeStepInfo,
4388 cellStatePrevTimeStepInfo,
4389 constOutputStateOutInfo,
4396 bool isDynamic =
false;
4401 validateFunc(outputInfo, isSupported);
4425 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4432 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4434 operation, 1, *layer, 1, model, data,
nullptr, validateFunc,
4435 ActivationFn::kActivationNone,
true) &&
4442 VLOG(DRIVER) <<
"Converter::ConvertQuantized16BitLstm()";
4443 VLOG(DRIVER) <<
"Policy::ConvertQuantized16BitLstm()";
4451 return Fail(
"%s: Could not read input 0: input", __func__);
4458 if (!previousCellStateIn.
IsValid())
4460 return Fail(
"%s: Could not read input 13: previousCellStateIn", __func__);
4467 if (!previousOutputIn.
IsValid())
4469 return Fail(
"%s: Could not read input 14: previousOutputIn", __func__);
4545 if (!inputToInputWeightsPin.
IsValid() ||
4546 !inputToForgetWeightsPin.
IsValid() ||
4547 !inputToCellWeightsPin.
IsValid() ||
4548 !inputToOutputWeightsPin.
IsValid() ||
4549 !recurrentToInputWeightsPin.
IsValid() ||
4550 !recurrentToForgetWeightsPin.
IsValid() ||
4551 !recurrentToCellWeightsPin.
IsValid() ||
4552 !recurrentToOutputWeightsPin.
IsValid() ||
4553 !inputGateBiasPin.
IsValid() ||
4554 !forgetGateBiasPin.
IsValid() ||
4558 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4568 return Fail(
"%s: Could not read output 0: cellStateOut", __func__);
4576 return Fail(
"%s: Could not read output 1: output", __func__);
4591 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4623 bool isSupported =
false;
4633 previousCellStateInInfo,
4634 previousOutputInInfo,
4640 bool isDynamic =
false;
4644 validateFunc(outputInfo, isSupported);
4672 operation, 1, *layer, 1, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
4679 VLOG(DRIVER) <<
"Converter::ConvertRank()";
4684 if (inputOperand ==
nullptr || outputOperand ==
nullptr)
4686 return Fail(
"%s: Operation has invalid inputs", __func__);
4689 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4690 const Shape outputOperandShape = GetOperandShape(*outputOperand);
4695 return Fail(
"%s: Could not read input 0", __func__);
4701 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4704 bool isSupported =
false;
4720 assert(layer !=
nullptr);
4728 VLOG(DRIVER) <<
"Converter::ConvertReLu()";
4736 return Fail(
"%s: Input 0 is invalid",
"operationName");
4747 bool isSupported =
false;
4767 validateFunc(outInfo, isSupported);
4785 VLOG(DRIVER) <<
"Converter::ConvertReLu1()";
4796 VLOG(DRIVER) <<
"Converter::ConvertReLu6()";
4806 VLOG(DRIVER) <<
"Converter::ConvertReshape()";
4812 if (inputOperand ==
nullptr
4813 || requestedShapeOperand ==
nullptr
4814 || outputOperand ==
nullptr)
4816 return Fail(
"%s: Operation has invalid inputs", __func__);
4819 if (requestedShapeOperand->dimensions.size() != 1)
4821 return Fail(
"%s: Input 1 expected to be one-dimensional (found %i dimensions)",
4822 __func__, requestedShapeOperand->dimensions.size());
4825 std::vector<int32_t> targetDimensions;
4828 return Fail(
"%s: Could not read values of input 1", __func__);
4831 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4833 Shape requestedShape;
4836 if (!reshapePrepare(inputOperandShape, targetDimensions.data(), targetDimensions.size(), &requestedShape))
4838 return Fail(
"%s: Failed to resolve the requested shape", __func__);
4844 return Fail(
"%s: Could not read input 0", __func__);
4849 requestedShape.dimensions.data());
4853 bool isSupported =
false;
4869 validateFunc(outputInfo, isSupported);
4883 assert(layer !=
nullptr);
4889 bool Converter::ConvertResize(
const Operation& operation,
4894 VLOG(DRIVER) <<
"Converter::ConvertResize()";
4900 return Fail(
"%s: Could not read input 0", __func__);
4906 return Fail(
"%s: Could not read output 0", __func__);
4913 descriptor.
m_Method = resizeMethod;
4922 return Fail(
"%s: Operation has invalid inputs", __func__);
4925 if (operandType1 != operandType2)
4927 return Fail(
"%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
4930 if (operandType1 == OperandType::INT32)
4933 int32_t targetWidth = 0;
4934 int32_t targetHeight = 0;
4936 if (!
GetInputInt32(operation, 1, targetWidth, model, data) ||
4939 return Fail(
"%s: Operation has invalid inputs for resizing by shape", __func__);
4942 if (targetWidth < 0 || targetHeight < 0)
4944 return Fail(
"%s: Operation has invalid inputs for resizing by shape. "
4945 "Target width/height cannot be < 0", __func__);
4948 descriptor.
m_TargetWidth =
static_cast<uint32_t
>(targetWidth);
4951 else if (operandType1 == OperandType::FLOAT32)
4954 float widthScale = 1.0f;
4955 float heightScale = 1.0f;
4960 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
4966 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
4967 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
4972 else if (operandType1 == OperandType::FLOAT16)
4977 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, widthScale, model, data) ||
4978 !
GetInputScalar(operation, 2, OperandType::FLOAT16, heightScale, model, data))
4980 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
4986 Half width =
static_cast<Half>(inputShape[dataLayoutIndexed.GetWidthIndex()]);
4987 Half height =
static_cast<Half>(inputShape[dataLayoutIndexed.GetHeightIndex()]);
4994 return Fail(
"%s: Operand has invalid data type for resizing by scale", __func__);
5000 bool isSupported =
false;
5020 validateFunc(outputInfo, isSupported);
5030 assert(layer !=
nullptr);
5038 VLOG(DRIVER) <<
"Converter::ConvertSpaceToBatchNd()";
5043 return Fail(
"%s: Operation has invalid inputs", __func__);
5048 unsigned int spatialDim = rank - 2;
5052 Fail(
"%s: Only inputs with rank 4 are supported", __func__);
5058 return Fail(
"%s: Could not read output 0", __func__);
5066 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
5069 return Fail(
"%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
5072 std::vector<int32_t> blockShape;
5075 return Fail(
"%s: Operation has an invalid or unsupported block size operand", __func__);
5077 if(std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i)
5080 return Fail(
"%s: Block shape must be at least 1 in all dimensions.", __func__);
5083 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
5086 return Fail(
"%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
5089 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
5090 std::vector<int32_t> paddings;
5093 return Fail(
"%s: Operation has an invalid or unsupported paddings operand", __func__);
5095 for (
unsigned int i = 0; i < paddings.size() - 1; i += 2)
5097 int paddingBeforeInput = paddings[i];
5098 int paddingAfterInput = paddings[i + 1];
5099 if(paddingBeforeInput < 0 || paddingAfterInput < 0)
5101 return Fail(
"%s: Operation has invalid paddings operand, invalid padding values.", __func__);
5104 paddingList.emplace_back((
unsigned int) paddingBeforeInput, (
unsigned int) paddingAfterInput);
5109 descriptor.
m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
5110 descriptor.
m_PadList.assign(paddingList.cbegin(), paddingList.cend());
5112 if(Is12OrLaterOperand(*output))
5117 bool isSupported =
false;
5136 validateFunc(outputInfo, isSupported);
5146 assert(layer !=
nullptr);
5154 VLOG(DRIVER) <<
"Converter::ConvertSpaceToDepth()";
5159 return Fail(
"%s: Operation has invalid inputs", __func__);
5166 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
5172 return Fail(
"%s: Could not read output 0", __func__);
5183 return Fail(
"%s: Block size must be at least 1 in all dimensions");
5188 bool isSupported =
false;
5208 validateFunc(outputInfo, isSupported);
5218 assert(layer !=
nullptr);
5226 VLOG(DRIVER) <<
"Converter::ConvertSoftmax()";
5231 return Fail(
"%s: Operation has invalid inputs", __func__);
5237 return Fail(
"%s: Operation has no outputs", __func__);
5246 if (outputType == OperandType::TENSOR_FLOAT16)
5250 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
5252 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5255 desc.
m_Beta =
static_cast<float>(value);
5261 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5272 return Fail(
"%s: Operation has invalid inputs", __func__);
5275 bool isSupported =
false;
5295 validateFunc(outputInfo, isSupported);
5305 assert(layer !=
nullptr);
5313 VLOG(DRIVER) <<
"Converter::ConvertSub()";
5320 return Fail(
"%s: Operation has invalid inputs", __func__);
5325 ActivationFn activationFunction;
5328 return Fail(
"%s: Operation has invalid inputs", __func__);
5334 return Fail(
"%s: Could not read output 0", __func__);
5339 bool isSupported =
false;
5359 validateFunc(outputInfo, isSupported);
5370 bool isReshapeSupported = BroadcastTensor(input0, input1, startLayer, data);
5371 if (!isReshapeSupported)
5376 data,
nullptr, validateFunc, activationFunction);
5381 VLOG(DRIVER) <<
"Converter::ConvertTanH()";
5393 VLOG(DRIVER) <<
"Converter::ConvertTransposeConv2d()";
5399 return Fail(
"%s: Operation has invalid inputs", __func__);
5406 return Fail(
"%s: Could not read output 0", __func__);
5416 if (weightsOperand ==
nullptr)
5418 return Fail(
"%s: Operand is invalid", __func__);
5424 bool implicitPadding = operation.inputs.size() == 9;
5426 if (implicitPadding )
5436 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
5437 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
5445 model, data, OHWIToOIHW) :
5454 return Fail(
"%s: Operation has invalid weights", __func__);
5459 return Fail(
"%s: Operation has invalid biases", __func__);
5464 SanitizeBiasQuantizationScale(bias.
GetInfo(), weights.
GetInfo(), inputInfo);
5466 ActivationFn activation;
5468 if (implicitPadding)
5473 int32_t padRight{0};
5475 int32_t padBottom{0};
5477 ::android::nn::PaddingScheme paddingScheme;
5479 !
GetInputScalar(operation, 5, OperandType::INT32, strideX, model, data) ||
5480 !
GetInputScalar(operation, 6, OperandType::INT32, strideY, model, data) ||
5483 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
5486 const uint32_t kernelX = weights.
GetShape()[widthIndex];
5487 const uint32_t kernelY = weights.
GetShape()[heightIndex];
5491 std::vector<int32_t> outputShape;
5492 if ((outputShapeOperand) && (
GetTensorInt32Values(*outputShapeOperand, outputShape, model, data)))
5495 for (
int dimension : outputShape)
5497 desc.
m_OutputShape.push_back(
static_cast<unsigned int>(dimension));
5507 if (outputShape.size() == 0)
5509 return Fail(
"%s: Padding sizes cannot be inferred", __func__);
5512 outputX = outputShape[widthIndex];
5513 outputY = outputShape[heightIndex];
5517 outputX = outputInfo.
GetShape()[widthIndex];
5518 outputY = outputInfo.
GetShape()[heightIndex];
5521 CalcPaddingTransposeConv(outputX, kernelX, strideX, padLeft, padRight, paddingScheme);
5522 CalcPaddingTransposeConv(outputY, kernelY, strideY, padTop, padBottom, paddingScheme);
5526 if (padLeft < 0 || padRight < 0 || padTop < 0 || padBottom < 0)
5528 return Fail(
"%s: Negative padding values are not supported", __func__);
5531 desc.
m_StrideX = armnn::numeric_cast<uint32_t>(strideX);
5532 desc.
m_StrideY = armnn::numeric_cast<uint32_t>(strideY);
5533 desc.
m_PadLeft = armnn::numeric_cast<uint32_t>(padLeft);
5534 desc.
m_PadRight = armnn::numeric_cast<uint32_t>(padRight);
5535 desc.
m_PadTop = armnn::numeric_cast<uint32_t>(padTop);
5536 desc.
m_PadBottom = armnn::numeric_cast<uint32_t>(padBottom);
5538 else if (operation.inputs.size() == 11)
5549 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
5554 return Fail(
"%s: Unsupported number of operation inputs", __func__);
5560 bool isSupported =
false;
5582 validateFunc(outputInfo, isSupported);
5594 return Fail(
"%s: AddTransposeConvolution2dLayer failed", __func__);
5600 data,
nullptr, validateFunc, activation);
5605 VLOG(DRIVER) <<
"Converter::ConvertSqrt()";
5614 VLOG(DRIVER) <<
"Converter::ConvertSqueeze()";
5619 return Fail(
"%s: Operation has invalid inputs", __func__);
5626 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5632 return Fail(
"%s: Could not read output 0", __func__);
5637 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
5644 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
5646 std::vector<int32_t> axis;
5649 axis.assign(dimensionSequence,
5650 dimensionSequence + rank);
5654 return Fail(
"%s: Operation has an invalid or unsupported axis operand", __func__);
5657 std::vector<uint32_t> outputDims;
5658 for (
unsigned int i = 0; i < rank; i++)
5660 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
5661 auto currentDimension = inputInfo.
GetShape()[i];
5662 if (skipSqueeze || currentDimension != 1)
5664 outputDims.push_back(currentDimension);
5676 bool isSupported =
false;
5694 assert(layer !=
nullptr);
5702 VLOG(DRIVER) <<
"Converter::ConvertStridedSlice()";
5707 return Fail(
"%s: Operation has invalid inputs", __func__);
5714 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5720 return Fail(
"%s: Could not read output 0", __func__);
5729 std::vector<int32_t> beginValues;
5730 std::vector<int32_t> endValues;
5731 std::vector<int32_t> stridesValues;
5734 auto ValidateInputOperands = [&] (
const Operand& operand, std::vector<int32_t>& operandValues)
5741 if (operandValues.size() != rank)
5749 if (!ValidateInputOperands(*beginOperand, beginValues)
5750 || !ValidateInputOperands(*endOperand, endValues)
5751 || !ValidateInputOperands(*stridesOperand, stridesValues))
5753 return Fail(
"%s: Operation has invalid input operand", __func__);
5757 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
5759 return Fail(
"%s: Stride must be non-zero value.", __func__);
5763 descriptor.
m_Begin.assign(beginValues.cbegin(), beginValues.cend());
5764 descriptor.
m_End.assign(endValues.cbegin(), endValues.cend());
5765 descriptor.
m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
5773 return Fail(
"%s: Operation has invalid inputs", __func__);
5776 bool isSupported =
false;
5796 validateFunc(outputInfo, isSupported);
5808 int stride = descriptor.
m_Stride[i];
5814 if (((descriptor.
m_Begin[i] - descriptor.
m_End[i]) > 1)
5815 || ((descriptor.
m_Begin[i] - descriptor.
m_End[i]) < -1))
5817 return Fail(
"%s: StridedSlice: Output will not be large enough to hold the slice", __func__);
5822 return Fail(
"%s: StridedSlice: Stride can not be negative while ShrinkAxisMask is set.", __func__);
5829 assert(layer !=
nullptr);
5837 VLOG(DRIVER) <<
"Converter::ConvertTranspose()";
5842 return Fail(
"%s: Operation has invalid inputs", __func__);
5849 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5856 std::vector<int32_t> perm(rank);
5857 if (!permOperand || (permOperand->lifetime == OperandLifeTime::NO_VALUE))
5859 for (
unsigned int i = rank; i > 0; i--)
5861 perm[rank - i] = armnn::numeric_cast<int> (i - 1);
5866 return Fail(
"%s: Operation has an invalid or unsupported permutation operand", __func__);
5869 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
5877 return Fail(
"%s: Could not read output 0", __func__);
5882 bool isSupported =
false;
5887 IsTransposeSupported,
5902 validateFunc(outputInfo, isSupported);
5912 assert(layer !=
nullptr);