18 const std::vector<const TensorInfo*>& inputs,
19 const std::vector<const TensorInfo*>& outputs,
25 throw armnn::Exception(
"ConvertReduceOperator: Must provide a valid input tensor.");
28 if (inputs[0]->IsQuantized() ^ outputs[0]->IsQuantized())
31 "Both input and output tensors must be either quantised or non-quantised data types.");
34 if (reduceDescriptor->
m_vAxis.empty())
36 throw armnn::Exception(
"ConvertReduceOperator: Reduce Operation with empty axis not implemented.");
40 std::string inputName =
"input_";
42 std::size_t intermediateCounter = 0;
44 std::string outputName =
"output0_";
58 std::vector<TosaSerializationTensor*> tensors;
59 std::vector<std::string> inputNames{inputName};
61 DType inputType =
ArmNNToDType(inputs[0]->GetDataType());
63 if (inputName.substr(0, 6) ==
"input_")
65 tensors.emplace_back(
new TosaSerializationTensor(inputName,
72 int64_t output_zp = 0;
74 double input_scale = 1.0;
75 double output_scale = 1.0;
77 int32_t input_multiplier = 1;
78 int32_t output_multiplier = 1;
80 int32_t input_shift = 0;
81 int32_t output_shift = 0;
83 int64_t numElemsOnReducedAxis = 1;
85 std::vector<int32_t> axes(reduceDescriptor->
m_vAxis.begin(), reduceDescriptor->
m_vAxis.end());
87 for (int64_t axis : axes)
89 numElemsOnReducedAxis *= inputShape[
static_cast<uint64_t
>(axis)];
92 std::vector<TosaSerializationOperator*> operators;
94 bool inputQuantised = inputs[0]->IsQuantized();
99 input_zp = inputs[0]->GetQuantizationOffset();
100 output_zp = outputs[0]->GetQuantizationOffset();
102 std::string outputNameRescale =
105 TosaSerializationOperator* rescaleOp1 =
nullptr;
109 case ReduceOperation::Sum:
112 input_scale =
static_cast<double>(1 << input_shift) * inputs[0]->GetQuantizationScale();
113 output_scale = 1.0 / (outputs[0]->GetQuantizationScale() *
static_cast<double>(1 << input_shift));
118 static_cast<int32_t
>(input_zp),
119 static_cast<int32_t
>(output_zp),
125 case ReduceOperation::Mean:
131 static_cast<double>(inputs[0]->GetQuantizationScale()) /
132 static_cast<double>(outputs[0]->GetQuantizationScale()),
137 int shift = 63 - __builtin_clzl(
static_cast<uint64_t
>(numElemsOnReducedAxis));
138 shift = std::min(shift, 32);
139 shift = std::min(shift, 62 - output_shift);
141 output_multiplier =
static_cast<int32_t
>(
142 (
static_cast<int64_t
>(output_multiplier) << shift) / numElemsOnReducedAxis);
144 output_shift += shift;
150 static_cast<int32_t
>(input_zp),
151 static_cast<int32_t
>(output_zp),
159 throw armnn::Exception(
"ConvertReduceOperator: Reduce Operation not implemented.");
162 operators.emplace_back(rescaleOp1);
164 tensors.emplace_back(
new TosaSerializationTensor(outputNameRescale,
171 for (
const auto axis : axes)
173 auto rank =
static_cast<int64_t
>(inputs[0]->GetNumDimensions());
175 if (axis < 0 || axis >= rank)
180 TosaAxisAttribute reduceAttribute(axis);
182 std::string outputNameReduce =
187 case ReduceOperation::Sum:
188 case ReduceOperation::Mean:
189 operators.emplace_back(
new TosaSerializationOperator(Op_REDUCE_SUM,
190 Attribute_AxisAttribute,
192 { tensors.back()->GetName() },
193 { outputNameReduce }));
196 throw armnn::Exception(
"ConvertReduceOperator: Reduce Operation not implemented.");
199 std::vector<int32_t> outputShapeReduce = tensors.back()->GetShape();
200 outputShapeReduce[
static_cast<std::size_t
>(axis)] = 1;
202 tensors.emplace_back(
new TosaSerializationTensor(outputNameReduce,
204 tensors.back()->GetDtype(),
211 std::string outputNameRescale =
214 TosaSerializationOperator* rescaleOp2 =
nullptr;
218 case ReduceOperation::Sum:
222 static_cast<int32_t
>(output_zp),
223 static_cast<int32_t
>(input_zp),
228 case ReduceOperation::Mean:
233 static_cast<int32_t
>(output_zp),
234 static_cast<int32_t
>(input_zp),
241 throw armnn::Exception(
"ConvertReduceOperator: Reduce Operation not implemented.");
244 operators.push_back(rescaleOp2);
246 tensors.emplace_back(
new TosaSerializationTensor(outputNameRescale,
247 tensors.back()->GetShape(),
255 std::string outputNameReshape = !inputQuantised && reduceDescriptor->
m_ReduceOperation == ReduceOperation::Mean
259 operators.emplace_back(
new TosaSerializationOperator(Op_RESHAPE,
260 Attribute_ReshapeAttribute,
262 { tensors.back()->GetName() },
263 { outputNameReshape }));
265 tensors.emplace_back(
new TosaSerializationTensor(outputNameReshape,
272 if (!inputQuantised && reduceDescriptor->
m_ReduceOperation == ReduceOperation::Mean)
276 inputNames.emplace_back(constNameDivScale);
278 operators.push_back(
new TosaSerializationOperator(Op_CONST,
282 { constNameDivScale }));
284 float divScale = 1.0f /
static_cast<float>(numElemsOnReducedAxis);
286 std::vector<uint8_t> uint8DivScale;
290 TosaSerializationHandler::ConvertF32toU8({divScale}, uint8DivScale);
293 TosaSerializationHandler::ConvertF16toU8({divScale}, uint8DivScale);
300 std::vector<int32_t> divConstantShape(outputShape.size(), 1);
302 tensors.push_back(
new TosaSerializationTensor(constNameDivScale,
308 TosaMulAttribute mulAttribute(0);
310 operators.emplace_back(
new TosaSerializationOperator(Op_MUL,
311 Attribute_MulAttribute,
313 { constNameDivScale, outputNameReshape },
316 tensors.push_back(
new TosaSerializationTensor(outputName,
322 return new TosaSerializationBasicBlock(blockName,