xref: /aosp_15_r20/external/armnn/src/backends/tosaCommon/test/TosaTestUtils.hpp (revision 89c4ff92f2867872bb9e2354d150bf0c8c502810)
1 //
2 // Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include <Layer.hpp>
9 
10 #include <tosaCommon/TosaMappings.hpp>
11 #include <tosaCommon/operatorMappings/TosaOperatorUtils.hpp>
12 
13 #include <doctest/doctest.h>
14 #include <numeric>
15 
16 using namespace armnn;
17 using namespace tosa;
18 
VerifyTosaAttribute(const BaseDescriptor & descriptor,const TosaAttributeBase * attribute,std::vector<int32_t> inputShape,std::vector<int32_t> outputShape,LayerType type,uint32_t mappingOpNumber=0)19 inline void VerifyTosaAttribute(const BaseDescriptor& descriptor,
20                                 const TosaAttributeBase* attribute,
21                                 std::vector<int32_t> inputShape,
22                                 std::vector<int32_t> outputShape,
23                                 LayerType type,
24                                 uint32_t mappingOpNumber = 0)
25 {
26     switch (type)
27     {
28         case LayerType::Convolution2d:
29         {
30             auto conv2dDesc = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor);
31             std::vector<int> pad = {static_cast<int>(conv2dDesc->m_PadTop),
32                                     static_cast<int>(conv2dDesc->m_PadBottom),
33                                     static_cast<int>(conv2dDesc->m_PadLeft),
34                                     static_cast<int>(conv2dDesc->m_PadRight)};
35 
36             std::vector<int> dilation = {static_cast<int>(conv2dDesc->m_DilationY),
37                                          static_cast<int>(conv2dDesc->m_DilationX)};
38             std::vector<int> stride = {static_cast<int>(conv2dDesc->m_StrideY),
39                                        static_cast<int>(conv2dDesc->m_StrideX)};
40             TosaConvAttribute convAttribute(attribute);
41             CHECK(pad == convAttribute.pad());
42             CHECK(dilation == convAttribute.dilation());
43             CHECK(stride == convAttribute.stride());
44             break;
45         }
46         case LayerType::Pooling2d:
47         {
48             auto poolDesc = PolymorphicDowncast<const Pooling2dDescriptor*>(&descriptor);
49             std::vector<int> pad = {static_cast<int>(poolDesc->m_PadTop),
50                                     static_cast<int>(poolDesc->m_PadBottom),
51                                     static_cast<int>(poolDesc->m_PadLeft),
52                                     static_cast<int>(poolDesc->m_PadRight)};
53 
54             bool avgPoolIgnoreValue =
55                      (poolDesc->m_PoolType == PoolingAlgorithm::Average) &&
56                      (poolDesc->m_PaddingMethod == PaddingMethod::IgnoreValue);
57             if (avgPoolIgnoreValue)
58             {
59                 if (mappingOpNumber == 0)
60                 {
61                     if (poolDesc->m_DataLayout == DataLayout::NHWC)
62                     {
63                         pad = {0,
64                                0,
65                                static_cast<int>(poolDesc->m_PadTop),
66                                static_cast<int>(poolDesc->m_PadBottom),
67                                static_cast<int>(poolDesc->m_PadLeft),
68                                static_cast<int>(poolDesc->m_PadRight),
69                                0,
70                                0
71                         };
72                     }
73                     else
74                     {
75                         pad = {0,
76                                0,
77                                0,
78                                0,
79                                static_cast<int>(poolDesc->m_PadTop),
80                                static_cast<int>(poolDesc->m_PadBottom),
81                                static_cast<int>(poolDesc->m_PadLeft),
82                                static_cast<int>(poolDesc->m_PadRight)
83                         };
84                     }
85 
86                     TosaPadAttribute padAttribute(attribute);
87 
88                     CHECK(pad == padAttribute.padding());
89                     CHECK(0.0f == padAttribute.pad_const_fp());
90                     CHECK(0 == padAttribute.pad_const_int());
91 
92                     break;
93                 }
94                 pad = {0, 0, 0, 0};
95             }
96 
97             std::vector<int> kernel = {static_cast<int>(poolDesc->m_PoolHeight),
98                                        static_cast<int>(poolDesc->m_PoolWidth)};
99             std::vector<int> stride = {static_cast<int>(poolDesc->m_StrideY),
100                                        static_cast<int>(poolDesc->m_StrideX)};
101             TosaPoolAttribute poolAttribute(attribute);
102             CHECK(pad == poolAttribute.pad());
103             CHECK(kernel == poolAttribute.kernel());
104             CHECK(stride == poolAttribute.stride());
105             break;
106         }
107         case LayerType::Reshape:
108         {
109             auto reshapeDesc = PolymorphicDowncast<const ReshapeDescriptor*>(&descriptor);
110             TosaReshapeAttribute reshapeAttribute(attribute);
111             std::vector<int32_t> shapeAttrib = reshapeAttribute.new_shape();
112 
113             CHECK(GetTosaTensorShape(reshapeDesc->m_TargetShape) == shapeAttrib);
114             CHECK(outputShape == shapeAttrib);
115 
116             auto numInputElements = std::accumulate(std::begin(inputShape),
117                                                     std::end(inputShape),
118                                                     1,
119                                                     std::multiplies<int32_t>());
120             auto numAttributeShapeElements = std::accumulate(std::begin(shapeAttrib),
121                                                              std::end(shapeAttrib),
122                                                              1,
123                                                              std::multiplies<int32_t>());
124             CHECK(numInputElements == numAttributeShapeElements);
125 
126             break;
127         }
128         case LayerType::Slice:
129         {
130             auto sliceDesc = PolymorphicDowncast<const SliceDescriptor*>(&descriptor);
131             TosaSliceAttribute reshapeAttribute(attribute);
132 
133             std::vector<int32_t> begin(sliceDesc->m_Begin.begin(), sliceDesc->m_Begin.end());
134             std::vector<int32_t> size(sliceDesc->m_Size.begin(), sliceDesc->m_Size.end());
135 
136             CHECK(begin == reshapeAttribute.start());
137             CHECK(size == reshapeAttribute.size());
138 
139             CHECK(begin.size() == inputShape.size());
140             CHECK(size.size() == inputShape.size());
141 
142             CHECK(begin.size() == outputShape.size());
143             CHECK(size.size() == outputShape.size());
144 
145             break;
146         }
147         case LayerType::TransposeConvolution2d:
148         {
149             auto transposeConv2dDesc = PolymorphicDowncast<const TransposeConvolution2dDescriptor*>(&descriptor);
150             std::vector<int> outPad = {-static_cast<int>(transposeConv2dDesc->m_PadTop),
151                                        -static_cast<int>(transposeConv2dDesc->m_PadBottom),
152                                        -static_cast<int>(transposeConv2dDesc->m_PadLeft),
153                                        -static_cast<int>(transposeConv2dDesc->m_PadRight)};
154             std::vector<int> stride = {static_cast<int>(transposeConv2dDesc->m_StrideY),
155                                        static_cast<int>(transposeConv2dDesc->m_StrideX)};
156             TosaTransposeConvAttribute transposeConvAttribute(attribute);
157             CHECK(outPad == transposeConvAttribute.out_pad());
158             CHECK(stride == transposeConvAttribute.stride());
159             break;
160         }
161         case LayerType::Transpose:
162         {
163             auto transposeDesc = PolymorphicDowncast<const TransposeDescriptor*>(&descriptor);
164             std::vector<int> outPerm(transposeDesc->m_DimMappings.begin(), transposeDesc->m_DimMappings.end());
165             TosaTransposeAttribute transposeAttribute(attribute);
166             CHECK(outPerm == transposeAttribute.perms());
167             break;
168         }
169         default:
170             break;
171     }
172     return;
173 }
174 
AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock * basicBlock,std::vector<std::vector<int32_t>> inputShape,std::vector<std::vector<int32_t>> outputShape,Op tosaOp,Attribute tosaAttribute,const BaseDescriptor & descriptor,LayerType type,DType dataType=DType_FP32)175 inline void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* basicBlock,
176                                                 std::vector<std::vector<int32_t>> inputShape,
177                                                 std::vector<std::vector<int32_t>> outputShape,
178                                                 Op tosaOp,
179                                                 Attribute tosaAttribute,
180                                                 const BaseDescriptor& descriptor,
181                                                 LayerType type,
182                                                 DType dataType = DType_FP32)
183 {
184     uint32_t numInputs = static_cast<uint32_t>(inputShape.size());
185     uint32_t numInputTensors = static_cast<uint32_t>(inputShape.size());
186     uint32_t numOutputs = static_cast<uint32_t>(outputShape.size());
187     std::string operatorString = TosaOpToString(tosaOp);
188 
189     // The number of tensors in the block can be different if there are constant layers, as they are created separately.
190     if(type == LayerType::Convolution2d)
191     {
192         numInputTensors = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor)->m_BiasEnabled ? 3 : 2;
193     }
194 
195     std::string blockStr = operatorString + "_block_";
196     CHECK(basicBlock->GetName().find(blockStr)  != std::string::npos);
197     CHECK(basicBlock->GetInputs().size() == numInputTensors);
198     CHECK(basicBlock->GetOutputs().size() == numOutputs);
199     CHECK(basicBlock->GetOperators().size() == 1);
200     CHECK(basicBlock->GetTensors().size() == (numInputs + numOutputs));
201 
202     TosaSerializationOperator* op = basicBlock->GetOperators().at(0);
203     CHECK(op->GetInputTensorNames().size() == numInputTensors);
204     CHECK(op->GetOutputTensorNames().size() == numOutputs);
205 
206     for (uint32_t i = 0; i < numInputs; i++)
207     {
208         std::basic_string<char> blockInputName = basicBlock->GetInputs()[i];
209         std::basic_string<char> operatorInputName  = op->GetInputTensorNames()[i];
210         std::basic_string<char> tensorName = basicBlock->GetTensors()[i]->GetName();
211 
212         std::string opStr = "input" + std::to_string(i) + "_";
213 
214         CHECK(blockInputName == operatorInputName);
215         CHECK(tensorName == operatorInputName);
216         CHECK(blockInputName.find(opStr) != std::string::npos);
217     }
218 
219     for (uint32_t i = 0; i < numOutputs; i++)
220     {
221         std::basic_string<char> blockOutputName = basicBlock->GetOutputs()[i];
222         std::basic_string<char> operatorOutputName  = op->GetOutputTensorNames()[i];
223         std::basic_string<char> tensorName = basicBlock->GetTensors()[numInputs + i]->GetName();
224 
225         std::string opStr = "output" + std::to_string(i) + "_";
226         if (tosaOp == Op_CONST)
227         {
228             opStr = "constant_";
229         }
230 
231         CHECK(blockOutputName == operatorOutputName);
232         CHECK(tensorName == operatorOutputName);
233         CHECK(blockOutputName.find(opStr)  != std::string::npos);
234     }
235 
236     CHECK(op->GetAttributeType() == tosaAttribute);
237     CHECK(op->GetOp() == tosaOp);
238 
239     for (uint32_t i = 0; i < numInputs; i++)
240     {
241         TosaSerializationTensor* tensor = basicBlock->GetTensors()[i];
242         CHECK(tensor->GetDtype() == dataType);
243         CHECK(tensor->GetData().size() == 0);
244         CHECK(tensor->GetShape() == inputShape[static_cast<unsigned long int>(i)]);
245     }
246 
247     for (uint32_t i = 0; i < numOutputs; i++)
248     {
249         TosaSerializationTensor* tensor = basicBlock->GetTensors()[i + inputShape.size()];
250         CHECK(tensor->GetDtype() == dataType);
251         CHECK(tensor->GetShape() == outputShape[static_cast<unsigned long int>(i)]);
252         if (tosaOp != Op_CONST)
253         {
254             // Const tensors contain data.
255             CHECK(tensor->GetData().size() == 0);
256         }
257     }
258 
259     std::vector<int32_t> input = {};
260     std::vector<int32_t> output = {};
261 
262     if (!inputShape.empty())
263     {
264         input = inputShape[0];
265     }
266 
267     if (!outputShape.empty())
268     {
269         output = outputShape[0];
270     }
271 
272     VerifyTosaAttribute(descriptor,
273                         op->GetAttribute(),
274                         input,
275                         output,
276                         type);
277 }