blob: 30df6eb0e66e10fcd92e7c89146fb27f03752b70 [file] [log] [blame]
surmeh01bceff2f2018-03-29 16:29:27 +01001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
surmeh01bceff2f2018-03-29 16:29:27 +01004//
5#include <boost/test/unit_test.hpp>
6
David Beckac42efd2018-09-26 17:41:13 +01007#include <armnn/ArmNN.hpp>
8#include <Graph.hpp>
9#include <Optimizer.hpp>
10#include <backends/CpuTensorHandle.hpp>
11#include <FloatingPointConverter.hpp>
surmeh01bceff2f2018-03-29 16:29:27 +010012
13namespace
14{
15template <typename LayerT>
16bool IsLayerOfType(const armnn::Layer* const layer)
17{
18 return (layer->GetType() == armnn::LayerEnumOf<LayerT>());
19}
20
21bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
22{
23 return (first == last);
24}
25
telsoa01c577f2c2018-08-31 09:22:23 +010026/// Checks each unary function in Us evaluates true for each correspondent layer in the sequence [first, last).
surmeh01bceff2f2018-03-29 16:29:27 +010027template <typename U, typename... Us>
28bool CheckSequence(const armnn::Graph::ConstIterator first,
29 const armnn::Graph::ConstIterator last,
30 U&& u,
31 Us&&... us)
32{
33 return u(*first) && CheckSequence(std::next(first), last, us...);
34}
telsoa01c577f2c2018-08-31 09:22:23 +010035
36template <typename LayerT>
37bool CheckRelatedLayers(armnn::Graph& graph, const std::list<std::string>& testRelatedLayers)
38{
39 for (auto& layer : graph)
40 {
41 if (layer->GetType() == armnn::LayerEnumOf<LayerT>())
42 {
43 auto& relatedLayers = layer->GetRelatedLayerNames();
44 if(!std::equal(relatedLayers.begin(), relatedLayers.end(),
45 testRelatedLayers.begin(), testRelatedLayers.end()))
46 {
47 return false;
48 }
49 }
50 }
51
52 return true;
53}
54
55// connects two layers
56using namespace armnn;
57void Connect(Layer* from, Layer* to, const TensorInfo& tensorInfo, unsigned int fromIndex = 0, unsigned int toIndex = 0)
58{
59 from->GetOutputSlot(fromIndex).Connect(to->GetInputSlot(toIndex));
60 from->GetOutputHandler(fromIndex).SetTensorInfo(tensorInfo);
61}
62
63void CreateLSTMLayerHelper(Graph &graph, bool CifgEnabled)
64{
65 LstmDescriptor layerDesc;
66 layerDesc.m_ActivationFunc = 4;
67 layerDesc.m_ClippingThresCell = 0.2f;
68 layerDesc.m_ClippingThresProj = 0.4f;
69 layerDesc.m_CifgEnabled = CifgEnabled;
70 layerDesc.m_PeepholeEnabled = false;
71 layerDesc.m_ProjectionEnabled = false;
72
73 LstmLayer* const layer = graph.AddLayer<LstmLayer>(layerDesc, "layer");
74 unsigned int batchSize = 3;
75 unsigned int inputSize = 2;
76 unsigned int numUnits = 4;
77 unsigned int outputSize = 4;
78
79 layer->m_BasicParameters.m_InputToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
80 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
81 layer->m_BasicParameters.m_InputToCellWeights = std::make_unique<ScopedCpuTensorHandle>
82 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
83 layer->m_BasicParameters.m_InputToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
84 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
85 layer->m_BasicParameters.m_RecurrentToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
86 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
87 layer->m_BasicParameters.m_RecurrentToCellWeights = std::make_unique<ScopedCpuTensorHandle>
88 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
89 layer->m_BasicParameters.m_RecurrentToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
90 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
91 layer->m_BasicParameters.m_ForgetGateBias = std::make_unique<ScopedCpuTensorHandle>
92 (TensorInfo({ numUnits }, DataType::Float32));
93 layer->m_BasicParameters.m_CellBias = std::make_unique<ScopedCpuTensorHandle>
94 (TensorInfo({ numUnits }, DataType::Float32));
95 layer->m_BasicParameters.m_OutputGateBias = std::make_unique<ScopedCpuTensorHandle>
96 (TensorInfo({ numUnits }, DataType::Float32));
97
98 layer->m_BasicParameters.m_InputToForgetWeights->Allocate();
99 layer->m_BasicParameters.m_InputToCellWeights->Allocate();
100 layer->m_BasicParameters.m_InputToOutputWeights->Allocate();
101 layer->m_BasicParameters.m_RecurrentToForgetWeights->Allocate();
102 layer->m_BasicParameters.m_RecurrentToCellWeights->Allocate();
103 layer->m_BasicParameters.m_RecurrentToOutputWeights->Allocate();
104 layer->m_BasicParameters.m_ForgetGateBias->Allocate();
105 layer->m_BasicParameters.m_CellBias->Allocate();
106 layer->m_BasicParameters.m_OutputGateBias->Allocate();
107
108 if (!layerDesc.m_CifgEnabled)
109 {
110 layer->m_CifgParameters.m_InputToInputWeights = std::make_unique<ScopedCpuTensorHandle>
111 (TensorInfo({ numUnits, inputSize }, DataType::Float32));
112 layer->m_CifgParameters.m_RecurrentToInputWeights = std::make_unique<ScopedCpuTensorHandle>
113 (TensorInfo({ numUnits, outputSize }, DataType::Float32));
114 layer->m_CifgParameters.m_CellToInputWeights = std::make_unique<ScopedCpuTensorHandle>
115 (TensorInfo({ numUnits }, DataType::Float32));
116 layer->m_CifgParameters.m_InputGateBias = std::make_unique<ScopedCpuTensorHandle>
117 (TensorInfo({ numUnits }, DataType::Float32));
118 layer->m_CifgParameters.m_InputToInputWeights->Allocate();
119 layer->m_CifgParameters.m_RecurrentToInputWeights->Allocate();
120 layer->m_CifgParameters.m_CellToInputWeights->Allocate();
121 layer->m_CifgParameters.m_InputGateBias->Allocate();
122 }
123
124 if (layerDesc.m_ProjectionEnabled)
125 {
126 layer->m_ProjectionParameters.m_ProjectionWeights = std::make_unique<ScopedCpuTensorHandle>
127 (TensorInfo({ outputSize, numUnits }, DataType::Float32));
128 layer->m_ProjectionParameters.m_ProjectionBias = std::make_unique<ScopedCpuTensorHandle>
129 (TensorInfo({ outputSize }, DataType::Float32));
130 layer->m_ProjectionParameters.m_ProjectionWeights->Allocate();
131 layer->m_ProjectionParameters.m_ProjectionBias->Allocate();
132 }
133
134 if (layerDesc.m_PeepholeEnabled)
135 {
136 layer->m_PeepholeParameters.m_CellToForgetWeights = std::make_unique<ScopedCpuTensorHandle>
137 (TensorInfo({ numUnits }, DataType::Float32));
138 layer->m_PeepholeParameters.m_CellToOutputWeights = std::make_unique<ScopedCpuTensorHandle>
139 (TensorInfo({ numUnits }, DataType::Float32));
140 layer->m_PeepholeParameters.m_CellToForgetWeights->Allocate();
141 layer->m_PeepholeParameters.m_CellToOutputWeights->Allocate();
142 }
143
144 // create input and output layers
145 Layer* const input = graph.AddLayer<InputLayer>(0, "input");
146 Layer* const outputStateIn = graph.AddLayer<InputLayer>(1, "outputStateIn");
147 Layer* const cellStateIn = graph.AddLayer<InputLayer>(2, "cellStateIn");
148 Layer* const scratchBuffer = graph.AddLayer<OutputLayer>(0, "scratchBuffer");
149 Layer* const outputStateOut = graph.AddLayer<OutputLayer>(1, "outputStateOut");
150 Layer* const cellStateOut = graph.AddLayer<OutputLayer>(2, "cellStateOut");
151 Layer* const output = graph.AddLayer<OutputLayer>(3, "output");
152
153 // connect up
154 armnn::TensorInfo lstmTensorInfo1({ batchSize, inputSize }, DataType::Float32);
155 armnn::TensorInfo lstmTensorInfo2({ batchSize, numUnits}, DataType::Float32);
156 armnn::TensorInfo lstmTensorInfo3({ batchSize, outputSize }, DataType::Float32);
157 armnn::TensorInfo lstmTensorInfoScratchBuff({ batchSize, numUnits*3 }, DataType::Float32);
158 if (layerDesc.m_CifgEnabled)
159 {
160 lstmTensorInfoScratchBuff.SetShape({ batchSize, numUnits*4 });
161 }
162
163 Connect(input, layer, lstmTensorInfo1, 0, 0);
164 Connect(cellStateIn, layer, lstmTensorInfo2, 0, 1);
165 Connect(outputStateIn, layer, lstmTensorInfo3, 0, 2);
166 Connect(layer, scratchBuffer, lstmTensorInfoScratchBuff, 0, 0);
167 Connect(layer, outputStateOut, lstmTensorInfo3, 1, 0);
168 Connect(layer, cellStateOut, lstmTensorInfo2, 2, 0);
169 Connect(layer, output, lstmTensorInfo3, 3, 0);
170}
171
surmeh01bceff2f2018-03-29 16:29:27 +0100172}
173
174BOOST_AUTO_TEST_SUITE(Optimizer)
telsoa01c577f2c2018-08-31 09:22:23 +0100175using namespace armnn::optimizations;
surmeh01bceff2f2018-03-29 16:29:27 +0100176
telsoa01c577f2c2018-08-31 09:22:23 +0100177BOOST_AUTO_TEST_CASE(OptimizeInversePermutesTest)
surmeh01bceff2f2018-03-29 16:29:27 +0100178{
179 armnn::Graph graph;
180
181 auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
182
183 graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
184
telsoa01c577f2c2018-08-31 09:22:23 +0100185 // Inserts two permutes, one the inverse of the other.
surmeh01bceff2f2018-03-29 16:29:27 +0100186 graph.InsertNewLayer<armnn::PermuteLayer>(output->GetInputSlot(0),
187 armnn::PermuteDescriptor({0, 2, 3, 1}),
188 "perm0231");
189 graph.InsertNewLayer<armnn::PermuteLayer>(output->GetInputSlot(0),
190 armnn::PermuteDescriptor({0, 3, 1, 2}),
191 "perm0312");
192
193 BOOST_TEST(CheckSequence(graph.cbegin(),
194 graph.cend(),
195 &IsLayerOfType<armnn::InputLayer>,
196 &IsLayerOfType<armnn::PermuteLayer>,
197 &IsLayerOfType<armnn::PermuteLayer>,
198 &IsLayerOfType<armnn::OutputLayer>));
199
telsoa01c577f2c2018-08-31 09:22:23 +0100200 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeInversePermutes()));
surmeh01bceff2f2018-03-29 16:29:27 +0100201
telsoa01c577f2c2018-08-31 09:22:23 +0100202 // The permutes are removed.
surmeh01bceff2f2018-03-29 16:29:27 +0100203 BOOST_TEST(CheckSequence(graph.cbegin(),
204 graph.cend(),
205 &IsLayerOfType<armnn::InputLayer>,
206 &IsLayerOfType<armnn::OutputLayer>));
207}
208
telsoa01c577f2c2018-08-31 09:22:23 +0100209BOOST_AUTO_TEST_CASE(LSTMValidateTensorShapesFromInputsCIFGDisabledTest)
210{
211 Graph graph;
212
213 //Helper function creates graph containing LSTM layer with required input and output layers
214 CreateLSTMLayerHelper(graph, false);
215
216 //This function used to call ValidateShapesFromInputs();
217 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
218}
219
220BOOST_AUTO_TEST_CASE(LSTMValidateTensorShapesFromInputsCIFGEnabledTest)
221{
222 Graph graph;
223
224 //Helper function creates graph containing LSTM layer with required input and output layers
225 CreateLSTMLayerHelper(graph, true);
226
227 //This function used to call ValidateShapesFromInputs();
228 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
229}
230
231BOOST_AUTO_TEST_CASE(MovePermuteUpTest)
surmeh01bceff2f2018-03-29 16:29:27 +0100232{
233 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
234 const armnn::TensorInfo permuted({ 1, 3, 5, 2 }, armnn::DataType::Float32);
235
236 armnn::Graph graph;
237
238 armnn::LayerBindingId inputId = 0;
239
240 armnn::Layer* head = graph.AddLayer<armnn::OutputLayer>(0, "output");
241
telsoa01c577f2c2018-08-31 09:22:23 +0100242 std::string permuteLayerName = "original_permute";
243
surmeh01bceff2f2018-03-29 16:29:27 +0100244 // Insert permute
245 head = graph.InsertNewLayer<armnn::PermuteLayer>(head->GetInputSlot(0),
telsoa01c577f2c2018-08-31 09:22:23 +0100246 armnn::PermuteDescriptor({ 0, 2, 3, 1 }),
247 permuteLayerName.c_str());
248
surmeh01bceff2f2018-03-29 16:29:27 +0100249 head->GetOutputHandler().SetTensorInfo(permuted);
250
telsoa01c577f2c2018-08-31 09:22:23 +0100251 // Inserts layers that don't care about data format.
surmeh01bceff2f2018-03-29 16:29:27 +0100252 head = graph.InsertNewLayer<armnn::ActivationLayer>(head->GetInputSlot(0),
253 armnn::ActivationDescriptor{}, "");
254 head->GetOutputHandler().SetTensorInfo(info);
255
256 head = graph.InsertNewLayer<armnn::AdditionLayer>(head->GetInputSlot(0), "");
257 head->GetOutputHandler().SetTensorInfo(info);
258
telsoa01c577f2c2018-08-31 09:22:23 +0100259 // Inserts input for 2nd input of Addition.
surmeh01bceff2f2018-03-29 16:29:27 +0100260 graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(1), inputId++, "")
261 ->GetOutputHandler().SetTensorInfo(info);
262
263 head = graph.InsertNewLayer<armnn::FakeQuantizationLayer>(head->GetInputSlot(0),
264 armnn::FakeQuantizationDescriptor{}, "");
265 head->GetOutputHandler().SetTensorInfo(info);
266
267 head = graph.InsertNewLayer<armnn::FloorLayer>(head->GetInputSlot(0), "");
268 head->GetOutputHandler().SetTensorInfo(info);
269
270 head = graph.InsertNewLayer<armnn::MemCopyLayer>(head->GetInputSlot(0), "");
271 head->GetOutputHandler().SetTensorInfo(info);
272
273 head = graph.InsertNewLayer<armnn::MultiplicationLayer>(head->GetInputSlot(0), "");
274 head->GetOutputHandler().SetTensorInfo(info);
275
telsoa01c577f2c2018-08-31 09:22:23 +0100276 // Inserts input for 2nd input of Multiplication.
surmeh01bceff2f2018-03-29 16:29:27 +0100277 graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(1), inputId++, "")
278 ->GetOutputHandler().SetTensorInfo(info);
279
telsoa01c577f2c2018-08-31 09:22:23 +0100280 // Inserts input.
surmeh01bceff2f2018-03-29 16:29:27 +0100281 graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(0), inputId++, "")
282 ->GetOutputHandler().SetTensorInfo(info);
283
284 BOOST_TEST(CheckSequence(graph.cbegin(),
285 graph.cend(),
286 &IsLayerOfType<armnn::InputLayer>,
287 &IsLayerOfType<armnn::InputLayer>,
288 &IsLayerOfType<armnn::InputLayer>,
289 &IsLayerOfType<armnn::MultiplicationLayer>,
290 &IsLayerOfType<armnn::MemCopyLayer>,
291 &IsLayerOfType<armnn::FloorLayer>,
292 &IsLayerOfType<armnn::FakeQuantizationLayer>,
293 &IsLayerOfType<armnn::AdditionLayer>,
294 &IsLayerOfType<armnn::ActivationLayer>,
295 &IsLayerOfType<armnn::PermuteLayer>,
296 &IsLayerOfType<armnn::OutputLayer>));
297
telsoa01c577f2c2018-08-31 09:22:23 +0100298 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(MovePermuteUp()));
surmeh01bceff2f2018-03-29 16:29:27 +0100299
telsoa01c577f2c2018-08-31 09:22:23 +0100300 // The permute is moved to the top. New permutes for layers with multiple inputs.
surmeh01bceff2f2018-03-29 16:29:27 +0100301 BOOST_TEST(CheckSequence(graph.cbegin(),
302 graph.cend(),
303 &IsLayerOfType<armnn::InputLayer>,
304 &IsLayerOfType<armnn::InputLayer>,
305 &IsLayerOfType<armnn::InputLayer>,
306 &IsLayerOfType<armnn::PermuteLayer>,
307 &IsLayerOfType<armnn::PermuteLayer>,
308 &IsLayerOfType<armnn::PermuteLayer>,
309 &IsLayerOfType<armnn::MultiplicationLayer>,
310 &IsLayerOfType<armnn::MemCopyLayer>,
311 &IsLayerOfType<armnn::FloorLayer>,
312 &IsLayerOfType<armnn::FakeQuantizationLayer>,
313 &IsLayerOfType<armnn::AdditionLayer>,
314 &IsLayerOfType<armnn::ActivationLayer>,
315 &IsLayerOfType<armnn::OutputLayer>));
telsoa01c577f2c2018-08-31 09:22:23 +0100316
317 std::list<std::string> testRelatedLayers = { permuteLayerName };
318
319 BOOST_TEST(CheckRelatedLayers<armnn::PermuteLayer>(graph, testRelatedLayers));
surmeh01bceff2f2018-03-29 16:29:27 +0100320}
321
telsoa01c577f2c2018-08-31 09:22:23 +0100322BOOST_AUTO_TEST_CASE(PermuteAsReshapeTest)
surmeh01bceff2f2018-03-29 16:29:27 +0100323{
324 armnn::Graph graph;
325
telsoa01c577f2c2018-08-31 09:22:23 +0100326 std::string permuteLayerName = "permute";
327
surmeh01bceff2f2018-03-29 16:29:27 +0100328 const armnn::TensorInfo infoIn({ 1, 2, 3, 1 }, armnn::DataType::Float32);
329 const armnn::TensorInfo infoOut({ 1, 1, 2, 3 }, armnn::DataType::Float32);
330
331 auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
332
333 graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input")
334 ->GetOutputHandler().SetTensorInfo(infoIn);
335
telsoa01c577f2c2018-08-31 09:22:23 +0100336 // Inserts permute.
surmeh01bceff2f2018-03-29 16:29:27 +0100337 graph.InsertNewLayer<armnn::PermuteLayer>(output->GetInputSlot(0),
telsoa01c577f2c2018-08-31 09:22:23 +0100338 armnn::PermuteDescriptor({ 0, 2, 3, 1 }), permuteLayerName.c_str())
surmeh01bceff2f2018-03-29 16:29:27 +0100339 ->GetOutputHandler().SetTensorInfo(infoOut);
340
341 BOOST_TEST(CheckSequence(graph.cbegin(),
342 graph.cend(),
343 &IsLayerOfType<armnn::InputLayer>,
344 &IsLayerOfType<armnn::PermuteLayer>,
345 &IsLayerOfType<armnn::OutputLayer>));
346
telsoa01c577f2c2018-08-31 09:22:23 +0100347 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(PermuteAsReshape()));
surmeh01bceff2f2018-03-29 16:29:27 +0100348
349 // The permute is replaced by an equivalent reshape.
350
351 auto checkReshape = [&infoOut](const armnn::Layer* const layer) -> bool
352 {
353 const auto reshapeLayer = static_cast<const armnn::ReshapeLayer*>(layer);
354 return IsLayerOfType<armnn::ReshapeLayer>(layer) &&
355 (reshapeLayer->GetParameters().m_TargetShape == infoOut.GetShape()) &&
356 (reshapeLayer->GetOutputHandler().GetTensorInfo().GetShape() == infoOut.GetShape());
357 };
358
359 BOOST_TEST(CheckSequence(graph.cbegin(),
360 graph.cend(),
361 &IsLayerOfType<armnn::InputLayer>,
362 checkReshape,
363 &IsLayerOfType<armnn::OutputLayer>));
telsoa01c577f2c2018-08-31 09:22:23 +0100364
365
366 std::list<std::string> testRelatedLayers = { permuteLayerName };
367 BOOST_TEST(CheckRelatedLayers<armnn::ReshapeLayer>(graph, testRelatedLayers));
surmeh01bceff2f2018-03-29 16:29:27 +0100368}
369
telsoa01c577f2c2018-08-31 09:22:23 +0100370BOOST_AUTO_TEST_CASE(OptimizeConsecutiveReshapesTest)
surmeh01bceff2f2018-03-29 16:29:27 +0100371{
372 armnn::Graph graph;
373
374 const armnn::TensorInfo info0({ 1, 2, 3, 5 }, armnn::DataType::Float32);
375
376 auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
377 auto input = graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
378
379 input->GetOutputHandler().SetTensorInfo(info0);
380
381 {
telsoa01c577f2c2018-08-31 09:22:23 +0100382 // Inserts two reshapes.
surmeh01bceff2f2018-03-29 16:29:27 +0100383 const armnn::TensorInfo info1({1, 30, 1, 1}, armnn::DataType::Float32);
384 const armnn::TensorInfo info2({1, 2, 1, 15}, armnn::DataType::Float32);
385
telsoa01c577f2c2018-08-31 09:22:23 +0100386 std::string reshape1Name = "reshape1";
387 std::string reshape2Name = "reshape2";
388
surmeh01bceff2f2018-03-29 16:29:27 +0100389 auto reshape1 = graph.InsertNewLayer<armnn::ReshapeLayer>(output->GetInputSlot(0),
390 armnn::ReshapeDescriptor{ info1.GetShape() },
telsoa01c577f2c2018-08-31 09:22:23 +0100391 reshape1Name.c_str());
surmeh01bceff2f2018-03-29 16:29:27 +0100392 auto reshape2 = graph.InsertNewLayer<armnn::ReshapeLayer>(output->GetInputSlot(0),
393 armnn::ReshapeDescriptor{ info2.GetShape() },
telsoa01c577f2c2018-08-31 09:22:23 +0100394 reshape2Name.c_str());
surmeh01bceff2f2018-03-29 16:29:27 +0100395
396 reshape1->GetOutputHandler().SetTensorInfo(info1);
397 reshape2->GetOutputHandler().SetTensorInfo(info2);
398
399 BOOST_TEST(CheckSequence(graph.cbegin(),
400 graph.cend(),
401 &IsLayerOfType<armnn::InputLayer>,
402 &IsLayerOfType<armnn::ReshapeLayer>,
403 &IsLayerOfType<armnn::ReshapeLayer>,
404 &IsLayerOfType<armnn::OutputLayer>));
405
telsoa01c577f2c2018-08-31 09:22:23 +0100406 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeConsecutiveReshapes()));
surmeh01bceff2f2018-03-29 16:29:27 +0100407
408 auto checkReshape = [&info2](const armnn::Layer* const layer) -> bool
409 {
410 const auto reshapeLayer = static_cast<const armnn::ReshapeLayer*>(layer);
411 return IsLayerOfType<armnn::ReshapeLayer>(layer) &&
412 (reshapeLayer->GetParameters().m_TargetShape == info2.GetShape()) &&
413 (reshapeLayer->GetOutputHandler().GetTensorInfo().GetShape() == info2.GetShape());
414 };
415
telsoa01c577f2c2018-08-31 09:22:23 +0100416 // The two reshapes are replaced by a single equivalent reshape.
surmeh01bceff2f2018-03-29 16:29:27 +0100417 BOOST_TEST(CheckSequence(graph.cbegin(),
418 graph.cend(),
419 &IsLayerOfType<armnn::InputLayer>,
420 checkReshape,
421 &IsLayerOfType<armnn::OutputLayer>));
telsoa01c577f2c2018-08-31 09:22:23 +0100422
423 // Check the new reshape layer has the other two reshapes as related layers
424 std::list<std::string> testRelatedLayers = { reshape2Name, reshape1Name };
425
426 BOOST_TEST(CheckRelatedLayers<armnn::ReshapeLayer>(graph, testRelatedLayers));
surmeh01bceff2f2018-03-29 16:29:27 +0100427 }
428
429 {
telsoa01c577f2c2018-08-31 09:22:23 +0100430 // Inserts a reshape to the input shape.
surmeh01bceff2f2018-03-29 16:29:27 +0100431 auto reshapeToIn = graph.InsertNewLayer<armnn::ReshapeLayer>(output->GetInputSlot(0),
432 armnn::ReshapeDescriptor{ info0.GetShape() },
433 "reshapeToIn");
434
435 reshapeToIn->GetOutputHandler().SetTensorInfo(info0);
436
telsoa01c577f2c2018-08-31 09:22:23 +0100437 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeConsecutiveReshapes()));
surmeh01bceff2f2018-03-29 16:29:27 +0100438
telsoa01c577f2c2018-08-31 09:22:23 +0100439 // The two reshapes are removed.
surmeh01bceff2f2018-03-29 16:29:27 +0100440 BOOST_TEST(CheckSequence(graph.cbegin(),
441 graph.cend(),
442 &IsLayerOfType<armnn::InputLayer>,
443 &IsLayerOfType<armnn::OutputLayer>));
444 }
445}
446
telsoa01c577f2c2018-08-31 09:22:23 +0100447BOOST_AUTO_TEST_CASE(SquashEqualSiblingsTest)
surmeh01bceff2f2018-03-29 16:29:27 +0100448{
449 armnn::Graph graph;
450
451 armnn::LayerBindingId outputId = 0;
452
453 const armnn::TensorInfo info({ 1, 2, 3, 5 }, armnn::DataType::Float32);
454 const armnn::TensorInfo permuted({ 1, 5, 2, 3 }, armnn::DataType::Float32);
455
456 auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
457 input->GetOutputSlot().SetTensorInfo(info);
458
telsoa01c577f2c2018-08-31 09:22:23 +0100459 // Inserts equal permutes, equal reshapes and something else.
surmeh01bceff2f2018-03-29 16:29:27 +0100460 const armnn::PermuteDescriptor permDesc({ 0, 2, 3, 1 });
461 const armnn::ReshapeDescriptor reshapeDesc{ { 1, 3, 1, 5 } };
462
463 armnn::Layer* layer;
464
465 layer = graph.AddLayer<armnn::PermuteLayer>(permDesc, "");
466 layer->GetOutputSlot().SetTensorInfo(permuted);
467 layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
468 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
469
470 layer = graph.AddLayer<armnn::ReshapeLayer>(reshapeDesc, "");
471 layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
472 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
473
474 layer = graph.AddLayer<armnn::FloorLayer>("");
475 layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
476 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
477
478 layer = graph.AddLayer<armnn::ReshapeLayer>(reshapeDesc, "");
479 layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
480 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
481
482 layer = graph.AddLayer<armnn::PermuteLayer>(permDesc, "");
483 layer->GetOutputSlot().SetTensorInfo(permuted);
484 layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
485 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
486
487 BOOST_TEST(CheckSequence(graph.cbegin(),
488 graph.cend(),
489 &IsLayerOfType<armnn::InputLayer>,
490 &IsLayerOfType<armnn::PermuteLayer>,
491 &IsLayerOfType<armnn::ReshapeLayer>,
492 &IsLayerOfType<armnn::FloorLayer>,
493 &IsLayerOfType<armnn::ReshapeLayer>,
494 &IsLayerOfType<armnn::PermuteLayer>,
495 &IsLayerOfType<armnn::OutputLayer>,
496 &IsLayerOfType<armnn::OutputLayer>,
497 &IsLayerOfType<armnn::OutputLayer>,
498 &IsLayerOfType<armnn::OutputLayer>,
499 &IsLayerOfType<armnn::OutputLayer>));
500
telsoa01c577f2c2018-08-31 09:22:23 +0100501 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(SquashEqualPermuteSiblings(),
502 SquashEqualReshapeSiblings()));
surmeh01bceff2f2018-03-29 16:29:27 +0100503
504 // The permutes and reshapes are squashed.
505
506 BOOST_TEST(CheckSequence(graph.cbegin(),
507 graph.cend(),
508 &IsLayerOfType<armnn::InputLayer>,
509 &IsLayerOfType<armnn::PermuteLayer>,
510 &IsLayerOfType<armnn::ReshapeLayer>,
511 &IsLayerOfType<armnn::FloorLayer>,
512 &IsLayerOfType<armnn::OutputLayer>,
513 &IsLayerOfType<armnn::OutputLayer>,
514 &IsLayerOfType<armnn::OutputLayer>,
515 &IsLayerOfType<armnn::OutputLayer>,
516 &IsLayerOfType<armnn::OutputLayer>));
517}
518
telsoa01c577f2c2018-08-31 09:22:23 +0100519BOOST_AUTO_TEST_CASE(ConvertConstantsHalfToFloatTest)
520{
521 armnn::Graph graph;
522
523 const armnn::TensorInfo info({ 1,1,1,2 }, armnn::DataType::Float32);
524
525 // Create the half precision input data
526 unsigned int dims[] = { 4,1,1,1 };
527 std::vector<float> convWeightsData{1.f, 2.f, 3.f, 4.f};
528 std::vector<uint16_t> halfWeights(4);
529 armnnUtils::FloatingPointConverter::ConvertFloat32To16(convWeightsData.data(),
530 convWeightsData.size(),
531 halfWeights.data());
532 armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float16), halfWeights);
533
534 //Create the simple test network
535 auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
536 input->GetOutputSlot().SetTensorInfo(info);
537
538 auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(armnn::FullyConnectedDescriptor(), "fc");
539 fc->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
540 fc->GetOutputSlot().SetTensorInfo(info);
541
542 auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
543
544 //Connect up the layers
545 input->GetOutputSlot().Connect(fc->GetInputSlot(0));
546 fc->GetOutputSlot().Connect(output->GetInputSlot(0));
547
548 //Test the tensor info is correct.
549 BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float16);
550
551 // Run the optimizer
552 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsHalfToFloat()));
553
554 //Test the tensor info is correct.
555 BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float32);
556
557 // Now test the data matches float32 data
558 float* data = fc->m_Weight->GetTensor<float>();
559 BOOST_CHECK(1.0f == data[0]);
560 BOOST_CHECK(2.0f == data[1]);
561 BOOST_CHECK(3.0f == data[2]);
562 BOOST_CHECK(4.0f == data[3]);
563}
564
565BOOST_AUTO_TEST_CASE(ConvertConstantsFloatToHalfTest)
566{
567 armnn::Graph graph;
568
569 const armnn::TensorInfo info({ 1, 1, 1, 2 }, armnn::DataType::Float16);
570
571 // Create const tensor from fp32 data
572 unsigned int dims[] = { 4, 1, 1, 1 };
573 std::vector<float> floatWeights{ 1.0f, 2.0f, 3.0f, 4.0f };
574 armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float32), floatWeights);
575
576 // Create simple test network
577 auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
578 input->GetOutputSlot().SetTensorInfo(info);
579
580 auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(armnn::FullyConnectedDescriptor(), "fc");
581 fc->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
582 fc->GetOutputSlot().SetTensorInfo(info);
583
584 auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
585
586 // Connect up the layers
587 input->GetOutputSlot().Connect(fc->GetInputSlot(0));
588 fc->GetOutputSlot().Connect(output->GetInputSlot(0));
589
590 // Check tensor data type before conversion
591 BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float32);
592
593 // Run the optimizer
594 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsFloatToHalf()));
595
596 // Check tensor data type after conversion
597 BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float16);
598
599 // Check whether data matches expected fp16 data
600 Half* data = fc->m_Weight->GetTensor<Half>();
601 BOOST_CHECK(data[0] == Half(1.0f));
602 BOOST_CHECK(data[1] == Half(2.0f));
603 BOOST_CHECK(data[2] == Half(3.0f));
604 BOOST_CHECK(data[3] == Half(4.0f));
605}
606
607BOOST_AUTO_TEST_CASE(OptimizeInverseConversionsTest)
608{
609 armnn::Graph graph;
610
611 auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
612
613 graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
614
615 // Fp32ToFp16 conversion followed by an inverse Fp16ToFp32 conversion
616 graph.InsertNewLayer<armnn::ConvertFp32ToFp16Layer>(output->GetInputSlot(0), "convert1");
617 graph.InsertNewLayer<armnn::ConvertFp16ToFp32Layer>(output->GetInputSlot(0), "convert2");
618
619 graph.InsertNewLayer<armnn::Convolution2dLayer>(output->GetInputSlot(0), Convolution2dDescriptor(), "conv");
620
621 // Fp16ToFp32 conversion followed by an inverse Fp32ToFp16 conversion
622 graph.InsertNewLayer<armnn::ConvertFp16ToFp32Layer>(output->GetInputSlot(0), "convert3");
623 graph.InsertNewLayer<armnn::ConvertFp32ToFp16Layer>(output->GetInputSlot(0), "convert4");
624
625 BOOST_TEST(CheckSequence(graph.cbegin(),
626 graph.cend(),
627 &IsLayerOfType<armnn::InputLayer>,
628 &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
629 &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
630 &IsLayerOfType<armnn::Convolution2dLayer>,
631 &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
632 &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
633 &IsLayerOfType<armnn::OutputLayer>));
634
635 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeInverseConversionsFp16(),
636 OptimizeInverseConversionsFp32()));
637
638 // Check that all consecutive inverse conversions are removed
639 BOOST_TEST(CheckSequence(graph.cbegin(),
640 graph.cend(),
641 &IsLayerOfType<armnn::InputLayer>,
642 &IsLayerOfType<armnn::Convolution2dLayer>,
643 &IsLayerOfType<armnn::OutputLayer>));
644}
645
646BOOST_AUTO_TEST_CASE(InsertConvertersTest)
647{
648 const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float16);
649
650 armnn::Graph graph;
651
652 armnn::LayerBindingId inputId = 0;
653
654 armnn::Layer* head = graph.AddLayer<armnn::OutputLayer>(0, "output");
655
656 head = graph.InsertNewLayer<armnn::AdditionLayer>(head->GetInputSlot(0), "");
657 head->GetOutputHandler().SetTensorInfo(info);
658
659 graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(1), inputId++, "")
660 ->GetOutputHandler().SetTensorInfo(info);
661
662 head = graph.InsertNewLayer<armnn::FloorLayer>(head->GetInputSlot(0), "");
663 head->GetOutputHandler().SetTensorInfo(info);
664
665 head = graph.InsertNewLayer<armnn::MemCopyLayer>(head->GetInputSlot(0), "");
666 head->GetOutputHandler().SetTensorInfo(info);
667
668 graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(0), inputId++, "")
669 ->GetOutputHandler().SetTensorInfo(info);
670
671 // Check graph layer sequence before inserting convert layers
672 BOOST_TEST(CheckSequence(graph.cbegin(),
673 graph.cend(),
674 &IsLayerOfType<armnn::InputLayer>,
675 &IsLayerOfType<armnn::InputLayer>,
676 &IsLayerOfType<armnn::MemCopyLayer>,
677 &IsLayerOfType<armnn::FloorLayer>,
678 &IsLayerOfType<armnn::AdditionLayer>,
679 &IsLayerOfType<armnn::OutputLayer>));
680
681 // Check layers have Float16 DataType
682 for (auto& layer : graph)
683 {
684 if(layer->GetType()==LayerType::Floor || layer->GetType() == LayerType::Addition)
685 {
686 BOOST_ASSERT(layer->GetOutputSlot(0).GetTensorInfo().GetDataType() == DataType::Float16);
687 BOOST_ASSERT(layer->GetDataType() == DataType::Float16);
688 }
689 }
690
691 // Insert convert layers either side of unsupported layer
692 for (auto& layer : graph)
693 {
694 if(layer->GetType()==LayerType::Floor || layer->GetType() == LayerType::Addition)
695 {
696 InsertConvertFp16ToFp32LayersBefore(graph, *layer);
697 InsertConvertFp32ToFp16LayersAfter(graph, *layer);
698 }
699 }
700
701 // Check layers have correct DataType after inserting convert layers
702 for (auto& layer : graph)
703 {
704 if (layer->GetType()==LayerType::Floor || layer->GetType() == LayerType::Addition)
705 {
706 BOOST_ASSERT(layer->GetOutputSlot(0).GetTensorInfo().GetDataType() == DataType::Float32);
707 BOOST_ASSERT(layer->GetDataType() == DataType::Float32);
708 }
709 else if (layer->GetType() == LayerType::ConvertFp16ToFp32)
710 {
711 BOOST_ASSERT(layer->GetOutputSlot(0).GetTensorInfo().GetDataType() == DataType::Float32);
712 BOOST_ASSERT(layer->GetDataType() == DataType::Float16);
713 }
714 else if (layer->GetType() == LayerType::ConvertFp32ToFp16)
715 {
716 BOOST_ASSERT(layer->GetOutputSlot(0).GetTensorInfo().GetDataType() == DataType::Float16);
717 BOOST_ASSERT(layer->GetDataType() == DataType::Float32);
718 }
719 }
720
721 // Check sequence of layers after inserting convert layers
722 BOOST_TEST(CheckSequence(graph.cbegin(),
723 graph.cend(),
724 &IsLayerOfType<armnn::InputLayer>,
725 &IsLayerOfType<armnn::InputLayer>,
726 &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
727 &IsLayerOfType<armnn::MemCopyLayer>,
728 &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
729 &IsLayerOfType<armnn::FloorLayer>,
730 &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
731 &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
732 &IsLayerOfType<armnn::AdditionLayer>,
733 &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
734 &IsLayerOfType<armnn::OutputLayer>));
735}
736
737BOOST_AUTO_TEST_CASE(Fp32NetworkToFp16OptimizationTest)
738{
739 armnn::Graph graph;
740
741 const armnn::TensorInfo infoFP32({ 2,2,1,3 }, armnn::DataType::Float32);
742
743 // Create the simple test network
744 auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
745 input->GetOutputSlot().SetTensorInfo(infoFP32);
746
747 auto floor = graph.AddLayer<armnn::FloorLayer>("floor");
748 floor->GetOutputSlot().SetTensorInfo(infoFP32);
749
750 auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
751
752 // Connect up the layers
753 input->GetOutputSlot().Connect(floor->GetInputSlot(0));
754 floor->GetOutputSlot().Connect(output->GetInputSlot(0));
755
756 BOOST_TEST(CheckSequence(graph.cbegin(),
757 graph.cend(),
758 &IsLayerOfType<armnn::InputLayer>,
759 &IsLayerOfType<armnn::FloorLayer>,
760 &IsLayerOfType<armnn::OutputLayer>));
761
762 // Run the optimizer
763 armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(Fp32NetworkToFp16Converter()));
764
765 BOOST_TEST(CheckSequence(graph.cbegin(),
766 graph.cend(),
767 &IsLayerOfType<armnn::InputLayer>,
768 &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
769 &IsLayerOfType<armnn::FloorLayer>,
770 &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
771 &IsLayerOfType<armnn::OutputLayer>));
772}
773
narpra017af76882018-10-26 17:36:32 +0100774void CreateConvolution2dGraph(Graph &graph, const unsigned int* inputShape,
775 const unsigned int* weightsShape, const unsigned int* outputShape,
776 DataLayout dataLayout = DataLayout::NCHW)
777{
778 armnn::TensorInfo inputInfo(4, inputShape, DataType::Float32);
779 armnn::TensorInfo outputInfo(4, outputShape, DataType::Float32);
780
781 std::vector<float> weightsVector(90);
782 armnn::ConstTensor weights(armnn::TensorInfo(4, weightsShape, armnn::DataType::Float32), weightsVector);
783
784 Convolution2dDescriptor desc;
785 desc.m_BiasEnabled = false;
786 desc.m_StrideX = 1;
787 desc.m_StrideY = 1;
788 desc.m_DataLayout = dataLayout;
789
790 Layer* input = graph.AddLayer<InputLayer>(0, "input");
791 input->GetOutputSlot().SetTensorInfo(inputInfo);
792
793 Convolution2dLayer* layer = graph.AddLayer<Convolution2dLayer>(desc, "conv2d");
794 layer->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
795 layer->GetOutputSlot().SetTensorInfo(outputInfo);
796
797 Layer* output = graph.AddLayer<OutputLayer>(0, "output");
798 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
799 layer->GetOutputSlot().Connect(output->GetInputSlot(0));
800}
801
802BOOST_AUTO_TEST_CASE(Conv2dValidateTensorShapesFromInputs)
803{
804 Graph graph;
805 const unsigned int inputShape[] = { 1, 3, 8, 16 };
806 const unsigned int weightsShape[] = { 2, 3, 5, 3 };
807 const unsigned int outputShape[] = { 1, 2, 4, 14 };
808 CreateConvolution2dGraph(graph, inputShape, weightsShape, outputShape);
809
810 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
811}
812
813BOOST_AUTO_TEST_CASE(Conv2dValidateTensorShapesFromInputsNhwc)
814{
815 Graph graph;
816 const unsigned int inputShape[] = { 1, 8, 16, 3 };
817 const unsigned int weightsShape[] = { 2, 5, 3, 3 };
818 const unsigned int outputShape[] = { 1, 4, 14, 2 };
819 CreateConvolution2dGraph(graph, inputShape, weightsShape, outputShape, DataLayout::NHWC);
820
821 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
822}
823
824void CreateDepthwiseConvolution2dGraph(Graph &graph, const unsigned int* inputShape,
825 const unsigned int* weightsShape, const unsigned int* outputShape,
826 DataLayout dataLayout = DataLayout::NCHW)
827{
828 armnn::TensorInfo inputInfo(4, inputShape, DataType::Float32);
829 armnn::TensorInfo outputInfo(4, outputShape, DataType::Float32);
830
831 std::vector<float> weightsVector(18);
832 armnn::ConstTensor weights(armnn::TensorInfo(4, weightsShape, armnn::DataType::Float32), weightsVector);
833
834 DepthwiseConvolution2dDescriptor desc;
835 desc.m_BiasEnabled = false;
836 desc.m_StrideX = 1;
837 desc.m_StrideY = 1;
838 desc.m_DataLayout = dataLayout;
839
840 Layer* input = graph.AddLayer<InputLayer>(0, "input");
841 input->GetOutputSlot().SetTensorInfo(inputInfo);
842
843 DepthwiseConvolution2dLayer* layer = graph.AddLayer<DepthwiseConvolution2dLayer>(desc, "depthwiseConv2d");
844 layer->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
845 layer->GetOutputSlot().SetTensorInfo(outputInfo);
846
847 Layer* output = graph.AddLayer<OutputLayer>(0, "output");
848 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
849 layer->GetOutputSlot().Connect(output->GetInputSlot(0));
850}
851
852BOOST_AUTO_TEST_CASE(DepthwiseConv2dValidateTensorShapesFromInputs)
853{
854 Graph graph;
855 const unsigned int inputShape[] = { 1, 2, 3, 3 };
856 const unsigned int weightsShape[] = { 1, 2, 3, 3 };
857 const unsigned int outputShape[] = { 1, 2, 1, 1 };
858 CreateDepthwiseConvolution2dGraph(graph, inputShape, weightsShape, outputShape);
859
860 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
861}
862
863BOOST_AUTO_TEST_CASE(DepthwiseConv2dValidateTensorShapesFromInputsNhwc)
864{
865 Graph graph;
866 const unsigned int inputShape[] = { 1, 3, 3, 2 };
867 const unsigned int weightsShape[] = { 1, 3, 3, 2 };
868 const unsigned int outputShape[] = { 1, 1, 1, 2 };
869 CreateDepthwiseConvolution2dGraph(graph, inputShape, weightsShape, outputShape, DataLayout::NHWC);
870
871 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
872}
873
874void CreatePooling2dGraph(Graph &graph, const unsigned int* inputShape, const unsigned int* outputShape,
875 DataLayout dataLayout = DataLayout::NCHW)
876{
877 armnn::TensorInfo inputInfo(4, inputShape, DataType::Float32);
878 armnn::TensorInfo outputInfo(4, outputShape, DataType::Float32);
879
880 Pooling2dDescriptor desc;
881 desc.m_PoolType = armnn::PoolingAlgorithm::Average;
882 desc.m_PoolWidth = desc.m_PoolHeight = 100;
883 desc.m_StrideX = desc.m_StrideY = 5;
884 desc.m_PadLeft = 50;
885 desc.m_PadRight = 50;
886 desc.m_PadTop = 50;
887 desc.m_PadBottom = 50;
888 desc.m_PaddingMethod = armnn::PaddingMethod::Exclude;
889 desc.m_DataLayout = dataLayout;
890
891 Layer* input = graph.AddLayer<InputLayer>(0, "input");
892 input->GetOutputSlot().SetTensorInfo(inputInfo);
893
894 Pooling2dLayer* layer = graph.AddLayer<Pooling2dLayer>(desc, "pooling2d");
895 layer->GetOutputSlot().SetTensorInfo(outputInfo);
896
897 Layer* output = graph.AddLayer<OutputLayer>(0, "output");
898 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
899 layer->GetOutputSlot().Connect(output->GetInputSlot(0));
900}
901
902BOOST_AUTO_TEST_CASE(Pooling2dValidateTensorShapesFromInputs)
903{
904 Graph graph;
905 const unsigned int inputShape[] = { 5, 3, 52, 60 };
906 const unsigned int outputShape[] = { 5, 3, 11, 13 };
907 CreatePooling2dGraph(graph, inputShape, outputShape, DataLayout::NCHW);
908
909 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
910}
911
912BOOST_AUTO_TEST_CASE(Pooling2dValidateTensorShapesFromInputsNhwc)
913{
914 Graph graph;
915 const unsigned int inputShape[] = { 5, 52, 60, 3 };
916 const unsigned int outputShape[] = { 5, 11, 13, 3 };
917 CreatePooling2dGraph(graph, inputShape, outputShape, DataLayout::NHWC);
918
919 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
920}
921
922void CreateResizeBilinearGraph(Graph &graph, const unsigned int* inputShape, const unsigned int* outputShape,
923 DataLayout dataLayout = DataLayout::NCHW)
924{
925 armnn::TensorInfo inputInfo(4, inputShape, DataType::Float32);
926 armnn::TensorInfo outputInfo(4, outputShape, DataType::Float32);
927
928 ResizeBilinearDescriptor desc;
929 desc.m_TargetHeight = 3;
930 desc.m_TargetWidth = 4;
931 desc.m_DataLayout = dataLayout;
932
933 Layer* input = graph.AddLayer<InputLayer>(0, "input");
934 input->GetOutputSlot().SetTensorInfo(inputInfo);
935
936 ResizeBilinearLayer* layer = graph.AddLayer<ResizeBilinearLayer>(desc, "resizeBilinear");
937 layer->GetOutputSlot().SetTensorInfo(outputInfo);
938
939 Layer* output = graph.AddLayer<OutputLayer>(0, "output");
940 input->GetOutputSlot().Connect(layer->GetInputSlot(0));
941 layer->GetOutputSlot().Connect(output->GetInputSlot(0));
942}
943
944BOOST_AUTO_TEST_CASE(ResizeBilinearValidateTensorShapesFromInputs)
945{
946 Graph graph;
947 const unsigned int inputShape[] = { 1, 2, 4, 5 };
948 const unsigned int outputShape[] = { 1, 2, 3, 4 };
949 CreateResizeBilinearGraph(graph, inputShape, outputShape);
950
951 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
952}
953
954BOOST_AUTO_TEST_CASE(ResizeBilinearValidateTensorShapesFromInputsNhwc)
955{
956 Graph graph;
957 const unsigned int inputShape[] = { 1, 4, 5, 2 };
958 const unsigned int outputShape[] = { 1, 3, 4, 2 };
959 CreateResizeBilinearGraph(graph, inputShape, outputShape, DataLayout::NHWC);
960
961 BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
962}
963
surmeh01bceff2f2018-03-29 16:29:27 +0100964BOOST_AUTO_TEST_SUITE_END()