ArmNN  NotReleased
PermuteAndBatchToSpaceAsDepthToSpaceTests.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2019 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "../TestUtils.hpp"
7 
8 #include <Network.hpp>
9 #include <Optimizer.hpp>
10 
11 #include <boost/test/unit_test.hpp>
12 
13 using namespace armnn;
14 
16 using namespace armnn::optimizations;
17 
18 namespace
19 {
20 
22 INetworkPtr CreateTestNetwork()
23 {
24  // Create a network
25  INetworkPtr network = INetwork::Create();
26 
27  auto input = network->AddInputLayer(0, "input");
28  const TensorInfo inputInfo({ 1, 2, 3, 4 }, DataType::Float32);
29  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
30 
31  // Insert Permute which swaps batches and channels dimensions
32  auto permute = network->AddPermuteLayer(PermuteDescriptor(PermutationVector{ 3, 1, 2, 0 }), "permute");
33  const TensorInfo permuteInfo({ 4, 2, 3, 1 }, DataType::Float32);
34  permute->GetOutputSlot(0).SetTensorInfo(permuteInfo);
35  input->GetOutputSlot(0).Connect(permute->GetInputSlot(0));
36 
37  // Insert BatchToSpace
38  BatchToSpaceNdDescriptor batchToSpaceDesc;
39  batchToSpaceDesc.m_BlockShape = { 2, 2 };
40  batchToSpaceDesc.m_DataLayout = DataLayout::NHWC;
41  auto batchToSpace = network->AddBatchToSpaceNdLayer(batchToSpaceDesc, "batchToSpace");
42  const TensorInfo batchToSpaceInfo({ 1, 4, 6, 1 }, DataType::Float32);
43  batchToSpace->GetOutputSlot(0).SetTensorInfo(batchToSpaceInfo);
44  permute->GetOutputSlot(0).Connect(batchToSpace->GetInputSlot(0));
45 
46  auto output = network->AddOutputLayer(0, "output");
47  batchToSpace->GetOutputSlot(0).Connect(output->GetInputSlot(0));
48 
49  return network;
50 }
51 
52 } // namespace
53 
56 BOOST_AUTO_TEST_CASE(PermuteAndBatchToSpaceAsDepthToSpaceOptimizerTest)
57 {
58  INetworkPtr network = CreateTestNetwork();
59  Graph graph = static_cast<Network*>(network.get())->GetGraph();
60 
61  // Confirm initial graph is as we expect
62  BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<InputLayer>, &IsLayerOfType<PermuteLayer>,
63  &IsLayerOfType<BatchToSpaceNdLayer>, &IsLayerOfType<OutputLayer>));
64 
65  // Perform the optimization which should merge the two layers into a DepthToSpace
67 
68  // Check that the replacement has been made as expected
69  auto checkDepthToSpace = [](const Layer* const layer) -> bool {
70  return IsLayerOfType<DepthToSpaceLayer>(layer) &&
71  static_cast<const DepthToSpaceLayer*>(layer)->GetParameters().m_BlockSize == 2 &&
72  static_cast<const DepthToSpaceLayer*>(layer)->GetParameters().m_DataLayout == DataLayout::NHWC &&
73  layer->GetOutputHandler().GetTensorInfo() == TensorInfo({ 1, 4, 6, 1 }, DataType::Float32);
74  };
75 
76  BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<InputLayer>, checkDepthToSpace,
77  &IsLayerOfType<OutputLayer>));
78 
79  // Check the new layer has the two merged layers listed as related layers
80  std::list<std::string> testRelatedLayers = { "batchToSpace", "permute" };
81  BOOST_TEST(CheckRelatedLayers<DepthToSpaceLayer>(graph, testRelatedLayers));
82 }
83 
84 // This unit test needs the reference backend, it's not available if the reference backend is not built
85 #if defined(ARMNNREF_ENABLED)
86 
89 BOOST_AUTO_TEST_CASE(PermuteAndBatchToSpaceAsDepthToSpaceCorrectnessTest)
90 {
91  INetworkPtr network = CreateTestNetwork();
92 
94  IOptimizedNetworkPtr optimizedNetwork = Optimize(*network, { Compute::CpuRef }, runtime->GetDeviceSpec());
95 
96  // Confirm that the optimization has actually taken place
97  const Graph& optGraph = static_cast<OptimizedNetwork*>(optimizedNetwork.get())->GetGraph();
98  BOOST_TEST(CheckSequence(optGraph.cbegin(), optGraph.cend(), &IsLayerOfType<InputLayer>,
99  &IsLayerOfType<DepthToSpaceLayer>, &IsLayerOfType<OutputLayer>));
100 
101  // Load the graph into a runtime so we can check it produces the correct output
102  NetworkId netId;
103  runtime->LoadNetwork(netId, std::move(optimizedNetwork));
104 
105  std::vector<float> inputData{
106  // Each row here is a row of pixels where each pixel has 4 channels
107  // clang-format off
108  1.0f, 2.0f, 3.0f, 4.0f, 10.0f, 20.0f, 30.0f, 40.0f, 100.0f, 200.0f, 300.0f, 400.0f,
109  -1.0f, -2.0f, -3.0f, -4.0f, -10.0f, -20.0f, -30.0f, -40.0f, -100.0f, -200.0f, -300.0f, -400.0f,
110  // clang-format on
111  };
112  ConstTensor input(TensorInfo({ 1, 2, 3, 4 }, DataType::Float32), inputData);
113  InputTensors inputs = { { 0, input } };
114  std::vector<float> outputData(4 * 6);
115  Tensor output(TensorInfo({ 1, 4, 6, 1 }, DataType::Float32), outputData.data());
116  OutputTensors outputs = { { 0, output } };
117  runtime->EnqueueWorkload(netId, inputs, outputs);
118 
119  // Check the output is as expected.
120  // Note this output has been generated by running the network *without* the optimization.
121  std::vector<float> expectedOutput = {
122  // Rows and columns here match exactly with the tensor, as there is only 1 channel.
123  // clang-format off
124  1.0f, 2.0f, 10.0f, 20.0f, 100.0f, 200.0f,
125  3.0f, 4.0f, 30.0f, 40.0f, 300.0f, 400.0f,
126 
127  -1.0f, -2.0f, -10.0f, -20.0f, -100.0f, -200.0f,
128  -3.0f, -4.0f, -30.0f, -40.0f, -300.0f, -400.0f,
129  // clang-format on
130  };
131  BOOST_TEST(outputData == expectedOutput);
132 }
133 #endif
134 
This layer represents a DepthToSpace operation.
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:199
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:226
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Definition: Network.cpp:807
OptimizeForConnection< PermuteLayer, BatchToSpaceNdLayer, PermuteAndBatchToSpaceAsDepthToSpaceImpl > PermuteAndBatchToSpaceAsDepthToSpace
BOOST_AUTO_TEST_CASE(CheckConvolution2dLayer)
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
static void Pass(Graph &graph, const Optimizations &optimizations)
Definition: Optimizer.cpp:16
bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
Definition: TestUtils.hpp:20
Private implementation of INetwork.
Definition: Network.hpp:27
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
Definition: Tensor.hpp:191
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:225
static INetworkPtr Create()
Definition: Network.cpp:48
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:85
CPU Execution: Reference C++ kernels.
static IRuntimePtr Create(const CreationOptions &options)
Definition: Runtime.cpp:32
ConstIterator cbegin() const
Returns const iterator pointing to the beginning of the list. Lowercase for range-based for loops...
Definition: Graph.hpp:168
Optimizer::Optimizations MakeOptimizations(Args &&... args)
Definition: Optimizer.hpp:43
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:544
ConstIterator cend() const
Returns const iterator pointing to the end of the list. Lowercase for range-based for loops...
Definition: Graph.hpp:170
A PermuteDescriptor for the PermuteLayer.
int NetworkId
Definition: IRuntime.hpp:19
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
Definition: IRuntime.hpp:24
std::vector< unsigned int > m_BlockShape
Block shape values.