ArmNN
 24.11
StackOperator.cpp File Reference
#include "StackOperator.hpp"
Include dependency graph for StackOperator.cpp:

Go to the source code of this file.

Functions

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

Function Documentation

◆ ConvertStackToTosaOperator()

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

Definition at line 14 of file StackOperator.cpp.

18 {
19  ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(inputs.size() >= 1,
20  "ConvertStackToTosaOperator: Stack must have at least one input");
21 
22  ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(outputs.size() == 1,
23  "ConvertStackToTosaOperator: Stack must have only one output");
24 
25  ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(inputs[0]->GetShape() != TensorShape(Dimensionality::Scalar),
26  "ConvertStackToTosaOperator: Scalar / Rank 0 input not supported");
27 
28  const auto inputTensorRank = inputs[0]->GetNumDimensions();
29 
30  ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(inputTensorRank != 0,
31  "ConvertStackToTosaOperator: Scalar / Rank 0 input not supported");
32 
33  // Verify axis value
34  if (stackDescriptor->m_Axis > inputTensorRank)
35  {
36  throw armnn::Exception("ConvertStackToTosaOperator: Axis is out of a valid range.");
37  }
38 
39  // Verify output rank
40  if (outputs[0]->GetNumDimensions() != inputTensorRank + 1)
41  {
42  throw armnn::Exception("ConvertStackToTosaOperator: Output shape mismatch.");
43  }
44 
45  auto inputDType = ArmNNToDType(inputs[0]->GetDataType());
46 
47  std::vector<TosaSerializationTensor*> tensors;
48  std::vector<TosaSerializationOperator*> operators;
49 
50  std::string blockName = std::string("Op_STACK_block_") + GetUniqueTosaMappingID();
51  auto blockOutputShape = GetTosaTensorShape(outputs[0]->GetShape());
52 
53  // Create input tensors
54  std::vector<std::string> inputNames;
55  for (unsigned int i = 0; i < inputs.size(); ++i)
56  {
57  if (inputs[i]->GetShape() != stackDescriptor->m_InputShape)
58  {
59  throw armnn::Exception("ConvertStackToTosaOperator: Inputs have mismatched shapes.");
60  }
61 
62  std::string inputName = "input" + std::to_string(i) + "_";
63 
64  if (layer != nullptr)
65  {
66  inputName = GenerateUniqueInputName(layer->GetInputSlot(i));
67  }
68 
69  tensors.emplace_back(new TosaSerializationTensor(inputName,
70  GetTosaTensorShape(inputs[i]->GetShape()),
71  inputDType,
72  {}));
73  inputNames.push_back(inputName);
74  }
75 
76  // Create output tensor
77  std::string outputName = std::string("output0_");
78  tensors.emplace_back(new TosaSerializationTensor(outputName,
79  blockOutputShape,
80  inputDType,
81  {}));
82 
83  bool transposeOpNeeded = (stackDescriptor->m_Axis == inputTensorRank);
84 
85  // Determine concatenation properties and transpose permutation
86  std::vector<int32_t> permutationOrder;
87  std::vector<int32_t> reshapeOutputShape;
88  uint32_t concatAxis;
89  if (transposeOpNeeded)
90  {
91  concatAxis = 0;
92 
93  reshapeOutputShape.push_back(static_cast<int32_t>(blockOutputShape[stackDescriptor->m_Axis]));
94 
95  for (unsigned int d = 0; d < inputTensorRank; d++)
96  {
97  permutationOrder.push_back(static_cast<int32_t>(d) + 1);
98  reshapeOutputShape.push_back(static_cast<int32_t>(blockOutputShape[d]));
99  }
100  permutationOrder.push_back(0);
101  }
102  else
103  {
104  concatAxis = stackDescriptor->m_Axis;
105  }
106 
107  // Determine concatenated output shape
108  std::vector<int32_t> concatOutputShape;
109  auto inputTensorShape = GetTosaTensorShape(stackDescriptor->m_InputShape);
110  for (unsigned int i = 0; i < inputTensorRank; i++)
111  {
112  concatOutputShape.push_back(inputTensorShape[i]);
113  }
114 
115  concatOutputShape[concatAxis] *= static_cast<int>(stackDescriptor->m_NumInputs);
116 
117  // Concatenation operator
118  std::string concatOutputName = std::string("intermediate1_concat_") + GetUniqueTosaMappingID();
119 
120  TosaAxisAttribute axisAttribute(static_cast<int32_t>(concatAxis));
121 
122  auto* concatOp = new TosaSerializationOperator(Op_CONCAT,
123  Attribute_AxisAttribute,
124  &axisAttribute,
125  inputNames,
126  {concatOutputName});
127  operators.push_back(concatOp);
128 
129  tensors.emplace_back(new TosaSerializationTensor(concatOutputName,
130  concatOutputShape,
131  inputDType,
132  {}));
133 
134  // Reshape operator
135  std::string reshapeOutputName = std::string("intermediate2_reshape_") + GetUniqueTosaMappingID();
136  std::string& reshapeOpOutputName = transposeOpNeeded ? reshapeOutputName : outputName;
137 
138  TosaReshapeAttribute reshapeAttribute = transposeOpNeeded ? reshapeOutputShape : blockOutputShape;
139 
140  auto* reshapeOp = new TosaSerializationOperator(Op_RESHAPE,
141  Attribute_ReshapeAttribute,
142  &reshapeAttribute,
143  {concatOutputName},
144  {reshapeOpOutputName});
145  operators.push_back(reshapeOp);
146 
147  if (transposeOpNeeded)
148  {
149  // Transpose operator
150  tensors.emplace_back(new TosaSerializationTensor(reshapeOutputName,
151  reshapeOutputShape,
152  inputDType,
153  {}));
154 
155  TosaTransposeAttribute transposeAttribute(permutationOrder);
156 
157  TosaSerializationOperator *transposeOp = new TosaSerializationOperator(Op_TRANSPOSE,
158  Attribute_TransposeAttribute,
159  &transposeAttribute,
160  {reshapeOutputName},
161  {outputName});
162  operators.push_back(transposeOp);
163  }
164 
165  // operatorInputNames/operatorOutputNames ends up being the same as
166  // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings
167  return new TosaSerializationBasicBlock(blockName, // name
168  mainName, // region name
169  operators, // operators
170  tensors, // tensors
171  inputNames, // inputs
172  {outputName}); // outputs
173 }

