blob: c9d6c71f18a2f839e5fd5aa7b0a5dcb343b1fab1 [file] [log] [blame]
Mike Kelly07810fc2020-11-12 10:58:48 +00001//
Mike Kellyec67a0f2022-11-25 13:55:24 +00002// Copyright © 2020,2022 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{
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
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{
80 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddAdditionLayer(name.c_str());
81 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
82
83 FuseLayer(optimizationViews,
84 baseLayer,
85 replacementLayer,
86 activationLayer,
87 activationDesc);
88
89 return replacementLayer;
90}
91
92template<typename LayerType>
93LayerType* FuseSubtractionLayer(OptimizationViews& optimizationViews,
94 LayerType* baseLayer,
95 ActivationLayer* activationLayer,
96 ActivationDescriptor& activationDesc,
97 std::string name)
98{
99 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddSubtractionLayer(name.c_str());
100 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
101
102 FuseLayer(optimizationViews,
103 baseLayer,
104 replacementLayer,
105 activationLayer,
106 activationDesc);
107
108 return replacementLayer;
109}
110
111template<typename LayerType>
112LayerType* FuseDivisionLayer(OptimizationViews& optimizationViews,
113 LayerType* baseLayer,
114 ActivationLayer* activationLayer,
115 ActivationDescriptor& activationDesc,
116 std::string name)
117{
118 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddDivisionLayer(name.c_str());
119 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
120
121 FuseLayer(optimizationViews,
122 baseLayer,
123 replacementLayer,
124 activationLayer,
125 activationDesc);
126
127 return replacementLayer;
128}
129
130template<typename LayerType>
131LayerType* FuseMultiplicationLayer(OptimizationViews& optimizationViews,
Mike Kelly07810fc2020-11-12 10:58:48 +0000132 LayerType* baseLayer,
133 ActivationLayer* activationLayer,
134 ActivationDescriptor& activationDesc,
135 std::string name)
136{
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000137 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddMultiplicationLayer(name.c_str());
138 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
Mike Kelly07810fc2020-11-12 10:58:48 +0000139
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000140 FuseLayer(optimizationViews,
141 baseLayer,
142 replacementLayer,
143 activationLayer,
144 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000145
Mike Kelly07810fc2020-11-12 10:58:48 +0000146 return replacementLayer;
147}
148
149template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000150LayerType* FuseBatchNormalizationLayer(OptimizationViews& optimizationViews,
151 LayerType* baseLayer,
152 ActivationLayer* activationLayer,
153 ActivationDescriptor& activationDesc,
154 std::string name)
Mike Kelly07810fc2020-11-12 10:58:48 +0000155{
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000156 IConnectableLayer* replacement =
157 optimizationViews.GetINetwork()->AddBatchNormalizationLayer(baseLayer->GetParameters(),
158 ConstTensor(),
159 ConstTensor(),
160 ConstTensor(),
161 ConstTensor(),
162 name.c_str());
163 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
164
165 FuseLayer(optimizationViews,
166 baseLayer,
167 replacementLayer,
168 activationLayer,
169 activationDesc);
170
Francis Murtagh56ccf682021-12-13 18:48:12 +0000171 SubgraphView substitutionSubgraph({baseLayer, activationLayer},
172 CreateIInputsFrom({baseLayer}),
173 CreateIOutputsFrom({activationLayer}));
174 SubgraphView replacementSubgraph(replacementLayer);
175
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000176 return replacementLayer;
177}
178
179template<typename LayerType>
180LayerType* FuseConvolution2dLayer(OptimizationViews& optimizationViews,
181 LayerType* baseLayer,
182 ActivationLayer* activationLayer,
183 ActivationDescriptor& activationDesc,
184 std::string name)
185{
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100186 IConnectableLayer* replacement = optimizationViews.GetINetwork()
187 ->AddConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000188
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000189 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
190
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100191
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000192 FuseLayer(optimizationViews,
193 baseLayer,
194 replacementLayer,
195 activationLayer,
196 activationDesc);
197
198 return replacementLayer;
199}
200
201template<typename LayerType>
202LayerType* FuseDepthwiseConvolution2dLayer(OptimizationViews& optimizationViews,
203 LayerType* baseLayer,
204 ActivationLayer* activationLayer,
205 ActivationDescriptor& activationDesc,
206 std::string name)
207{
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100208 IConnectableLayer* replacement =
209 optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
210
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000211 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
212
Cathal Corbett06902652022-04-14 17:55:11 +0100213
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000214 FuseLayer(optimizationViews,
215 baseLayer,
216 replacementLayer,
217 activationLayer,
218 activationDesc);
219
220 return replacementLayer;
221}
222
223template<typename LayerType>
224LayerType* FuseFullyConnectedLayer(OptimizationViews& optimizationViews,
225 LayerType* baseLayer,
226 ActivationLayer* activationLayer,
227 ActivationDescriptor& activationDesc,
228 std::string name)
229{
230 IConnectableLayer* replacement =
231 optimizationViews.GetINetwork()->AddFullyConnectedLayer(baseLayer->GetParameters(),
232 name.c_str());
233 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
234
235 FuseLayer(optimizationViews,
236 baseLayer,
237 replacementLayer,
238 activationLayer,
239 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000240
Mike Kelly07810fc2020-11-12 10:58:48 +0000241
242 return replacementLayer;
243}
244
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100245//
246// If reduce layer has multiple axes, add new layer for each axis to simulate the same behaviour
247// as currently only one axis is supported.
248//
249template<typename LayerType>
Francis Murtagh56ccf682021-12-13 18:48:12 +0000250std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100251 LayerType* baseLayer,
252 ReduceDescriptor& desc)
253{
254 // Vector of new chained layers, used for substitution.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000255 std::vector<IConnectableLayer*> layers;
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100256
257 // Vector of axes so each layer is reshaped correctly.
258 std::vector<uint32_t> axes;
259 unsigned int recalulatedAxis = 0;
260
261 for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
262 {
263 // Get TensorInfo from base layer and reduce shape using axis.
264 TensorInfo layerInfo = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
265
266 axes.emplace_back(desc.m_vAxis[i]);
267
268 const TensorInfo& reducedTensorInfo = ComputeReductionTensorShape(layerInfo,
269 axes,
270 desc.m_KeepDims);
271
272 // Create a vector for the single axis to be assigned to the descriptor.
273 // Update axis if keepDims is set reduce layers correctly.
274 std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
275
276 // Create a descriptor and assign single axis.
277 ReduceDescriptor newReduceDescriptor = baseLayer->GetParameters();
278 newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
279
280 // Add new layer to graph.
281 std::string layerName = "reduce_layer_" + std::to_string(i);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000282
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000283 Layer* replacementLayer = PolymorphicDowncast<Layer*>(
284 optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
285 layerName.c_str()));
Francis Murtagh56ccf682021-12-13 18:48:12 +0000286
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100287 // Connect previous layer with new layer.
288 // The first and last layer will be connected when the subgraph is replaced.
289 if (!layers.empty())
290 {
291 layers[i - 1]->GetOutputSlot(0).Connect(replacementLayer->GetInputSlot(0));
292 }
293
294 // Set updated tensorInfo for new layer.
295 replacementLayer->GetOutputSlot(0).SetTensorInfo(reducedTensorInfo);
296
297 if (!desc.m_KeepDims)
298 {
299 recalulatedAxis++;
300 }
301
302 layers.emplace_back(replacementLayer);
303 }
304
305 // Check if the TensorInfo from the last layer equals the inferred output from the original layer.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000306 ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() ==
307 PolymorphicDowncast<Layer*>(layers.back())->GetOutputSlot().GetTensorInfo());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100308
309 return layers;
310}
311
312//
313// Substitute baseLayer with new subgraph
314//
315template<typename LayerType>
316void ReplaceLayers(OptimizationViews& optimizationViews,
317 LayerType* baseLayer,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000318 std::vector<IConnectableLayer*>& layers)
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100319{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000320 std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100321
322 SubgraphView substitutionSubgraph(baseLayer);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000323 SubgraphView replacementSubgraph(std::move(replacementLayers),
324 CreateIInputsFrom({replacementLayers.front()}),
325 CreateIOutputsFrom({replacementLayers.back()}));
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100326
327 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
328}
329
Mike Kelly07810fc2020-11-12 10:58:48 +0000330} // namespace armnn