ArmNN
 26.07
TosaRefLayerSupport.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2022-2025 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
7 
9 
10 #include <armnn/Types.hpp>
12 
13 #include <graph_status.h>
14 #include <model_runner.h>
15 
16 #include <vector>
17 
18 namespace armnn
19 {
20 
22  const std::vector<TensorInfo>& infos,
23  const BaseDescriptor& descriptor,
24  const Optional<LstmInputParamsInfo>& lstmParamsInfo,
25  const Optional<QuantizedLstmInputParamsInfo>& quantizedLstmInputParamsInfo,
26  Optional<std::string&> reasonIfUnsupported) const
27 {
28  for (const auto& info : infos)
29  {
30  if (info.GetDataType() == DataType::Signed64)
31  {
32  reasonIfUnsupported.value() = "TOSA does not have INT64 support for TOSARef backend";
33  return false;
34  }
35 
36  // ArmNN U8 tensors are supported for TOSA if they are followed or preceeded by a Quantize layer
37  if (info.GetDataType() == DataType::QAsymmU8 &&
38  type != LayerType::Input &&
39  type != LayerType::Quantize &&
40  type != LayerType::Output)
41  {
42  reasonIfUnsupported.value() = "Must use a Quantize layer to/from unsigned INT for TOSARef backend";
43  return false;
44  }
45  }
46 
47  IgnoreUnused(lstmParamsInfo);
48  IgnoreUnused(quantizedLstmInputParamsInfo);
49  IgnoreUnused(reasonIfUnsupported);
50 
51  std::vector<const TensorInfo*> inputInfos;
52  std::vector<const TensorInfo*> outputInfos;
53 
54  switch (type)
55  {
56  case LayerType::Input:
57  case LayerType::Output:
58  return true;
62  case LayerType::Gather:
65  case LayerType::Prelu:
66  // Setup inputs and outputs
67  inputInfos.push_back(&infos[0]);
68  inputInfos.push_back(&infos[1]);
69  outputInfos.push_back(&infos[2]);
70  break;
71  case LayerType::Concat:
72  for (unsigned int i = 0; i < infos.size() - 1; ++i)
73  {
74  inputInfos.push_back(&infos[i]);
75  }
76  outputInfos.push_back(&infos.back());
77  break;
79  outputInfos.push_back(&infos[0]);
80  break;
82  {
83  inputInfos.push_back(&infos[0]); // input
84  outputInfos.push_back(&infos[1]); // output
85  inputInfos.push_back(&infos[2]); // weights
86 
87  auto conv2dDesc = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor);
88  if(conv2dDesc->m_BiasEnabled)
89  {
90  inputInfos.push_back(&infos[3]); // bias
91  }
92  break;
93  }
95  {
96  inputInfos.push_back(&infos[0]); // input
97  outputInfos.push_back(&infos[1]); // output
98  inputInfos.push_back(&infos[2]); // weights
99 
100  auto conv3dDesc = PolymorphicDowncast<const Convolution3dDescriptor*>(&descriptor);
101  if(conv3dDesc->m_BiasEnabled)
102  {
103  inputInfos.push_back(&infos[3]); // bias
104  }
105  break;
106  }
108  {
109  inputInfos.push_back(&infos[0]); // input
110  outputInfos.push_back(&infos[1]); // output
111  inputInfos.push_back(&infos[2]); // weights
112 
113  auto conv2dDesc = PolymorphicDowncast<const DepthwiseConvolution2dDescriptor*>(&descriptor);
114  if(conv2dDesc->m_BiasEnabled)
115  {
116  inputInfos.push_back(&infos[3]); // bias
117  }
118  break;
119  }
121  {
122  inputInfos.push_back(&infos[0]); // input
123  outputInfos.push_back(&infos[1]); // output
124  inputInfos.push_back(&infos[2]); // weights
125  auto fullyConnectedDesc = PolymorphicDowncast<const FullyConnectedDescriptor*>(&descriptor);
126  if(fullyConnectedDesc->m_BiasEnabled)
127  {
128  inputInfos.push_back(&infos[3]); // bias
129  }
130  break;
131  }
136  case LayerType::Pad:
138  case LayerType::Mean:
139  case LayerType::Quantize:
140  case LayerType::Reduce:
141  case LayerType::Reshape:
142  case LayerType::Resize:
143  case LayerType::Slice:
144  case LayerType::Softmax:
149  {
150  inputInfos.push_back(&infos[0]);
151  outputInfos.push_back(&infos[1]);
152  break;
153  }
154  case LayerType::Splitter:
155  {
156  inputInfos.push_back(&infos[0]);
157  for (unsigned int i = 1; i < infos.size(); ++i)
158  {
159  outputInfos.push_back(&infos[i]);
160  }
161  break;
162  }
164  {
165  inputInfos.push_back(&infos[0]); // input
166  outputInfos.push_back(&infos[1]); // output
167  inputInfos.push_back(&infos[2]); // weights
168 
169  auto conv2dDesc = PolymorphicDowncast<const TransposeConvolution2dDescriptor*>(&descriptor);
170  if(conv2dDesc->m_BiasEnabled)
171  {
172  inputInfos.push_back(&infos[3]); // bias
173  }
174  break;
175  }
176  case LayerType::Stack:
177  {
178  auto stackDesc = PolymorphicDowncast<const StackDescriptor*>(&descriptor);
179  for (unsigned int i = 0; i < stackDesc->m_NumInputs; ++i)
180  {
181  inputInfos.emplace_back(&infos[i]);
182  }
183  outputInfos.emplace_back(&infos[stackDesc->m_NumInputs]);
184  break;
185  }
186  default:
187  // Default to false for all unsupported layers.
188  return false;
189  }
190 
191  auto mappings = GetTosaMapping(nullptr, type, inputInfos, outputInfos, descriptor);
192  if (mappings->GetName() == "")
193  {
194  // There currently isn't a TOSA mapping for this layer, as the default was returned.
195  return false;
196  }
197 
198  TosaSerializationHandler handler;
199 
200  // Add all mappings to main block.
201  auto* block = new TosaSerializationBasicBlock("main",
202  "main",
203  mappings->GetOperators(),
204  mappings->GetTensors(),
205  mappings->GetInputs(),
206  mappings->GetOutputs());
207 
208  std::vector<TosaSerializationBasicBlock*> blocks;
209  blocks.emplace_back(block);
210 
211  // Add blocks to the main region.
212  auto* region = new TosaSerializationRegion("main", blocks);
213  handler.GetRegions().emplace_back(region);
214 
215  GraphStatus status;
216  TosaReference::IModelRunner runner;
217 
218 #if !defined(TOSA_REFERENCE_MODEL_OUTPUT)
219  // There currently isn't a way to disable the output from the TOSA Reference Model, but it does have a file pointer
220  // to write debug output to, so set this to /dev/null (if it exists on the system) to hide the output.
221  func_debug_t funcDebug;
222 
223  FILE* file = fopen("/dev/null", "w");
224  funcDebug.func_debug_file = (file == nullptr) ? stderr : file;
225 
226  runner.setFuncDebug(funcDebug);
227 #endif
228 
229  // Initialise the model runner with the TosaSerializationHandler, which runs validation on the mapping.
230  status = runner.initialize(handler);
231 
232 #if !defined(TOSA_REFERENCE_MODEL_OUTPUT)
233  // Reset FuncDebug as they can persist across multiple IModelRunner instances.
234  funcDebug.func_debug_file = stderr;
235  runner.setFuncDebug(funcDebug);
236 #endif
237 
238  if(status == GraphStatus::TOSA_ERROR || status == GraphStatus::TOSA_UNPREDICTABLE)
239  {
240  return false;
241  }
242  else
243  {
244  return true;
245  }
246 }
247 
248 } // namespace armnn
TosaSerializationBasicBlock * GetTosaMapping(const Layer *layer, const LayerType type, const std::vector< const TensorInfo * > &inputs, const std::vector< const TensorInfo * > &outputs, const BaseDescriptor &descriptor)
bool IsLayerSupported(const LayerType &type, const std::vector< TensorInfo > &infos, const BaseDescriptor &descriptor, const Optional< LstmInputParamsInfo > &lstmParamsInfo, const Optional< QuantizedLstmInputParamsInfo > &, Optional< std::string & > reasonIfUnsupported) const override
Default implementation of the ILayerSupport interface, Backends should implement this as a switch sta...
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
LayerType
When adding a new layer, adapt also the LastLayer enum value in the enum class LayerType below.
Definition: Types.hpp:494
Base class for all descriptors.
Definition: Descriptors.hpp:23