ArmNN
 25.11
Loading...
Searching...
No Matches
SoftmaxOperator.cpp
Go to the documentation of this file.
1//
2// Copyright © 2025 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5//
6// Copyright © 2020 The TensorFlow Authors. All Rights Reserved.
7// SPDX-License-Identifier: Apache-2.0
8//
9
10#include "SoftmaxOperator.hpp"
11
14
15// This function is paraphrased from:
16// tensorflow/compiler/mlir/tosa/transforms/legalize_common.cc from function convertSoftmaxOp
17TosaSerializationBasicBlock* ConvertSoftmaxToTosaOperator(const Layer* layer,
18 const std::vector<const TensorInfo*>& inputs,
19 const std::vector<const TensorInfo*>& outputs,
20 const SoftmaxDescriptor* softmaxDescriptor)
21
22{
24 "ConvertSoftmaxToTosaOperator: Softmax currently only supports Int8 Quantized inputs");
25
26 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(inputs.size() == 1,
27 "ConvertSoftmaxToTosaOperator: Softmax must have only one input");
28
29 ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(outputs.size() >= 1,
30 "ConvertSoftmaxToTosaOperator: Softmax must have at least one output");
31
32 std::string inputName = std::string("input_");
33 std::string outputName = std::string("output0_");
34 std::string blockName = std::string("Op_SOFTMAX_block_") + GetUniqueTosaMappingID();
35
36 std::string inputNameConst1 = std::string("layer_intermediate_constant1_") + GetUniqueTosaMappingID();
37 std::string inputNameConst2 = std::string("layer_intermediate_constant2_") + GetUniqueTosaMappingID();
38 std::string inputNameConst3 = std::string("layer_intermediate_constant3_") + GetUniqueTosaMappingID();
39 std::string inputNameConst3a = std::string("layer_intermediate_constant3a_") + GetUniqueTosaMappingID();
40 std::string inputNameConst4 = std::string("layer_intermediate_constant4_") + GetUniqueTosaMappingID();
41 std::string inputNameConst5 = std::string("layer_intermediate_constant5_") + GetUniqueTosaMappingID();
42 std::string inputNameConst6 = std::string("layer_intermediate_constant6_") + GetUniqueTosaMappingID();
43 std::string inputNameConst7 = std::string("layer_intermediate_constant7_") + GetUniqueTosaMappingID();
44 std::string inputNameConst8 = std::string("layer_intermediate_constant8_") + GetUniqueTosaMappingID();
45 std::string inputNameConst8a = std::string("layer_intermediate_constant8a_") + GetUniqueTosaMappingID();
46 std::string inputNameConst8b = std::string("layer_intermediate_constant8b_") + GetUniqueTosaMappingID();
47 std::string inputNameConst9 = std::string("layer_intermediate_constant9_") + GetUniqueTosaMappingID();
48 std::string inputNameConst9a = std::string("layer_intermediate_constant9a_") + GetUniqueTosaMappingID();
49 std::string inputNameConst9b = std::string("layer_intermediate_constant9b_") + GetUniqueTosaMappingID();
50 std::string inputNameConst10 = std::string("layer_intermediate_constant10_") + GetUniqueTosaMappingID();
51
52 std::string outputNameRescale1 = std::string("layer_intermediate0_") + GetUniqueTosaMappingID();
53 std::string outputNameReduceMax1 = std::string("layer_intermediate1_") + GetUniqueTosaMappingID();
54 std::string outputNameSub1 = std::string("layer_intermediate2_") + GetUniqueTosaMappingID();
55 std::string outputNameRescale2 = std::string("layer_intermediate3_") + GetUniqueTosaMappingID();
56 std::string outputNameTable1 = std::string("layer_intermediate4_") + GetUniqueTosaMappingID();
57 std::string outputNameTable2 = std::string("layer_intermediate5_") + GetUniqueTosaMappingID();
58 std::string outputNameTable3 = std::string("layer_intermediate6_") + GetUniqueTosaMappingID();
59 std::string outputNameTable4 = std::string("layer_intermediate7_") + GetUniqueTosaMappingID();
60 std::string outputNameLogicalL1 = std::string("layer_intermediate8_") + GetUniqueTosaMappingID();
61 std::string outputNameLogicalL2 = std::string("layer_intermediate9_") + GetUniqueTosaMappingID();
62 std::string outputNameLogicalL3 = std::string("layer_intermediate10_") + GetUniqueTosaMappingID();
63 std::string outputNameArithmeticR1 = std::string("layer_intermediate11_") + GetUniqueTosaMappingID();
64 std::string outputNameAdd1 = std::string("layer_intermediate12_") + GetUniqueTosaMappingID();
65 std::string outputNameAdd2 = std::string("layer_intermediate13_") + GetUniqueTosaMappingID();
66 std::string outputNameAdd3 = std::string("layer_intermediate14_") + GetUniqueTosaMappingID();
67 std::string outputNameArithmeticR2 = std::string("layer_intermediate15_") + GetUniqueTosaMappingID();
68 std::string outputNameReduceSum1 = std::string("layer_intermediate16_") + GetUniqueTosaMappingID();
69 std::string outputNameCLZ1 = std::string("layer_intermediate17_") + GetUniqueTosaMappingID();
70 std::string outputNameSub2 = std::string("layer_intermediate18_") + GetUniqueTosaMappingID();
71 std::string outputNameLogicalL4 = std::string("layer_intermediate19_") + GetUniqueTosaMappingID();
72 std::string outputNameMul1 = std::string("layer_intermediate20_") + GetUniqueTosaMappingID();
73 std::string outputNameAdd4 = std::string("layer_intermediate21_") + GetUniqueTosaMappingID();
74 std::string outputNameMul2 = std::string("layer_intermediate22_") + GetUniqueTosaMappingID();
75 std::string outputNameSub3 = std::string("layer_intermediate23_") + GetUniqueTosaMappingID();
76 std::string outputNameMul3 = std::string("layer_intermediate24_") + GetUniqueTosaMappingID();
77 std::string outputNameMul4 = std::string("layer_intermediate25_") + GetUniqueTosaMappingID();
78 std::string outputNameAdd5 = std::string("layer_intermediate26_") + GetUniqueTosaMappingID();
79 std::string outputNameMul5 = std::string("layer_intermediate27_") + GetUniqueTosaMappingID();
80 std::string outputNameSub4 = std::string("layer_intermediate28_") + GetUniqueTosaMappingID();
81 std::string outputNameMul6 = std::string("layer_intermediate29_") + GetUniqueTosaMappingID();
82 std::string outputNameMul7 = std::string("layer_intermediate30_") + GetUniqueTosaMappingID();
83 std::string outputNameAdd6 = std::string("layer_intermediate31_") + GetUniqueTosaMappingID();
84 std::string outputNameMul8 = std::string("layer_intermediate32_") + GetUniqueTosaMappingID();
85 std::string outputNameSub5 = std::string("layer_intermediate33_") + GetUniqueTosaMappingID();
86 std::string outputNameMul9 = std::string("layer_intermediate34_") + GetUniqueTosaMappingID();
87 std::string outputNameMul10 = std::string("layer_intermediate35_") + GetUniqueTosaMappingID();
88 std::string outputNameAdd7 = std::string("layer_intermediate36_") + GetUniqueTosaMappingID();
89 std::string outputNameMul11 = std::string("layer_intermediate37_") + GetUniqueTosaMappingID();
90 std::string outputNameSub6 = std::string("layer_intermediate38_") + GetUniqueTosaMappingID();
91 std::string outputNameArithmeticR3 = std::string("layer_intermediate39_") + GetUniqueTosaMappingID();
92 std::string inputMinConst = std::string("layer_intermediate40_const_") + GetUniqueTosaMappingID();
93 std::string outputShiftMin = std::string("layer_intermediate40_min_") + GetUniqueTosaMappingID();
94
95 // If a layer is present then the block will be used for execution, so input and output names need to be determined
96 // using the previous and following layers so the graph is connected correctly. For validation this doesn't matter.
97 if (layer != nullptr)
98 {
99 inputName = GenerateUniqueInputName(layer->GetInputSlot(0));
100 outputName = GenerateUniqueOutputName(*layer);
101 }
102
103 const TensorInfo& inputInfo = *inputs[0];
104 const TensorInfo& outputInfo = *outputs[0];
105
106 std::vector<TosaSerializationTensor *> tensors;
107 std::vector<TosaSerializationOperator *> operators;
108
109 std::vector<int32_t> inputShape0 = GetTosaTensorShape(inputInfo.GetShape());
110 std::vector<int32_t> outputShape0 = GetTosaTensorShape(outputInfo.GetShape());
111
112 DType inputDType0 = ArmNNToDType(inputInfo.GetDataType());
113 DType outputDType0 = ArmNNToDType(outputInfo.GetDataType());
114
115 // Only add input tensors if connected layer is an input layer.
116 // As intermediate or constant tensors will be created separately.
117 // There also can't be duplicate tensor.
118 if (inputName.find("input_") != std::string::npos)
119 {
120 tensors.push_back(new TosaSerializationTensor(inputName, inputShape0, inputDType0, {}));
121 }
122
123 float inScale = inputInfo.GetQuantizationScale();
124
125 int32_t input_zp = inputInfo.GetQuantizationOffset();
126 int32_t output_zp = outputInfo.GetQuantizationOffset();
127
128 std::vector<uint8_t> uint8Data;
129
130 unsigned int rank = inputInfo.GetNumDimensions();
131 const std::vector<int32_t> singleValueShape(rank,1);
132 auto axis = static_cast<int32_t>(rank - 1);
133 TosaAxisAttribute tosaAxisAttribute(axis);
134
135 // softmax calculations done using only the last tensor dimension
136 std::vector<int32_t> reduceShape = inputShape0;
137 reduceShape[static_cast<unsigned long>(axis)] = 1;
138
139 TosaSerializationOperator *rescaleOp1 = nullptr;
140 CreateRescaleTosaOperator(inputName, outputNameRescale1, 1.0f, input_zp, 0,
141 false, false, false, true, &rescaleOp1);
142
143 tensors.push_back(new TosaSerializationTensor(outputNameRescale1, inputShape0, DType_INT32, {}));
144 operators.push_back(rescaleOp1);
145
146 auto *reduceMaxOp1 = new TosaSerializationOperator(Op_REDUCE_MAX,
147 Attribute_AxisAttribute,
148 &tosaAxisAttribute,
149 {outputNameRescale1},
150 {outputNameReduceMax1});
151 tensors.push_back(new TosaSerializationTensor(outputNameReduceMax1, reduceShape, DType_INT32, {}));
152 operators.push_back(reduceMaxOp1);
153
154 auto *subOp1 = new TosaSerializationOperator(Op_SUB,
155 Attribute_NONE,
156 nullptr,
157 {outputNameRescale1, outputNameReduceMax1},
158 {outputNameSub1});
159 tensors.push_back(new TosaSerializationTensor(outputNameSub1, inputShape0, DType_INT32, {}));
160 operators.push_back(subOp1);
161
162 TosaSerializationOperator *rescaleOp2 = nullptr;
163 CreateRescaleTosaOperator(outputNameSub1, outputNameRescale2, 128.0f, 0, 0, false, false, false, true, &rescaleOp2);
164 tensors.push_back(new TosaSerializationTensor(outputNameRescale2, inputShape0, DType_INT16, {}));
165 operators.push_back(rescaleOp2);
166
167 std::array<std::vector <int16_t>, 4> lookupTables;
168 CalculateSoftmaxTableValues(softmaxDescriptor->m_Beta, inScale, lookupTables);
169
170 const std::vector<int16_t> first = lookupTables[0];
171 const std::vector<int16_t> table1(&first[0],&first[0]+513);
172 const std::vector<int16_t> second = lookupTables[1];
173 const std::vector<int16_t> table2(&second[0],&second[0]+513);
174 const std::vector<int16_t> third = lookupTables[2];
175 const std::vector<int16_t> table3(&third[0],&third[0]+513);
176 const std::vector<int16_t> fourth = lookupTables[3];
177 const std::vector<int16_t> table4(&fourth[0],&fourth[0]+513);
178
179 TosaTableAttribute tosaTableAttribute1(table1);
180 TosaTableAttribute tosaTableAttribute2(table2);
181 TosaTableAttribute tosaTableAttribute3(table3);
182 TosaTableAttribute tosaTableAttribute4(table4);
183
184 auto* tableOp1 = new TosaSerializationOperator(Op_TABLE,
185 Attribute_TableAttribute,
186 &tosaTableAttribute1,
187 {outputNameRescale2},
188 {outputNameTable1});
189 tensors.push_back(new TosaSerializationTensor(outputNameTable1, inputShape0, DType_INT32, {}));
190 operators.push_back(tableOp1);
191
192 auto* tableOp2 = new TosaSerializationOperator(Op_TABLE,
193 Attribute_TableAttribute,
194 &tosaTableAttribute2,
195 {outputNameRescale2},
196 {outputNameTable2});
197 tensors.push_back(new TosaSerializationTensor(outputNameTable2, inputShape0, DType_INT32, {}));
198 operators.push_back(tableOp2);
199
200 auto* tableOp3 = new TosaSerializationOperator(Op_TABLE,
201 Attribute_TableAttribute,
202 &tosaTableAttribute3,
203 {outputNameRescale2},
204 {outputNameTable3});
205 tensors.push_back(new TosaSerializationTensor(outputNameTable3, inputShape0, DType_INT32, {}));
206 operators.push_back(tableOp3);
207
208 auto* tableOp4 = new TosaSerializationOperator(Op_TABLE,
209 Attribute_TableAttribute,
210 &tosaTableAttribute4,
211 {outputNameRescale2},
212 {outputNameTable4});
213 tensors.push_back(new TosaSerializationTensor(outputNameTable4, inputShape0, DType_INT32, {}));
214 operators.push_back(tableOp4);
215
216 TosaSerializationHandler::ConvertI32toU8({17}, uint8Data);
217 tensors.push_back(new TosaSerializationTensor(inputNameConst1,singleValueShape, DType_INT32,uint8Data));
218 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst1}));
219
220 auto* logicalLOp1 = new TosaSerializationOperator(Op_LOGICAL_LEFT_SHIFT,
221 Attribute_NONE,
222 nullptr,
223 {outputNameTable1, inputNameConst1},
224 {outputNameLogicalL1});
225 tensors.push_back(new TosaSerializationTensor(outputNameLogicalL1, inputShape0, DType_INT32, {}));
226 operators.push_back(logicalLOp1);
227
228 TosaSerializationHandler::ConvertI32toU8({9}, uint8Data);
229 tensors.push_back(new TosaSerializationTensor(inputNameConst2, singleValueShape, DType_INT32,uint8Data));
230 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst2}));
231
232 auto* logicalLOp2 = new TosaSerializationOperator(Op_LOGICAL_LEFT_SHIFT,
233 Attribute_NONE,
234 nullptr,
235 {outputNameTable2, inputNameConst2},
236 {outputNameLogicalL2});
237 tensors.push_back(new TosaSerializationTensor(outputNameLogicalL2, inputShape0, DType_INT32, {}));
238 operators.push_back(logicalLOp2);
239
240 TosaSerializationHandler::ConvertI32toU8({1}, uint8Data);
241 tensors.push_back(new TosaSerializationTensor(inputNameConst3, singleValueShape, DType_INT32,uint8Data));
242 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst3}));
243
244 auto* logicalLOp3 = new TosaSerializationOperator(Op_LOGICAL_LEFT_SHIFT,
245 Attribute_NONE,
246 nullptr,
247 {outputNameTable3, inputNameConst3},
248 {outputNameLogicalL3});
249 tensors.push_back(new TosaSerializationTensor(outputNameLogicalL3, inputShape0, DType_INT32, {}));
250 operators.push_back(logicalLOp3);
251
252 bool rounding = true;
253 TosaArithmeticRightShiftAttribute shiftRAttribute(rounding);
254
255 TosaSerializationHandler::ConvertI32toU8({7}, uint8Data);
256 tensors.push_back(new TosaSerializationTensor(inputNameConst4, singleValueShape, DType_INT32,uint8Data));
257 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst4}));
258
259 auto* arithmeticROp1 = new TosaSerializationOperator(Op_ARITHMETIC_RIGHT_SHIFT,
260 Attribute_ArithmeticRightShiftAttribute,
261 &shiftRAttribute,
262 {outputNameTable4, inputNameConst4},
263 {outputNameArithmeticR1});
264 tensors.push_back(new TosaSerializationTensor(outputNameArithmeticR1, inputShape0, DType_INT32, {}));
265 operators.push_back(arithmeticROp1);
266
267 auto* addOp1 = new TosaSerializationOperator(Op_ADD,
268 Attribute_NONE,
269 nullptr,
270 {outputNameLogicalL1, outputNameLogicalL2},
271 {outputNameAdd1});
272 tensors.push_back(new TosaSerializationTensor(outputNameAdd1, inputShape0, DType_INT32, {}));
273 operators.push_back(addOp1);
274
275 auto* addOp2 = new TosaSerializationOperator(Op_ADD,
276 Attribute_NONE,
277 nullptr,
278 {outputNameAdd1, outputNameLogicalL3},
279 {outputNameAdd2});
280 tensors.push_back(new TosaSerializationTensor(outputNameAdd2, inputShape0, DType_INT32, {}));
281 operators.push_back(addOp2);
282
283 auto* addOp3 = new TosaSerializationOperator(Op_ADD,
284 Attribute_NONE,
285 nullptr,
286 {outputNameAdd2, outputNameArithmeticR1},
287 {outputNameAdd3});
288 tensors.push_back(new TosaSerializationTensor(outputNameAdd3, inputShape0, DType_INT32, {}));
289 operators.push_back(addOp3);
290
291 TosaSerializationHandler::ConvertI32toU8({12}, uint8Data);
292 tensors.push_back(new TosaSerializationTensor(inputNameConst5, singleValueShape, DType_INT32,uint8Data));
293 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst5}));
294
295 auto* arithmeticROp2 = new TosaSerializationOperator(Op_ARITHMETIC_RIGHT_SHIFT,
296 Attribute_ArithmeticRightShiftAttribute,
297 &shiftRAttribute,
298 {outputNameAdd3, inputNameConst5},
299 {outputNameArithmeticR2});
300 tensors.push_back(new TosaSerializationTensor(outputNameArithmeticR2, inputShape0, DType_INT32, {}));
301 operators.push_back(arithmeticROp2);
302
303 auto* reduceSumOp1 = new TosaSerializationOperator(Op_REDUCE_SUM,
304 Attribute_AxisAttribute,
305 &tosaAxisAttribute,
306 {outputNameArithmeticR2},
307 {outputNameReduceSum1});
308 tensors.push_back(new TosaSerializationTensor(outputNameReduceSum1, reduceShape, DType_INT32, {}));
309 operators.push_back(reduceSumOp1);
310
311 auto* countLeadingZeroOp1 = new TosaSerializationOperator(Op_CLZ,
312 Attribute_NONE,
313 nullptr,
314 {outputNameReduceSum1},
315 {outputNameCLZ1});
316 tensors.push_back(new TosaSerializationTensor(outputNameCLZ1, reduceShape, DType_INT32, {}));
317 operators.push_back(countLeadingZeroOp1);
318
319 TosaSerializationHandler::ConvertI32toU8({1}, uint8Data);
320 tensors.push_back(new TosaSerializationTensor(inputNameConst3a, singleValueShape, DType_INT32, uint8Data));
321 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst3a}));
322
323 auto* subOp2 = new TosaSerializationOperator(Op_SUB,
324 Attribute_NONE,
325 nullptr,
326 {outputNameCLZ1, inputNameConst3a},
327 {outputNameSub2});
328 tensors.push_back(new TosaSerializationTensor(outputNameSub2, reduceShape, DType_INT32, {}));
329 operators.push_back(subOp2);
330
331 // half_denominator
332 auto* logicalLOp4 = new TosaSerializationOperator(Op_LOGICAL_LEFT_SHIFT,
333 Attribute_NONE,
334 nullptr,
335 {outputNameReduceSum1, outputNameSub2},
336 {outputNameLogicalL4});
337 tensors.push_back(new TosaSerializationTensor(outputNameLogicalL4, reduceShape, DType_INT32, {}));
338 operators.push_back(logicalLOp4);
339
340 TosaMulAttribute mulAttribute1(31);
341
342 TosaSerializationHandler::ConvertI32toU8({-1010580540}, uint8Data); // constant_neg_32_over_17
343 tensors.push_back(new TosaSerializationTensor(inputNameConst6, singleValueShape, DType_INT32,uint8Data));
344 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst6}));
345
346 // mul_half_denominator
347 auto* mulOp1 = new TosaSerializationOperator(Op_MUL,
348 Attribute_MulAttribute,
349 &mulAttribute1,
350 {outputNameLogicalL4, inputNameConst6},
351 {outputNameMul1});
352 tensors.push_back(new TosaSerializationTensor(outputNameMul1, reduceShape, DType_INT32, {}));
353 operators.push_back(mulOp1);
354
355 TosaSerializationHandler::ConvertI32toU8({1515870810}, uint8Data); // constant_48_over_17
356 tensors.push_back(new TosaSerializationTensor(inputNameConst7, singleValueShape, DType_INT32,uint8Data));
357 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst7}));
358
359 // nr_x
360 auto* addOp4 = new TosaSerializationOperator(Op_ADD,
361 Attribute_NONE,
362 nullptr,
363 {outputNameMul1, inputNameConst7},
364 {outputNameAdd4});
365 tensors.push_back(new TosaSerializationTensor(outputNameAdd4, reduceShape, DType_INT32, {}));
366 operators.push_back(addOp4);
367
368 // Newton-Raphson 3 iterations of MUL SUB MUL MUL ADD sequence
369 auto* mulOp2 = new TosaSerializationOperator(Op_MUL,
370 Attribute_MulAttribute,
371 &mulAttribute1,
372 {outputNameAdd4, outputNameLogicalL4},
373 {outputNameMul2});
374 tensors.push_back(new TosaSerializationTensor(outputNameMul2, reduceShape, DType_INT32, {}));
375 operators.push_back(mulOp2);
376
377 TosaSerializationHandler::ConvertI32toU8({536870912}, uint8Data); // F2_one constant
378 tensors.push_back(new TosaSerializationTensor(inputNameConst8, singleValueShape, DType_INT32,uint8Data));
379 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst8}));
380
381 auto* subOp3 = new TosaSerializationOperator(Op_SUB,
382 Attribute_NONE,
383 nullptr,
384 {inputNameConst8, outputNameMul2},
385 {outputNameSub3});
386 tensors.push_back(new TosaSerializationTensor(outputNameSub3, reduceShape, DType_INT32, {}));
387 operators.push_back(subOp3);
388
389 auto* mulOp3 = new TosaSerializationOperator(Op_MUL,
390 Attribute_MulAttribute,
391 &mulAttribute1,
392 {outputNameAdd4, outputNameSub3},
393 {outputNameMul3});
394 tensors.push_back(new TosaSerializationTensor(outputNameMul3, reduceShape, DType_INT32, {}));
395 operators.push_back(mulOp3);
396
397 TosaMulAttribute mulAttribute2(0);
398
399 TosaSerializationHandler::ConvertI32toU8({4}, uint8Data);
400 tensors.push_back(new TosaSerializationTensor(inputNameConst9, singleValueShape, DType_INT32,uint8Data));
401 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst9}));
402
403 auto* mulOp4 = new TosaSerializationOperator(Op_MUL,
404 Attribute_MulAttribute,
405 &mulAttribute2,
406 {outputNameMul3, inputNameConst9},
407 {outputNameMul4});
408 tensors.push_back(new TosaSerializationTensor(outputNameMul4, reduceShape, DType_INT32, {}));
409 operators.push_back(mulOp4);
410
411 auto* addOp5 = new TosaSerializationOperator(Op_ADD,
412 Attribute_NONE,
413 nullptr,
414 {outputNameAdd4, outputNameMul4},
415 {outputNameAdd5});
416 tensors.push_back(new TosaSerializationTensor(outputNameAdd5, reduceShape, DType_INT32, {}));
417 operators.push_back(addOp5);
418
419 // Newton-Raphson 2nd iteration... nr_x = op25_add_x_op24.getResult();
420 auto* mulOp5 = new TosaSerializationOperator(Op_MUL,
421 Attribute_MulAttribute,
422 &mulAttribute1,
423 {outputNameAdd5, outputNameLogicalL4},
424 {outputNameMul5});
425 tensors.push_back(new TosaSerializationTensor(outputNameMul5, reduceShape, DType_INT32, {}));
426 operators.push_back(mulOp5);
427
428 TosaSerializationHandler::ConvertI32toU8({536870912}, uint8Data);
429 tensors.push_back(new TosaSerializationTensor(inputNameConst8a, singleValueShape, DType_INT32,uint8Data));
430 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst8a}));
431
432 auto* subOp4 = new TosaSerializationOperator(Op_SUB,
433 Attribute_NONE,
434 nullptr,
435 {inputNameConst8a, outputNameMul5},
436 {outputNameSub4});
437 tensors.push_back(new TosaSerializationTensor(outputNameSub4, reduceShape, DType_INT32, {}));
438 operators.push_back(subOp4);
439
440 auto* mulOp6 = new TosaSerializationOperator(Op_MUL,
441 Attribute_MulAttribute,
442 &mulAttribute1,
443 {outputNameAdd5, outputNameSub4},
444 {outputNameMul6});
445 tensors.push_back(new TosaSerializationTensor(outputNameMul6, reduceShape, DType_INT32, {}));
446 operators.push_back(mulOp6);
447
448 TosaSerializationHandler::ConvertI32toU8({4}, uint8Data);
449 tensors.push_back(new TosaSerializationTensor(inputNameConst9a, singleValueShape, DType_INT32,uint8Data));
450 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst9a}));
451
452 auto* mulOp7 = new TosaSerializationOperator(Op_MUL,
453 Attribute_MulAttribute,
454 &mulAttribute2,
455 {outputNameMul6, inputNameConst9a},
456 {outputNameMul7});
457 tensors.push_back(new TosaSerializationTensor(outputNameMul7, reduceShape, DType_INT32, {}));
458 operators.push_back(mulOp7);
459
460 auto* addOp6 = new TosaSerializationOperator(Op_ADD,
461 Attribute_NONE,
462 nullptr,
463 {outputNameAdd5, outputNameMul7},
464 {outputNameAdd6});
465 tensors.push_back(new TosaSerializationTensor(outputNameAdd6, reduceShape, DType_INT32, {}));
466 operators.push_back(addOp6);
467
468 // Newton-Raphson 3rd iteration... nr_x = op25_add_x_op24.getResult();
469 auto* mulOp8 = new TosaSerializationOperator(Op_MUL,
470 Attribute_MulAttribute,
471 &mulAttribute1,
472 {outputNameAdd6, outputNameLogicalL4},
473 {outputNameMul8});
474 tensors.push_back(new TosaSerializationTensor(outputNameMul8, reduceShape, DType_INT32, {}));
475 operators.push_back(mulOp8);
476
477 TosaSerializationHandler::ConvertI32toU8({536870912}, uint8Data);
478 tensors.push_back(new TosaSerializationTensor(inputNameConst8b, singleValueShape, DType_INT32,uint8Data));
479 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst8b}));
480
481 auto* subOp5 = new TosaSerializationOperator(Op_SUB,
482 Attribute_NONE,
483 nullptr,
484 {inputNameConst8b, outputNameMul8},
485 {outputNameSub5});
486 tensors.push_back(new TosaSerializationTensor(outputNameSub5, reduceShape, DType_INT32, {}));
487 operators.push_back(subOp5);
488
489 auto* mulOp9 = new TosaSerializationOperator(Op_MUL,
490 Attribute_MulAttribute,
491 &mulAttribute1,
492 {outputNameAdd6, outputNameSub5},
493 {outputNameMul9});
494 tensors.push_back(new TosaSerializationTensor(outputNameMul9, reduceShape, DType_INT32, {}));
495 operators.push_back(mulOp9);
496
497 TosaSerializationHandler::ConvertI32toU8({4}, uint8Data);
498 tensors.push_back(new TosaSerializationTensor(inputNameConst9b, singleValueShape, DType_INT32,uint8Data));
499 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst9b}));
500
501 auto* mulOp10 = new TosaSerializationOperator(Op_MUL,
502 Attribute_MulAttribute,
503 &mulAttribute2,
504 {outputNameMul9, inputNameConst9b},
505 {outputNameMul10});
506 tensors.push_back(new TosaSerializationTensor(outputNameMul10, reduceShape, DType_INT32, {}));
507 operators.push_back(mulOp10);
508
509 auto* addOp7 = new TosaSerializationOperator(Op_ADD,
510 Attribute_NONE,
511 nullptr,
512 {outputNameAdd6, outputNameMul10},
513 {outputNameAdd7});
514 tensors.push_back(new TosaSerializationTensor(outputNameAdd7, reduceShape, DType_INT32, {}));
515 operators.push_back(addOp7);
516
517 TosaMulAttribute mulAttribute3(30);
518
519 auto* mulOp11 = new TosaSerializationOperator(Op_MUL,
520 Attribute_MulAttribute,
521 &mulAttribute3,
522 {outputNameAdd3, outputNameAdd7},
523 {outputNameMul11});
524 tensors.push_back(new TosaSerializationTensor(outputNameMul11, outputShape0, DType_INT32, {}));
525 operators.push_back(mulOp11);
526
527 TosaSerializationHandler::ConvertI32toU8({35}, uint8Data);
528 tensors.push_back(new TosaSerializationTensor(inputNameConst10, singleValueShape, DType_INT32,uint8Data));
529 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {inputNameConst10}));
530
531 auto* subOp6 = new TosaSerializationOperator(Op_SUB,
532 Attribute_NONE,
533 nullptr,
534 {inputNameConst10, outputNameCLZ1},
535 {outputNameSub6});
536 tensors.push_back(new TosaSerializationTensor(outputNameSub6, reduceShape, DType_INT32, {}));
537 operators.push_back(subOp6);
538
539 TosaSerializationHandler::ConvertI32toU8({31}, uint8Data);
540 tensors.push_back(new TosaSerializationTensor(inputMinConst, singleValueShape, DType_INT32,uint8Data));
541 operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr,{}, {inputMinConst}));
542
543 auto* minOp = new TosaSerializationOperator(Op_MINIMUM,
544 Attribute_NONE, nullptr,
545 {outputNameSub6,inputMinConst},
546 {outputShiftMin});
547
548 tensors.push_back(new TosaSerializationTensor(outputShiftMin, reduceShape, DType_INT32, {}));
549 operators.push_back(minOp);
550
551 auto* arithmeticROp3 = new TosaSerializationOperator(Op_ARITHMETIC_RIGHT_SHIFT,
552 Attribute_ArithmeticRightShiftAttribute,
553 &shiftRAttribute,
554 {outputNameMul11, outputShiftMin},
555 {outputNameArithmeticR3});
556 tensors.push_back(new TosaSerializationTensor(outputNameArithmeticR3, outputShape0, DType_INT32, {}));
557 operators.push_back(arithmeticROp3);
558
559 TosaSerializationOperator* rescaleOp3 = nullptr;
560 CreateRescaleTosaOperator(outputNameArithmeticR3,
561 outputName,
562 1.0f,
563 0,
564 output_zp,
565 false,
566 false,
567 false,
568 true,
569 &rescaleOp3);
570
571 tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
572 operators.push_back(rescaleOp3);
573
574 return new TosaSerializationBasicBlock(blockName,
575 mainName,
576 {operators},
577 tensors,
578 {inputName},
579 {outputName});
580}
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
TosaSerializationBasicBlock * ConvertSoftmaxToTosaOperator(const Layer *layer, const std::vector< const TensorInfo * > &inputs, const std::vector< const TensorInfo * > &outputs, const SoftmaxDescriptor *softmaxDescriptor)
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.
void CalculateSoftmaxTableValues(double softmaxBeta, double scale, std::array< std::vector< int16_t >, 4 > &tables)
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition Layer.hpp:337
float GetQuantizationScale() const
Definition Tensor.cpp:461
const TensorShape & GetShape() const
Definition Tensor.hpp:193
unsigned int GetNumDimensions() const
Definition Tensor.hpp:197
int32_t GetQuantizationOffset() const
Definition Tensor.cpp:482
DataType GetDataType() const
Definition Tensor.hpp:200
constexpr bool IsQuantized8BitType(DataType dataType)
A SoftmaxDescriptor for the SoftmaxLayer.
float m_Beta
Exponentiation value.