16{
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
58 "ConvertSpaceToBatchToTosaOperator: SpaceToBatch must have only one input");
59
61 "ConvertSpaceToBatchToTosaOperator: SpaceToBatch must have only one output");
62
63 std::string inputName = "input_";
67 std::string outputName = "output0_";
69
70 if (layer != nullptr)
71 {
74 }
75
76 const auto& paddings = spaceToBatchDescriptor->
m_PadList;
77 const auto& blockShape = spaceToBatchDescriptor->
m_BlockShape;
78 const unsigned int inputRank = inputs[0]->GetShape().GetNumDimensions();
79 const unsigned int blockRank = static_cast<unsigned int>(blockShape.size());
81
82 if (inputRank <= blockRank)
83 {
84 throw armnn::Exception(
"ConvertSpaceToBatchToTosaOperator: input rank must be greater than block rank");
85 }
86
87 std::vector<TosaSerializationTensor*> tensors;
88 std::vector<TosaSerializationOperator*> operators;
89
90
91
92 std::vector<int32_t> a0Pad(2 * inputRank, 0);
93 std::vector<int32_t> paddedShape = inputShape;
94
95 DType inputDType =
ArmNNToDType(inputs[0]->GetDataType());
96
97 if (inputName.find("input_") != std::string::npos)
98 {
99 tensors.push_back(new TosaSerializationTensor(inputName, inputShape, inputDType, {}));
100 }
101
102 for (size_t i = 0; i < blockShape.size(); ++i)
103 {
104 int32_t loPad = static_cast<int32_t>(paddings[i].first);
105 int32_t hiPad = static_cast<int32_t>(paddings[i].second);
106 size_t dimIndex = i + 1;
107 a0Pad[2 * dimIndex] = loPad;
108 a0Pad[2 * dimIndex + 1] = hiPad;
109 paddedShape[dimIndex] = inputShape[dimIndex] + loPad + hiPad;
110 }
111
112 std::string padOutput = outputNamePad + "_padded";
113
114 tensors.push_back(new TosaSerializationTensor(padOutput, paddedShape, inputDType, {}));
115
116
117 float padValue = 0.0f;
118 if (inputs[0]->IsQuantized())
119 {
120 padValue = static_cast<float>(inputs[0]->GetQuantizationOffset()) * inputs[0]->GetQuantizationScale();
121 }
122
123 TosaPadAttribute padAttr(a0Pad, 0, padValue);
124 operators.push_back(new TosaSerializationOperator(Op_PAD,
125 Attribute_PadAttribute,
126 &padAttr,
127 {inputName},
128 {padOutput}));
129
130
131 std::vector<int32_t> reshape1;
132
133 reshape1.push_back(inputShape[0]);
134
135
136 int32_t blockNumElems = 1;
137
138
139 for (size_t i = 0; i < blockShape.size(); ++i)
140 {
141 int32_t paddedDim = paddedShape[i + 1];
142 int32_t blockDim = static_cast<int32_t>(blockShape[i]);
143 if (paddedDim % blockDim != 0)
144 {
145 throw armnn::Exception(
"ConvertSpaceToBatchToTosaOperator: padded spatial dim not divisible by block size");
146 }
147 reshape1.push_back(paddedDim / blockDim);
148 reshape1.push_back(blockDim);
149
150 blockNumElems *= blockDim;
151 }
152
153
154 for (size_t i = 1 + blockShape.size(); i < inputShape.size(); ++i)
155 {
156 reshape1.push_back(inputShape[i]);
157 }
158
159 tensors.push_back(new TosaSerializationTensor(outputNameReshape1, reshape1, inputDType, {}));
160 TosaReshapeAttribute reshapeAttr(reshape1);
161 operators.push_back(new TosaSerializationOperator(Op_RESHAPE,
162 Attribute_ReshapeAttribute,
163 &reshapeAttr,
164 {padOutput},
165 {outputNameReshape1}));
166
167 std::vector<int32_t> transposeVec;
168
169
170 for (size_t i = 0; i < blockShape.size(); ++i)
171 {
172 transposeVec.push_back(static_cast<int32_t>(1 + 2 * i + 1));
173 }
174
175 transposeVec.push_back(0);
176
177
178 for (size_t i = 0; i < blockShape.size(); ++i)
179 {
180 transposeVec.push_back(static_cast<int32_t>(1 + 2 * i));
181 }
182
183
184 for (size_t i = 1 + 2 * blockShape.size(); i < reshape1.size(); ++i)
185 {
186 transposeVec.push_back(static_cast<int32_t>(i));
187 }
188
189 std::vector<int32_t> transposeShape(transposeVec.size());
190 for (size_t i = 0; i < transposeVec.size(); ++i)
191 {
192 transposeShape[i] = reshape1[static_cast<size_t>(transposeVec[i])];
193 }
194 tensors.push_back(new TosaSerializationTensor(outputNameTranspose, transposeShape, inputDType, {}));
195
196 TosaTransposeAttribute transposeAttr(transposeVec);
197
198 operators.push_back(new TosaSerializationOperator(Op_TRANSPOSE,
199 Attribute_TransposeAttribute,
200 &transposeAttr,
201 {outputNameReshape1},
202 {outputNameTranspose}));
203
204
205 std::vector<int32_t> reshape2;
206
207 const int32_t newBatch = static_cast<int32_t>(inputShape[0]) * static_cast<int32_t>(blockNumElems);
208 reshape2.push_back(newBatch);
209
210
211 for (size_t i = 0; i < blockShape.size(); ++i)
212 {
213 int32_t paddedDim = paddedShape[i + 1];
214 int32_t blockDim = static_cast<int32_t>(blockShape[i]);
215
216 if (blockDim == 0 || paddedDim % blockDim != 0)
217 {
218 throw armnn::Exception(
"ConvertSpaceToBatchToTosaOperator: Invalid block Shape or padding in final reshape");
219 }
220
221 reshape2.push_back(paddedDim / blockDim);
222 }
223
224
225 reshape2.push_back(inputShape.back());
226 tensors.push_back(new TosaSerializationTensor(outputName, reshape2, inputDType, {}));
227
228 TosaReshapeAttribute reshape2Attr(reshape2);
229 operators.push_back(new TosaSerializationOperator(Op_RESHAPE,
230 Attribute_ReshapeAttribute,
231 &reshape2Attr,
232 {outputNameTranspose},
233 {outputName}));
234
236
237 if (reshape2 != expectedShape)
238 {
239 throw armnn::Exception(
"ConvertSpaceToBatchToTosaOperator: Mismatch expected output and generated shape differ");
240 }
241
242 return new TosaSerializationBasicBlock(blockName,
mainName, operators, tensors, {inputName}, {outputName});
243}
#define ARMNN_THROW_INVALIDARG_MSG_IF_FALSE(_cond, _str)
std::string GenerateUniqueOutputName(const Layer &layer, uint32_t layerSlot=0)
const std::string mainName
DType ArmNNToDType(const DataType &type)
std::string GenerateUniqueInputName(const armnn::InputSlot &slot)
std::string GetUniqueTosaMappingID()
std::vector< int32_t > GetTosaTensorShape(const TensorShape &shape)
Base class for all ArmNN exceptions so that users can filter to just those.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
std::vector< unsigned int > m_BlockShape
Block shape value.
std::vector< std::pair< unsigned int, unsigned int > > m_PadList
Specifies the padding values for the input dimension: heightPad{top, bottom} widthPad{left,...