ArmNN
 26.07
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 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  if(inputName.find("input_") != std::string::npos)
73  {
74  tensors.emplace_back(new TosaSerializationTensor(inputName,
75  GetTosaTensorShape(inputs[i]->GetShape()),
76  inputDType,
77  {}));
78  }
79 
80  inputNames.push_back(inputName);
81  }
82 
83  // Create output tensor
84 
85  tensors.emplace_back(new TosaSerializationTensor(outputName,
86  blockOutputShape,
87  inputDType,
88  {}));
89 
90  bool transposeOpNeeded = (stackDescriptor->m_Axis == inputTensorRank);
91 
92  // Determine concatenation properties and transpose permutation
93  std::vector<int32_t> permutationOrder;
94  std::vector<int32_t> reshapeOutputShape;
95  uint32_t concatAxis;
96  if (transposeOpNeeded)
97  {
98  concatAxis = 0;
99 
100  reshapeOutputShape.push_back(static_cast<int32_t>(blockOutputShape[stackDescriptor->m_Axis]));
101 
102  for (unsigned int d = 0; d < inputTensorRank; d++)
103  {
104  permutationOrder.push_back(static_cast<int32_t>(d) + 1);
105  reshapeOutputShape.push_back(static_cast<int32_t>(blockOutputShape[d]));
106  }
107  permutationOrder.push_back(0);
108  }
109  else
110  {
111  concatAxis = stackDescriptor->m_Axis;
112  }
113 
114  // Determine concatenated output shape
115  std::vector<int32_t> concatOutputShape;
116  auto inputTensorShape = GetTosaTensorShape(stackDescriptor->m_InputShape);
117  for (unsigned int i = 0; i < inputTensorRank; i++)
118  {
119  concatOutputShape.push_back(inputTensorShape[i]);
120  }
121 
122  concatOutputShape[concatAxis] *= static_cast<int>(stackDescriptor->m_NumInputs);
123 
124  // Concatenation operator
125  std::string concatOutputName = std::string("layer_intermediate1_concat_") + GetUniqueTosaMappingID();
126 
127  TosaAxisAttribute axisAttribute(static_cast<int32_t>(concatAxis));
128 
129  auto* concatOp = new TosaSerializationOperator(Op_CONCAT,
130  Attribute_AxisAttribute,
131  &axisAttribute,
132  inputNames,
133  {concatOutputName});
134  operators.push_back(concatOp);
135 
136  tensors.emplace_back(new TosaSerializationTensor(concatOutputName,
137  concatOutputShape,
138  inputDType,
139  {}));
140 
141  // Reshape operator
142  std::string reshapeOutputName = std::string("layer_intermediate2_reshape_") + GetUniqueTosaMappingID();
143  std::string& reshapeOpOutputName = transposeOpNeeded ? reshapeOutputName : outputName;
144 
145  TosaReshapeAttribute reshapeAttribute = transposeOpNeeded ? reshapeOutputShape : blockOutputShape;
146 
147  auto* reshapeOp = new TosaSerializationOperator(Op_RESHAPE,
148  Attribute_ReshapeAttribute,
149  &reshapeAttribute,
150  {concatOutputName},
151  {reshapeOpOutputName});
152  operators.push_back(reshapeOp);
153 
154  if (transposeOpNeeded)
155  {
156  // Transpose operator
157  tensors.emplace_back(new TosaSerializationTensor(reshapeOutputName,
158  reshapeOutputShape,
159  inputDType,
160  {}));
161 
162  TosaTransposeAttribute transposeAttribute(permutationOrder);
163 
164  TosaSerializationOperator *transposeOp = new TosaSerializationOperator(Op_TRANSPOSE,
165  Attribute_TransposeAttribute,
166  &transposeAttribute,
167  {reshapeOutputName},
168  {outputName});
169  operators.push_back(transposeOp);
170  }
171 
172  // operatorInputNames/operatorOutputNames ends up being the same as
173  // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings
174  return new TosaSerializationBasicBlock(blockName, // name
175  mainName, // region name
176  operators, // operators
177  tensors, // tensors
178  inputNames, // inputs
179  {outputName}); // outputs
180 }
#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().