ArmNN
 24.02
TosaOperatorUtils.hpp
Go to the documentation of this file.
1 //
2 // Copyright © 2022-2024 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include <Layer.hpp>
9 #include <armnn/Tensor.hpp>
10 #include <armnn/Types.hpp>
11 
12 #include "common/include/ProfilingGuid.hpp"
13 
14 #include <tosa_serialization_handler.h>
15 
16 using namespace armnn;
17 using namespace tosa;
18 
19 const std::string mainName = "main";
20 
21 // Function to return Tosa datatype from input ArmNN datatype.
22 inline DType ArmNNToDType(const DataType& type)
23 {
24  switch (type)
25  {
26  case DataType::Float16:
27  return DType_FP16;
28  case DataType::BFloat16:
29  return DType_BF16;
30  case DataType::Float32:
31  return DType_FP32;
32  case DataType::QAsymmU8:
33  return DType_UINT8;
34  case DataType::QSymmS8:
35  case DataType::QAsymmS8:
36  return DType_INT8;
37  case DataType::QSymmS16:
38  return DType_INT16;
39  case DataType::Signed32:
40  return DType_INT32;
41  case DataType::Signed64:
42  // No signed 64, only DType_INT48.
43  return DType_UNKNOWN;
44  case DataType::Boolean:
45  return DType_BOOL;
46  default:
47  return DType_UNKNOWN;
48  }
49 }
50 
51 // Function to return Tosa tensor shape from input ArmNN tensor shape.
52 inline std::vector<int32_t> GetTosaTensorShape(const TensorShape& shape)
53 {
54  std::vector<int32_t> returnShape;
55  for (u_int32_t i = 0; i < shape.GetNumDimensions(); i++)
56  {
57  returnShape.push_back(static_cast<int32_t>(shape[i]));
58  }
59  return returnShape;
60 }
61 
62 // Function that generates unique name using the layer type, input slot and layer guid.
63 inline std::string GenerateUniqueName(const Layer& layer, uint32_t layerSlot)
64 {
65  std::string guid = std::to_string(layer.GetGuid());
66  std::string slotAndGuid = std::to_string(layerSlot) + "_" + guid;
67 
68  switch (layer.GetType())
69  {
70  case LayerType::Input:
71  return "input" + slotAndGuid;
72  case LayerType::Output:
73  return "output" + slotAndGuid;
75  return "constant_" + guid;
76  default:
77  return "intermediate" + slotAndGuid;
78  }
79 }
80 
81 // Function that generates unique output name using the layer type, input slot and layer guid.
82 inline std::string GenerateUniqueOutputName(const Layer& layer, uint32_t layerSlot)
83 {
84  Layer& connectedLayer = layer.GetOutputSlot().GetConnection(0)->GetOwningLayer();
85 
86  // Get the layer connected to the output slot, if output use that layer and id,
87  // otherwise use current layer and id.
88  if(connectedLayer.GetType() == LayerType::Output)
89  {
90  return GenerateUniqueName(connectedLayer, layerSlot);
91  }
92  else
93  {
94  return GenerateUniqueName(layer, layerSlot);
95  }
96 }
97 
98 // Function to return unique int as a string to ensure uniqueness between all input, output and block names.
99 static int uniqueTosaMappingID = 0;
100 inline std::string GetUniqueTosaMappingID()
101 {
102  return std::to_string(++uniqueTosaMappingID);
103 }
104 
105 // Function to return Tosa DType as string.
106 inline std::string TosaDTypeToString(DType tosaDType)
107 {
108  switch (tosaDType)
109  {
110  case DType_UNKNOWN:
111  return "DType_UNKNOWN";
112  case DType_BOOL:
113  return "DType_BOOL";
114  case DType_UINT8:
115  return "DType_UINT8";
116  case DType_INT4:
117  return "DType_INT4";
118  case DType_INT8:
119  return "DType_INT8";
120  case DType_INT16:
121  return "DType_INT16";
122  case DType_INT32:
123  return "DType_INT32";
124  case DType_INT48:
125  return "DType_INT48";
126  case DType_FP32:
127  return "DType_FP32";
128  case DType_UINT16:
129  return "DType_UINT16";
130  case DType_FP16:
131  return "DType_FP16";
132  case DType_BF16:
133  return "DType_BF16";
134  }
135  return "";
136 }
137 
138 // Function to return Tosa Op as string.
139 inline std::string TosaOpToString(Op tosaOp)
140 {
141  switch (tosaOp)
142  {
143  case Op_ADD:
144  return "Op_ADD";
145  case Op_AVG_POOL2D:
146  return "Op_AVG_POOL2D";
147  case Op_MAX_POOL2D:
148  return "Op_MAX_POOL2D";
149  case Op_PAD:
150  return "Op_PAD";
151  case Op_UNKNOWN:
152  return "Op_UNKNOWN";
153  case Op_ARGMAX:
154  return "Op_ARGMAX";
155  case Op_CONV2D:
156  return "Op_CONV2D";
157  case Op_CONV3D:
158  return "Op_CONV3D";
159  case Op_DEPTHWISE_CONV2D:
160  return "Op_DEPTHWISE_CONV2D";
161  case Op_FULLY_CONNECTED:
162  return "Op_FULLY_CONNECTED";
163  case Op_MATMUL:
164  return "Op_MATMUL";
165  case Op_TRANSPOSE_CONV2D:
166  return "Op_TRANSPOSE_CONV2D";
167  case Op_CLAMP:
168  return "Op_CLAMP";
169  case Op_RESERVED:
170  return "Op_RESERVED";
171  case Op_SIGMOID:
172  return "Op_SIGMOID";
173  case Op_TANH:
174  return "Op_TANH";
175  case Op_ARITHMETIC_RIGHT_SHIFT:
176  return "Op_ARITHMETIC_RIGHT_SHIFT";
177  case Op_BITWISE_AND:
178  return "Op_BITWISE_AND";
179  case Op_BITWISE_OR:
180  return "Op_BITWISE_OR";
181  case Op_BITWISE_XOR:
182  return "Op_BITWISE_XOR";
183  case Op_INTDIV:
184  return "Op_INTDIV";
185  case Op_LOGICAL_AND:
186  return "Op_LOGICAL_AND";
187  case Op_LOGICAL_LEFT_SHIFT:
188  return "Op_LOGICAL_LEFT_SHIFT";
189  case Op_LOGICAL_RIGHT_SHIFT:
190  return "Op_LOGICAL_RIGHT_SHIFT";
191  case Op_LOGICAL_OR:
192  return "Op_LOGICAL_OR";
193  case Op_LOGICAL_XOR:
194  return "Op_LOGICAL_XOR";
195  case Op_MAXIMUM:
196  return "Op_MAXIMUM";
197  case Op_MINIMUM:
198  return "Op_MINIMUM";
199  case Op_MUL:
200  return "Op_MUL";
201  case Op_POW:
202  return "Op_POW";
203  case Op_SUB:
204  return "Op_SUB";
205  case Op_TABLE:
206  return "Op_TABLE";
207  case Op_ABS:
208  return "Op_ABS";
209  case Op_BITWISE_NOT:
210  return "Op_BITWISE_NOT";
211  case Op_CEIL:
212  return "Op_CEIL";
213  case Op_CLZ:
214  return "Op_CLZ";
215  case Op_EXP:
216  return "Op_EXP";
217  case Op_FLOOR:
218  return "Op_FLOOR";
219  case Op_LOG:
220  return "Op_LOG";
221  case Op_LOGICAL_NOT:
222  return "Op_LOGICAL_NOT";
223  case Op_NEGATE:
224  return "Op_NEGATE";
225  case Op_RECIPROCAL:
226  return "Op_RECIPROCAL";
227  case Op_RSQRT:
228  return "Op_RSQRT";
229  case Op_SELECT:
230  return "Op_SELECT";
231  case Op_EQUAL:
232  return "Op_EQUAL";
233  case Op_GREATER:
234  return "Op_GREATER";
235  case Op_GREATER_EQUAL:
236  return "Op_GREATER_EQUAL";
237  case Op_REDUCE_ANY:
238  return "Op_REDUCE_ANY";
239  case Op_REDUCE_ALL:
240  return "Op_REDUCE_ALL";
241  case Op_REDUCE_MAX:
242  return "Op_REDUCE_MAX";
243  case Op_REDUCE_MIN:
244  return "Op_REDUCE_MIN";
245  case Op_REDUCE_PRODUCT:
246  return "Op_REDUCE_PRODUCT";
247  case Op_REDUCE_SUM:
248  return "Op_REDUCE_SUM";
249  case Op_CONCAT:
250  return "Op_CONCAT";
251  case Op_RESHAPE:
252  return "Op_RESHAPE";
253  case Op_REVERSE:
254  return "Op_REVERSE";
255  case Op_SLICE:
256  return "Op_SLICE";
257  case Op_TILE:
258  return "Op_TILE";
259  case Op_TRANSPOSE:
260  return "Op_TRANSPOSE";
261  case Op_GATHER:
262  return "Op_GATHER";
263  case Op_SCATTER:
264  return "Op_SCATTER";
265  case Op_RESIZE:
266  return "Op_RESIZE";
267  case Op_CAST:
268  return "Op_CAST";
269  case Op_RESCALE:
270  return "Op_RESCALE";
271  case Op_CONST:
272  return "Op_CONST";
273  case Op_IDENTITY:
274  return "Op_IDENTITY";
275  case Op_CUSTOM:
276  return "Op_CUSTOM";
277  case Op_COND_IF:
278  return "Op_COND_IF";
279  case Op_WHILE_LOOP:
280  return "Op_WHILE_LOOP";
281  case Op_FFT2D:
282  return "Op_FFT2D";
283  case Op_RFFT2D:
284  return "Op_RFFT2D";
285  }
286  return "";
287 }
288 
289 inline std::vector<uint8_t> ConvertConstantTensorDataToBuffer(const std::shared_ptr<ConstTensorHandle>& tensorHandle)
290 {
291  tosa_err_t error = tosa_err_t::TOSA_OK;
292  std::vector<uint8_t> uint8Data;
293  auto tensorInfo = tensorHandle->GetTensorInfo();
294 
295  switch (tensorInfo.GetDataType())
296  {
297  case DataType::Float32:
298  {
299  std::vector<float> data(tensorInfo.GetNumElements());
300  memcpy(data.data(), tensorHandle->Map(true), tensorInfo.GetNumBytes());
301 
302  error = TosaSerializationHandler::ConvertF32toU8(data, uint8Data);
303  break;
304  }
305  case DataType::Float16:
306  {
307  std::vector<float> data(tensorInfo.GetNumElements());
308  memcpy(data.data(), tensorHandle->Map(true), tensorInfo.GetNumBytes());
309 
310  error = TosaSerializationHandler::ConvertF16toU8(data, uint8Data);
311  break;
312  }
313  case DataType::QSymmS8:
314  case DataType::QAsymmS8:
315  {
316  std::vector<int8_t> data(tensorInfo.GetNumElements());
317  memcpy(data.data(), tensorHandle->Map(true), tensorInfo.GetNumBytes());
318 
319  error = TosaSerializationHandler::ConvertI8toU8(data, uint8Data);
320  break;
321  }
322  case DataType::QAsymmU8:
323  {
324  memcpy(uint8Data.data(), tensorHandle->Map(true), tensorInfo.GetNumBytes());
325  break;
326  }
327  case DataType::QSymmS16:
328  {
329  std::vector<int16_t> data(tensorInfo.GetNumElements());
330  memcpy(data.data(), tensorHandle->Map(true), tensorInfo.GetNumBytes());
331 
332  error = TosaSerializationHandler::ConvertI16toU8(data, uint8Data);
333  break;
334  }
335  case DataType::Signed32:
336  {
337  std::vector<int32_t> data(tensorInfo.GetNumElements());
338  memcpy(data.data(), tensorHandle->Map(true), tensorInfo.GetNumBytes());
339 
340  error = TosaSerializationHandler::ConvertI32toU8(data, uint8Data);
341  break;
342  }
343  default:
344  {
345  throw armnn::Exception("SetConstantTensorData: An unsupported data type was encountered.");
346  }
347  }
348 
349  if(error != tosa_err_t::TOSA_OK)
350  {
351  throw armnn::Exception("SetConstantTensorData: An error occurred when converting constant data");
352  }
353 
354  tensorHandle->Unmap();
355  return uint8Data;
356 }
357 
358 inline std::vector<uint8_t> CreateConstTosaData(const void* value,
359  DType dtype,
360  const std::vector<int32_t>& shape)
361 {
362  std::vector<uint8_t> uint8Data;
363  tosa_err_t error = tosa_err_t::TOSA_OK;
364 
365  unsigned int numElements = 1;
366  for (auto s : shape)
367  {
368  if (s < 0)
369  {
370  throw armnn::Exception("CreateConstTosaData: negative shape elements unhandled.");
371  }
372  numElements = numElements * static_cast<unsigned int>(s);
373  }
374 
375  switch (dtype)
376  {
377  case DType::DType_FP32:
378  {
379  std::vector<float> data(numElements, *static_cast<const float*>(value));
380  error = TosaSerializationHandler::ConvertF32toU8(data, uint8Data);
381  break;
382  }
383  case DType::DType_FP16:
384  {
385  std::vector<float> data(numElements, *static_cast<const float*>(value));
386  error = TosaSerializationHandler::ConvertF16toU8(data, uint8Data);
387  break;
388  }
389  case DType::DType_INT48:
390  {
391  std::vector<int64_t> data(numElements, *static_cast<const int64_t*>(value));
392  error = TosaSerializationHandler::ConvertI48toU8(data, uint8Data);
393  break;
394  }
395  case DType::DType_INT32:
396  {
397  std::vector<int32_t> data(numElements, *static_cast<const int32_t*>(value));
398  error = TosaSerializationHandler::ConvertI32toU8(data, uint8Data);
399  break;
400  }
401  case DType::DType_INT16:
402  {
403  std::vector<int16_t> data(numElements, *static_cast<const int16_t*>(value));
404  error = TosaSerializationHandler::ConvertI16toU8(data, uint8Data);
405  break;
406  }
407  case DType::DType_INT8:
408  {
409  std::vector<int8_t> data(numElements, *static_cast<const int8_t*>(value));
410  error = TosaSerializationHandler::ConvertI8toU8(data, uint8Data);
411  break;
412  }
413  case DType::DType_INT4:
414  {
415  std::vector<int8_t> data(numElements, *static_cast<const int8_t*>(value));
416  error = TosaSerializationHandler::ConvertI4toU8(data, uint8Data);
417  break;
418  }
419  case DType::DType_BOOL:
420  {
421  std::vector<bool> data(numElements, *static_cast<const bool*>(value));
422  error = TosaSerializationHandler::ConvertBooltoU8(data, uint8Data);
423  break;
424  }
425  default:
426  {
427  throw armnn::Exception("CreateConstTosaData: An unsupported data type was encountered.");
428  }
429  }
430 
431  if(error != tosa_err_t::TOSA_OK)
432  {
433  throw armnn::Exception("CreateConstTosaData: An error occurred when converting constant data");
434  }
435 
436  return uint8Data;
437 }
438 
439 template<typename T>
440 inline void CreateConstTosaOperator(const std::string& outputName,
441  const T value,
442  DType dtype,
443  const std::vector<int32_t>& shape,
444  TosaSerializationOperator*& op,
445  TosaSerializationTensor*& tensor)
446 {
447  std::vector<uint8_t> uint8Data = CreateConstTosaData(static_cast<const void *>(&value), dtype, shape);
448 
449  op = new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {outputName});
450  ARMNN_THROW_MSG_IF_FALSE(op, armnn::Exception, "CreateConstTosaOperator: failed to created operator");
451 
452  tensor = new TosaSerializationTensor(outputName, shape, dtype, uint8Data);
453  ARMNN_THROW_MSG_IF_FALSE(tensor, armnn::Exception, "CreateConstTosaOperator: failed to created tensor");
454 }
455 
456 // Macro to preserve usage of a code block as the TOSA library version advances. Parameters
457 // specify the minimum version required by the code block.
458 #define TOSA_COMPAT_VERSION(_major, _minor, _patch) \
459  (TOSA_VERSION_MAJOR >= _major) || \
460  (TOSA_VERSION_MINOR >= _minor) || \
461  (TOSA_VERSION_PATCH >= _patch)
armnn::DataType::Boolean
@ Boolean
armnn::InputSlot::GetOwningLayer
Layer & GetOwningLayer() const
Definition: Layer.hpp:53
armnn::DataType::Float32
@ Float32
armnn::Layer::GetOutputSlot
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:339
ConvertConstantTensorDataToBuffer
std::vector< uint8_t > ConvertConstantTensorDataToBuffer(const std::shared_ptr< ConstTensorHandle > &tensorHandle)
Definition: TosaOperatorUtils.hpp:289
armnn::DataType::QAsymmU8
@ QAsymmU8
armnn::DataType::QSymmS8
@ QSymmS8
TosaOpToString
std::string TosaOpToString(Op tosaOp)
Definition: TosaOperatorUtils.hpp:139
armnn::BoostLogSeverityMapping::error
@ error
armnn::DataType::QSymmS16
@ QSymmS16
armnn::DataType::BFloat16
@ BFloat16
armnn::Layer
Definition: Layer.hpp:230
mainName
const std::string mainName
Definition: TosaOperatorUtils.hpp:19
armnn::TensorShape
Definition: Tensor.hpp:20
armnn::DataType::Float16
@ Float16
armnn::TensorShape::GetNumDimensions
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
Definition: Tensor.cpp:174
ArmNNToDType
DType ArmNNToDType(const DataType &type)
Definition: TosaOperatorUtils.hpp:22
GenerateUniqueOutputName
std::string GenerateUniqueOutputName(const Layer &layer, uint32_t layerSlot)
Definition: TosaOperatorUtils.hpp:82
armnn::DataType
DataType
Definition: Types.hpp:48
armnn::Layer::GetGuid
LayerGuid GetGuid() const final
Returns the unique id of the layer.
Definition: Layer.hpp:343
armnn::Exception
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
ARMNN_THROW_MSG_IF_FALSE
#define ARMNN_THROW_MSG_IF_FALSE(_cond, _except, _str)
Definition: Exceptions.hpp:206
armnn::DataType::Signed32
@ Signed32
armnn::DataType::QAsymmS8
@ QAsymmS8
CreateConstTosaOperator
void CreateConstTosaOperator(const std::string &outputName, const T value, DType dtype, const std::vector< int32_t > &shape, TosaSerializationOperator *&op, TosaSerializationTensor *&tensor)
Definition: TosaOperatorUtils.hpp:440
CreateConstTosaData
std::vector< uint8_t > CreateConstTosaData(const void *value, DType dtype, const std::vector< int32_t > &shape)
Definition: TosaOperatorUtils.hpp:358
armnn::Layer::GetType
LayerType GetType() const override
Returns the armnn::LayerType of this layer.
Definition: Layer.hpp:286
Tensor.hpp
GenerateUniqueName
std::string GenerateUniqueName(const Layer &layer, uint32_t layerSlot)
Definition: TosaOperatorUtils.hpp:63
TosaDTypeToString
std::string TosaDTypeToString(DType tosaDType)
Definition: TosaOperatorUtils.hpp:106
GetTosaTensorShape
std::vector< int32_t > GetTosaTensorShape(const TensorShape &shape)
Definition: TosaOperatorUtils.hpp:52
armnn
Copyright (c) 2021 ARM Limited and Contributors.
Definition: 01_00_quick_start.dox:6
Types.hpp
Layer.hpp
armnn::LayerType::Input
@ Input
armnn::DataType::Signed64
@ Signed64
armnn::OutputSlot::GetConnection
const InputSlot * GetConnection(unsigned int index) const override
Definition: Layer.cpp:75
armnn::LayerType::Output
@ Output
armnn::LayerType::Constant
@ Constant
GetUniqueTosaMappingID
std::string GetUniqueTosaMappingID()
Definition: TosaOperatorUtils.hpp:100