• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2020-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #pragma once
7 
8 #include <armnn/backends/OptimizationViews.hpp>
9 #include <armnn/utility/Assert.hpp>
10 
11 #include <aclCommon/ArmComputeUtils.hpp>
12 #include <backendsCommon/SubgraphUtils.hpp>
13 
14 namespace armnn
15 {
16 
17 namespace
18 {
19 
20 //
21 // this helper only works if all layers where the inputs connect to are not selected
22 //
23 
checkDataTypeInputandOutput(const Layer & layer)24 bool checkDataTypeInputandOutput(const Layer& layer)
25 {
26     auto inputInfo = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
27     auto outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
28     bool sameDataType = (inputInfo.GetDataType() == outputInfo.GetDataType());
29 
30     // Check is same quantization info (same scale and offset)
31     if (sameDataType)
32     {
33         if (IsQuantizedType(inputInfo.GetDataType()))
34         {
35             bool sameScale = (inputInfo.GetQuantizationScale() == outputInfo.GetQuantizationScale());
36             bool sameOffset = (inputInfo.GetQuantizationOffset() == outputInfo.GetQuantizationOffset());
37 
38             return (sameScale && sameOffset);
39         }
40         else
41         {
42             return true;
43         }
44     }
45     else
46     {
47         return false;
48     }
49 }
50 
51 } // namespace
52 
53 template<typename LayerType>
FuseLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,LayerType * replacementLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc)54 LayerType* FuseLayer(OptimizationViews& optimizationViews,
55                      LayerType* baseLayer,
56                      LayerType* replacementLayer,
57                      ActivationLayer* activationLayer,
58                      ActivationDescriptor& activationDesc)
59 {
60     replacementLayer->SetAdditionalInfoForObject(
61         std::make_shared<ActivationDescriptor>(activationDesc));
62 
63     SubgraphView substitutionSubgraph({baseLayer, activationLayer},
64                                       CreateIInputsFrom({baseLayer}),
65                                       CreateIOutputsFrom({activationLayer}));
66     SubgraphView replacementSubgraph(replacementLayer);
67 
68     optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
69 
70     return replacementLayer;
71 }
72 
73 template<typename LayerType>
FuseAdditionLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)74 LayerType* FuseAdditionLayer(OptimizationViews& optimizationViews,
75                              LayerType* baseLayer,
76                              ActivationLayer* activationLayer,
77                              ActivationDescriptor& activationDesc,
78                              std::string name)
79 {
80     ARMNN_NO_DEPRECATE_WARN_BEGIN
81     IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddAdditionLayer(name.c_str());
82     ARMNN_NO_DEPRECATE_WARN_END
83     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
84 
85     FuseLayer(optimizationViews,
86               baseLayer,
87               replacementLayer,
88               activationLayer,
89               activationDesc);
90 
91     return replacementLayer;
92 }
93 
94 template<typename LayerType>
FuseSubtractionLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)95 LayerType* FuseSubtractionLayer(OptimizationViews& optimizationViews,
96                                 LayerType* baseLayer,
97                                 ActivationLayer* activationLayer,
98                                 ActivationDescriptor& activationDesc,
99                                 std::string name)
100 {
101     ARMNN_NO_DEPRECATE_WARN_BEGIN
102     IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddSubtractionLayer(name.c_str());
103     ARMNN_NO_DEPRECATE_WARN_END
104     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
105 
106     FuseLayer(optimizationViews,
107               baseLayer,
108               replacementLayer,
109               activationLayer,
110               activationDesc);
111 
112     return replacementLayer;
113 }
114 
115 template<typename LayerType>
FuseDivisionLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)116 LayerType* FuseDivisionLayer(OptimizationViews& optimizationViews,
117                              LayerType* baseLayer,
118                              ActivationLayer* activationLayer,
119                              ActivationDescriptor& activationDesc,
120                              std::string name)
121 {
122     ARMNN_NO_DEPRECATE_WARN_BEGIN
123     IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddDivisionLayer(name.c_str());
124     ARMNN_NO_DEPRECATE_WARN_END
125     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
126 
127     FuseLayer(optimizationViews,
128               baseLayer,
129               replacementLayer,
130               activationLayer,
131               activationDesc);
132 
133     return replacementLayer;
134 }
135 
136 template<typename LayerType>
FuseMultiplicationLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)137 LayerType* FuseMultiplicationLayer(OptimizationViews& optimizationViews,
138                                    LayerType* baseLayer,
139                                    ActivationLayer* activationLayer,
140                                    ActivationDescriptor& activationDesc,
141                                    std::string name)
142 {
143     ARMNN_NO_DEPRECATE_WARN_BEGIN
144     IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddMultiplicationLayer(name.c_str());
145     ARMNN_NO_DEPRECATE_WARN_END
146     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
147 
148     FuseLayer(optimizationViews,
149               baseLayer,
150               replacementLayer,
151               activationLayer,
152               activationDesc);
153 
154     return replacementLayer;
155 }
156 
157 template<typename LayerType>
FuseElementwiseBinaryLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,BinaryOperation operation,std::string name)158 LayerType* FuseElementwiseBinaryLayer(OptimizationViews& optimizationViews,
159                                       LayerType* baseLayer,
160                                       ActivationLayer* activationLayer,
161                                       ActivationDescriptor& activationDesc,
162                                       BinaryOperation operation,
163                                       std::string name)
164 {
165     IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddElementwiseBinaryLayer(operation,
166                                                                                                 name.c_str());
167     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
168 
169     FuseLayer(optimizationViews,
170               baseLayer,
171               replacementLayer,
172               activationLayer,
173               activationDesc);
174 
175     return replacementLayer;
176 }
177 
178 template<typename LayerType>
FuseBatchNormalizationLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)179 LayerType* FuseBatchNormalizationLayer(OptimizationViews& optimizationViews,
180                                        LayerType* baseLayer,
181                                        ActivationLayer* activationLayer,
182                                        ActivationDescriptor& activationDesc,
183                                        std::string name)
184 {
185     IConnectableLayer* replacement =
186         optimizationViews.GetINetwork()->AddBatchNormalizationLayer(baseLayer->GetParameters(),
187                                                                     ConstTensor(),
188                                                                     ConstTensor(),
189                                                                     ConstTensor(),
190                                                                     ConstTensor(),
191                                                                     name.c_str());
192     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
193 
194     FuseLayer(optimizationViews,
195               baseLayer,
196               replacementLayer,
197               activationLayer,
198               activationDesc);
199 
200     SubgraphView substitutionSubgraph({baseLayer, activationLayer},
201                                       CreateIInputsFrom({baseLayer}),
202                                       CreateIOutputsFrom({activationLayer}));
203     SubgraphView replacementSubgraph(replacementLayer);
204 
205     return replacementLayer;
206 }
207 
208 template<typename LayerType>
FuseConvolution2dLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)209 LayerType* FuseConvolution2dLayer(OptimizationViews& optimizationViews,
210                                   LayerType* baseLayer,
211                                   ActivationLayer* activationLayer,
212                                   ActivationDescriptor& activationDesc,
213                                   std::string name)
214 {
215     IConnectableLayer* replacement = optimizationViews.GetINetwork()
216                                                       ->AddConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
217 
218     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
219 
220 
221     FuseLayer(optimizationViews,
222               baseLayer,
223               replacementLayer,
224               activationLayer,
225               activationDesc);
226 
227     return replacementLayer;
228 }
229 
230 template<typename LayerType>
FuseDepthwiseConvolution2dLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)231 LayerType* FuseDepthwiseConvolution2dLayer(OptimizationViews& optimizationViews,
232                                            LayerType* baseLayer,
233                                            ActivationLayer* activationLayer,
234                                            ActivationDescriptor& activationDesc,
235                                            std::string name)
236 {
237     IConnectableLayer* replacement =
238         optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
239 
240     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
241 
242 
243     FuseLayer(optimizationViews,
244               baseLayer,
245               replacementLayer,
246               activationLayer,
247               activationDesc);
248 
249     return replacementLayer;
250 }
251 
252 template<typename LayerType>
FuseFullyConnectedLayer(OptimizationViews & optimizationViews,LayerType * baseLayer,ActivationLayer * activationLayer,ActivationDescriptor & activationDesc,std::string name)253 LayerType* FuseFullyConnectedLayer(OptimizationViews& optimizationViews,
254                                    LayerType* baseLayer,
255                                    ActivationLayer* activationLayer,
256                                    ActivationDescriptor& activationDesc,
257                                    std::string name)
258 {
259     IConnectableLayer* replacement =
260         optimizationViews.GetINetwork()->AddFullyConnectedLayer(baseLayer->GetParameters(),
261                                                                 name.c_str());
262     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
263 
264     FuseLayer(optimizationViews,
265               baseLayer,
266               replacementLayer,
267               activationLayer,
268               activationDesc);
269 
270 
271     return replacementLayer;
272 }
273 
274 //
275 // If reduce layer has multiple axes, add new layer for each axis to simulate the same behaviour
276 // as currently only one axis is supported.
277 //
278 template<typename LayerType>
ChainReduceLayers(OptimizationViews & optimizationViews,LayerType * baseLayer,ReduceDescriptor & desc)279 std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
280                                       LayerType* baseLayer,
281                                       ReduceDescriptor& desc)
282 {
283     // Vector of new chained layers, used for substitution.
284     std::vector<IConnectableLayer*> layers;
285 
286     // Vector of axes so each layer is reshaped correctly.
287     std::vector<uint32_t> axes;
288     unsigned int recalulatedAxis = 0;
289 
290     for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
291     {
292         // Get TensorInfo from base layer and reduce shape using axis.
293         TensorInfo layerInfo = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
294 
295         axes.emplace_back(desc.m_vAxis[i]);
296 
297         const TensorInfo& reducedTensorInfo = ComputeReductionTensorShape(layerInfo,
298                                                                           axes,
299                                                                           desc.m_KeepDims);
300 
301         // Create a vector for the single axis to be assigned to the descriptor.
302         // Update axis if keepDims is set reduce layers correctly.
303         std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
304 
305         // Create a descriptor and assign single axis.
306         ReduceDescriptor newReduceDescriptor = baseLayer->GetParameters();
307         newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
308 
309         // Add new layer to graph.
310         std::string layerName = "reduce_layer_" + std::to_string(i);
311 
312         Layer* replacementLayer = PolymorphicDowncast<Layer*>(
313             optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
314                                                             layerName.c_str()));
315 
316         // Connect previous layer with new layer.
317         // The first and last layer will be connected when the subgraph is replaced.
318         if (!layers.empty())
319         {
320             layers[i - 1]->GetOutputSlot(0).Connect(replacementLayer->GetInputSlot(0));
321         }
322 
323         // Set updated tensorInfo for new layer.
324         replacementLayer->GetOutputSlot(0).SetTensorInfo(reducedTensorInfo);
325 
326         if (!desc.m_KeepDims)
327         {
328             recalulatedAxis++;
329         }
330 
331         layers.emplace_back(replacementLayer);
332     }
333 
334     // Check if the TensorInfo from the last layer equals the inferred output from the original layer.
335     ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() ==
336                  PolymorphicDowncast<Layer*>(layers.back())->GetOutputSlot().GetTensorInfo());
337 
338     return layers;
339 }
340 
341 //
342 // Substitute baseLayer with new subgraph
343 //
344 template<typename LayerType>
ReplaceLayers(OptimizationViews & optimizationViews,LayerType * baseLayer,std::vector<IConnectableLayer * > & layers)345 void ReplaceLayers(OptimizationViews& optimizationViews,
346                    LayerType* baseLayer,
347                    std::vector<IConnectableLayer*>& layers)
348 {
349     std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
350 
351     SubgraphView substitutionSubgraph(baseLayer);
352     SubgraphView replacementSubgraph(std::move(replacementLayers),
353                                      CreateIInputsFrom({replacementLayers.front()}),
354                                      CreateIOutputsFrom({replacementLayers.back()}));
355 
356     optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
357 }
358 
359 } // namespace armnn
360