ArmNN
 25.11
Loading...
Searching...
No Matches
PReluOperator.cpp File Reference
Include dependency graph for PReluOperator.cpp:

Go to the source code of this file.

Functions

TosaSerializationBasicBlock * ConvertPReluToTosaOperator (const Layer *layer, const std::vector< const TensorInfo * > &inputs, const std::vector< const TensorInfo * > &outputs)

Function Documentation

◆ ConvertPReluToTosaOperator()

TosaSerializationBasicBlock * ConvertPReluToTosaOperator ( const Layer * layer,
const std::vector< const TensorInfo * > & inputs,
const std::vector< const TensorInfo * > & outputs )

Definition at line 17 of file PReluOperator.cpp.

20{
22 IsQuantized8BitType(outputs[0]->GetDataType()),
23 "ConvertPReluToTosaOperator: Prelu currently only supports Int8 Quantized inputs");
24 if (inputs.size() != 2) {
25 throw armnn::Exception("ConvertPReluToTosaOperator: 2 input tensors required.");
26 }
27
28 if (outputs.size() != 1) {
29 throw armnn::Exception("ConvertPReluToTosaOperator: 1 output tensor required.");
30 }
31
32 std::string inputName0 = std::string("input_0");
33 std::string inputName1 = std::string("input_1");
34 std::string inputNameZero = std::string("constant1_") + GetUniqueTosaMappingID();
35 std::string outputNameMul = std::string("layer_intermediate2_") + GetUniqueTosaMappingID();
36 std::string outputNameClampEq = std::string("layer_intermediate3_") + GetUniqueTosaMappingID();
37 std::string outputNameRescaleTo32 = std::string("layer_intermediate4_") + GetUniqueTosaMappingID();
38 std::string outputNameRescaleSlope = std::string("layer_intermediate5_") + GetUniqueTosaMappingID();
39 std::string outputNameRescaleSlope2 = std::string("layer_intermediate6_") + GetUniqueTosaMappingID();
40 std::string outputNameRescaleIdentity = std::string("layer_intermediate7_") + GetUniqueTosaMappingID();
41 std::string outputNameClamp = std::string("layer_intermediate8_") + GetUniqueTosaMappingID();
42 std::string outputNameClampTo32 = std::string("layer_intermediate9_") + GetUniqueTosaMappingID();
43 std::string outputName = std::string("output0_");
44 std::string blockName = std::string("Op_PRELU_block_") + GetUniqueTosaMappingID();
45
46 double scale_alpha = inputs[0]->GetQuantizationScale() * inputs[1]->GetQuantizationScale() /
47 outputs[0]->GetQuantizationScale();
48 double scale_identity = inputs[0]->GetQuantizationScale() / outputs[0]->GetQuantizationScale();
49 int32_t input0_zp = inputs[0]->GetQuantizationOffset();
50 int32_t input1_zp = inputs[1]->GetQuantizationOffset();
51 int32_t output_zp = outputs[0]->GetQuantizationOffset();
52
53 // If a layer is present then the block will be used for execution, so input and output names need to be determined
54 // using the previous and following layers so the graph is connected correctly. For validation this doesn't matter.
55 if (layer != nullptr) {
56 inputName0 = GenerateUniqueInputName(layer->GetInputSlot(0));
57 inputName1 = GenerateUniqueInputName(layer->GetInputSlot(1));
58 outputName = GenerateUniqueOutputName(*layer);
59 }
60
61 std::vector<TosaSerializationTensor *> tensors;
62 std::vector<TosaSerializationOperator *> operators;
63
64 // Only add input tensors if connected layer is an input layer.
65 // As intermediate or constant tensors will be created separately.
66 // There also can't be duplicate tensor.
67 std::vector<int32_t> inputShape0;
68 inputShape0 = GetTosaTensorShape(inputs[0]->GetShape());
69 DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType());
70 if (inputName0.find("input_") != std::string::npos) {
71 tensors.push_back(new TosaSerializationTensor(inputName0, inputShape0, inputDType0, {}));
72 }
73
74 std::vector<int32_t> inputShape1;
75 inputShape1 = GetTosaTensorShape(inputs[1]->GetShape());
76 if (inputName1.find("input_") != std::string::npos) {
77 tensors.push_back(new TosaSerializationTensor(inputName1, inputShape1, inputDType0, {}));
78 }
79
80 std::vector<int32_t> outputShape0 = GetTosaTensorShape(outputs[0]->GetShape());
81 DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType());
82
83 // Implement PReLU as:
84 // rescaled_in = rescale(in)
85 // rescaled_alpha = rescale(alpha)
86 // rescaled_identity_in = rescale(in, scale_identity)
87 // slope_in = mul(rescaled_in, rescaled_alpha)
88 // rescaled_slope_in = rescale(slope_in, scale_alpha)
89 // cond_result = greater_equal(rescaled_in, 0)
90 // output = select(cond_result, rescaled_identity_in, rescaled_slope_in)
91
92 TosaSerializationOperator* op_rescale_in = nullptr;
94 outputNameRescaleTo32,
95 1.0f,
96 input0_zp,
97 0,
98 false,
99 false,
100 true,
101 true,
102 &op_rescale_in);
103 operators.emplace_back(op_rescale_in);
104 tensors.emplace_back(new TosaSerializationTensor(outputNameRescaleTo32,
105 inputShape0,
106 DType_INT32,
107 {}));
108
109 int32_t clamp_min = 0;
110 int32_t clamp_max = std::numeric_limits<int8_t>::max();
111 float float_max = std::numeric_limits<float>::max();
112
113 // If CLAMP result matches original then no negative values
114 // CLAMP does not support INT32
115 TosaClampAttribute attribute(clamp_min, clamp_max, 0, float_max);
116 auto* clamp_op = new TosaSerializationOperator(Op_CLAMP,
117 Attribute_ClampAttribute,
118 &attribute,
119 {inputName0},
120 {outputNameClamp});
121 operators.push_back(clamp_op);
122 tensors.push_back(new TosaSerializationTensor(outputNameClamp, inputShape0, inputDType0, {}));
123
124 // EQUAL does not support INT8 so RESCALE CLAMP output required
125 TosaSerializationOperator* op_clamp = nullptr;
126 CreateRescaleTosaOperator(outputNameClamp,
127 outputNameClampTo32,
128 1.0f,
129 input0_zp,
130 0,
131 false,
132 false,
133 true,
134 true,
135 &op_clamp);
136 operators.emplace_back(op_clamp);
137 tensors.emplace_back(new TosaSerializationTensor(outputNameClampTo32,
138 inputShape0,
139 DType_INT32,
140 {}));
141
142 TosaSerializationOperator *op_ge = new TosaSerializationOperator(Op_EQUAL,
143 Attribute_NONE,
144 nullptr,
145 {outputNameRescaleTo32, outputNameClampTo32},
146 {outputNameClampEq});
147 operators.push_back(op_ge);
148 tensors.push_back(new TosaSerializationTensor(outputNameClampEq, inputShape0, DType_BOOL, {}));
149
150 // RESHAPE for outputNameRescaleSlope not required as already done on input2 by AddBroadCastReshapeLayer
151 TosaSerializationOperator* op_rescale_slope_in = nullptr;
152 CreateRescaleTosaOperator(inputName1,
153 outputNameRescaleSlope,
154 1.0f,
155 input1_zp,
156 0,
157 false,
158 false,
159 true,
160 true,
161 &op_rescale_slope_in);
162 operators.emplace_back(op_rescale_slope_in);
163 tensors.emplace_back(new TosaSerializationTensor(outputNameRescaleSlope,
164 inputShape1,
165 DType_INT32,
166 {}));
167 // mul shift
168 int32_t shift = 0;
169 TosaMulAttribute mulAttribute(shift);
170 TosaSerializationOperator *mulOp = new TosaSerializationOperator(Op_MUL,
171 Attribute_MulAttribute,
172 &mulAttribute,
173 {outputNameRescaleTo32,
174 outputNameRescaleSlope},
175 {outputNameMul});
176 operators.push_back(mulOp);
177 tensors.push_back(new TosaSerializationTensor(outputNameMul, outputShape0, DType_INT32, {}));
178
179 TosaSerializationOperator *op_rescale_slope_in2 = nullptr;
180 CreateRescaleTosaOperator(outputNameMul,
181 outputNameRescaleSlope2,
182 scale_alpha,
183 0,
184 output_zp,
185 false,
186 false,
187 true,
188 true,
189 &op_rescale_slope_in2);
190 operators.push_back(op_rescale_slope_in2);
191 tensors.push_back(new TosaSerializationTensor(outputNameRescaleSlope2,
192 outputShape0,
193 outputDType0, {}));
194
195 TosaSerializationOperator *op_rescale_identity_in = nullptr;
196 CreateRescaleTosaOperator(inputName0,
197 outputNameRescaleIdentity,
198 scale_identity,
199 input0_zp,
200 output_zp,
201 false,
202 false,
203 true,
204 true,
205 &op_rescale_identity_in);
206 operators.push_back(op_rescale_identity_in);
207 tensors.push_back(new TosaSerializationTensor(outputNameRescaleIdentity,
208 outputShape0,
209 outputDType0, {}));
210
211 TosaSerializationOperator *selectOp = new TosaSerializationOperator(Op_SELECT,
212 Attribute_NONE,
213 nullptr,
214 {outputNameClampEq,
215 outputNameRescaleIdentity,
216 outputNameRescaleSlope2},
217 {outputName});
218 operators.push_back(selectOp);
219 tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
220
221 // operatorInputNames/operatorOutputNames ends up being the same as
222 // blockInputNames/blockOutputNames for one-to-one ArmNN to Tosa mappings
223 return new TosaSerializationBasicBlock(blockName, // name
224 mainName, // region name
225 operators, // operators
226 tensors, // tensors
227 {inputName0,inputName1},// inputs
228 {outputName}); // outputs
229
230}
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
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.
Definition Layer.hpp:337
constexpr bool IsQuantized8BitType(DataType dataType)

References ARMNN_THROW_INVALIDARG_MSG_IF_FALSE, ArmNNToDType(), CreateRescaleTosaOperator(), GenerateUniqueInputName(), GenerateUniqueOutputName(), Layer::GetInputSlot(), GetTosaTensorShape(), GetUniqueTosaMappingID(), armnn::IsQuantized8BitType(), and mainName.

Referenced by GetTosaMapping().