ArmNN
 25.02
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
StackOperator.hpp File Reference
Include dependency graph for StackOperator.hpp:
This graph shows which files directly or indirectly include this file:

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 outputName = std::string("output0_");
51 
52  std::string blockName = std::string("Op_STACK_block_") + GetUniqueTosaMappingID();
53  auto blockOutputShape = GetTosaTensorShape(outputs[0]->GetShape());
54 
55  // Create input tensors
56  std::vector<std::string> inputNames;
57  for (unsigned int i = 0; i < inputs.size(); ++i)
58  {
59  if (inputs[i]->GetShape() != stackDescriptor->m_InputShape)
60  {
61  throw armnn::Exception("ConvertStackToTosaOperator: Inputs have mismatched shapes.");
62  }
63 
64  std::string inputName = "input" + std::to_string(i) + "_";
65 
66  if (layer != nullptr)
67  {
68  inputName = GenerateUniqueInputName(layer->GetInputSlot(i));
69  outputName = GenerateUniqueOutputName(*layer);
70  }
71 
72  tensors.emplace_back(new TosaSerializationTensor(inputName,
73  GetTosaTensorShape(inputs[i]->GetShape()),
74  inputDType,
75  {}));
76  inputNames.push_back(inputName);
77  }
78 
79  // Create output tensor
80  tensors.emplace_back(new TosaSerializationTensor(outputName,
81  blockOutputShape,
82  inputDType,
83  {}));
84 
85  bool transposeOpNeeded = (stackDescriptor->m_Axis == inputTensorRank);
86 
87  // Determine concatenation properties and transpose permutation
88  std::vector<int32_t> permutationOrder;
89  std::vector<int32_t> reshapeOutputShape;
90  uint32_t concatAxis;
91  if (transposeOpNeeded)
92  {
93  concatAxis = 0;
94 
95  reshapeOutputShape.push_back(static_cast<int32_t>(blockOutputShape[stackDescriptor->m_Axis]));
96 
97  for (unsigned int d = 0; d < inputTensorRank; d++)
98  {
99  permutationOrder.push_back(static_cast<int32_t>(d) + 1);
100  reshapeOutputShape.push_back(static_cast<int32_t>(blockOutputShape[d]));
101  }
102  permutationOrder.push_back(0);
103  }
104  else
105  {
106  concatAxis = stackDescriptor->m_Axis;
107  }
108 
109  // Determine concatenated output shape
110  std::vector<int32_t> concatOutputShape;
111  auto inputTensorShape = GetTosaTensorShape(stackDescriptor->m_InputShape);
112  for (unsigned int i = 0; i < inputTensorRank; i++)
113  {
114  concatOutputShape.push_back(inputTensorShape[i]);
115  }
116 
117  concatOutputShape[concatAxis] *= static_cast<int>(stackDescriptor->m_NumInputs);
118 
119  // Concatenation operator
120  std::string concatOutputName = std::string("intermediate1_concat_") + GetUniqueTosaMappingID();
121 
122  TosaAxisAttribute axisAttribute(static_cast<int32_t>(concatAxis));
123 
124  auto* concatOp = new TosaSerializationOperator(Op_CONCAT,
125  Attribute_AxisAttribute,
126  &axisAttribute,
127  inputNames,
128  {concatOutputName});
129  operators.push_back(concatOp);
130 
131  tensors.emplace_back(new TosaSerializationTensor(concatOutputName,
132  concatOutputShape,
133  inputDType,
134  {}));
135 
136  // Reshape operator
137  std::string reshapeOutputName = std::string("intermediate2_reshape_") + GetUniqueTosaMappingID();
138  std::string& reshapeOpOutputName = transposeOpNeeded ? reshapeOutputName : outputName;
139 
140  TosaReshapeAttribute reshapeAttribute = transposeOpNeeded ? reshapeOutputShape : blockOutputShape;
141 
142  auto* reshapeOp = new TosaSerializationOperator(Op_RESHAPE,
143  Attribute_ReshapeAttribute,
144  &reshapeAttribute,
145  {concatOutputName},
146  {reshapeOpOutputName});
147  operators.push_back(reshapeOp);
148 
149  if (transposeOpNeeded)
150  {
151  // Transpose operator
152  tensors.emplace_back(new TosaSerializationTensor(reshapeOutputName,
153  reshapeOutputShape,
154  inputDType,
155  {}));
156 
157  TosaTransposeAttribute transposeAttribute(permutationOrder);
158 
159  TosaSerializationOperator *transposeOp = new TosaSerializationOperator(Op_TRANSPOSE,
160  Attribute_TransposeAttribute,
161  &transposeAttribute,
162  {reshapeOutputName},
163  {outputName});
164  operators.push_back(transposeOp);
165  }
166 
167  // operatorInputNames/operatorOutputNames ends up being the same as
168  // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings
169  return new TosaSerializationBasicBlock(blockName, // name
170  mainName, // region name
171  operators, // operators
172  tensors, // tensors
173  inputNames, // inputs
174  {outputName}); // outputs
175 }
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
Definition: Exceptions.hpp:210
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()
Base class for all ArmNN exceptions so that users can filter to just those.
Definition: Exceptions.hpp:47
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition: Layer.hpp:337
TensorShape m_InputShape
Required shape of all input tensors.
uint32_t m_Axis
0-based axis along which to stack the input tensors.
uint32_t m_NumInputs
Number of input tensors.

References ARMNN_THROW_INVALIDARG_MSG_IF_FALSE.

Referenced by GetTosaMapping().