blob: 766bf2d2ccb6f5b67867519336d0ec960edb2a67 [file] [log] [blame]
Mike Kelly07810fc2020-11-12 10:58:48 +00001//
Cathal Corbettb7e5f532022-07-22 16:03:36 +01002// Copyright © 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 Corbettb7e5f532022-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 replacementLayer->m_Weight = std::move(baseLayer->m_Weight);
192 replacementLayer->m_Bias = std::move(baseLayer->m_Bias);
193
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000194 FuseLayer(optimizationViews,
195 baseLayer,
196 replacementLayer,
197 activationLayer,
198 activationDesc);
199
200 return replacementLayer;
201}
202
203template<typename LayerType>
204LayerType* FuseDepthwiseConvolution2dLayer(OptimizationViews& optimizationViews,
205 LayerType* baseLayer,
206 ActivationLayer* activationLayer,
207 ActivationDescriptor& activationDesc,
208 std::string name)
209{
Keith Davisb4dd5cc2022-04-07 11:32:00 +0100210 IConnectableLayer* replacement =
211 optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
212
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000213 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
214
Cathal Corbett06902652022-04-14 17:55:11 +0100215 replacementLayer->m_Weight = std::move(baseLayer->m_Weight);
216 replacementLayer->m_Bias = std::move(baseLayer->m_Bias);
217
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000218 FuseLayer(optimizationViews,
219 baseLayer,
220 replacementLayer,
221 activationLayer,
222 activationDesc);
223
224 return replacementLayer;
225}
226
227template<typename LayerType>
228LayerType* FuseFullyConnectedLayer(OptimizationViews& optimizationViews,
229 LayerType* baseLayer,
230 ActivationLayer* activationLayer,
231 ActivationDescriptor& activationDesc,
232 std::string name)
233{
234 IConnectableLayer* replacement =
235 optimizationViews.GetINetwork()->AddFullyConnectedLayer(baseLayer->GetParameters(),
236 name.c_str());
237 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
238
239 FuseLayer(optimizationViews,
240 baseLayer,
241 replacementLayer,
242 activationLayer,
243 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000244
245 replacementLayer->m_Weight = std::move(baseLayer->m_Weight);
246 replacementLayer->m_Bias = std::move(baseLayer->m_Bias);
247
248 return replacementLayer;
249}
250
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100251//
252// If reduce layer has multiple axes, add new layer for each axis to simulate the same behaviour
253// as currently only one axis is supported.
254//
255template<typename LayerType>
Francis Murtagh56ccf682021-12-13 18:48:12 +0000256std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100257 LayerType* baseLayer,
258 ReduceDescriptor& desc)
259{
260 // Vector of new chained layers, used for substitution.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000261 std::vector<IConnectableLayer*> layers;
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100262
263 // Vector of axes so each layer is reshaped correctly.
264 std::vector<uint32_t> axes;
265 unsigned int recalulatedAxis = 0;
266
267 for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
268 {
269 // Get TensorInfo from base layer and reduce shape using axis.
270 TensorInfo layerInfo = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
271
272 axes.emplace_back(desc.m_vAxis[i]);
273
274 const TensorInfo& reducedTensorInfo = ComputeReductionTensorShape(layerInfo,
275 axes,
276 desc.m_KeepDims);
277
278 // Create a vector for the single axis to be assigned to the descriptor.
279 // Update axis if keepDims is set reduce layers correctly.
280 std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
281
282 // Create a descriptor and assign single axis.
283 ReduceDescriptor newReduceDescriptor = baseLayer->GetParameters();
284 newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
285
286 // Add new layer to graph.
287 std::string layerName = "reduce_layer_" + std::to_string(i);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000288
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000289 Layer* replacementLayer = PolymorphicDowncast<Layer*>(
290 optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
291 layerName.c_str()));
Francis Murtagh56ccf682021-12-13 18:48:12 +0000292
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100293 // Connect previous layer with new layer.
294 // The first and last layer will be connected when the subgraph is replaced.
295 if (!layers.empty())
296 {
297 layers[i - 1]->GetOutputSlot(0).Connect(replacementLayer->GetInputSlot(0));
298 }
299
300 // Set updated tensorInfo for new layer.
301 replacementLayer->GetOutputSlot(0).SetTensorInfo(reducedTensorInfo);
302
303 if (!desc.m_KeepDims)
304 {
305 recalulatedAxis++;
306 }
307
308 layers.emplace_back(replacementLayer);
309 }
310
311 // Check if the TensorInfo from the last layer equals the inferred output from the original layer.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000312 ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() ==
313 PolymorphicDowncast<Layer*>(layers.back())->GetOutputSlot().GetTensorInfo());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100314
315 return layers;
316}
317
318//
319// Substitute baseLayer with new subgraph
320//
321template<typename LayerType>
322void ReplaceLayers(OptimizationViews& optimizationViews,
323 LayerType* baseLayer,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000324 std::vector<IConnectableLayer*>& layers)
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100325{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000326 std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100327
328 SubgraphView substitutionSubgraph(baseLayer);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000329 SubgraphView replacementSubgraph(std::move(replacementLayers),
330 CreateIInputsFrom({replacementLayers.front()}),
331 CreateIOutputsFrom({replacementLayers.back()}));
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100332
333 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
334}
335
Mike Kelly07810fc2020-11-12 10:58:48 +0000336} // namespace armnn