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:
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:
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:
107 case OperationType::MEAN:
108 return ConvertMean(operation, model, data);
109 case OperationType::MINIMUM:
111 case OperationType::MUL:
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::POW:
124 return ConvertElementwiseBinary(operation, model, data, BinaryOperation::Power);
125 case OperationType::QUANTIZE:
126 return ConvertQuantize(operation, model, data);
127 case OperationType::QUANTIZED_LSTM:
128 return ConvertQuantizedLstm(operation, model, data);
129 case OperationType::QUANTIZED_16BIT_LSTM:
130 return ConvertQuantized16BitLstm(operation, model, data);
131 case OperationType::RANK:
132 return ConvertRank(operation, model, data);
133 case OperationType::REDUCE_MAX:
135 case OperationType::REDUCE_MIN:
137 case OperationType::REDUCE_PROD:
139 case OperationType::REDUCE_SUM:
141 case OperationType::RELU:
142 return ConvertReLu(operation, model, data);
143 case OperationType::RELU1:
144 return ConvertReLu1(operation, model, data);
145 case OperationType::RELU6:
146 return ConvertReLu6(operation, model, data);
147 case OperationType::RESHAPE:
148 return ConvertReshape(operation, model, data);
149 case OperationType::RESIZE_BILINEAR:
150 return ConvertResize(operation, model, data, ResizeMethod::Bilinear);
151 case OperationType::RESIZE_NEAREST_NEIGHBOR:
152 return ConvertResize(operation, model, data, ResizeMethod::NearestNeighbor);
153 case OperationType::REVERSE:
154 return ConvertReverseV2(operation, model, data);
155 case OperationType::RSQRT:
156 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Rsqrt);
157 case OperationType::SIN:
158 return ConvertElementwiseUnary(operation, model, data, UnaryOperation::Sin);
159 case OperationType::SOFTMAX:
160 return ConvertSoftmax(operation, model, data);
161 case OperationType::SPACE_TO_BATCH_ND :
162 return ConvertSpaceToBatchNd(operation, model, data);
163 case OperationType::SPACE_TO_DEPTH:
164 return ConvertSpaceToDepth(operation, model, data);
165 case OperationType::SQRT:
166 return ConvertSqrt(operation, model, data);
167 case OperationType::SQUEEZE:
168 return ConvertSqueeze(operation, model, data);
169 case OperationType::STRIDED_SLICE:
170 return ConvertStridedSlice(operation, model, data);
171 case OperationType::SUB:
172 return ConvertElementwiseBinary(operation, model, data, BinaryOperation::Sub);
173 case OperationType::TILE:
174 return ConvertTile(operation, model, data);
175 case OperationType::TRANSPOSE:
176 return ConvertTranspose(operation, model, data);
177 case OperationType::TRANSPOSE_CONV_2D:
178 return ConvertTransposeConv2d(operation, model, data);
179 case OperationType::TANH:
180 return ConvertTanH(operation, model, data);
182 VLOG(DRIVER) <<
"Operation type: " << operation.type <<
"is not supported in ArmnnDriver";
187 bool Converter::ConvertArgMinMax(
const Operation& operation,
192 VLOG(DRIVER) <<
"Converter::ConvertArgMinMax()";
199 return Fail(
"%s: Operation has invalid inputs", __func__);
203 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
205 return Fail(
"%s: Operation has invalid inputs. Failed to read axis.", __func__);
211 if (((axis < -rank) && (axis < 0)) || ((axis >= rank) && (axis > 0)))
216 return Fail(
"%s: Axis must be in range [-n, n)", __func__);
222 return Fail(
"%s: Could not read output 0", __func__);
233 bool isSupported =
false;
238 IsArgMinMaxSupported,
253 validateFunc(outputInfo, isSupported);
263 assert(layer !=
nullptr);
272 VLOG(DRIVER) <<
"Converter::ConvertAveragePool2d()";
273 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Average, model, data);
278 VLOG(DRIVER) <<
"Converter::ConvertBatchMatMul()";
284 return Fail(
"%s: Operation has invalid inputs", __func__);
291 if (rankInput0 > 4 || rankInput0 < 2)
293 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
297 if (rankInput1 > 4 || rankInput1 < 2)
299 Fail(
"%s: Only inputs with rank at least 2 and up to 4 are supported", __func__);
306 return Fail(
"%s: Operation has invalid inputs", __func__);
313 return Fail(
"%s: Operation has invalid inputs", __func__);
316 if (input0Type != input1Type)
318 return Fail(
"%s: Operation has invalid inputs (Inputs must have same OperandCode)", __func__);
324 return Fail(
"%s: Could not read output 0", __func__);
336 bool isSupported =
false;
341 IsBatchMatMulSupported,
353 validateFunc(outputInfo, isSupported);
368 assert(layer !=
nullptr);
377 VLOG(DRIVER) <<
"Converter::ConvertBatchToSpaceNd()";
381 return Fail(
"%s: Operation has invalid inputs", __func__);
387 return Fail(
"%s: Could not read output 0", __func__);
395 return Fail(
"%s: Could not read input 1", __func__);
399 std::vector<int32_t> block;
402 return Fail(
"%s: Input 1 has invalid values", __func__);
410 Fail(
"%s: Only inputs with rank equal to 4 are supported", __func__);
413 if (std::any_of(block.cbegin(), block.cend(), [](int32_t i){ return i < 1; }))
415 return Fail(
"%s: Block sizes for each spatial dimension of the input tensor must be"
416 " greater than or equal to 1", __func__);
420 batchToSpaceNdDesc.
m_BlockShape.assign(block.cbegin(), block.cend());
423 if (Is12OrLaterOperand(*output))
428 batchToSpaceNdDesc.
m_Crops = {{0, 0}, {0, 0}};
430 bool isSupported =
false;
435 IsBatchToSpaceNdSupported,
446 validateFunc(outputInfo, isSupported);
461 assert(layer !=
nullptr);
469 VLOG(DRIVER) <<
"Converter::ConvertCast()";
475 return Fail(
"%s: Operation has invalid inputs", __func__);
481 return Fail(
"%s: Could not read output 0", __func__);
487 bool isSupported =
false;
502 validateFunc(outputInfo, isSupported);
516 assert(layer !=
nullptr);
522 bool Converter::ConvertComparison(
const Operation& operation,
527 VLOG(DRIVER) <<
"Converter::ConvertComparison()";
535 return Fail(
"%s: Operation has invalid inputs", __func__);
541 return Fail(
"%s: Could not read output 0", __func__);
550 bool isSupported =
false;
555 IsComparisonSupported,
567 validateFunc(outputInfo, isSupported);
581 assert(layer !=
nullptr);
583 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
584 if (!isReshapeSupported)
601 VLOG(DRIVER) <<
"Converter::ConvertConcatenation()";
604 if (operation.inputs.size() <= 1)
606 return Fail(
"%s: Operation has insufficient arguments", __func__);
610 const std::size_t numInputTensors = operation.inputs.size() - 1;
613 if (!
GetInputScalar(operation, numInputTensors, OperandType::INT32, concatDim, model, data))
615 return Fail(
"%s: Operation has invalid inputs", __func__);
621 return Fail(
"%s: Operation has no outputs", __func__);
637 if (concatDim >=
static_cast<int32_t
>(outputShape.
GetNumDimensions()) || concatDim < 0)
639 return Fail(
"%s: Operation has invalid concat axis: %d", __func__, concatDim);
642 std::vector<LayerInputHandle> inputHandles;
643 std::vector<armnn::TensorShape> inputShapes;
645 inputHandles.reserve(numInputTensors);
646 inputShapes.reserve(numInputTensors);
648 bool inputsHaveBeenReshaped =
false;
649 unsigned int tensorDimensionsAdded = 0;
650 for (uint32_t i = 0; i < numInputTensors; ++i)
655 return Fail(
"%s: Operation has invalid inputs", __func__);
659 if (!operandInputHandle.
IsValid())
661 return Fail(
"%s: Operation has invalid inputs", __func__);
667 return Fail(
"%s: Operands with rank 0 are not supported", __func__);
670 if (RequiresReshape(operandShape))
672 inputsHaveBeenReshaped =
true;
680 tensorDimensionsAdded = 1;
685 tensorDimensionsAdded = 2;
691 bool isSupported =
false;
710 operandShape = reshapeInfo.
GetShape();
714 inputShapes.emplace_back(operandShape);
715 inputHandles.emplace_back(operandInputHandle);
717 if (!inputHandles.back().IsValid())
719 return Fail(
"%s: Operation has invalid inputs", __func__);
723 if (inputShapes.size() != inputHandles.size())
725 return Fail(
"%s: invalid model input shapes size doesn't match input handles size: %i != %i", __func__,
726 inputShapes.size(), inputHandles.size());
729 if (inputsHaveBeenReshaped)
732 concatDim += tensorDimensionsAdded;
735 if (tensorDimensionsAdded == 1)
746 else if (tensorDimensionsAdded == 2)
761 std::pair<armnn::PermutationVector, armnn::PermutationVector> permutationPair =
762 std::make_pair(IdentityPermutation4D, IdentityPermutation4D);
763 bool needPermute = CreateConcatPermutationParameters(inputShapes[0].GetNumDimensions(),
768 if (!isDynamicTensor)
779 if (!TransposeInputTensors(data, inputHandles, inputShapes, permutationPair.first))
794 }
catch (std::exception& error)
796 return Fail(
"%s: Error preparing concat descriptor. %s", __func__,
error.what());
801 if (!isDynamicTensor)
803 if (!ValidateConcatOutputShape(inputShapes, outputShape, concatDim))
805 return Fail(
"%s: Error validating the output shape for concat", __func__);
809 std::vector<const armnn::TensorInfo*> inputTensorInfos;
810 std::transform(inputHandles.begin(), inputHandles.end(), std::back_inserter(inputTensorInfos),
813 bool isSupported =
false;
826 if (!isDynamicTensor)
828 validateFunc(outputInfo, isSupported);
842 assert(layer !=
nullptr);
846 assert(
static_cast<std::size_t
>(numInputSlots) == inputHandles.size());
847 for (
int i = 0; i < numInputSlots; ++i)
854 auto transposeOutputShape = [&](){
859 permutationPair.second);
863 IsTransposeSupported,
876 permutationPair.second);
878 layer = &deswizzleLayer;
883 if (needPermute && !isDynamicTensor)
885 transposeOutputShape();
888 if (inputsHaveBeenReshaped)
894 if (!ValidateConcatOutputShape(inputShapes,
898 return Fail(
"%s: Error validating the output shape for concat", __func__);
900 transposeOutputShape();
905 if (tensorDimensionsAdded == 1)
910 else if (tensorDimensionsAdded == 2)
921 auto validateReshapeFunc = [&](
const armnn::TensorInfo& afterConcatInfo,
bool& isSupported){
934 validateReshapeFunc(afterConcatInfo, isSupported);
953 validateReshapeFunc);
961 VLOG(DRIVER) <<
"Converter::ConvertConv2d()";
966 return Fail(
"%s: Operation has invalid inputs", __func__);
972 return Fail(
"%s: Could not read output 0", __func__);
982 bool implicitPadding = operation.inputs.size() == 7
983 || (operation.inputs.size() >= 8
990 else if (operation.inputs.size() >= 10)
1004 return Fail(
"%s: Operation has unsupported weights OperandLifeTime", __func__);
1013 return Fail(
"%s: Operation has invalid inputs", __func__);
1019 return Fail(
"%s: Operation has invalid inputs", __func__);
1026 ActivationFn activation;
1027 if (implicitPadding)
1029 ::android::nn::PaddingScheme paddingScheme;
1036 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1040 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1041 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1042 const uint32_t kernelX = weightsInfo.
GetShape()[widthIndex];
1043 const uint32_t kernelY = weightsInfo.
GetShape()[heightIndex];
1044 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1045 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1051 else if (operation.inputs.size() >= 10)
1063 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1068 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1074 bool requiresValidation =
true;
1083 requiresValidation =
false;
1084 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Weights and Biases are as INPUTS.";
1088 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1090 IsConvolution2dSupported,
1101 if (requiresValidation)
1103 VLOG(DRIVER) <<
"Converter::ConvertConv2d(): Requires Validation!";
1104 bool isSupported =
false;
1107 validateFunc(outputInfo, isSupported);
1125 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
1137 VLOG(DRIVER) <<
"Converter::ConvertDepthToSpace()";
1142 return Fail(
"%s: Operation has invalid inputs", __func__);
1149 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
1155 return Fail(
"%s: Could not read output 0", __func__);
1165 return Fail(
"%s: Block size must be at least 1 in all dimensions", __func__);
1169 if (Is12OrLaterOperand(*output))
1174 bool isSupported =
false;
1179 IsDepthToSpaceSupported,
1190 validateFunc(outputInfo, isSupported);
1204 assert(layer !=
nullptr);
1212 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d()";
1218 return Fail(
"%s: Operation has invalid inputs", __func__);
1225 return Fail(
"%s: Could not read output 0", __func__);
1235 if (!weightsOperand)
1237 return Fail(
"%s: Could not read weights", __func__);
1242 if (weightsOperand->dimensions[0] != 1)
1244 return Fail(
"%s: Filter operand dimension 0 is invalid, should be 1", __func__);
1251 bool implicitPadding = operation.inputs.size() == 8
1252 || (operation.inputs.size() >= 9
1256 const uint32_t dataLayoutFlagIndex = implicitPadding ? 8 : 11;
1260 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
1261 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
1266 return Fail(
"%s: Operation has invalid inputs", __func__);
1272 return Fail(
"%s: Could not read bias", __func__);
1278 return Fail(
"%s: Operation has invalid inputs", __func__);
1285 ActivationFn activation;
1286 if (implicitPadding)
1288 ::android::nn::PaddingScheme paddingScheme;
1295 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
1298 const uint32_t kernelX = weightsInfo.
GetShape()[2];
1299 const uint32_t kernelY = weightsInfo.
GetShape()[1];
1300 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
1301 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
1306 else if (operation.inputs.size() >= 11)
1318 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
1323 return Fail(
"%s: Unsupported number of operation inputs", __func__);
1329 bool requiresValidation =
true;
1335 requiresValidation =
false;
1336 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Weights and Biases are as INPUTS.";
1340 auto validateFunc = [&](
const armnn::TensorInfo& outputInfo,
bool& isSupported) {
1342 IsDepthwiseConvolutionSupported,
1353 if (requiresValidation)
1355 VLOG(DRIVER) <<
"Converter::ConvertDepthwiseConv2d(): Requires Validation!";
1356 bool isSupported =
false;
1359 validateFunc(outputInfo, isSupported);
1377 return Fail(
"%s: AddDepthwiseConvolution2dLayer failed", __func__);
1391 VLOG(DRIVER) <<
"Converter::ConvertDequantize()";
1396 return Fail(
"%s: Operation has invalid input", __func__);
1403 return Fail(
"%s: Operation has quantization dimension different than 0", __func__);
1409 return Fail(
"%s: Operation has invalid outputs", __func__);
1414 bool isSupported =
false;
1419 IsDequantizeSupported,
1433 validateFunc(outputInfo, isSupported);
1443 assert(layer !=
nullptr);
1449 bool Converter::ConvertElementwiseBinary(
const Operation& operation,
1454 VLOG(DRIVER) <<
"Converter::ConvertElementwiseBinary()";
1462 return Fail(
"%s: Operation has invalid inputs", __func__);
1466 ActivationFn activationFunction;
1469 return Fail(
"%s: Operation has invalid optional input: activation function", __func__);
1475 return Fail(
"%s: Could not read output", __func__);
1482 bool isSupported =
false;
1486 IsElementwiseBinarySupported,
1498 validateFunc(outputInfo, isSupported);
1513 return Fail(
"%s: Could not add the ElementwiseBinaryLayer", __func__);
1515 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
1516 if (!isReshapeSupported)
1522 data,
nullptr, validateFunc, activationFunction);
1525 bool Converter::ConvertElementwiseUnary(
const Operation& operation,
1530 VLOG(DRIVER) <<
"Converter::ConvertElementwiseUnary()";
1537 return Fail(
"%s: Operation has invalid input", __func__);
1543 return Fail(
"%s: Could not read output 0", __func__);
1551 bool isSupported =
false;
1556 IsElementwiseUnarySupported,
1567 validateFunc(outputInfo, isSupported);
1581 assert(layer !=
nullptr);
1589 VLOG(DRIVER) <<
"Converter::ConvertElu()";
1594 return Fail(
"%s: Operation has invalid inputs", __func__);
1601 return Fail(
"%s: Operation has invalid inputs", __func__);
1608 if (inputType == OperandType::TENSOR_FLOAT16)
1612 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, alpha, model, data))
1614 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
1617 desc.
m_A =
static_cast<float>(alpha);
1619 else if (inputType == OperandType::TENSOR_FLOAT32)
1623 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
1628 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
1636 VLOG(DRIVER) <<
"Converter::ConvertExpandDims()";
1642 return Fail(
"%s: Operation has invalid input", __func__);
1648 return Fail(
"%s: Operation has invalid output", __func__);
1654 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
1656 return Fail(
"%s: failed to get axis input value", __func__);
1665 catch (
const std::exception& e)
1667 return Fail(
"%s: %s", __func__, e.what());
1673 bool isSupported =
false;
1689 if (targetShape != outputInfo.
GetShape())
1691 return Fail(
"%s: Shape of the output operand does not match the resolved expanded shape", __func__);
1693 validateFunc(outputInfo, isSupported);
1707 assert(layer !=
nullptr);
1715 VLOG(DRIVER) <<
"Converter::ConvertFill()";
1719 return Fail(
"%s: Operation has invalid inputs", __func__);
1725 return Fail(
"%s: Could not read output", __func__);
1732 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
1739 if (outputType == OperandType::TENSOR_FLOAT16)
1743 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
1745 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1748 descriptor.
m_Value =
static_cast<float>(value);
1750 else if (outputType == OperandType::TENSOR_FLOAT32)
1754 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1757 else if (outputType == OperandType::TENSOR_INT32)
1761 if (!
GetInputScalar(operation, 1, OperandType::INT32, value, model, data))
1763 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
1766 descriptor.
m_Value =
static_cast<float>(value);
1770 return Fail(
"%s: Unsupported input tensor type: %d", __func__, outputType);
1773 bool isSupported =
false;
1790 assert(layer !=
nullptr);
1798 VLOG(DRIVER) <<
"Converter::ConvertFloor()";
1802 return Fail(
"%s: Operation has invalid inputs", __func__);
1808 return Fail(
"%s: Operation has invalid outputs", __func__);
1813 bool isSupported =
false;
1828 validateFunc(outputInfo, isSupported);
1842 assert(layer !=
nullptr);
1850 VLOG(DRIVER) <<
"Converter::ConvertFullyConnected()";
1854 return Fail(
"%s: Operation has invalid inputs", __func__);
1860 return Fail(
"%s: Could not read output 0", __func__);
1868 if (!weightsOperand)
1870 return Fail(
"%s: Could not read weights", __func__);
1878 return Fail(
"%s: Operation has invalid inputs", __func__);
1885 return Fail(
"%s: Could not read bias", __func__);
1893 return Fail(
"%s: Operation has invalid inputs", __func__);
1902 catch (
const std::exception& e)
1904 return Fail(
"%s: %s", __func__, e.what());
1909 SanitizeBiasQuantizationScale(biasInfo, weightsInfo, reshapedInfo);
1911 ActivationFn activationFunction;
1914 return Fail(
"%s: Operation has invalid inputs", __func__);
1922 bool isSupported =
false;
1926 if (!VerifyFullyConnectedShapes(reshapedInfo.
GetShape(),
1931 isSupported =
false;
1932 Fail(
"%s: Expected outputShape does not match actual outputShape", __func__);
1937 IsFullyConnectedSupported,
1950 validateFunc(outputInfo, isSupported);
1972 assert(reshapeLayer !=
nullptr);
1987 data,
nullptr, validateFunc, activationFunction);
1992 VLOG(DRIVER) <<
"Converter::ConvertGather()";
1997 return Fail(
"%s: Operation has invalid input", __func__);
2004 return Fail(
"%s: Operation has invalid indices", __func__);
2011 return Fail(
"%s: Operation has invalid output", __func__);
2015 if (outputDimensions != inputDimensions + indicesDimensions - 1)
2017 return Fail(
"%s: Operation has invalid output dimensions: %d. Output must be an (%d + %d - 1)-D tensor",
2018 __func__, outputDimensions, inputDimensions, indicesDimensions);
2022 if (!
GetInputScalar(operation, 1, OperandType::INT32, axis, model, data))
2024 return Fail(
"%s: Operation has invalid or unsupported axis operand", __func__);
2026 int32_t inputDimensions_int =
static_cast<int32_t
>(inputDimensions);
2027 if ((axis < -inputDimensions_int) || (inputDimensions_int <= axis))
2029 return Fail(
"%s: Operation has invalid axis: %d. It is out of bounds [-%d, %d))", __func__, axis,
2030 inputDimensions, inputDimensions);
2036 bool isSupported =
false;
2053 validateFunc(outputInfo, isSupported);
2067 assert(layer !=
nullptr);
2076 VLOG(DRIVER) <<
"Converter::ConvertGroupedConv2d()";
2083 return Fail(
"%s: Operation has invalid inputs", __func__);
2090 return Fail(
"%s: Could not read output 0", __func__);
2096 if (operation.inputs.size() == 12)
2110 const ConstTensorPin weightsPin = (dataLayout == DataLayout::NCHW) ?
2112 model, data, ohwiToOihw) :
2118 return Fail(
"%s: Operation has invalid inputs", __func__);
2123 SanitizeBiasQuantizationScale(biases.
GetInfo(), weights.
GetInfo(), inputInfo);
2131 const unsigned int channelsIndex = dataLayoutIndexed.GetChannelsIndex();
2132 const unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
2133 const unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
2140 ActivationFn activation;
2142 if (operation.inputs.size() == 12)
2150 !
GetInputScalar(operation, 9, OperandType::INT32, numGroups, model, data) ||
2153 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
2157 else if (operation.inputs.size() == 9)
2159 ::android::nn::PaddingScheme paddingScheme;
2163 !
GetInputScalar(operation, 6, OperandType::INT32, numGroups, model, data) ||
2166 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
2169 const uint32_t inputX = inputInfo.
GetShape()[widthIndex];
2170 const uint32_t inputY = inputInfo.
GetShape()[heightIndex];
2172 const uint32_t kernelX = weightsShape[widthIndex];
2173 const uint32_t kernelY = weightsShape[heightIndex];
2180 return Fail(
"%s: Unsupported number of operation inputs", __func__);
2184 const unsigned int outputChannels = weightsShape[0];
2186 const unsigned int channelsPerGroup = weightsShape[channelsIndex];
2187 const unsigned int channelMultiplier = outputChannels / numGroups;
2194 return Fail(
"%s: Number of groups must be greater than 0. Got: %d", __func__, numGroups);
2197 if (outputChannels % numGroups != 0u)
2199 return Fail(
"%s: Output channels must be divisible by the number of groups", __func__);
2205 unsigned int splitterDimSizes[4] = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
2206 splitterDimSizes[channelsIndex] /= numGroups;
2214 std::vector<std::reference_wrapper<TensorInfo>> splitterOutputInfos(numGroups, std::ref(splitterOutputInfo));
2217 for (
unsigned int group = 0u; group < numGroups; ++group)
2219 splitterDesc.SetViewOriginCoord(group, channelsIndex, splitterDimSizes[channelsIndex] * group);
2220 for (
unsigned int dimIdx = 0u; dimIdx < 4u; dimIdx++)
2222 splitterDesc.SetViewSize(group, dimIdx, splitterDimSizes[dimIdx]);
2226 bool isSupported =
false;
2229 IsSplitterSupported,
2234 splitterOutputInfos,
2245 return Fail(
"%s: Failed to add SplitterLayer", __func__);
2249 for (
unsigned int group = 0u; group < splitterLayer->
GetNumOutputSlots(); ++group)
2260 groupInputShape[channelsIndex] = channelsPerGroup;
2263 groupWeightsShape[0] /= channelMultiplier * numGroups;
2269 groupInputInfo.SetShape(groupInputShape);
2273 groupWeightsInfo.SetShape(groupWeightsShape);
2277 groupBiasesInfo.SetShape(groupBiasesShape);
2285 groupOutputShape[channelsIndex] = 1;
2287 groupOutputInfo.SetShape(groupOutputShape);
2289 const unsigned int weightsDataTypeSize =
GetDataTypeSize(groupWeightsInfo.GetDataType());
2290 const unsigned int biasesDataTypeSize =
GetDataTypeSize(groupBiasesInfo.GetDataType());
2292 std::vector<IConnectableLayer*> convLayers(numGroups * channelMultiplier,
nullptr);
2293 for (
unsigned int group = 0u; group < numGroups; ++group)
2295 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2297 auto index = group * channelMultiplier + m;
2299 const unsigned int weightsDataOffset = groupWeightsShape.GetNumElements() * index * weightsDataTypeSize;
2300 const unsigned int biasesDataOffset = groupBiasesShape.GetNumElements() * index * biasesDataTypeSize;
2306 groupWeightsInfo.SetQuantizationScales(
2307 std::vector<float>(weightsQuantScales.begin() + index,
2308 weightsQuantScales.begin() + index + groupWeightsShape[0]));
2312 groupBiasesInfo.SetQuantizationScales(
2313 std::vector<float>(biasesQuantScales.begin() + index,
2314 biasesQuantScales.begin() + index + groupWeightsShape[0]));
2319 static_cast<const void *
>(
reinterpret_cast<const char *
>(weights.
GetMemoryArea()) +
2320 weightsDataOffset));
2322 static_cast<const void *
>(
reinterpret_cast<const char *
>(biases.
GetMemoryArea()) +
2325 isSupported =
false;
2330 IsConvolution2dSupported,
2343 validateFunc(groupOutputInfo, isSupported);
2363 return Fail(
"%s: AddConvolution2dLayer failed", __func__);
2388 convLayers[index] = convLayer;
2398 for (
unsigned int group = 0u; group < numGroups; ++group)
2400 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2402 auto index = group * channelMultiplier + m;
2408 isSupported =
false;
2415 std::vector<const TensorInfo*>(numGroups * channelMultiplier, &groupOutputInfo),
2428 return Fail(
"%s: AddConcatLayer failed", __func__);
2431 for (
unsigned int group = 0u; group < numGroups; ++group)
2433 for (
unsigned int m = 0u; m < channelMultiplier; ++m)
2435 auto index = group * channelMultiplier + m;
2436 convLayers[index]->GetOutputSlot(0).Connect(concatLayer->
GetInputSlot(index));
2442 data,
nullptr,
nullptr, activation);
2447 VLOG(DRIVER) <<
"Converter::ConvertHardSwish()";
2449 desc.
m_Function = ActivationFunction::HardSwish;
2456 VLOG(DRIVER) <<
"Converter::ConvertInstanceNormalization()";
2461 return Fail(
"%s: Operation has an invalid input 0", __func__);
2467 return Fail(
"%s: Operation has an invalid output", __func__);
2476 return Fail(
"%s: Operation has invalid inputs", __func__);
2482 if (inputType == OperandType::TENSOR_FLOAT16)
2488 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Gamma, model, data) ||
2489 !
GetInputScalar(operation, 2, OperandType::FLOAT16, fp16Beta, model, data) ||
2490 !
GetInputScalar(operation, 3, OperandType::FLOAT16, fp16Epsilon, model, data))
2492 return Fail(
"%s: Operation has invalid inputs (FLOAT16)", __func__);
2495 desc.
m_Gamma =
static_cast<float>(fp16Gamma);
2496 desc.
m_Beta =
static_cast<float>(fp16Beta);
2497 desc.
m_Eps =
static_cast<float>(fp16Epsilon);
2499 else if (inputType == OperandType::TENSOR_FLOAT32)
2505 return Fail(
"%s: Operation has invalid inputs (FLOAT32)", __func__);
2510 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2515 bool isSupported =
false;
2520 IsInstanceNormalizationSupported,
2535 validateFunc(outputInfo, isSupported);
2552 VLOG(DRIVER) <<
"Converter::ConvertL2Normalization()";
2554 if (operation.inputs.size() != 1)
2556 return Fail(
"%s: Optional inputs are not supported", __func__);
2562 return Fail(
"%s: Operation has invalid inputs", __func__);
2568 return Fail(
"%s: Could not read output 0", __func__);
2576 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2582 bool isSupported =
false;
2587 IsL2NormalizationSupported,
2598 validateFunc(outputInfo, isSupported);
2612 assert(layer !=
nullptr);
2620 VLOG(DRIVER) <<
"Converter::ConvertL2Pool2d()";
2621 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::L2, model, data);
2624 bool Converter::ConvertLocalResponseNormalization(
const Operation& operation,
2628 VLOG(DRIVER) <<
"Converter::ConvertLocalResponseNormalization()";
2630 if (operation.inputs.size() != 5)
2632 return Fail(
"%s: Optional inputs are not supported", __func__);
2638 return Fail(
"%s: Operation has invalid inputs", __func__);
2644 return Fail(
"%s: Could not read output 0", __func__);
2652 return Fail(
"%s: Tensor Rank other than 4 is not supported", __func__);
2666 return Fail(
"%s: Operation has invalid inputs", __func__);
2673 bool isSupported =
false;
2678 IsNormalizationSupported,
2689 validateFunc(outputInfo, isSupported);
2704 assert(layer !=
nullptr);
2710 bool Converter::ConvertLogicalBinary(
const Operation& operation,
2715 VLOG(DRIVER) <<
"Converter::ConvertLogicalBinary()";
2716 VLOG(DRIVER) <<
"ConvertLogicalBinary()";
2724 return Fail(
"%s: Operation has invalid inputs", __func__);
2730 return Fail(
"%s: Could not read output 0", __func__);
2739 bool isSupported =
false;
2744 IsLogicalBinarySupported,
2756 validateFunc(outputInfo, isSupported);
2770 assert(layer !=
nullptr);
2772 bool isReshapeSupported = BroadcastTensor(input0, input1, layer, data);
2773 if (!isReshapeSupported)
2783 VLOG(DRIVER) <<
"Converter::ConvertLogistic()";
2792 VLOG(DRIVER) <<
"Converter::ConvertLogSoftmax()";
2797 return Fail(
"%s: Failed to read input 0", __func__);
2803 return Fail(
"%s: Failed to read output", __func__);
2812 return Fail(
"%s: Operation has invalid inputs", __func__);
2818 if (inputType == OperandType::TENSOR_FLOAT16)
2821 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, fp16Beta, model, data))
2823 return Fail(
"%s: Failed to read input 1 (FLOAT16)", __func__);
2826 descriptor.
m_Beta =
static_cast<float>(fp16Beta);
2828 else if (inputType == OperandType::TENSOR_FLOAT32)
2832 return Fail(
"%s: Failed to read input 1 (FLOAT32)", __func__);
2837 return Fail(
"%s: Unsupported input tensor type: %d", __func__, inputType);
2843 return Fail(
"%s: Failed to read input 2", __func__);
2846 bool isSupported =
false;
2851 IsLogSoftmaxSupported,
2866 validateFunc(outputInfo, isSupported);
2878 return Fail(
"%s: AddLogSoftmaxLayer() returned nullptr", __func__);
2888 VLOG(DRIVER) <<
"Converter::ConvertLstm()";
2896 return Fail(
"%s: Could not read input 0: input", __func__);
2902 return Fail(
"%s: Could not read input 18: outputStateIn", __func__);
2908 return Fail(
"%s: Could not read input 19: cellStateIn", __func__);
2946 if (!inputToForgetWeightsPin.
IsValid() ||
2947 !inputToCellWeightsPin.
IsValid() ||
2948 !inputToOutputWeightsPin.
IsValid() ||
2949 !recurrentToForgetWeightsPin.
IsValid() ||
2950 !recurrentToCellWeightsPin.
IsValid() ||
2951 !recurrentToOutputWeightsPin.
IsValid() ||
2952 !forgetGateBiasPin.
IsValid() ||
2956 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3002 if ((!inputToInputWeightsPin.
IsValid() && !inputToInputWeightsPin.
IsOptional()) ||
3003 (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional()) ||
3011 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3021 ActivationFn activation = ActivationFn::kActivationNone;
3025 !
GetInputScalar(operation, 21, OperandType::FLOAT32, cellClip, model, data) ||
3026 !
GetInputScalar(operation, 22, OperandType::FLOAT32, projClip, model, data))
3028 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
3076 return Fail(
"%s: Could not read output 0: scratchBuffer", __func__);
3080 if (!outputStateOut)
3082 return Fail(
"%s: Could not read output 1: outputStateOut", __func__);
3088 return Fail(
"%s: Could not read output 2: cellStateOut", __func__);
3095 return Fail(
"%s: Could not read output 3: output", __func__);
3144 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
3145 " and input gate bias must be provided", __func__);
3150 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
3158 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
3159 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
3168 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
3169 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
3234 bool isSupported =
false;
3254 bool isDynamic =
false;
3260 validateFunc(outputInfo, isSupported);
3296 operation, 3, *layer, 3, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
3303 VLOG(DRIVER) <<
"Converter::ConvertMaxPool2d()";
3304 return ConvertPooling2d(operation, __func__, PoolingAlgorithm::Max, model, data);
3309 VLOG(DRIVER) <<
"Converter::ConvertMean()";
3314 return Fail(
"%s: Operation has invalid inputs", __func__);
3320 return Fail(
"%s: Could not read output 0", __func__);
3328 return Fail(
"%s: Could not read input 1", __func__);
3331 std::vector<int32_t> axis;
3334 return Fail(
"%s: Input 1 has invalid values", __func__);
3341 std::set<unsigned int> uniqueAxis;
3342 std::transform(axis.begin(), axis.end(),
3343 std::inserter(uniqueAxis, uniqueAxis.begin()),
3344 [rank](
int i) ->
unsigned int { return (i + rank) % rank; });
3347 int32_t keepDims = 0;
3350 return Fail(
"%s: Could not read input 2", __func__);
3354 descriptor.
m_Axis.assign(uniqueAxis.begin(), uniqueAxis.end());
3357 bool isSupported =
false;
3373 validateFunc(outputInfo, isSupported);
3387 assert(layer !=
nullptr);
3395 VLOG(DRIVER) <<
"Converter::ConvertPad()";
3400 return Fail(
"%s: Operation has invalid inputs", __func__);
3409 return Fail(
"%s: Could not convert paddings", __func__);
3425 return Fail(
"%s: Could not read output", __func__);
3430 bool isSupported =
false;
3446 validateFunc(outputInfo, isSupported);
3460 assert(layer !=
nullptr);
3468 VLOG(DRIVER) <<
"Converter::ConvertPadV2()";
3473 return Fail(
"%s: Could not read input 0", __func__);
3479 return Fail(
"%s: Could not read output", __func__);
3488 return Fail(
"%s: Could not convert paddings", __func__);
3500 return Fail(
"%s: Operation has invalid inputs", __func__);
3504 if (operandType0 == OperandType::TENSOR_FLOAT16 && operandType2 == OperandType::FLOAT16)
3507 if (!
GetInputScalar(operation, 2, operandType2, f16PadValue, model, data))
3509 return Fail(
"%s: Could not read input 2 (FLOAT16)", __func__);
3514 else if (operandType0 == OperandType::TENSOR_FLOAT32 && operandType2 == OperandType::FLOAT32)
3518 return Fail(
"%s: Could not read input 2 (FLOAT32)", __func__);
3523 int32_t intPadValue = 0;
3526 return Fail(
"%s: Could not read input 2 (INT32)", __func__);
3532 return Fail(
"%s: Operation has invalid inputs: type mismatch", __func__);
3535 bool isSupported =
false;
3555 validateFunc(outputInfo, isSupported);
3565 assert(layer !=
nullptr);
3573 VLOG(DRIVER) <<
"Converter::ConvertPrelu()";
3580 return Fail(
"%s: Operation has invalid inputs", __func__);
3587 return Fail(
"%s: Could not read output", __func__);
3594 bool isSupported =
false;
3614 validateFunc(outputInfo, isSupported);
3627 return Fail(
"%s: AddPreluLayer failed", __func__);
3630 bool isReshapeSupported = BroadcastTensor(input, alpha, layer, data);
3631 if (!isReshapeSupported)
3641 VLOG(DRIVER) <<
"Converter::ConvertQuantize()";
3646 return Fail(
"%s: Operation has invalid input", __func__);
3652 return Fail(
"%s: Operation has invalid outputs", __func__);
3657 bool isSupported =
false;
3662 IsQuantizeSupported,
3676 validateFunc(outputInfo, isSupported);
3686 assert(layer !=
nullptr);
3694 VLOG(DRIVER) <<
"Converter::ConvertQuantizedLstm()";
3696 VLOG(DRIVER) <<
"ConvertQuantizedLstm()";
3704 return Fail(
"%s: Could not read input 0: input", __func__);
3709 if (!outputStatePrevTimeStep.
IsValid())
3711 return Fail(
"%s: Could not read input 18: outputStatePrevTimeStep", __func__);
3716 if (!cellStatePrevTimeStep.
IsValid())
3718 return Fail(
"%s: Could not read input 19: cellStatePrevTimeStep", __func__);
3765 if (!inputToForgetWeightsPin.
IsValid() ||
3766 !inputToCellWeightsPin.
IsValid() ||
3767 !inputToOutputWeightsPin.
IsValid() ||
3768 !recurrentToForgetWeightsPin.
IsValid() ||
3769 !recurrentToCellWeightsPin.
IsValid() ||
3770 !recurrentToOutputWeightsPin.
IsValid() ||
3771 !forgetGateBiasPin.
IsValid() ||
3775 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3868 || (!recurrentToInputWeightsPin.
IsValid() && !recurrentToInputWeightsPin.
IsOptional())
3876 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3926 if ((!inputLayerNormWeightsPin.
IsValid() && !inputLayerNormWeightsPin.
IsOptional())
3927 || (!forgetLayerNormWeightsPin.
IsValid() && !forgetLayerNormWeightsPin.
IsOptional())
3928 || (!cellLayerNormWeightsPin.
IsValid() && !cellLayerNormWeightsPin.
IsOptional())
3929 || (!outputLayerNormWeightsPin.
IsValid() && !outputLayerNormWeightsPin.
IsOptional()))
3931 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
3945 float cellClip, projClip, matMulInputGate, matMulForgetGate, matMulCellGate, matMulOutputGate, projInputScale;
3946 int projInputZeroPoint;
3948 if (!
GetInputScalar(operation, 24, OperandType::FLOAT32, cellClip, model, data,
true) ||
3949 !
GetInputScalar(operation, 25, OperandType::FLOAT32, projClip, model, data,
true) ||
3950 !
GetInputScalar(operation, 26, OperandType::FLOAT32, matMulInputGate, model, data) ||
3951 !
GetInputScalar(operation, 27, OperandType::FLOAT32, matMulForgetGate, model, data) ||
3952 !
GetInputScalar(operation, 28, OperandType::FLOAT32, matMulCellGate, model, data) ||
3953 !
GetInputScalar(operation, 29, OperandType::FLOAT32, matMulOutputGate, model, data) ||
3954 !
GetInputScalar(operation, 30, OperandType::INT32, projInputZeroPoint, model, data) ||
3955 !
GetInputScalar(operation, 31, OperandType::FLOAT32, projInputScale, model, data))
3957 return Fail(
"%s: Operation has invalid scalar inputs", __func__);
3964 if (!outputStateOut)
3966 return Fail(
"%s: Could not read output 0: outputStateOut", __func__);
3973 return Fail(
"%s: Could not read output 1: cellStateOut", __func__);
3981 return Fail(
"%s: Could not read output 2: output", __func__);
4035 return Fail(
"%s: All, or none, of input-to-input weights, recurrent-to-input weights,"
4036 " and input gate bias must be provided", __func__);
4041 return Fail(
"%s: projection bias should not be provided without projection weights", __func__);
4049 return Fail(
"%s: All, or none, of cell-to-forget weights and cell-to-output weights must be provided"
4050 " and, if CIFG is not enabled, cell-to-input weights must also be provided", __func__);
4059 return Fail(
"%s: All, or none, of forget-norm weights, cell-norm weights and output-norm weights must be"
4060 " provided and, if CIFG is not enabled, input-norm weights must also be provided", __func__);
4116 const TensorInfo constOutputStateOutInfo(outputStateOutInfo);
4117 const TensorInfo constOutputInfo(outputInfo);
4137 bool isSupported =
false;
4139 auto validateFunc = [&](
const armnn::TensorInfo& cellStateOutInfo,
bool& isSupported)
4147 outputStatePrevTimeStepInfo,
4148 cellStatePrevTimeStepInfo,
4149 constOutputStateOutInfo,
4156 bool isDynamic =
false;
4161 validateFunc(outputInfo, isSupported);
4185 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4192 operation, 0, *layer, 0, model, data, &constOutputStateOutInfo) &&
4194 operation, 1, *layer, 1, model, data,
nullptr, validateFunc,
4195 ActivationFn::kActivationNone,
true) &&
4202 VLOG(DRIVER) <<
"Converter::ConvertQuantized16BitLstm()";
4203 VLOG(DRIVER) <<
"Policy::ConvertQuantized16BitLstm()";
4211 return Fail(
"%s: Could not read input 0: input", __func__);
4218 if (!previousCellStateIn.
IsValid())
4220 return Fail(
"%s: Could not read input 13: previousCellStateIn", __func__);
4227 if (!previousOutputIn.
IsValid())
4229 return Fail(
"%s: Could not read input 14: previousOutputIn", __func__);
4305 if (!inputToInputWeightsPin.
IsValid() ||
4306 !inputToForgetWeightsPin.
IsValid() ||
4307 !inputToCellWeightsPin.
IsValid() ||
4308 !inputToOutputWeightsPin.
IsValid() ||
4309 !recurrentToInputWeightsPin.
IsValid() ||
4310 !recurrentToForgetWeightsPin.
IsValid() ||
4311 !recurrentToCellWeightsPin.
IsValid() ||
4312 !recurrentToOutputWeightsPin.
IsValid() ||
4313 !inputGateBiasPin.
IsValid() ||
4314 !forgetGateBiasPin.
IsValid() ||
4318 return Fail(
"%s: Operation has invalid tensor inputs", __func__);
4328 return Fail(
"%s: Could not read output 0: cellStateOut", __func__);
4336 return Fail(
"%s: Could not read output 1: output", __func__);
4351 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4383 bool isSupported =
false;
4388 IsQuantizedLstmSupported,
4393 previousCellStateInInfo,
4394 previousOutputInInfo,
4400 bool isDynamic =
false;
4404 validateFunc(outputInfo, isSupported);
4432 operation, 1, *layer, 1, model, data,
nullptr, validateFunc, ActivationFn::kActivationNone,
true));
4439 VLOG(DRIVER) <<
"Converter::ConvertRank()";
4444 if (inputOperand ==
nullptr || outputOperand ==
nullptr)
4446 return Fail(
"%s: Operation has invalid inputs", __func__);
4449 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4450 const Shape outputOperandShape = GetOperandShape(*outputOperand);
4455 return Fail(
"%s: Could not read input 0", __func__);
4461 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
4464 bool isSupported =
false;
4480 assert(layer !=
nullptr);
4488 VLOG(DRIVER) <<
"Converter::ConvertReLu()";
4496 return Fail(
"%s: Input 0 is invalid",
"operationName", __func__);
4507 bool isSupported =
false;
4512 IsActivationSupported,
4527 validateFunc(outInfo, isSupported);
4545 VLOG(DRIVER) <<
"Converter::ConvertReLu1()";
4556 VLOG(DRIVER) <<
"Converter::ConvertReLu6()";
4566 VLOG(DRIVER) <<
"Converter::ConvertReshape()";
4572 if (inputOperand ==
nullptr
4573 || requestedShapeOperand ==
nullptr
4574 || outputOperand ==
nullptr)
4576 return Fail(
"%s: Operation has invalid inputs", __func__);
4579 if (requestedShapeOperand->dimensions.size() != 1)
4581 return Fail(
"%s: Input 1 expected to be one-dimensional (found %i dimensions)",
4582 __func__, requestedShapeOperand->dimensions.size());
4585 std::vector<int32_t> targetDimensions;
4588 return Fail(
"%s: Could not read values of input 1", __func__);
4591 const Shape inputOperandShape = GetOperandShape(*inputOperand);
4593 Shape requestedShape;
4596 if (!reshapePrepare(inputOperandShape, targetDimensions.data(), targetDimensions.size(), &requestedShape))
4598 return Fail(
"%s: Failed to resolve the requested shape", __func__);
4604 return Fail(
"%s: Could not read input 0", __func__);
4609 requestedShape.dimensions.data());
4613 bool isSupported =
false;
4629 validateFunc(outputInfo, isSupported);
4643 assert(layer !=
nullptr);
4649 bool Converter::ConvertResize(
const Operation& operation,
4654 VLOG(DRIVER) <<
"Converter::ConvertResize()";
4660 return Fail(
"%s: Could not read input 0", __func__);
4666 return Fail(
"%s: Could not read output 0", __func__);
4673 descriptor.
m_Method = resizeMethod;
4682 return Fail(
"%s: Operation has invalid inputs", __func__);
4685 if (operandType1 != operandType2)
4687 return Fail(
"%s: Operation has invalid inputs. Type of input 1 and 2 should be the same", __func__);
4690 if (operandType1 == OperandType::INT32)
4693 int32_t targetWidth = 0;
4694 int32_t targetHeight = 0;
4696 if (!
GetInputInt32(operation, 1, targetWidth, model, data) ||
4699 return Fail(
"%s: Operation has invalid inputs for resizing by shape", __func__);
4702 if (targetWidth < 0 || targetHeight < 0)
4704 return Fail(
"%s: Operation has invalid inputs for resizing by shape. "
4705 "Target width/height cannot be < 0", __func__);
4708 descriptor.
m_TargetWidth =
static_cast<uint32_t
>(targetWidth);
4711 else if (operandType1 == OperandType::FLOAT32)
4714 float widthScale = 1.0f;
4715 float heightScale = 1.0f;
4720 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
4726 float width = inputShape[dataLayoutIndexed.GetWidthIndex()];
4727 float height = inputShape[dataLayoutIndexed.GetHeightIndex()];
4732 else if (operandType1 == OperandType::FLOAT16)
4737 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, widthScale, model, data) ||
4738 !
GetInputScalar(operation, 2, OperandType::FLOAT16, heightScale, model, data))
4740 return Fail(
"%s: Operation has invalid inputs for resizing by scale", __func__);
4746 Half width =
static_cast<Half>(inputShape[dataLayoutIndexed.GetWidthIndex()]);
4747 Half height =
static_cast<Half>(inputShape[dataLayoutIndexed.GetHeightIndex()]);
4754 return Fail(
"%s: Operand has invalid data type for resizing by scale", __func__);
4760 bool isSupported =
false;
4780 validateFunc(outputInfo, isSupported);
4790 assert(layer !=
nullptr);
4798 VLOG(DRIVER) <<
"Converter::ConvertReverseV2()";
4804 return Fail(
"%s: Operation has invalid inputs", __func__);
4812 return Fail(
"%s: Could not read output 0", __func__);
4816 bool isSupported =
false;
4821 IsReverseV2Supported,
4832 validateFunc(outputInfo, isSupported);
4846 assert(layer !=
nullptr);
4855 VLOG(DRIVER) <<
"Converter::ConvertSpaceToBatchNd()";
4860 return Fail(
"%s: Operation has invalid inputs", __func__);
4865 unsigned int spatialDim = rank - 2;
4869 Fail(
"%s: Only inputs with rank 4 are supported", __func__);
4875 return Fail(
"%s: Could not read output 0", __func__);
4883 armnn::TensorShape blockShapeOperandShape = GetTensorShapeForOperand(*blockShapeOperand);
4886 return Fail(
"%s: Operation has invalid block shape operand: expected shape [%d]", __func__, spatialDim);
4889 std::vector<int32_t> blockShape;
4892 return Fail(
"%s: Operation has an invalid or unsupported block size operand", __func__);
4894 if(std::any_of(blockShape.cbegin(), blockShape.cend(), [](int32_t i)
4897 return Fail(
"%s: Block shape must be at least 1 in all dimensions.", __func__);
4900 armnn::TensorShape paddingsOperandShape = GetTensorShapeForOperand(*paddingsOperand);
4903 return Fail(
"%s: Operation has invalid paddings operand: expected shape [%d, 2]", __func__, spatialDim);
4906 std::vector<std::pair<unsigned int, unsigned int>> paddingList;
4907 std::vector<int32_t> paddings;
4910 return Fail(
"%s: Operation has an invalid or unsupported paddings operand", __func__);
4912 for (
unsigned int i = 0; i < paddings.size() - 1; i += 2)
4914 int paddingBeforeInput = paddings[i];
4915 int paddingAfterInput = paddings[i + 1];
4916 if(paddingBeforeInput < 0 || paddingAfterInput < 0)
4918 return Fail(
"%s: Operation has invalid paddings operand, invalid padding values.", __func__);
4921 paddingList.emplace_back((
unsigned int) paddingBeforeInput, (
unsigned int) paddingAfterInput);
4926 descriptor.
m_BlockShape.assign(blockShape.cbegin(), blockShape.cend());
4927 descriptor.
m_PadList.assign(paddingList.cbegin(), paddingList.cend());
4929 if(Is12OrLaterOperand(*output))
4934 bool isSupported =
false;
4939 IsSpaceToBatchNdSupported,
4953 validateFunc(outputInfo, isSupported);
4963 assert(layer !=
nullptr);
4971 VLOG(DRIVER) <<
"Converter::ConvertSpaceToDepth()";
4976 return Fail(
"%s: Operation has invalid inputs", __func__);
4983 return Fail(
"%s: Only inputs with rank 4 are supported", __func__);
4989 return Fail(
"%s: Could not read output 0", __func__);
5000 return Fail(
"%s: Block size must be at least 1 in all dimensions", __func__);
5005 bool isSupported =
false;
5010 IsSpaceToDepthSupported,
5025 validateFunc(outputInfo, isSupported);
5035 assert(layer !=
nullptr);
5043 VLOG(DRIVER) <<
"Converter::ConvertSoftmax()";
5048 return Fail(
"%s: Operation has invalid inputs", __func__);
5054 return Fail(
"%s: Operation has no outputs", __func__);
5063 if (outputType == OperandType::TENSOR_FLOAT16)
5067 if (!
GetInputScalar(operation, 1, OperandType::FLOAT16, value, model, data))
5069 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5072 desc.
m_Beta =
static_cast<float>(value);
5078 return Fail(
"%s: Operation has invalid inputs %d", __func__, outputType);
5089 return Fail(
"%s: Operation has invalid inputs", __func__);
5092 bool isSupported =
false;
5112 validateFunc(outputInfo, isSupported);
5122 assert(layer !=
nullptr);
5130 VLOG(DRIVER) <<
"Converter::ConvertTanH()";
5142 VLOG(DRIVER) <<
"Converter::ConvertTile()";
5147 return Fail(
"%s: Operation has invalid inputs", __func__);
5154 return Fail(
"%s: Operation has no outputs", __func__);
5159 if (!multiplesOperand)
5161 return Fail(
"%s: Could not read input 1", __func__);
5163 std::vector<int32_t> multiples;
5166 return Fail(
"%s: Input 1 has invalid values", __func__);
5170 descriptor.
m_Multiples.assign(multiples.begin(), multiples.end());
5172 bool isSupported =
false;
5192 validateFunc(outputInfo, isSupported);
5202 assert(layer !=
nullptr);
5210 VLOG(DRIVER) <<
"Converter::ConvertTransposeConv2d()";
5216 return Fail(
"%s: Operation has invalid inputs", __func__);
5223 return Fail(
"%s: Could not read output 0", __func__);
5233 if (weightsOperand ==
nullptr)
5235 return Fail(
"%s: Operand is invalid", __func__);
5241 bool implicitPadding = operation.inputs.size() == 9;
5243 if (implicitPadding )
5253 unsigned int widthIndex = dataLayoutIndexed.GetWidthIndex();
5254 unsigned int heightIndex = dataLayoutIndexed.GetHeightIndex();
5262 model, data, OHWIToOIHW) :
5271 return Fail(
"%s: Operation has invalid weights", __func__);
5276 return Fail(
"%s: Operation has invalid biases", __func__);
5281 SanitizeBiasQuantizationScale(bias.
GetInfo(), weights.
GetInfo(), inputInfo);
5283 ActivationFn activation;
5285 if (implicitPadding)
5290 int32_t padRight{0};
5292 int32_t padBottom{0};
5294 ::android::nn::PaddingScheme paddingScheme;
5296 !
GetInputScalar(operation, 5, OperandType::INT32, strideX, model, data) ||
5297 !
GetInputScalar(operation, 6, OperandType::INT32, strideY, model, data) ||
5300 return Fail(
"%s: Operation has invalid inputs (implicit padding)", __func__);
5303 const uint32_t kernelX = weights.
GetShape()[widthIndex];
5304 const uint32_t kernelY = weights.
GetShape()[heightIndex];
5308 std::vector<int32_t> outputShape;
5309 if ((outputShapeOperand) && (
GetTensorInt32Values(*outputShapeOperand, outputShape, model, data)))
5312 for (
int dimension : outputShape)
5314 desc.
m_OutputShape.push_back(
static_cast<unsigned int>(dimension));
5324 if (outputShape.size() == 0)
5326 return Fail(
"%s: Padding sizes cannot be inferred", __func__);
5329 outputX = outputShape[widthIndex];
5330 outputY = outputShape[heightIndex];
5334 outputX = outputInfo.
GetShape()[widthIndex];
5335 outputY = outputInfo.
GetShape()[heightIndex];
5338 CalcPaddingTransposeConv(outputX, kernelX, strideX, padLeft, padRight, paddingScheme);
5339 CalcPaddingTransposeConv(outputY, kernelY, strideY, padTop, padBottom, paddingScheme);
5343 if (padLeft < 0 || padRight < 0 || padTop < 0 || padBottom < 0)
5345 return Fail(
"%s: Negative padding values are not supported", __func__);
5348 desc.
m_StrideX = armnn::numeric_cast<uint32_t>(strideX);
5349 desc.
m_StrideY = armnn::numeric_cast<uint32_t>(strideY);
5350 desc.
m_PadLeft = armnn::numeric_cast<uint32_t>(padLeft);
5351 desc.
m_PadRight = armnn::numeric_cast<uint32_t>(padRight);
5352 desc.
m_PadTop = armnn::numeric_cast<uint32_t>(padTop);
5353 desc.
m_PadBottom = armnn::numeric_cast<uint32_t>(padBottom);
5355 else if (operation.inputs.size() == 11)
5366 return Fail(
"%s: Operation has invalid inputs (explicit padding)", __func__);
5371 return Fail(
"%s: Unsupported number of operation inputs", __func__);
5377 bool isSupported =
false;
5382 IsTransposeConvolution2dSupported,
5399 validateFunc(outputInfo, isSupported);
5411 return Fail(
"%s: AddTransposeConvolution2dLayer failed", __func__);
5417 data,
nullptr, validateFunc, activation);
5422 VLOG(DRIVER) <<
"Converter::ConvertSqrt()";
5431 VLOG(DRIVER) <<
"Converter::ConvertSqueeze()";
5436 return Fail(
"%s: Operation has invalid inputs", __func__);
5443 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5449 return Fail(
"%s: Could not read output 0", __func__);
5454 return Fail(
"%s: Dynamic output tensors are not supported", __func__);
5461 const uint32_t dimensionSequence[] = { 0, 1, 2, 3 };
5463 std::vector<int32_t> axis;
5466 axis.assign(dimensionSequence,
5467 dimensionSequence + rank);
5471 return Fail(
"%s: Operation has an invalid or unsupported axis operand", __func__);
5474 std::vector<uint32_t> outputDims;
5475 for (
unsigned int i = 0; i < rank; i++)
5477 bool skipSqueeze = (std::find(axis.begin(), axis.end(), i) == axis.end());
5478 auto currentDimension = inputInfo.
GetShape()[i];
5479 if (skipSqueeze || currentDimension != 1)
5481 outputDims.push_back(currentDimension);
5493 bool isSupported =
false;
5511 assert(layer !=
nullptr);
5519 VLOG(DRIVER) <<
"Converter::ConvertStridedSlice()";
5524 return Fail(
"%s: Operation has invalid inputs", __func__);
5531 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5537 return Fail(
"%s: Could not read output 0", __func__);
5546 std::vector<int32_t> beginValues;
5547 std::vector<int32_t> endValues;
5548 std::vector<int32_t> stridesValues;
5551 auto ValidateInputOperands = [&] (
const Operand& operand, std::vector<int32_t>& operandValues)
5558 if (operandValues.size() != rank)
5566 if (!ValidateInputOperands(*beginOperand, beginValues)
5567 || !ValidateInputOperands(*endOperand, endValues)
5568 || !ValidateInputOperands(*stridesOperand, stridesValues))
5570 return Fail(
"%s: Operation has invalid input operand", __func__);
5574 if (std::any_of(stridesValues.cbegin(), stridesValues.cend(), [](int32_t i){ return i == 0; }))
5576 return Fail(
"%s: Stride must be non-zero value.", __func__);
5580 descriptor.
m_Begin.assign(beginValues.cbegin(), beginValues.cend());
5581 descriptor.
m_End.assign(endValues.cbegin(), endValues.cend());
5582 descriptor.
m_Stride.assign(stridesValues.cbegin(), stridesValues.cend());
5590 return Fail(
"%s: Operation has invalid inputs", __func__);
5593 bool isSupported =
false;
5598 IsStridedSliceSupported,
5613 validateFunc(outputInfo, isSupported);
5625 int stride = descriptor.
m_Stride[i];
5631 if (((descriptor.
m_Begin[i] - descriptor.
m_End[i]) > 1)
5632 || ((descriptor.
m_Begin[i] - descriptor.
m_End[i]) < -1))
5634 return Fail(
"%s: StridedSlice: Output will not be large enough to hold the slice", __func__);
5639 return Fail(
"%s: StridedSlice: Stride can not be negative while ShrinkAxisMask is set.", __func__);
5646 assert(layer !=
nullptr);
5654 VLOG(DRIVER) <<
"Converter::ConvertTranspose()";
5659 return Fail(
"%s: Operation has invalid inputs", __func__);
5666 Fail(
"%s: Inputs with rank greater than 4 are not supported", __func__);
5673 std::vector<int32_t> perm(rank);
5674 if (!permOperand || (permOperand->lifetime == OperandLifeTime::NO_VALUE))
5676 for (
unsigned int i = rank; i > 0; i--)
5678 perm[rank - i] = armnn::numeric_cast<int> (i - 1);
5683 return Fail(
"%s: Operation has an invalid or unsupported permutation operand", __func__);
5686 std::vector<uint32_t> outputDims(perm.begin(), perm.begin() + rank);
5694 return Fail(
"%s: Could not read output 0", __func__);
5699 bool isSupported =
false;
5704 IsTransposeSupported,
5719 validateFunc(outputInfo, isSupported);
5729 assert(layer !=
nullptr);