11 const std::vector<const TensorInfo*>& inputs,
12 const std::vector<const TensorInfo*>& outputs,
15 std::string input0Name = std::string(
"input_0");
16 std::string input1Name = std::string(
"input_1");
17 std::string outputName = std::string(
"output0_");
20 std::string blockName;
31 TosaSerializationOperator* op =
nullptr;
33 std::vector<TosaSerializationTensor*> tensors;
34 std::vector<TosaSerializationOperator*> operators;
35 DType inputDType0 =
ArmNNToDType(inputs[0]->GetDataType());
36 DType inputDType1 =
ArmNNToDType(inputs[1]->GetDataType());
37 DType outputDType0 =
ArmNNToDType(outputs[0]->GetDataType());
38 bool isInputInt8 = (inputDType0 == DType_INT8);
43 if(input0Name.find(
"input_") != std::string::npos)
46 tensors.push_back(
new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {}));
48 if(input1Name.find(
"input_") != std::string::npos)
51 tensors.push_back(
new TosaSerializationTensor(input1Name, inputShape1, inputDType1, {}));
58 std::string outputElemenwiseBinaryName;
62 tensors.push_back(
new TosaSerializationTensor(outputElemenwiseBinaryName, outputShape0, DType_INT32, {}));
66 tensors.push_back(
new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
71 bool isMulDesc = descriptor ? descriptor->
m_Operation == BinaryOperation::Mul :
false;
72 bool isMulOp = (type == LayerType::Multiplication) || isMulDesc ?
true :
false;
73 if (isInputInt8 && !isMulOp)
75 TosaSerializationOperator* rescaleOp0 =
nullptr;
77 input0ElemenwiseBinaryName,
78 inputs[0]->GetQuantizationScale() / outputs[0]->GetQuantizationScale(),
79 inputs[0]->GetQuantizationOffset(),
86 tensors.push_back(
new TosaSerializationTensor(input0ElemenwiseBinaryName,
90 operators.push_back(rescaleOp0);
92 TosaSerializationOperator* rescaleOp1 =
nullptr;
94 input1ElemenwiseBinaryName,
95 inputs[1]->GetQuantizationScale() / outputs[0]->GetQuantizationScale(),
96 inputs[1]->GetQuantizationOffset(),
103 tensors.push_back(
new TosaSerializationTensor(input1ElemenwiseBinaryName,
107 operators.push_back(rescaleOp1);
110 std::string& elementwiseInput0Str = isInputInt8 ? input0ElemenwiseBinaryName : input0Name;
111 std::string& elementwiseInput1Str = isInputInt8 ? input1ElemenwiseBinaryName : input1Name;
112 std::string& elementwiseOutputStr = isInputInt8 ? outputElemenwiseBinaryName : outputName;
116 case LayerType::Addition:
118 op =
new TosaSerializationOperator(Op_ADD,
121 {input0Name, input1Name},
126 case LayerType::ElementwiseBinary:
130 case BinaryOperation::Add:
132 op =
new TosaSerializationOperator(Op_ADD,
135 {elementwiseInput0Str, elementwiseInput1Str},
136 {elementwiseOutputStr});
140 case BinaryOperation::Maximum:
142 op =
new TosaSerializationOperator(Op_MAXIMUM,
145 {elementwiseInput0Str, elementwiseInput1Str},
146 {elementwiseOutputStr});
150 case BinaryOperation::Mul:
153 TosaMulAttribute mulAttribute(shift);
157 op =
new TosaSerializationOperator(Op_MUL,
158 Attribute_MulAttribute,
160 {input0Name, input1Name},
161 {elementwiseOutputStr});
165 case BinaryOperation::Sub:
167 op =
new TosaSerializationOperator(Op_SUB,
170 {elementwiseInput0Str, elementwiseInput1Str},
171 {elementwiseOutputStr});
175 case BinaryOperation::SqDiff:
177 throw Exception(
"TOSA mappings of Squared Difference operator "
178 "implemented under ConvertSquaredDifferenceToTosaOperator().");
181 throw Exception(
"ConvertElementwiseBinaryToTosaOperator: Unsupported layer type.");
185 case LayerType::Multiplication:
188 TosaMulAttribute mulAttribute(shift);
189 op =
new TosaSerializationOperator(Op_MUL,
190 Attribute_MulAttribute,
192 {input0Name, input1Name},
197 case LayerType::Subtraction:
199 op =
new TosaSerializationOperator(Op_SUB,
202 {input0Name, input1Name},
208 throw Exception(
"ConvertElementwiseBinaryToTosaOperator: Unsupported layer type.");
211 operators.push_back(op);
215 if (inputDType0 == DType_INT8)
218 float input0QScale = inputs[0]->IsQuantized()?inputs[0]->GetQuantizationScale():1.0f;
219 float input1QScale = inputs[1]->IsQuantized()?inputs[1]->GetQuantizationScale():1.0f;
220 float outputQScale = outputs[0]->IsQuantized()?outputs[0]->GetQuantizationScale():1.0f;
221 double combinedQScale = input0QScale * input1QScale / outputQScale;
223 TosaSerializationOperator* rescaleOp =
nullptr;
228 outputs[0]->GetQuantizationOffset(),
234 tensors.push_back(
new TosaSerializationTensor(outputName,
238 operators.push_back(rescaleOp);
241 return new TosaSerializationBasicBlock(blockName,
245 {input0Name, input1Name},
251 const std::vector<const TensorInfo*>& inputs,
252 const std::vector<const TensorInfo*>& outputs,
255 if (descriptor->
m_Operation != BinaryOperation::SqDiff)
257 throw Exception(
"ElementwiseBinaryDescriptor operation must be SqDiff"
258 "in ConvertSquaredDifferenceToTosaOperator().");
261 std::string input0Name = std::string(
"input_0");
262 std::string input1Name = std::string(
"input_1");
263 std::string outputName = std::string(
"output0_");
269 if (layer !=
nullptr)
282 std::vector<TosaSerializationTensor*> tensors {};
283 std::vector<TosaSerializationOperator*> operators {};
284 DType inputDType0 =
ArmNNToDType(inputs[0]->GetDataType());
285 DType inputDType1 =
ArmNNToDType(inputs[1]->GetDataType());
286 DType outputDType0 =
ArmNNToDType(outputs[0]->GetDataType());
287 bool isInputInt8 = (inputDType0 == DType_INT8);
292 if(input0Name.find(
"input_") != std::string::npos)
295 tensors.push_back(
new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {}));
297 if(input1Name.find(
"input_") != std::string::npos)
300 tensors.push_back(
new TosaSerializationTensor(input1Name, inputShape1, inputDType1, {}));
305 if (inputDType0 == DType_FP32 ||
306 inputDType0 == DType_FP16 ||
307 inputDType0 == DType_INT32)
309 operators.push_back(
new TosaSerializationOperator(
313 {input0Name, input1Name},
314 {interElemenwiseBinaryName}));
315 tensors.push_back(
new TosaSerializationTensor(interElemenwiseBinaryName,
321 TosaMulAttribute mulAttribute(shift);
323 operators.push_back(
new TosaSerializationOperator(
325 Attribute_MulAttribute,
327 {interElemenwiseBinaryName, interElemenwiseBinaryName},
330 else if (isInputInt8)
341 double in_x_scale = inputs[0]->GetQuantizationScale();
342 double in_y_scale = inputs[1]->GetQuantizationScale();
343 double result_scale = outputs[0]->GetQuantizationScale();
344 double twice_max_input_scale = 2.0 * std::max(in_x_scale, in_y_scale);
345 const int32_t LEFT_SHIFT = 7;
346 double x_rescale_scale = in_x_scale / twice_max_input_scale;
347 double y_rescale_scale = in_y_scale / twice_max_input_scale;
348 double output_rescale_scale =
349 (twice_max_input_scale * twice_max_input_scale) /
350 ((
static_cast<double>(1 << LEFT_SHIFT * 2)) * result_scale);
352 TosaSerializationOperator* xShiftOp =
nullptr;
356 inputs[0]->GetQuantizationOffset(),
363 operators.push_back(xShiftOp);
364 tensors.push_back(
new TosaSerializationTensor(rescale0Output0Name,
369 TosaSerializationOperator* yShiftOp =
nullptr;
373 inputs[1]->GetQuantizationOffset(),
380 operators.push_back(yShiftOp);
381 tensors.push_back(
new TosaSerializationTensor(rescale0Output1Name,
386 TosaSerializationOperator* xScaledOp =
nullptr;
397 operators.push_back(xScaledOp);
398 tensors.push_back(
new TosaSerializationTensor(rescale1Output0Name,
403 TosaSerializationOperator* yScaledOp =
nullptr;
414 operators.push_back(yScaledOp);
415 tensors.push_back(
new TosaSerializationTensor(rescale1Output1Name,
422 operators.push_back(
new TosaSerializationOperator(
426 {rescale1Output0Name, rescale1Output1Name},
427 {interElemenwiseBinaryName}));
428 tensors.push_back(
new TosaSerializationTensor(interElemenwiseBinaryName,
433 TosaMulAttribute mulAttribute(shift);
435 operators.push_back(
new TosaSerializationOperator(
437 Attribute_MulAttribute,
439 {interElemenwiseBinaryName, interElemenwiseBinaryName},
441 tensors.push_back(
new TosaSerializationTensor(mulOutputName,
447 TosaSerializationOperator* rescaleOutputOp =
nullptr;
450 output_rescale_scale,
452 outputs[0]->GetQuantizationOffset(),
458 operators.push_back(rescaleOutputOp);
462 throw Exception(
"TOSA spec only supports INT8, INT32, FP16 and FP32 datatypes for SqDiff.");
465 tensors.push_back(
new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
467 return new TosaSerializationBasicBlock(blockName,
471 {input0Name, input1Name},
TosaSerializationBasicBlock * ConvertElementwiseBinaryToTosaOperator(const Layer *layer, const LayerType type, const std::vector< const TensorInfo * > &inputs, const std::vector< const TensorInfo * > &outputs, const ElementwiseBinaryDescriptor *descriptor)
TosaSerializationBasicBlock * ConvertSquaredDifferenceToTosaOperator(const Layer *layer, const LayerType, const std::vector< const TensorInfo * > &inputs, const std::vector< const TensorInfo * > &outputs, const ElementwiseBinaryDescriptor *descriptor)
std::string GenerateUniqueOutputName(const Layer &layer, uint32_t layerSlot=0)
const std::string mainName
DType ArmNNToDType(const DataType &type)
std::vector< int32_t > GetTosaTensorShape(const TensorShape &shape)
std::string GenerateUniqueInputName(const armnn::InputSlot &slot)
std::string GetUniqueTosaMappingID()
void CreateRescaleTosaOperator(const std::string &inputName, const std::string &outputName, double scale, int32_t input_zp, int32_t output_zp, bool input_unsigned, bool output_unsigned, bool double_round, bool scale32, TosaSerializationOperator **op)
Base class for all ArmNN exceptions so that users can filter to just those.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
Layer & GetOwningLayer() const
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below.
A ElementwiseBinaryDescriptor for the ElementwiseBinaryLayer.
BinaryOperation m_Operation
Specifies the elementwiseBinary operation to execute.