blob: 9b889141be4df1c2120af70c3d0f7d8e4de1f823 [file] [log] [blame]
Mike Kelly07810fc2020-11-12 10:58:48 +00001//
Colm Donelanb4ef1632024-02-01 15:00:43 +00002// Copyright © 2020-2024 Arm Ltd and Contributors. All rights reserved.
Mike Kelly07810fc2020-11-12 10:58:48 +00003// SPDX-License-Identifier: MIT
4//
5
6#pragma once
7
8#include <armnn/backends/OptimizationViews.hpp>
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +01009
10#include <aclCommon/ArmComputeUtils.hpp>
Cathal Corbett3883b272022-07-22 16:03:36 +010011#include <backendsCommon/SubgraphUtils.hpp>
Mike Kelly07810fc2020-11-12 10:58:48 +000012
13namespace armnn
14{
15
16namespace
17{
18
19//
20// this helper only works if all layers where the inputs connect to are not selected
21//
Francis Murtagh56ccf682021-12-13 18:48:12 +000022
Teresa Charlind672f5d2021-01-18 18:07:57 +000023bool checkDataTypeInputandOutput(const Layer& layer)
24{
Mike Kellya9ac6ba2023-06-30 15:18:26 +010025 auto inputInfo = layer.GetInputSlot(0).GetTensorInfo();
Teresa Charlind672f5d2021-01-18 18:07:57 +000026 auto outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
27 bool sameDataType = (inputInfo.GetDataType() == outputInfo.GetDataType());
28
29 // Check is same quantization info (same scale and offset)
30 if (sameDataType)
31 {
32 if (IsQuantizedType(inputInfo.GetDataType()))
33 {
34 bool sameScale = (inputInfo.GetQuantizationScale() == outputInfo.GetQuantizationScale());
35 bool sameOffset = (inputInfo.GetQuantizationOffset() == outputInfo.GetQuantizationOffset());
36
37 return (sameScale && sameOffset);
38 }
39 else
40 {
41 return true;
42 }
43 }
44 else
45 {
46 return false;
47 }
48}
49
Mike Kelly07810fc2020-11-12 10:58:48 +000050} // namespace
51
Mike Kelly07810fc2020-11-12 10:58:48 +000052template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +000053LayerType* FuseLayer(OptimizationViews& optimizationViews,
54 LayerType* baseLayer,
55 LayerType* replacementLayer,
56 ActivationLayer* activationLayer,
57 ActivationDescriptor& activationDesc)
Mike Kelly07810fc2020-11-12 10:58:48 +000058{
Cathal Corbettcbfd7182021-12-15 17:12:59 +000059 replacementLayer->SetAdditionalInfoForObject(
60 std::make_shared<ActivationDescriptor>(activationDesc));
Mike Kelly07810fc2020-11-12 10:58:48 +000061
Francis Murtagh56ccf682021-12-13 18:48:12 +000062 SubgraphView substitutionSubgraph({baseLayer, activationLayer},
63 CreateIInputsFrom({baseLayer}),
64 CreateIOutputsFrom({activationLayer}));
Mike Kelly07810fc2020-11-12 10:58:48 +000065 SubgraphView replacementSubgraph(replacementLayer);
66
67 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
Cathal Corbettcbfd7182021-12-15 17:12:59 +000068
Mike Kelly07810fc2020-11-12 10:58:48 +000069 return replacementLayer;
70}
71
72template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +000073LayerType* FuseAdditionLayer(OptimizationViews& optimizationViews,
74 LayerType* baseLayer,
75 ActivationLayer* activationLayer,
76 ActivationDescriptor& activationDesc,
77 std::string name)
78{
Mike Kelly2c14db62023-03-15 15:06:23 +000079 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +000080 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddAdditionLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +000081 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +000082 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
83
84 FuseLayer(optimizationViews,
85 baseLayer,
86 replacementLayer,
87 activationLayer,
88 activationDesc);
89
90 return replacementLayer;
91}
92
93template<typename LayerType>
94LayerType* FuseSubtractionLayer(OptimizationViews& optimizationViews,
95 LayerType* baseLayer,
96 ActivationLayer* activationLayer,
97 ActivationDescriptor& activationDesc,
98 std::string name)
99{
Mike Kelly2c14db62023-03-15 15:06:23 +0000100 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000101 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddSubtractionLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +0000102 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000103 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
104
105 FuseLayer(optimizationViews,
106 baseLayer,
107 replacementLayer,
108 activationLayer,
109 activationDesc);
110
111 return replacementLayer;
112}
113
114template<typename LayerType>
115LayerType* FuseDivisionLayer(OptimizationViews& optimizationViews,
116 LayerType* baseLayer,
117 ActivationLayer* activationLayer,
118 ActivationDescriptor& activationDesc,
119 std::string name)
120{
Mike Kelly2c14db62023-03-15 15:06:23 +0000121 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000122 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddDivisionLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +0000123 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000124 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
125
126 FuseLayer(optimizationViews,
127 baseLayer,
128 replacementLayer,
129 activationLayer,
130 activationDesc);
131
132 return replacementLayer;
133}
134
135template<typename LayerType>
136LayerType* FuseMultiplicationLayer(OptimizationViews& optimizationViews,
Mike Kelly07810fc2020-11-12 10:58:48 +0000137 LayerType* baseLayer,
138 ActivationLayer* activationLayer,
139 ActivationDescriptor& activationDesc,
140 std::string name)
141{
Mike Kelly2c14db62023-03-15 15:06:23 +0000142 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000143 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddMultiplicationLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +0000144 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000145 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
Mike Kelly07810fc2020-11-12 10:58:48 +0000146
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000147 FuseLayer(optimizationViews,
148 baseLayer,
149 replacementLayer,
150 activationLayer,
151 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000152
Mike Kelly07810fc2020-11-12 10:58:48 +0000153 return replacementLayer;
154}
155
156template<typename LayerType>
Mike Kelly3ec30772023-03-08 13:47:17 +0000157LayerType* FuseElementwiseBinaryLayer(OptimizationViews& optimizationViews,
158 LayerType* baseLayer,
159 ActivationLayer* activationLayer,
160 ActivationDescriptor& activationDesc,
161 BinaryOperation operation,
162 std::string name)
163{
164 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddElementwiseBinaryLayer(operation,
165 name.c_str());
166 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
167
168 FuseLayer(optimizationViews,
169 baseLayer,
170 replacementLayer,
171 activationLayer,
172 activationDesc);
173
174 return replacementLayer;
175}
176
177template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000178LayerType* FuseBatchNormalizationLayer(OptimizationViews& optimizationViews,
179 LayerType* baseLayer,
180 ActivationLayer* activationLayer,
181 ActivationDescriptor& activationDesc,
182 std::string name)
Mike Kelly07810fc2020-11-12 10:58:48 +0000183{
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000184 IConnectableLayer* replacement =
185 optimizationViews.GetINetwork()->AddBatchNormalizationLayer(baseLayer->GetParameters(),
186 ConstTensor(),
187 ConstTensor(),
188 ConstTensor(),
189 ConstTensor(),
190 name.c_str());
191 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
192
193 FuseLayer(optimizationViews,
194 baseLayer,
195 replacementLayer,
196 activationLayer,
197 activationDesc);
198
Francis Murtagh56ccf682021-12-13 18:48:12 +0000199 SubgraphView substitutionSubgraph({baseLayer, activationLayer},
200 CreateIInputsFrom({baseLayer}),
201 CreateIOutputsFrom({activationLayer}));
202 SubgraphView replacementSubgraph(replacementLayer);
203
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000204 return replacementLayer;
205}
206
207template<typename LayerType>
208LayerType* FuseConvolution2dLayer(OptimizationViews& optimizationViews,
209 LayerType* baseLayer,
210 ActivationLayer* activationLayer,
211 ActivationDescriptor& activationDesc,
212 std::string name)
213{
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100214 IConnectableLayer* replacement = optimizationViews.GetINetwork()
215 ->AddConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000216
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000217 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
218
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100219
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000220 FuseLayer(optimizationViews,
221 baseLayer,
222 replacementLayer,
223 activationLayer,
224 activationDesc);
225
226 return replacementLayer;
227}
228
229template<typename LayerType>
230LayerType* FuseDepthwiseConvolution2dLayer(OptimizationViews& optimizationViews,
231 LayerType* baseLayer,
232 ActivationLayer* activationLayer,
233 ActivationDescriptor& activationDesc,
234 std::string name)
235{
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100236 IConnectableLayer* replacement =
237 optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
238
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000239 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
240
Cathal Corbett06902652022-04-14 17:55:11 +0100241
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000242 FuseLayer(optimizationViews,
243 baseLayer,
244 replacementLayer,
245 activationLayer,
246 activationDesc);
247
248 return replacementLayer;
249}
250
251template<typename LayerType>
252LayerType* FuseFullyConnectedLayer(OptimizationViews& optimizationViews,
253 LayerType* baseLayer,
254 ActivationLayer* activationLayer,
255 ActivationDescriptor& activationDesc,
256 std::string name)
257{
258 IConnectableLayer* replacement =
259 optimizationViews.GetINetwork()->AddFullyConnectedLayer(baseLayer->GetParameters(),
260 name.c_str());
261 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
262
263 FuseLayer(optimizationViews,
264 baseLayer,
265 replacementLayer,
266 activationLayer,
267 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000268
Mike Kelly07810fc2020-11-12 10:58:48 +0000269
270 return replacementLayer;
271}
272
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100273//
274// If reduce layer has multiple axes, add new layer for each axis to simulate the same behaviour
275// as currently only one axis is supported.
276//
277template<typename LayerType>
Francis Murtagh56ccf682021-12-13 18:48:12 +0000278std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100279 LayerType* baseLayer,
280 ReduceDescriptor& desc)
281{
282 // Vector of new chained layers, used for substitution.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000283 std::vector<IConnectableLayer*> layers;
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100284
285 // Vector of axes so each layer is reshaped correctly.
286 std::vector<uint32_t> axes;
287 unsigned int recalulatedAxis = 0;
288
289 for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
290 {
291 // Get TensorInfo from base layer and reduce shape using axis.
292 TensorInfo layerInfo = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
293
294 axes.emplace_back(desc.m_vAxis[i]);
295
296 const TensorInfo& reducedTensorInfo = ComputeReductionTensorShape(layerInfo,
297 axes,
298 desc.m_KeepDims);
299
300 // Create a vector for the single axis to be assigned to the descriptor.
301 // Update axis if keepDims is set reduce layers correctly.
302 std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
303
304 // Create a descriptor and assign single axis.
305 ReduceDescriptor newReduceDescriptor = baseLayer->GetParameters();
306 newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
307
308 // Add new layer to graph.
309 std::string layerName = "reduce_layer_" + std::to_string(i);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000310
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000311 Layer* replacementLayer = PolymorphicDowncast<Layer*>(
312 optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
313 layerName.c_str()));
Francis Murtagh56ccf682021-12-13 18:48:12 +0000314
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100315 // Connect previous layer with new layer.
316 // The first and last layer will be connected when the subgraph is replaced.
317 if (!layers.empty())
318 {
319 layers[i - 1]->GetOutputSlot(0).Connect(replacementLayer->GetInputSlot(0));
320 }
321
322 // Set updated tensorInfo for new layer.
323 replacementLayer->GetOutputSlot(0).SetTensorInfo(reducedTensorInfo);
324
325 if (!desc.m_KeepDims)
326 {
327 recalulatedAxis++;
328 }
329
330 layers.emplace_back(replacementLayer);
331 }
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100332 return layers;
333}
334
335//
336// Substitute baseLayer with new subgraph
337//
338template<typename LayerType>
339void ReplaceLayers(OptimizationViews& optimizationViews,
340 LayerType* baseLayer,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000341 std::vector<IConnectableLayer*>& layers)
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100342{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000343 std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100344
345 SubgraphView substitutionSubgraph(baseLayer);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000346 SubgraphView replacementSubgraph(std::move(replacementLayers),
347 CreateIInputsFrom({replacementLayers.front()}),
348 CreateIOutputsFrom({replacementLayers.back()}));
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100349
350 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
351}
352
Tracy Narine6440ce82023-09-20 14:19:07 +0100353//
354// Substitute a multi-layer subgraph with one new layer
355//
356template<typename LayerType>
357void ReplaceMultipleLayers(OptimizationViews& optimizationViews,
358 std::vector<IConnectableLayer*>& originalLayers,
359 LayerType* baseLayer,
360 const std::vector<SlotList> inputLayersSlotLists,
361 const std::vector<SlotList> outputLayersSlotLists)
362{
363 std::list<IConnectableLayer*> originalLayerList(originalLayers.begin(), originalLayers.end());
364
365 SubgraphView substitutionSubgraph(
366 std::move(originalLayerList),
367 CreateIInputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, inputLayersSlotLists),
368 CreateIOutputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, outputLayersSlotLists));
369 SubgraphView replacementSubgraph(baseLayer);
370
371 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
372}
373
Mike Kelly07810fc2020-11-12 10:58:48 +0000374} // namespace armnn