aboutsummaryrefslogtreecommitdiff
path: root/src/armnn/test/optimizations
diff options
context:
space:
mode:
Diffstat (limited to 'src/armnn/test/optimizations')
-rw-r--r--src/armnn/test/optimizations/MoveTransposeUpTests.cpp93
-rw-r--r--src/armnn/test/optimizations/OptimizeInversePermutesTests.cpp27
-rw-r--r--src/armnn/test/optimizations/PermuteAndBatchToSpaceAsDepthToSpaceTests.cpp108
-rw-r--r--src/armnn/test/optimizations/TransposeAsReshapeTests.cpp60
4 files changed, 288 insertions, 0 deletions
diff --git a/src/armnn/test/optimizations/MoveTransposeUpTests.cpp b/src/armnn/test/optimizations/MoveTransposeUpTests.cpp
new file mode 100644
index 0000000000..e2fb3abffb
--- /dev/null
+++ b/src/armnn/test/optimizations/MoveTransposeUpTests.cpp
@@ -0,0 +1,93 @@
+//
+// Copyright © 2020 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "../TestUtils.hpp"
+
+#include <Optimizer.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE(Optimizer)
+using namespace armnn::optimizations;
+
+BOOST_AUTO_TEST_CASE(MoveTransposeUpTest)
+{
+ const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
+ const armnn::TensorInfo transposed({ 1, 3, 5, 2 }, armnn::DataType::Float32);
+
+ armnn::Graph graph;
+
+ armnn::LayerBindingId inputId = 0;
+
+ armnn::Layer* head = graph.AddLayer<armnn::OutputLayer>(0, "output");
+
+ std::string transposeLayerName = "original_transpose";
+
+ // Insert transpose
+ head = graph.InsertNewLayer<armnn::TransposeLayer>(head->GetInputSlot(0),
+ armnn::TransposeDescriptor({ 0, 3, 1, 2 }),
+ transposeLayerName.c_str());
+
+ head->GetOutputHandler().SetTensorInfo(transposed);
+
+ // Inserts layers that don't care about data format.
+ head = graph.InsertNewLayer<armnn::ActivationLayer>(head->GetInputSlot(0), armnn::ActivationDescriptor{}, "");
+ head->GetOutputHandler().SetTensorInfo(info);
+
+ head = graph.InsertNewLayer<armnn::AdditionLayer>(head->GetInputSlot(0), "");
+ head->GetOutputHandler().SetTensorInfo(info);
+
+ // Inserts input for 2nd input of Addition.
+ graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(1), inputId++, "")
+ ->GetOutputHandler()
+ .SetTensorInfo(info);
+
+ head = graph.InsertNewLayer<armnn::FakeQuantizationLayer>(head->GetInputSlot(0),
+ armnn::FakeQuantizationDescriptor{}, "");
+ head->GetOutputHandler().SetTensorInfo(info);
+
+ head = graph.InsertNewLayer<armnn::FloorLayer>(head->GetInputSlot(0), "");
+ head->GetOutputHandler().SetTensorInfo(info);
+
+ head = graph.InsertNewLayer<armnn::MemCopyLayer>(head->GetInputSlot(0), "");
+ head->GetOutputHandler().SetTensorInfo(info);
+
+ head = graph.InsertNewLayer<armnn::MultiplicationLayer>(head->GetInputSlot(0), "");
+ head->GetOutputHandler().SetTensorInfo(info);
+
+ // Inserts input for 2nd input of Multiplication.
+ graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(1), inputId++, "")
+ ->GetOutputHandler()
+ .SetTensorInfo(info);
+
+ // Inserts input.
+ graph.InsertNewLayer<armnn::InputLayer>(head->GetInputSlot(0), inputId++, "")
+ ->GetOutputHandler()
+ .SetTensorInfo(info);
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::InputLayer>, &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::MultiplicationLayer>, &IsLayerOfType<armnn::MemCopyLayer>,
+ &IsLayerOfType<armnn::FloorLayer>, &IsLayerOfType<armnn::FakeQuantizationLayer>,
+ &IsLayerOfType<armnn::AdditionLayer>, &IsLayerOfType<armnn::ActivationLayer>,
+ &IsLayerOfType<armnn::TransposeLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(MoveTransposeUp()));
+
+ // The transpose is moved to the top. New transposes for layers with multiple inputs.
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::InputLayer>, &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::TransposeLayer>, &IsLayerOfType<armnn::TransposeLayer>,
+ &IsLayerOfType<armnn::TransposeLayer>, &IsLayerOfType<armnn::MultiplicationLayer>,
+ &IsLayerOfType<armnn::MemCopyLayer>, &IsLayerOfType<armnn::FloorLayer>,
+ &IsLayerOfType<armnn::FakeQuantizationLayer>, &IsLayerOfType<armnn::AdditionLayer>,
+ &IsLayerOfType<armnn::ActivationLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ std::list<std::string> testRelatedLayers = { transposeLayerName };
+
+ BOOST_TEST(CheckRelatedLayers<armnn::TransposeLayer>(graph, testRelatedLayers));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/OptimizeInversePermutesTests.cpp b/src/armnn/test/optimizations/OptimizeInversePermutesTests.cpp
index dcf955956d..21f791c5ff 100644
--- a/src/armnn/test/optimizations/OptimizeInversePermutesTests.cpp
+++ b/src/armnn/test/optimizations/OptimizeInversePermutesTests.cpp
@@ -39,4 +39,31 @@ BOOST_AUTO_TEST_CASE(OptimizeInversePermutesTest)
&IsLayerOfType<armnn::OutputLayer>));
}
+BOOST_AUTO_TEST_CASE(OptimizeInverseTransposesTest)
+{
+ armnn::Graph graph;
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
+
+ graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
+
+ // Inserts two permutes, one the inverse of the other.
+ graph.InsertNewLayer<armnn::TransposeLayer>(output->GetInputSlot(0),
+ armnn::TransposeDescriptor({ 0, 3, 1, 2 }),
+ "transpose0312");
+ graph.InsertNewLayer<armnn::TransposeLayer>(output->GetInputSlot(0),
+ armnn::TransposeDescriptor({ 0, 2, 3, 1 }),
+ "transpose0231");
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::TransposeLayer>, &IsLayerOfType<armnn::TransposeLayer>,
+ &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeInverseTransposes()));
+
+ // The permutes are removed.
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::OutputLayer>));
+}
+
BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/PermuteAndBatchToSpaceAsDepthToSpaceTests.cpp b/src/armnn/test/optimizations/PermuteAndBatchToSpaceAsDepthToSpaceTests.cpp
index 74ee18b482..c2180a63ca 100644
--- a/src/armnn/test/optimizations/PermuteAndBatchToSpaceAsDepthToSpaceTests.cpp
+++ b/src/armnn/test/optimizations/PermuteAndBatchToSpaceAsDepthToSpaceTests.cpp
@@ -49,6 +49,37 @@ INetworkPtr CreateTestNetwork()
return network;
}
+/// Shared function for the below tests, so that we test the same network in both cases.
+INetworkPtr CreateTransposeTestNetwork()
+{
+ // Create a network
+ INetworkPtr network = INetwork::Create();
+
+ auto input = network->AddInputLayer(0, "input");
+ const TensorInfo inputInfo({ 1, 2, 3, 4 }, DataType::Float32);
+ input->GetOutputSlot(0).SetTensorInfo(inputInfo);
+
+ // Insert Permute which swaps batches and channels dimensions
+ auto permute = network->AddTransposeLayer(TransposeDescriptor(PermutationVector{ 3, 1, 2, 0 }), "permute");
+ const TensorInfo permuteInfo({ 4, 2, 3, 1 }, DataType::Float32);
+ permute->GetOutputSlot(0).SetTensorInfo(permuteInfo);
+ input->GetOutputSlot(0).Connect(permute->GetInputSlot(0));
+
+ // Insert BatchToSpace
+ BatchToSpaceNdDescriptor batchToSpaceDesc;
+ batchToSpaceDesc.m_BlockShape = { 2, 2 };
+ batchToSpaceDesc.m_DataLayout = DataLayout::NHWC;
+ auto batchToSpace = network->AddBatchToSpaceNdLayer(batchToSpaceDesc, "batchToSpace");
+ const TensorInfo batchToSpaceInfo({ 1, 4, 6, 1 }, DataType::Float32);
+ batchToSpace->GetOutputSlot(0).SetTensorInfo(batchToSpaceInfo);
+ permute->GetOutputSlot(0).Connect(batchToSpace->GetInputSlot(0));
+
+ auto output = network->AddOutputLayer(0, "output");
+ batchToSpace->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ return network;
+}
+
} // namespace
/// Tests that the optimization performed by PermuteAndBatchToSpaceAsDepthToSpace is as expected.
@@ -81,6 +112,36 @@ BOOST_AUTO_TEST_CASE(PermuteAndBatchToSpaceAsDepthToSpaceOptimizerTest)
BOOST_TEST(CheckRelatedLayers<DepthToSpaceLayer>(graph, testRelatedLayers));
}
+/// Tests that the optimization performed by PermuteAndBatchToSpaceAsDepthToSpace is as expected.
+/// Note this does not ensure the correctness of the optimization - that is done in the below test.
+BOOST_AUTO_TEST_CASE(TransposeAndBatchToSpaceAsDepthToSpaceOptimizerTest)
+{
+ INetworkPtr network = CreateTransposeTestNetwork();
+ Graph graph = static_cast<Network*>(network.get())->GetGraph();
+
+ // Confirm initial graph is as we expect
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<InputLayer>, &IsLayerOfType<TransposeLayer>,
+ &IsLayerOfType<BatchToSpaceNdLayer>, &IsLayerOfType<OutputLayer>));
+
+ // Perform the optimization which should merge the two layers into a DepthToSpace
+ armnn::Optimizer::Pass(graph, MakeOptimizations(TransposeAndBatchToSpaceAsDepthToSpace()));
+
+ // Check that the replacement has been made as expected
+ auto checkDepthToSpace = [](const Layer* const layer) -> bool {
+ return IsLayerOfType<DepthToSpaceLayer>(layer) &&
+ static_cast<const DepthToSpaceLayer*>(layer)->GetParameters().m_BlockSize == 2 &&
+ static_cast<const DepthToSpaceLayer*>(layer)->GetParameters().m_DataLayout == DataLayout::NHWC &&
+ layer->GetOutputHandler().GetTensorInfo() == TensorInfo({ 1, 4, 6, 1 }, DataType::Float32);
+ };
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<InputLayer>, checkDepthToSpace,
+ &IsLayerOfType<OutputLayer>));
+
+ // Check the new layer has the two merged layers listed as related layers
+ std::list<std::string> testRelatedLayers = { "batchToSpace", "permute" };
+ BOOST_TEST(CheckRelatedLayers<DepthToSpaceLayer>(graph, testRelatedLayers));
+}
+
// This unit test needs the reference backend, it's not available if the reference backend is not built
#if defined(ARMNNREF_ENABLED)
@@ -130,6 +191,53 @@ BOOST_AUTO_TEST_CASE(PermuteAndBatchToSpaceAsDepthToSpaceCorrectnessTest)
};
BOOST_TEST(outputData == expectedOutput);
}
+
+/// Tests that a optimization performed by PermuteAndBatchToSpaceAsDepthToSpace does not change the behaviour
+/// of the network (i.e. it still produces the correct output).
+BOOST_AUTO_TEST_CASE(TransposeAndBatchToSpaceAsDepthToSpaceCorrectnessTest)
+{
+ INetworkPtr network = CreateTransposeTestNetwork();
+
+ IRuntimePtr runtime = IRuntime::Create(IRuntime::CreationOptions());
+ IOptimizedNetworkPtr optimizedNetwork = Optimize(*network, { Compute::CpuRef }, runtime->GetDeviceSpec());
+
+ // Confirm that the optimization has actually taken place
+ const Graph& optGraph = static_cast<OptimizedNetwork*>(optimizedNetwork.get())->GetGraph();
+ BOOST_TEST(CheckSequence(optGraph.cbegin(), optGraph.cend(), &IsLayerOfType<InputLayer>,
+ &IsLayerOfType<DepthToSpaceLayer>, &IsLayerOfType<OutputLayer>));
+
+ // Load the graph into a runtime so we can check it produces the correct output
+ NetworkId netId;
+ runtime->LoadNetwork(netId, std::move(optimizedNetwork));
+
+ std::vector<float> inputData{
+ // Each row here is a row of pixels where each pixel has 4 channels
+ // clang-format off
+ 1.0f, 2.0f, 3.0f, 4.0f, 10.0f, 20.0f, 30.0f, 40.0f, 100.0f, 200.0f, 300.0f, 400.0f,
+ -1.0f, -2.0f, -3.0f, -4.0f, -10.0f, -20.0f, -30.0f, -40.0f, -100.0f, -200.0f, -300.0f, -400.0f,
+ // clang-format on
+ };
+ ConstTensor input(TensorInfo({ 1, 2, 3, 4 }, DataType::Float32), inputData);
+ InputTensors inputs = { { 0, input } };
+ std::vector<float> outputData(4 * 6);
+ Tensor output(TensorInfo({ 1, 4, 6, 1 }, DataType::Float32), outputData.data());
+ OutputTensors outputs = { { 0, output } };
+ runtime->EnqueueWorkload(netId, inputs, outputs);
+
+ // Check the output is as expected.
+ // Note this output has been generated by running the network *without* the optimization.
+ std::vector<float> expectedOutput = {
+ // Rows and columns here match exactly with the tensor, as there is only 1 channel.
+ // clang-format off
+ 1.0f, 2.0f, 10.0f, 20.0f, 100.0f, 200.0f,
+ 3.0f, 4.0f, 30.0f, 40.0f, 300.0f, 400.0f,
+
+ -1.0f, -2.0f, -10.0f, -20.0f, -100.0f, -200.0f,
+ -3.0f, -4.0f, -30.0f, -40.0f, -300.0f, -400.0f,
+ // clang-format on
+ };
+ BOOST_TEST(outputData == expectedOutput);
+}
#endif
BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/TransposeAsReshapeTests.cpp b/src/armnn/test/optimizations/TransposeAsReshapeTests.cpp
new file mode 100644
index 0000000000..3c6ed6eea8
--- /dev/null
+++ b/src/armnn/test/optimizations/TransposeAsReshapeTests.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright © 2020 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "../TestUtils.hpp"
+
+#include <Optimizer.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace armnn;
+
+BOOST_AUTO_TEST_SUITE(Optimizer)
+using namespace armnn::optimizations;
+
+BOOST_AUTO_TEST_CASE(TransposeAsReshapeTest)
+{
+ armnn::Graph graph;
+
+ std::string transposeLayerName = "transpose";
+
+ const armnn::TensorInfo infoIn({ 1, 2, 3, 1 }, armnn::DataType::Float32);
+ const armnn::TensorInfo infoOut({ 1, 1, 2, 3 }, armnn::DataType::Float32);
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
+
+ graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input")
+ ->GetOutputHandler()
+ .SetTensorInfo(infoIn);
+
+ // Inserts transpose.
+ graph
+ .InsertNewLayer<armnn::TransposeLayer>(output->GetInputSlot(0), armnn::TransposeDescriptor({ 0, 3, 1, 2 }),
+ transposeLayerName.c_str())
+ ->GetOutputHandler()
+ .SetTensorInfo(infoOut);
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::TransposeLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(TransposeAsReshape()));
+
+ // The transpose is replaced by an equivalent reshape.
+
+ auto checkReshape = [&infoOut](const armnn::Layer* const layer) -> bool {
+ const auto reshapeLayer = static_cast<const armnn::ReshapeLayer*>(layer);
+ return IsLayerOfType<armnn::ReshapeLayer>(layer) &&
+ (reshapeLayer->GetParameters().m_TargetShape == infoOut.GetShape()) &&
+ (reshapeLayer->GetOutputHandler().GetTensorInfo().GetShape() == infoOut.GetShape());
+ };
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>, checkReshape,
+ &IsLayerOfType<armnn::OutputLayer>));
+
+ std::list<std::string> testRelatedLayers = { transposeLayerName };
+ BOOST_TEST(CheckRelatedLayers<armnn::ReshapeLayer>(graph, testRelatedLayers));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file