ArmNN
 26.07
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
17 TosaSerializationBasicBlock* 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)
Definition: Exceptions.hpp:210
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::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)
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
unsigned int GetNumDimensions() const
Definition: Tensor.hpp:197
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:482
const TensorShape & GetShape() const
Definition: Tensor.hpp:193
DataType GetDataType() const
Definition: Tensor.hpp:200
constexpr bool IsQuantized8BitType(DataType dataType)
Definition: TypesUtils.hpp:317
A SoftmaxDescriptor for the SoftmaxLayer.
float m_Beta
Exponentiation value.