References ARMNN_THROW_INVALIDARG_MSG_IF_FALSE.

Referenced by GetTosaMapping().

armnn::Layer::GetInputSlot
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:337
mainName
const std::string mainName
Definition: TosaOperatorUtils.hpp:19
armnn::TensorShape
Definition: Tensor.hpp:20
armnn::StackDescriptor::m_NumInputs
uint32_t m_NumInputs
Number of input tensors.
Definition: Descriptors.hpp:1275
ArmNNToDType
DType ArmNNToDType(const DataType &type)
Definition: TosaOperatorUtils.hpp:22
armnn::StackDescriptor::m_Axis
uint32_t m_Axis
0-based axis along which to stack the input tensors.
Definition: Descriptors.hpp:1273
armnn::Exception
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:46
armnn::StackDescriptor::m_InputShape
TensorShape m_InputShape
Required shape of all input tensors.
Definition: Descriptors.hpp:1277
GetTosaTensorShape
std::vector< int32_t > GetTosaTensorShape(const TensorShape &shape)
Definition: TosaOperatorUtils.hpp:79
GenerateUniqueInputName
std::string GenerateUniqueInputName(const armnn::InputSlot &slot)
Definition: TosaOperatorUtils.hpp:109
GetUniqueTosaMappingID
std::string GetUniqueTosaMappingID()
Definition: TosaOperatorUtils.hpp:138
ARMNN_THROW_INVALIDARG_MSG_IF_FALSE
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
Definition: Exceptions.hpp:210