21{
22 if (inputs.size() != 1)
23 {
24 throw armnn::Exception(
"ConvertReluToTosaOperator: 1 input tensors required.");
25 }
26
27 if (outputs.size() != 1)
28 {
29 throw armnn::Exception(
"ConvertReluToTosaOperator: 1 output tensor required.");
30 }
31
32 std::string inputName = std::string("input_");
33 std::string outputName = std::string("output0_");
35
36
37
38 if (layer != nullptr)
39 {
42 }
43
44 std::vector<TosaSerializationTensor*> tensors;
45 std::vector<TosaSerializationOperator*> operators;
46
47
48
49
51 DType inputDType0 =
ArmNNToDType(inputs[0]->GetDataType());
52 if(inputName.find("input_") != std::string::npos)
53 {
54 tensors.push_back(new TosaSerializationTensor(inputName, inputShape0, inputDType0, {}));
55 }
56
58 DType outputDType0 =
ArmNNToDType(outputs[0]->GetDataType());
59 tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
60
61 int32_t clamp_min = 0;
62 int32_t clamp_max = 0;
63 float float_max = 0.0f;
64 switch (desc->m_Function)
65 {
66 case ActivationFunction::ReLu:
67 {
68 clamp_max = std::numeric_limits<int32_t>::max();
69 float_max = std::numeric_limits<float>::max();
70 break;
71 }
72 case ActivationFunction::BoundedReLu:
73 {
74 clamp_max = static_cast<int32_t>(desc->m_A);
75 float_max = desc->m_A;
76 break;
77 }
78 case ActivationFunction::LeakyReLu:
79 {
80 throw Exception(
"LeakyRelu TOSA mappings are performed in ConvertLeakyReluToTosaOperator().");
81 }
82 default:
83 {
84 throw Exception(
"Activation function is not supported in ConvertReluToTosaOperator().");
85 }
86 }
87
88 std::string clampInputNameStr = inputName;
89 if (inputDType0 == tosa::DType::DType_INT8 || inputDType0 == tosa::DType::DType_INT16)
90 {
92 clampInputNameStr = outputNameRescale;
93
94 double scale = inputs[0]->GetQuantizationScale() / outputs[0]->GetQuantizationScale();
95 int32_t input_zp = inputs[0]->GetQuantizationOffset();
96 int32_t output_zp = outputs[0]->GetQuantizationOffset();
97
98 clamp_min = output_zp;
99
100 if (desc->m_Function == ActivationFunction::BoundedReLu)
101 {
102 clamp_max = static_cast<int32_t>(std::round(desc->m_A / outputs[0]->GetQuantizationScale())) + output_zp;
103 }
104
105 if (inputDType0 == tosa::DType::DType_INT8)
106 {
107 clamp_min =
108 clamp_min < std::numeric_limits<int8_t>::min() ? std::numeric_limits<int8_t>::min() : clamp_min;
109 clamp_max =
110 clamp_max > std::numeric_limits<int8_t>::max() ? std::numeric_limits<int8_t>::max() : clamp_max;
111 }
112 else
113 {
114 clamp_min =
115 clamp_min < std::numeric_limits<int16_t>::min() ? std::numeric_limits<int16_t>::min() : clamp_min;
116 clamp_max =
117 clamp_max > std::numeric_limits<int16_t>::max() ? std::numeric_limits<int16_t>::max() : clamp_max;
118 }
119
120 TosaSerializationOperator* rescaleOp = nullptr;
122 outputNameRescale,
123 scale,
124 input_zp,
125 output_zp,
126 false,
127 false,
128 false,
129 true,
130 &rescaleOp);
131 operators.push_back(rescaleOp);
132 tensors.push_back(new TosaSerializationTensor(outputNameRescale,
133 inputShape0,
134 inputDType0,
135 {}));
136 }
137 TosaClampAttribute attribute(clamp_min, clamp_max, 0, float_max);
138 auto* clamp_op = new TosaSerializationOperator(Op_CLAMP,
139 Attribute_ClampAttribute,
140 &attribute,
141 {clampInputNameStr},
142 {outputName});
143 operators.push_back(clamp_op);
144
145
146
147 return new TosaSerializationBasicBlock(blockName,
149 operators,
150 tensors,
151 {inputName},
152 {outputName});
153}
std::string GenerateUniqueOutputName(const Layer &layer, uint32_t layerSlot=0)
const std::string mainName
DType ArmNNToDType(const DataType &type)
std::string GenerateUniqueInputName(const armnn::InputSlot &slot)
std::string GetUniqueTosaMappingID()
std::vector< int32_t > GetTosaTensorShape(const TensorShape &shape)
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)
Creates a Tosa rescale operator.
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.