blob: a44acb0f5488b8f4689abf2208a48685ca812560 [file] [log] [blame]
Mike Kelly07810fc2020-11-12 10:58:48 +00001//
Mike Kelly3ec30772023-03-08 13:47:17 +00002// Copyright © 2020-2023 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#include <armnn/utility/Assert.hpp>
10
11#include <aclCommon/ArmComputeUtils.hpp>
Cathal Corbett3883b272022-07-22 16:03:36 +010012#include <backendsCommon/SubgraphUtils.hpp>
Mike Kelly07810fc2020-11-12 10:58:48 +000013
14namespace armnn
15{
16
17namespace
18{
19
20//
21// this helper only works if all layers where the inputs connect to are not selected
22//
Francis Murtagh56ccf682021-12-13 18:48:12 +000023
Teresa Charlind672f5d2021-01-18 18:07:57 +000024bool checkDataTypeInputandOutput(const Layer& layer)
25{
Mike Kellya9ac6ba2023-06-30 15:18:26 +010026 auto inputInfo = layer.GetInputSlot(0).GetTensorInfo();
Teresa Charlind672f5d2021-01-18 18:07:57 +000027 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
Mike Kelly07810fc2020-11-12 10:58:48 +000051} // namespace
52
Mike Kelly07810fc2020-11-12 10:58:48 +000053template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +000054LayerType* FuseLayer(OptimizationViews& optimizationViews,
55 LayerType* baseLayer,
56 LayerType* replacementLayer,
57 ActivationLayer* activationLayer,
58 ActivationDescriptor& activationDesc)
Mike Kelly07810fc2020-11-12 10:58:48 +000059{
Cathal Corbettcbfd7182021-12-15 17:12:59 +000060 replacementLayer->SetAdditionalInfoForObject(
61 std::make_shared<ActivationDescriptor>(activationDesc));
Mike Kelly07810fc2020-11-12 10:58:48 +000062
Francis Murtagh56ccf682021-12-13 18:48:12 +000063 SubgraphView substitutionSubgraph({baseLayer, activationLayer},
64 CreateIInputsFrom({baseLayer}),
65 CreateIOutputsFrom({activationLayer}));
Mike Kelly07810fc2020-11-12 10:58:48 +000066 SubgraphView replacementSubgraph(replacementLayer);
67
68 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
Cathal Corbettcbfd7182021-12-15 17:12:59 +000069
Mike Kelly07810fc2020-11-12 10:58:48 +000070 return replacementLayer;
71}
72
73template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +000074LayerType* FuseAdditionLayer(OptimizationViews& optimizationViews,
75 LayerType* baseLayer,
76 ActivationLayer* activationLayer,
77 ActivationDescriptor& activationDesc,
78 std::string name)
79{
Mike Kelly2c14db62023-03-15 15:06:23 +000080 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +000081 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddAdditionLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +000082 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +000083 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
84
85 FuseLayer(optimizationViews,
86 baseLayer,
87 replacementLayer,
88 activationLayer,
89 activationDesc);
90
91 return replacementLayer;
92}
93
94template<typename LayerType>
95LayerType* FuseSubtractionLayer(OptimizationViews& optimizationViews,
96 LayerType* baseLayer,
97 ActivationLayer* activationLayer,
98 ActivationDescriptor& activationDesc,
99 std::string name)
100{
Mike Kelly2c14db62023-03-15 15:06:23 +0000101 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000102 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddSubtractionLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +0000103 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000104 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
105
106 FuseLayer(optimizationViews,
107 baseLayer,
108 replacementLayer,
109 activationLayer,
110 activationDesc);
111
112 return replacementLayer;
113}
114
115template<typename LayerType>
116LayerType* FuseDivisionLayer(OptimizationViews& optimizationViews,
117 LayerType* baseLayer,
118 ActivationLayer* activationLayer,
119 ActivationDescriptor& activationDesc,
120 std::string name)
121{
Mike Kelly2c14db62023-03-15 15:06:23 +0000122 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000123 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddDivisionLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +0000124 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000125 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
126
127 FuseLayer(optimizationViews,
128 baseLayer,
129 replacementLayer,
130 activationLayer,
131 activationDesc);
132
133 return replacementLayer;
134}
135
136template<typename LayerType>
137LayerType* FuseMultiplicationLayer(OptimizationViews& optimizationViews,
Mike Kelly07810fc2020-11-12 10:58:48 +0000138 LayerType* baseLayer,
139 ActivationLayer* activationLayer,
140 ActivationDescriptor& activationDesc,
141 std::string name)
142{
Mike Kelly2c14db62023-03-15 15:06:23 +0000143 ARMNN_NO_DEPRECATE_WARN_BEGIN
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000144 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddMultiplicationLayer(name.c_str());
Mike Kelly2c14db62023-03-15 15:06:23 +0000145 ARMNN_NO_DEPRECATE_WARN_END
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000146 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
Mike Kelly07810fc2020-11-12 10:58:48 +0000147
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000148 FuseLayer(optimizationViews,
149 baseLayer,
150 replacementLayer,
151 activationLayer,
152 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000153
Mike Kelly07810fc2020-11-12 10:58:48 +0000154 return replacementLayer;
155}
156
157template<typename LayerType>
Mike Kelly3ec30772023-03-08 13:47:17 +0000158LayerType* 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
178template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000179LayerType* FuseBatchNormalizationLayer(OptimizationViews& optimizationViews,
180 LayerType* baseLayer,
181 ActivationLayer* activationLayer,
182 ActivationDescriptor& activationDesc,
183 std::string name)
Mike Kelly07810fc2020-11-12 10:58:48 +0000184{
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000185 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
Francis Murtagh56ccf682021-12-13 18:48:12 +0000200 SubgraphView substitutionSubgraph({baseLayer, activationLayer},
201 CreateIInputsFrom({baseLayer}),
202 CreateIOutputsFrom({activationLayer}));
203 SubgraphView replacementSubgraph(replacementLayer);
204
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000205 return replacementLayer;
206}
207
208template<typename LayerType>
209LayerType* FuseConvolution2dLayer(OptimizationViews& optimizationViews,
210 LayerType* baseLayer,
211 ActivationLayer* activationLayer,
212 ActivationDescriptor& activationDesc,
213 std::string name)
214{
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100215 IConnectableLayer* replacement = optimizationViews.GetINetwork()
216 ->AddConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000217
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000218 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
219
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100220
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000221 FuseLayer(optimizationViews,
222 baseLayer,
223 replacementLayer,
224 activationLayer,
225 activationDesc);
226
227 return replacementLayer;
228}
229
230template<typename LayerType>
231LayerType* FuseDepthwiseConvolution2dLayer(OptimizationViews& optimizationViews,
232 LayerType* baseLayer,
233 ActivationLayer* activationLayer,
234 ActivationDescriptor& activationDesc,
235 std::string name)
236{
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100237 IConnectableLayer* replacement =
238 optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
239
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000240 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
241
Cathal Corbett06902652022-04-14 17:55:11 +0100242
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000243 FuseLayer(optimizationViews,
244 baseLayer,
245 replacementLayer,
246 activationLayer,
247 activationDesc);
248
249 return replacementLayer;
250}
251
252template<typename LayerType>
253LayerType* 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);
Mike Kelly07810fc2020-11-12 10:58:48 +0000269
Mike Kelly07810fc2020-11-12 10:58:48 +0000270
271 return replacementLayer;
272}
273
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100274//
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//
278template<typename LayerType>
Francis Murtagh56ccf682021-12-13 18:48:12 +0000279std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100280 LayerType* baseLayer,
281 ReduceDescriptor& desc)
282{
283 // Vector of new chained layers, used for substitution.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000284 std::vector<IConnectableLayer*> layers;
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100285
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);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000311
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000312 Layer* replacementLayer = PolymorphicDowncast<Layer*>(
313 optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
314 layerName.c_str()));
Francis Murtagh56ccf682021-12-13 18:48:12 +0000315
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100316 // 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.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000335 ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() ==
336 PolymorphicDowncast<Layer*>(layers.back())->GetOutputSlot().GetTensorInfo());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100337
338 return layers;
339}
340
341//
342// Substitute baseLayer with new subgraph
343//
344template<typename LayerType>
345void ReplaceLayers(OptimizationViews& optimizationViews,
346 LayerType* baseLayer,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000347 std::vector<IConnectableLayer*>& layers)
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100348{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000349 std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100350
351 SubgraphView substitutionSubgraph(baseLayer);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000352 SubgraphView replacementSubgraph(std::move(replacementLayers),
353 CreateIInputsFrom({replacementLayers.front()}),
354 CreateIOutputsFrom({replacementLayers.back()}));
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100355
356 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
357}
358
Tracy Narine6440ce82023-09-20 14:19:07 +0100359//
360// Substitute a multi-layer subgraph with one new layer
361//
362template<typename LayerType>
363void ReplaceMultipleLayers(OptimizationViews& optimizationViews,
364 std::vector<IConnectableLayer*>& originalLayers,
365 LayerType* baseLayer,
366 const std::vector<SlotList> inputLayersSlotLists,
367 const std::vector<SlotList> outputLayersSlotLists)
368{
369 std::list<IConnectableLayer*> originalLayerList(originalLayers.begin(), originalLayers.end());
370
371 SubgraphView substitutionSubgraph(
372 std::move(originalLayerList),
373 CreateIInputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, inputLayersSlotLists),
374 CreateIOutputsFromSlotLists<armnn::IConnectableLayer>(originalLayers, outputLayersSlotLists));
375 SubgraphView replacementSubgraph(baseLayer);
376
377 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
378}
379
Mike Kelly07810fc2020-11-12 10:58:48 +0000380} // namespace armnn