• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "LayersFwd.hpp"
7 #include <Network.hpp>
8 #include <TestUtils.hpp>
9 #include <doctest/doctest.h>
10 #include <armnn/backends/TensorHandle.hpp>
11 #include <Optimizer.hpp>
12 
13 TEST_SUITE("Optimizer")
14 {
15 using namespace armnn;
16 using namespace armnn::optimizations;
17 
18 // Helpers for testing
19 auto checkConstantFloat32 = [](const armnn::Layer *const layer)
__anon9f0260d60102(const armnn::Layer *const layer) 20 {
21     return IsLayerOfType<ConstantLayer>(layer) && (layer->GetDataType() == DataType::Float32);
22 };
23 
24 auto checkConstantFloat16 = [](const armnn::Layer *const layer)
__anon9f0260d60202(const armnn::Layer *const layer) 25 {
26     return IsLayerOfType<ConstantLayer>(layer) && (layer->GetDataType() == DataType::Float16);
27 };
28 
29 auto checkConstantQAsymmS8 = [](const armnn::Layer *const layer)
__anon9f0260d60302(const armnn::Layer *const layer) 30 {
31     return IsLayerOfType<ConstantLayer>(layer) && (layer->GetDataType() == DataType::QAsymmS8);
32 };
33 
34 auto checkPadFoldedIntoConv2d = [](const Layer* const layer)
__anon9f0260d60402(const Layer* const layer) 35 {
36     const auto conv2dLayer       = static_cast<const Convolution2dLayer*>(layer);
37     const auto conv2dLayerParams = conv2dLayer->GetParameters();
38 
39     return IsLayerOfType<Convolution2dLayer>(layer) &&
40            (layer->GetNameStr() == "folded-pad-into-conv2d") &&
41            (conv2dLayerParams.m_PadLeft == 2) &&
42            (conv2dLayerParams.m_PadRight == 2) &&
43            (conv2dLayerParams.m_PadTop == 2) &&
44            (conv2dLayerParams.m_PadBottom == 2) &&
45            (conv2dLayerParams.m_StrideX == 1) &&
46            (conv2dLayerParams.m_StrideY == 1) &&
47            (conv2dLayerParams.m_BiasEnabled == false) &&
48            (conv2dLayerParams.m_DataLayout == DataLayout::NHWC);
49 };
50 
51 TEST_CASE("ConvertConstFloat16DequantizeToConstFloat32")
52 {
53     Graph graph;
54     const unsigned int shape[] = {1, 2, 2, 3};
55 
56     const TensorInfo constTensorInfo(4, shape, DataType::Float16, 1.0, 0, true);
57     const TensorInfo outputDequantizeInfo(4, shape, DataType::Float32, 1.0, 0, true);
58 
59     auto constantLayer = graph.AddLayer<ConstantLayer>("constant");
60     std::vector<float> constantValues(constTensorInfo.GetNumElements(), 4.5f);
61     ConstTensor constTensor(constTensorInfo, constantValues.data());
62     constantLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
63     constantLayer->GetOutputSlot().SetTensorInfo(constTensorInfo);
64 
65     auto dequantizeLayer = graph.AddLayer<DequantizeLayer>("dequantize");
66     dequantizeLayer->GetOutputSlot().SetTensorInfo(outputDequantizeInfo);
67 
68     auto output = graph.AddLayer<OutputLayer>(0, "output");
69 
70     // Connect up constant -> dequantize -> output
71     constantLayer->GetOutputSlot().Connect(dequantizeLayer->GetInputSlot(0));
72     dequantizeLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
73 
74 
75     CHECK(CheckSequence(graph.cbegin(), graph.cend(),
76                         checkConstantFloat16,
77                         &IsLayerOfType<DequantizeLayer>,
78                         &IsLayerOfType<OutputLayer>));
79 
80     armnn::Optimizer::Pass(graph, MakeOptimizations(ConvertConstDequantisationLayersToConstLayers()));
81 
82     CHECK(CheckSequence(graph.cbegin(), graph.cend(),
83                         checkConstantFloat32,
84                         &IsLayerOfType<OutputLayer>));
85 }
86 
87 TEST_CASE("ConvertConstFloat16DequantizeToConstFloat32PlusFusePadWithConv2d")
88 {
89     Graph graph;
90     const unsigned int shape[] = {1, 2, 2, 3};
91 
92     const TensorInfo constTensorInfo(4, shape, DataType::Float16, 1.0, 0, true);
93     const TensorInfo outputDequantizeInfo(4, shape, DataType::Float32, 1.0, 0, true);
94 
95     auto constantLayer = graph.AddLayer<ConstantLayer>("constant");
96     std::vector<float> constantValues(constTensorInfo.GetNumElements(), 4.5f);
97     ConstTensor constTensor(constTensorInfo, constantValues.data());
98     constantLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
99     constantLayer->GetOutputSlot().SetTensorInfo(constTensorInfo);
100 
101     auto dequantizeLayer = graph.AddLayer<DequantizeLayer>("dequantize");
102     dequantizeLayer->GetOutputSlot().SetTensorInfo(outputDequantizeInfo);
103 
104     auto output = graph.AddLayer<OutputLayer>(0, "output");
105 
106     Convolution2dDescriptor convolution2dDescriptor;
107     convolution2dDescriptor.m_BiasEnabled = false;
108     convolution2dDescriptor.m_StrideX     = 1;
109     convolution2dDescriptor.m_StrideY     = 1;
110     convolution2dDescriptor.m_DataLayout  = DataLayout::NHWC;
111     auto conv2d = graph.AddLayer<Convolution2dLayer>(convolution2dDescriptor, "conv2d");
112 
113 
114     auto inputLayer = graph.AddLayer<InputLayer>(0, "input");
115 
116     PadDescriptor padDescriptor({{0, 0},
117                                  {2, 2},
118                                  {2, 2},
119                                  {0, 0}});
120 
121     const unsigned int paddedShape[]  = {1, 6, 6, 3};
122 
123     TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
124 
125     auto padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
126     padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
127 
128     // Connect up:
129     //           input -> pad -> conv2d -> output
130     // constant -> dequantize ->
131     constantLayer->GetOutputSlot().Connect(dequantizeLayer->GetInputSlot(0));
132     dequantizeLayer->GetOutputSlot().Connect(conv2d->GetInputSlot(1));
133     inputLayer->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
134     padLayer->GetOutputSlot().Connect(conv2d->GetInputSlot(0));
135     conv2d->GetOutputSlot().Connect(output->GetInputSlot(0));
136 
137     CHECK(CheckSequence(graph.cbegin(), graph.cend(),
138                         &IsLayerOfType<InputLayer>,
139                         checkConstantFloat16,
140                         &IsLayerOfType<DequantizeLayer>,
141                         &IsLayerOfType<Convolution2dLayer>,
142                         &IsLayerOfType<PadLayer>,
143                         &IsLayerOfType<OutputLayer>));
144 
145     armnn::Optimizer::Pass(graph, MakeOptimizations(ConvertConstDequantisationLayersToConstLayers()));
146     armnn::Optimizer::Pass(graph, MakeOptimizations(FoldPadIntoConvolution2d()));
147 
148     // Ensure that the const and dequantize are now constant of type fp32
149     // Ensure pad and conv2d are now just convolution
150     CHECK(CheckSequence(graph.cbegin(), graph.cend(),
151                         &IsLayerOfType<InputLayer>,
152                         checkConstantFloat32,
153                         checkPadFoldedIntoConv2d,
154                         &IsLayerOfType<OutputLayer>));
155 }
156 
157 TEST_CASE("ConvertConstInt8DequantizeToConstFloat32")
158 {
159     Graph graph;
160     const unsigned int shape[] = {1, 2, 2, 3};
161 
162     const TensorInfo constTensorInfo(4, shape, DataType::QAsymmS8, 1.0, 0, true);
163     const TensorInfo outputDequantizeInfo(4, shape, DataType::Float32, 1.0, 0, true);
164 
165     auto constantLayer = graph.AddLayer<ConstantLayer>("constant");
166     std::vector<int8_t> constantValues(constTensorInfo.GetNumElements(), 5);
167     ConstTensor constTensor(constTensorInfo, constantValues.data());
168     constantLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
169     constantLayer->GetOutputSlot().SetTensorInfo(constTensorInfo);
170 
171     auto dequantizeLayer = graph.AddLayer<DequantizeLayer>("dequantize");
172     dequantizeLayer->GetOutputSlot().SetTensorInfo(outputDequantizeInfo);
173 
174     auto output = graph.AddLayer<OutputLayer>(0, "output");
175 
176     // Connect up constant -> dequantize -> output
177     constantLayer->GetOutputSlot().Connect(dequantizeLayer->GetInputSlot(0));
178     dequantizeLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
179 
180     CHECK(CheckSequence(graph.cbegin(), graph.cend(),
181                         checkConstantQAsymmS8,
182                         &IsLayerOfType<DequantizeLayer>,
183                         &IsLayerOfType<OutputLayer>));
184 
185     armnn::Optimizer::Pass(graph, MakeOptimizations(ConvertConstDequantisationLayersToConstLayers()));
186 
187     CHECK(CheckSequence(graph.cbegin(), graph.cend(),
188                         checkConstantFloat32,
189                         &IsLayerOfType<OutputLayer>));
190 }
191 }
192