blob: de3a34ee08f5b9a53a48026a88595851a24955e9 [file] [log] [blame]
Mike Kelly07810fc2020-11-12 10:58:48 +00001//
2// Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3// 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>
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
23SubgraphView::IInputSlots CreateIInputsFrom(const std::vector<armnn::IConnectableLayer*>& layers)
Mike Kelly07810fc2020-11-12 10:58:48 +000024{
Francis Murtagh56ccf682021-12-13 18:48:12 +000025 SubgraphView::IInputSlots result;
Mike Kelly07810fc2020-11-12 10:58:48 +000026 for (auto&& layer : layers)
27 {
Francis Murtagh56ccf682021-12-13 18:48:12 +000028 for (unsigned int i = 0 ; i < layer->GetNumInputSlots(); ++i)
Mike Kelly07810fc2020-11-12 10:58:48 +000029 {
Francis Murtagh56ccf682021-12-13 18:48:12 +000030 result.push_back(&(layer->GetInputSlot(i)));
Mike Kelly07810fc2020-11-12 10:58:48 +000031 }
32 }
33 return result;
34}
35
36//
37// this helper only works if all layers where the outputs connect to are not selected
38//
Francis Murtagh56ccf682021-12-13 18:48:12 +000039
40SubgraphView::IOutputSlots CreateIOutputsFrom(const std::vector<armnn::IConnectableLayer*>& layers)
Mike Kelly07810fc2020-11-12 10:58:48 +000041{
Francis Murtagh56ccf682021-12-13 18:48:12 +000042 SubgraphView::IOutputSlots result;
43 for (auto &&layer: layers)
Mike Kelly07810fc2020-11-12 10:58:48 +000044 {
Francis Murtagh56ccf682021-12-13 18:48:12 +000045 for (unsigned int i = 0; i < layer->GetNumOutputSlots(); ++i)
Mike Kelly07810fc2020-11-12 10:58:48 +000046 {
Francis Murtagh56ccf682021-12-13 18:48:12 +000047 result.push_back(&(layer->GetOutputSlot(i)));
Mike Kelly07810fc2020-11-12 10:58:48 +000048 }
49 }
50 return result;
51}
52
Teresa Charlind672f5d2021-01-18 18:07:57 +000053bool checkDataTypeInputandOutput(const Layer& layer)
54{
55 auto inputInfo = layer.GetInputSlot(0).GetConnection()->GetTensorInfo();
56 auto outputInfo = layer.GetOutputSlot(0).GetTensorInfo();
57 bool sameDataType = (inputInfo.GetDataType() == outputInfo.GetDataType());
58
59 // Check is same quantization info (same scale and offset)
60 if (sameDataType)
61 {
62 if (IsQuantizedType(inputInfo.GetDataType()))
63 {
64 bool sameScale = (inputInfo.GetQuantizationScale() == outputInfo.GetQuantizationScale());
65 bool sameOffset = (inputInfo.GetQuantizationOffset() == outputInfo.GetQuantizationOffset());
66
67 return (sameScale && sameOffset);
68 }
69 else
70 {
71 return true;
72 }
73 }
74 else
75 {
76 return false;
77 }
78}
79
Mike Kelly07810fc2020-11-12 10:58:48 +000080} // namespace
81
Mike Kelly1ac690a2020-11-17 11:41:38 +000082inline void ReportUntouchedLayers(OptimizationViews& optimizationViews, std::map<LayerGuid, Layer*> untouched)
Mike Kelly07810fc2020-11-12 10:58:48 +000083{
Mike Kelly1ac690a2020-11-17 11:41:38 +000084 std::vector<Layer*> untouchedVector;
85 for (const auto& pair : untouched)
Mike Kelly07810fc2020-11-12 10:58:48 +000086 {
Mike Kelly1ac690a2020-11-17 11:41:38 +000087 Layer* layer = pair.second;
Francis Murtagh56ccf682021-12-13 18:48:12 +000088 SubgraphView subgraphView({layer},
89 CreateIInputsFrom({layer}),
90 CreateIOutputsFrom({layer}));
Mike Kelly1ac690a2020-11-17 11:41:38 +000091 optimizationViews.AddUntouchedSubgraph(std::move(subgraphView));
Mike Kelly07810fc2020-11-12 10:58:48 +000092 }
Mike Kelly07810fc2020-11-12 10:58:48 +000093}
94
95template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +000096LayerType* FuseLayer(OptimizationViews& optimizationViews,
97 LayerType* baseLayer,
98 LayerType* replacementLayer,
99 ActivationLayer* activationLayer,
100 ActivationDescriptor& activationDesc)
Mike Kelly07810fc2020-11-12 10:58:48 +0000101{
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000102 replacementLayer->SetAdditionalInfoForObject(
103 std::make_shared<ActivationDescriptor>(activationDesc));
Mike Kelly07810fc2020-11-12 10:58:48 +0000104
Francis Murtagh56ccf682021-12-13 18:48:12 +0000105 SubgraphView substitutionSubgraph({baseLayer, activationLayer},
106 CreateIInputsFrom({baseLayer}),
107 CreateIOutputsFrom({activationLayer}));
Mike Kelly07810fc2020-11-12 10:58:48 +0000108 SubgraphView replacementSubgraph(replacementLayer);
109
110 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000111
Mike Kelly07810fc2020-11-12 10:58:48 +0000112 return replacementLayer;
113}
114
115template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000116LayerType* FuseAdditionLayer(OptimizationViews& optimizationViews,
117 LayerType* baseLayer,
118 ActivationLayer* activationLayer,
119 ActivationDescriptor& activationDesc,
120 std::string name)
121{
122 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddAdditionLayer(name.c_str());
123 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
124
125 FuseLayer(optimizationViews,
126 baseLayer,
127 replacementLayer,
128 activationLayer,
129 activationDesc);
130
131 return replacementLayer;
132}
133
134template<typename LayerType>
135LayerType* FuseSubtractionLayer(OptimizationViews& optimizationViews,
136 LayerType* baseLayer,
137 ActivationLayer* activationLayer,
138 ActivationDescriptor& activationDesc,
139 std::string name)
140{
141 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddSubtractionLayer(name.c_str());
142 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
143
144 FuseLayer(optimizationViews,
145 baseLayer,
146 replacementLayer,
147 activationLayer,
148 activationDesc);
149
150 return replacementLayer;
151}
152
153template<typename LayerType>
154LayerType* FuseDivisionLayer(OptimizationViews& optimizationViews,
155 LayerType* baseLayer,
156 ActivationLayer* activationLayer,
157 ActivationDescriptor& activationDesc,
158 std::string name)
159{
160 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddDivisionLayer(name.c_str());
161 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
162
163 FuseLayer(optimizationViews,
164 baseLayer,
165 replacementLayer,
166 activationLayer,
167 activationDesc);
168
169 return replacementLayer;
170}
171
172template<typename LayerType>
173LayerType* FuseMultiplicationLayer(OptimizationViews& optimizationViews,
Mike Kelly07810fc2020-11-12 10:58:48 +0000174 LayerType* baseLayer,
175 ActivationLayer* activationLayer,
176 ActivationDescriptor& activationDesc,
177 std::string name)
178{
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000179 IConnectableLayer* replacement = optimizationViews.GetINetwork()->AddMultiplicationLayer(name.c_str());
180 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
Mike Kelly07810fc2020-11-12 10:58:48 +0000181
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000182 FuseLayer(optimizationViews,
183 baseLayer,
184 replacementLayer,
185 activationLayer,
186 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000187
Mike Kelly07810fc2020-11-12 10:58:48 +0000188 return replacementLayer;
189}
190
191template<typename LayerType>
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000192LayerType* FuseBatchNormalizationLayer(OptimizationViews& optimizationViews,
193 LayerType* baseLayer,
194 ActivationLayer* activationLayer,
195 ActivationDescriptor& activationDesc,
196 std::string name)
Mike Kelly07810fc2020-11-12 10:58:48 +0000197{
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000198 IConnectableLayer* replacement =
199 optimizationViews.GetINetwork()->AddBatchNormalizationLayer(baseLayer->GetParameters(),
200 ConstTensor(),
201 ConstTensor(),
202 ConstTensor(),
203 ConstTensor(),
204 name.c_str());
205 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
206
207 FuseLayer(optimizationViews,
208 baseLayer,
209 replacementLayer,
210 activationLayer,
211 activationDesc);
212
Francis Murtagh56ccf682021-12-13 18:48:12 +0000213 SubgraphView substitutionSubgraph({baseLayer, activationLayer},
214 CreateIInputsFrom({baseLayer}),
215 CreateIOutputsFrom({activationLayer}));
216 SubgraphView replacementSubgraph(replacementLayer);
217
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000218 return replacementLayer;
219}
220
221template<typename LayerType>
222LayerType* FuseConvolution2dLayer(OptimizationViews& optimizationViews,
223 LayerType* baseLayer,
224 ActivationLayer* activationLayer,
225 ActivationDescriptor& activationDesc,
226 std::string name)
227{
228 std::shared_ptr<ConstTensorHandle> weightHandle = baseLayer->m_Weight;
229 TensorInfo weightInfo = weightHandle->GetTensorInfo();
230
231 std::shared_ptr<ConstTensorHandle> biasHandle = baseLayer->m_Bias;
232 ConstTensor biasTensor;
233 if (!biasHandle)
234 {
235 biasTensor = ConstTensor();
236 }
237 else
238 {
239 biasTensor = ConstTensor(biasHandle->GetTensorInfo(), biasHandle->Map(true));
240 }
241
242 IConnectableLayer* replacement =
243 optimizationViews.GetINetwork()->
244 AddConvolution2dLayer(baseLayer->GetParameters(),
245 ConstTensor(weightInfo, weightHandle->Map(true)),
246 Optional<ConstTensor>(biasTensor),
247 name.c_str());
248 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
249
250 FuseLayer(optimizationViews,
251 baseLayer,
252 replacementLayer,
253 activationLayer,
254 activationDesc);
255
256 return replacementLayer;
257}
258
259template<typename LayerType>
260LayerType* FuseDepthwiseConvolution2dLayer(OptimizationViews& optimizationViews,
261 LayerType* baseLayer,
262 ActivationLayer* activationLayer,
263 ActivationDescriptor& activationDesc,
264 std::string name)
265{
Cathal Corbett06902652022-04-14 17:55:11 +0100266 IConnectableLayer* replacement = optimizationViews.GetINetwork()->
267 AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000268 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
269
Cathal Corbett06902652022-04-14 17:55:11 +0100270 replacementLayer->m_Weight = std::move(baseLayer->m_Weight);
271 replacementLayer->m_Bias = std::move(baseLayer->m_Bias);
272
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000273 FuseLayer(optimizationViews,
274 baseLayer,
275 replacementLayer,
276 activationLayer,
277 activationDesc);
278
279 return replacementLayer;
280}
281
282template<typename LayerType>
283LayerType* FuseFullyConnectedLayer(OptimizationViews& optimizationViews,
284 LayerType* baseLayer,
285 ActivationLayer* activationLayer,
286 ActivationDescriptor& activationDesc,
287 std::string name)
288{
289 IConnectableLayer* replacement =
290 optimizationViews.GetINetwork()->AddFullyConnectedLayer(baseLayer->GetParameters(),
291 name.c_str());
292 LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
293
294 FuseLayer(optimizationViews,
295 baseLayer,
296 replacementLayer,
297 activationLayer,
298 activationDesc);
Mike Kelly07810fc2020-11-12 10:58:48 +0000299
300 replacementLayer->m_Weight = std::move(baseLayer->m_Weight);
301 replacementLayer->m_Bias = std::move(baseLayer->m_Bias);
302
303 return replacementLayer;
304}
305
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100306//
307// If reduce layer has multiple axes, add new layer for each axis to simulate the same behaviour
308// as currently only one axis is supported.
309//
310template<typename LayerType>
Francis Murtagh56ccf682021-12-13 18:48:12 +0000311std::vector<IConnectableLayer*> ChainReduceLayers(OptimizationViews& optimizationViews,
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100312 LayerType* baseLayer,
313 ReduceDescriptor& desc)
314{
315 // Vector of new chained layers, used for substitution.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000316 std::vector<IConnectableLayer*> layers;
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100317
318 // Vector of axes so each layer is reshaped correctly.
319 std::vector<uint32_t> axes;
320 unsigned int recalulatedAxis = 0;
321
322 for (unsigned int i = 0; i != desc.m_vAxis.size(); ++i)
323 {
324 // Get TensorInfo from base layer and reduce shape using axis.
325 TensorInfo layerInfo = baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo();
326
327 axes.emplace_back(desc.m_vAxis[i]);
328
329 const TensorInfo& reducedTensorInfo = ComputeReductionTensorShape(layerInfo,
330 axes,
331 desc.m_KeepDims);
332
333 // Create a vector for the single axis to be assigned to the descriptor.
334 // Update axis if keepDims is set reduce layers correctly.
335 std::vector<uint32_t> singleAxis(1, desc.m_vAxis[i] - recalulatedAxis);
336
337 // Create a descriptor and assign single axis.
338 ReduceDescriptor newReduceDescriptor = baseLayer->GetParameters();
339 newReduceDescriptor.m_vAxis.assign(singleAxis.begin(), singleAxis.end());
340
341 // Add new layer to graph.
342 std::string layerName = "reduce_layer_" + std::to_string(i);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000343
Cathal Corbettcbfd7182021-12-15 17:12:59 +0000344 Layer* replacementLayer = PolymorphicDowncast<Layer*>(
345 optimizationViews.GetINetwork()->AddReduceLayer(newReduceDescriptor,
346 layerName.c_str()));
Francis Murtagh56ccf682021-12-13 18:48:12 +0000347
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100348 // Connect previous layer with new layer.
349 // The first and last layer will be connected when the subgraph is replaced.
350 if (!layers.empty())
351 {
352 layers[i - 1]->GetOutputSlot(0).Connect(replacementLayer->GetInputSlot(0));
353 }
354
355 // Set updated tensorInfo for new layer.
356 replacementLayer->GetOutputSlot(0).SetTensorInfo(reducedTensorInfo);
357
358 if (!desc.m_KeepDims)
359 {
360 recalulatedAxis++;
361 }
362
363 layers.emplace_back(replacementLayer);
364 }
365
366 // Check if the TensorInfo from the last layer equals the inferred output from the original layer.
Francis Murtagh56ccf682021-12-13 18:48:12 +0000367 ARMNN_ASSERT(baseLayer->GetOutputSlot(0).GetTensorInfo() ==
368 PolymorphicDowncast<Layer*>(layers.back())->GetOutputSlot().GetTensorInfo());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100369
370 return layers;
371}
372
373//
374// Substitute baseLayer with new subgraph
375//
376template<typename LayerType>
377void ReplaceLayers(OptimizationViews& optimizationViews,
378 LayerType* baseLayer,
Francis Murtagh56ccf682021-12-13 18:48:12 +0000379 std::vector<IConnectableLayer*>& layers)
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100380{
Francis Murtagh56ccf682021-12-13 18:48:12 +0000381 std::list<IConnectableLayer*> replacementLayers(layers.begin(), layers.end());
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100382
383 SubgraphView substitutionSubgraph(baseLayer);
Francis Murtagh56ccf682021-12-13 18:48:12 +0000384 SubgraphView replacementSubgraph(std::move(replacementLayers),
385 CreateIInputsFrom({replacementLayers.front()}),
386 CreateIOutputsFrom({replacementLayers.back()}));
Matthew Sloyan5fc0fd62021-05-03 12:22:03 +0100387
388 optimizationViews.AddSubstitution({substitutionSubgraph, replacementSubgraph});
389}
390
Mike Kelly07810fc2020-11-12 10:58:48 +0000391} // namespace armnn