aboutsummaryrefslogtreecommitdiff
path: root/src/armnn
diff options
context:
space:
mode:
Diffstat (limited to 'src/armnn')
-rw-r--r--src/armnn/test/OptimizerTests.cpp558
-rw-r--r--src/armnn/test/TestUtils.hpp38
-rw-r--r--src/armnn/test/optimizations/ConvertConstantsFloatToHalfTests.cpp60
-rw-r--r--src/armnn/test/optimizations/ConvertConstantsHalfToFloatTests.cpp60
-rw-r--r--src/armnn/test/optimizations/Fp32NetworkToFp16ConverterTests.cpp45
-rw-r--r--src/armnn/test/optimizations/InsertDebugLayerTests.cpp45
-rw-r--r--src/armnn/test/optimizations/MovePermuteUpTests.cpp92
-rw-r--r--src/armnn/test/optimizations/OptimizeConsecutiveReshapesTests.cpp80
-rw-r--r--src/armnn/test/optimizations/OptimizeInverseConversionsTests.cpp49
-rw-r--r--src/armnn/test/optimizations/OptimizeInversePermutesTests.cpp42
-rw-r--r--src/armnn/test/optimizations/PermuteAsReshapeTests.cpp60
-rw-r--r--src/armnn/test/optimizations/SquashEqualSiblingsTests.cpp74
12 files changed, 645 insertions, 558 deletions
diff --git a/src/armnn/test/OptimizerTests.cpp b/src/armnn/test/OptimizerTests.cpp
index b06403c8d6..c0ad9c8927 100644
--- a/src/armnn/test/OptimizerTests.cpp
+++ b/src/armnn/test/OptimizerTests.cpp
@@ -17,45 +17,6 @@ using namespace armnn;
namespace
{
-template <typename LayerT>
-bool IsLayerOfType(const armnn::Layer* const layer)
-{
- return (layer->GetType() == armnn::LayerEnumOf<LayerT>());
-}
-
-bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
-{
- return (first == last);
-}
-
-/// Checks each unary function in Us evaluates true for each correspondent layer in the sequence [first, last).
-template <typename U, typename... Us>
-bool CheckSequence(const armnn::Graph::ConstIterator first,
- const armnn::Graph::ConstIterator last,
- U&& u,
- Us&&... us)
-{
- return u(*first) && CheckSequence(std::next(first), last, us...);
-}
-
-template <typename LayerT>
-bool CheckRelatedLayers(armnn::Graph& graph, const std::list<std::string>& testRelatedLayers)
-{
- for (auto& layer : graph)
- {
- if (layer->GetType() == armnn::LayerEnumOf<LayerT>())
- {
- auto& relatedLayers = layer->GetRelatedLayerNames();
- if(!std::equal(relatedLayers.begin(), relatedLayers.end(),
- testRelatedLayers.begin(), testRelatedLayers.end()))
- {
- return false;
- }
- }
- }
-
- return true;
-}
void CreateLSTMLayerHelper(Graph &graph, bool CifgEnabled)
{
@@ -168,38 +129,6 @@ void CreateLSTMLayerHelper(Graph &graph, bool CifgEnabled)
BOOST_AUTO_TEST_SUITE(Optimizer)
using namespace armnn::optimizations;
-BOOST_AUTO_TEST_CASE(OptimizeInversePermutesTest)
-{
- 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::PermuteLayer>(output->GetInputSlot(0),
- armnn::PermuteDescriptor({0, 2, 3, 1}),
- "perm0231");
- graph.InsertNewLayer<armnn::PermuteLayer>(output->GetInputSlot(0),
- armnn::PermuteDescriptor({0, 3, 1, 2}),
- "perm0312");
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeInversePermutes()));
-
- // The permutes are removed.
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-}
-
BOOST_AUTO_TEST_CASE(LSTMValidateTensorShapesFromInputsCIFGDisabledTest)
{
Graph graph;
@@ -222,421 +151,6 @@ BOOST_AUTO_TEST_CASE(LSTMValidateTensorShapesFromInputsCIFGEnabledTest)
BOOST_CHECK_NO_THROW(graph.InferTensorInfos());
}
-BOOST_AUTO_TEST_CASE(MovePermuteUpTest)
-{
- const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
- const armnn::TensorInfo permuted({ 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 permuteLayerName = "original_permute";
-
- // Insert permute
- head = graph.InsertNewLayer<armnn::PermuteLayer>(head->GetInputSlot(0),
- armnn::PermuteDescriptor({ 0, 2, 3, 1 }),
- permuteLayerName.c_str());
-
- head->GetOutputHandler().SetTensorInfo(permuted);
-
- // 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::PermuteLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(MovePermuteUp()));
-
- // The permute is moved to the top. New permutes for layers with multiple inputs.
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &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 = { permuteLayerName };
-
- BOOST_TEST(CheckRelatedLayers<armnn::PermuteLayer>(graph, testRelatedLayers));
-}
-
-BOOST_AUTO_TEST_CASE(PermuteAsReshapeTest)
-{
- armnn::Graph graph;
-
- std::string permuteLayerName = "permute";
-
- 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 permute.
- graph.InsertNewLayer<armnn::PermuteLayer>(output->GetInputSlot(0),
- armnn::PermuteDescriptor({ 0, 2, 3, 1 }), permuteLayerName.c_str())
- ->GetOutputHandler().SetTensorInfo(infoOut);
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(PermuteAsReshape()));
-
- // The permute 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 = { permuteLayerName };
- BOOST_TEST(CheckRelatedLayers<armnn::ReshapeLayer>(graph, testRelatedLayers));
-}
-
-BOOST_AUTO_TEST_CASE(OptimizeConsecutiveReshapesTest)
-{
- armnn::Graph graph;
-
- const armnn::TensorInfo info0({ 1, 2, 3, 5 }, armnn::DataType::Float32);
-
- auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
- auto input = graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
-
- input->GetOutputHandler().SetTensorInfo(info0);
-
- {
- // Inserts two reshapes.
- const armnn::TensorInfo info1({1, 30, 1, 1}, armnn::DataType::Float32);
- const armnn::TensorInfo info2({1, 2, 1, 15}, armnn::DataType::Float32);
-
- std::string reshape1Name = "reshape1";
- std::string reshape2Name = "reshape2";
-
- auto reshape1 = graph.InsertNewLayer<armnn::ReshapeLayer>(output->GetInputSlot(0),
- armnn::ReshapeDescriptor{ info1.GetShape() },
- reshape1Name.c_str());
- auto reshape2 = graph.InsertNewLayer<armnn::ReshapeLayer>(output->GetInputSlot(0),
- armnn::ReshapeDescriptor{ info2.GetShape() },
- reshape2Name.c_str());
-
- reshape1->GetOutputHandler().SetTensorInfo(info1);
- reshape2->GetOutputHandler().SetTensorInfo(info2);
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::ReshapeLayer>,
- &IsLayerOfType<armnn::ReshapeLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeConsecutiveReshapes()));
-
- auto checkReshape = [&info2](const armnn::Layer* const layer) -> bool
- {
- const auto reshapeLayer = static_cast<const armnn::ReshapeLayer*>(layer);
- return IsLayerOfType<armnn::ReshapeLayer>(layer) &&
- (reshapeLayer->GetParameters().m_TargetShape == info2.GetShape()) &&
- (reshapeLayer->GetOutputHandler().GetTensorInfo().GetShape() == info2.GetShape());
- };
-
- // The two reshapes are replaced by a single equivalent reshape.
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- checkReshape,
- &IsLayerOfType<armnn::OutputLayer>));
-
- // Check the new reshape layer has the other two reshapes as related layers
- std::list<std::string> testRelatedLayers = { reshape2Name, reshape1Name };
-
- BOOST_TEST(CheckRelatedLayers<armnn::ReshapeLayer>(graph, testRelatedLayers));
- }
-
- {
- // Inserts a reshape to the input shape.
- auto reshapeToIn = graph.InsertNewLayer<armnn::ReshapeLayer>(output->GetInputSlot(0),
- armnn::ReshapeDescriptor{ info0.GetShape() },
- "reshapeToIn");
-
- reshapeToIn->GetOutputHandler().SetTensorInfo(info0);
-
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeConsecutiveReshapes()));
-
- // The two reshapes are removed.
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
- }
-}
-
-BOOST_AUTO_TEST_CASE(SquashEqualSiblingsTest)
-{
- armnn::Graph graph;
-
- armnn::LayerBindingId outputId = 0;
-
- const armnn::TensorInfo info({ 1, 2, 3, 5 }, armnn::DataType::Float32);
- const armnn::TensorInfo permuted({ 1, 5, 2, 3 }, armnn::DataType::Float32);
-
- auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
- input->GetOutputSlot().SetTensorInfo(info);
-
- // Inserts equal permutes, equal reshapes and something else.
- const armnn::PermuteDescriptor permDesc({ 0, 2, 3, 1 });
- const armnn::ReshapeDescriptor reshapeDesc{ { 1, 3, 1, 5 } };
-
- armnn::Layer* layer;
-
- layer = graph.AddLayer<armnn::PermuteLayer>(permDesc, "");
- layer->GetOutputSlot().SetTensorInfo(permuted);
- layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
- input->GetOutputSlot().Connect(layer->GetInputSlot(0));
-
- layer = graph.AddLayer<armnn::ReshapeLayer>(reshapeDesc, "");
- layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
- input->GetOutputSlot().Connect(layer->GetInputSlot(0));
-
- layer = graph.AddLayer<armnn::FloorLayer>("");
- layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
- input->GetOutputSlot().Connect(layer->GetInputSlot(0));
-
- layer = graph.AddLayer<armnn::ReshapeLayer>(reshapeDesc, "");
- layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
- input->GetOutputSlot().Connect(layer->GetInputSlot(0));
-
- layer = graph.AddLayer<armnn::PermuteLayer>(permDesc, "");
- layer->GetOutputSlot().SetTensorInfo(permuted);
- layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
- input->GetOutputSlot().Connect(layer->GetInputSlot(0));
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::ReshapeLayer>,
- &IsLayerOfType<armnn::FloorLayer>,
- &IsLayerOfType<armnn::ReshapeLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(SquashEqualPermuteSiblings(),
- SquashEqualReshapeSiblings()));
-
- // The permutes and reshapes are squashed.
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::PermuteLayer>,
- &IsLayerOfType<armnn::ReshapeLayer>,
- &IsLayerOfType<armnn::FloorLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-}
-
-BOOST_AUTO_TEST_CASE(ConvertConstantsHalfToFloatTest)
-{
- armnn::Graph graph;
-
- const armnn::TensorInfo info({ 1,1,1,2 }, armnn::DataType::Float32);
-
- // Create the half precision input data
- unsigned int dims[] = { 4,1,1,1 };
- std::vector<float> convWeightsData{1.f, 2.f, 3.f, 4.f};
- std::vector<uint16_t> halfWeights(4);
- armnnUtils::FloatingPointConverter::ConvertFloat32To16(convWeightsData.data(),
- convWeightsData.size(),
- halfWeights.data());
- armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float16), halfWeights);
-
- //Create the simple test network
- auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
- input->GetOutputSlot().SetTensorInfo(info);
-
- auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(armnn::FullyConnectedDescriptor(), "fc");
- fc->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
- fc->GetOutputSlot().SetTensorInfo(info);
-
- auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
-
- //Connect up the layers
- input->GetOutputSlot().Connect(fc->GetInputSlot(0));
- fc->GetOutputSlot().Connect(output->GetInputSlot(0));
-
- //Test the tensor info is correct.
- BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float16);
-
- // Run the optimizer
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsHalfToFloat()));
-
- //Test the tensor info is correct.
- BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float32);
-
- // Now test the data matches float32 data
- float* data = fc->m_Weight->GetTensor<float>();
- BOOST_CHECK(1.0f == data[0]);
- BOOST_CHECK(2.0f == data[1]);
- BOOST_CHECK(3.0f == data[2]);
- BOOST_CHECK(4.0f == data[3]);
-}
-
-BOOST_AUTO_TEST_CASE(ConvertConstantsFloatToHalfTest)
-{
- armnn::Graph graph;
-
- const armnn::TensorInfo info({ 1, 1, 1, 2 }, armnn::DataType::Float16);
-
- // Create const tensor from fp32 data
- unsigned int dims[] = { 4, 1, 1, 1 };
- std::vector<float> floatWeights{ 1.0f, 2.0f, 3.0f, 4.0f };
- armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float32), floatWeights);
-
- // Create simple test network
- auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
- input->GetOutputSlot().SetTensorInfo(info);
-
- auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(armnn::FullyConnectedDescriptor(), "fc");
- fc->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
- fc->GetOutputSlot().SetTensorInfo(info);
-
- auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
-
- // Connect up the layers
- input->GetOutputSlot().Connect(fc->GetInputSlot(0));
- fc->GetOutputSlot().Connect(output->GetInputSlot(0));
-
- // Check tensor data type before conversion
- BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float32);
-
- // Run the optimizer
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsFloatToHalf()));
-
- // Check tensor data type after conversion
- BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float16);
-
- // Check whether data matches expected fp16 data
- Half* data = fc->m_Weight->GetTensor<Half>();
- BOOST_CHECK(data[0] == Half(1.0f));
- BOOST_CHECK(data[1] == Half(2.0f));
- BOOST_CHECK(data[2] == Half(3.0f));
- BOOST_CHECK(data[3] == Half(4.0f));
-}
-
-BOOST_AUTO_TEST_CASE(OptimizeInverseConversionsTest)
-{
- armnn::Graph graph;
-
- auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
-
- graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
-
- // Fp32ToFp16 conversion followed by an inverse Fp16ToFp32 conversion
- graph.InsertNewLayer<armnn::ConvertFp32ToFp16Layer>(output->GetInputSlot(0), "convert1");
- graph.InsertNewLayer<armnn::ConvertFp16ToFp32Layer>(output->GetInputSlot(0), "convert2");
-
- graph.InsertNewLayer<armnn::Convolution2dLayer>(output->GetInputSlot(0), Convolution2dDescriptor(), "conv");
-
- // Fp16ToFp32 conversion followed by an inverse Fp32ToFp16 conversion
- graph.InsertNewLayer<armnn::ConvertFp16ToFp32Layer>(output->GetInputSlot(0), "convert3");
- graph.InsertNewLayer<armnn::ConvertFp32ToFp16Layer>(output->GetInputSlot(0), "convert4");
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
- &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
- &IsLayerOfType<armnn::Convolution2dLayer>,
- &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
- &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeInverseConversionsFp16(),
- OptimizeInverseConversionsFp32()));
-
- // Check that all consecutive inverse conversions are removed
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::Convolution2dLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-}
-
BOOST_AUTO_TEST_CASE(InsertConvertersTest)
{
const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float16);
@@ -728,79 +242,7 @@ BOOST_AUTO_TEST_CASE(InsertConvertersTest)
&IsLayerOfType<armnn::OutputLayer>));
}
-BOOST_AUTO_TEST_CASE(Fp32NetworkToFp16OptimizationTest)
-{
- armnn::Graph graph;
-
- const armnn::TensorInfo infoFP32({ 2,2,1,3 }, armnn::DataType::Float32);
-
- // Create the simple test network
- auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
- input->GetOutputSlot().SetTensorInfo(infoFP32);
-
- auto floor = graph.AddLayer<armnn::FloorLayer>("floor");
- floor->GetOutputSlot().SetTensorInfo(infoFP32);
-
- auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
-
- // Connect up the layers
- input->GetOutputSlot().Connect(floor->GetInputSlot(0));
- floor->GetOutputSlot().Connect(output->GetInputSlot(0));
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::FloorLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- // Run the optimizer
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(Fp32NetworkToFp16Converter()));
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
- &IsLayerOfType<armnn::FloorLayer>,
- &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
- &IsLayerOfType<armnn::OutputLayer>));
-}
-
-BOOST_AUTO_TEST_CASE(InsertDebugOptimizationTest)
-{
- armnn::Graph graph;
-
- const armnn::TensorInfo info({ 2,2,1,3 }, armnn::DataType::Float32);
-
- // Create the simple test network
- auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
- input->GetOutputSlot().SetTensorInfo(info);
- auto floor = graph.AddLayer<armnn::FloorLayer>("floor");
- floor->GetOutputSlot().SetTensorInfo(info);
-
- auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
-
- // Connect up the layers
- input->GetOutputSlot().Connect(floor->GetInputSlot(0));
- floor->GetOutputSlot().Connect(output->GetInputSlot(0));
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::FloorLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-
- // Run the optimizer
- armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(InsertDebugLayer()));
-
- BOOST_TEST(CheckSequence(graph.cbegin(),
- graph.cend(),
- &IsLayerOfType<armnn::InputLayer>,
- &IsLayerOfType<armnn::DebugLayer>,
- &IsLayerOfType<armnn::FloorLayer>,
- &IsLayerOfType<armnn::DebugLayer>,
- &IsLayerOfType<armnn::OutputLayer>));
-}
void CreateConvolution2dGraph(Graph &graph, const unsigned int* inputShape,
const unsigned int* weightsShape, const unsigned int* outputShape,
diff --git a/src/armnn/test/TestUtils.hpp b/src/armnn/test/TestUtils.hpp
index 9129d91886..9b1a3bf18d 100644
--- a/src/armnn/test/TestUtils.hpp
+++ b/src/armnn/test/TestUtils.hpp
@@ -6,6 +6,44 @@
#pragma once
#include <armnn/INetwork.hpp>
+#include <Graph.hpp>
void Connect(armnn::IConnectableLayer* from, armnn::IConnectableLayer* to, const armnn::TensorInfo& tensorInfo,
unsigned int fromIndex = 0, unsigned int toIndex = 0);
+
+template <typename LayerT>
+bool IsLayerOfType(const armnn::Layer* const layer)
+{
+ return (layer->GetType() == armnn::LayerEnumOf<LayerT>());
+}
+
+inline bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
+{
+ return (first == last);
+}
+
+/// Checks each unary function in Us evaluates true for each correspondent layer in the sequence [first, last).
+template <typename U, typename... Us>
+bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last, U&& u, Us&&... us)
+{
+ return u(*first) && CheckSequence(std::next(first), last, us...);
+}
+
+template <typename LayerT>
+bool CheckRelatedLayers(armnn::Graph& graph, const std::list<std::string>& testRelatedLayers)
+{
+ for (auto& layer : graph)
+ {
+ if (layer->GetType() == armnn::LayerEnumOf<LayerT>())
+ {
+ auto& relatedLayers = layer->GetRelatedLayerNames();
+ if (!std::equal(relatedLayers.begin(), relatedLayers.end(), testRelatedLayers.begin(),
+ testRelatedLayers.end()))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
diff --git a/src/armnn/test/optimizations/ConvertConstantsFloatToHalfTests.cpp b/src/armnn/test/optimizations/ConvertConstantsFloatToHalfTests.cpp
new file mode 100644
index 0000000000..b40bd2de41
--- /dev/null
+++ b/src/armnn/test/optimizations/ConvertConstantsFloatToHalfTests.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright © 2017 Arm Ltd. All rights reserved.
+// SPDX-License-Identifier: MIT
+//
+
+#include "../TestUtils.hpp"
+
+#include <Optimizer.hpp>
+#include <Half.hpp>
+
+#include <boost/test/unit_test.hpp>
+
+using namespace armnn;
+
+BOOST_AUTO_TEST_SUITE(Optimizer)
+using namespace armnn::optimizations;
+
+BOOST_AUTO_TEST_CASE(ConvertConstantsFloatToHalfTest)
+{
+ armnn::Graph graph;
+
+ const armnn::TensorInfo info({ 1, 1, 1, 2 }, armnn::DataType::Float16);
+
+ // Create const tensor from fp32 data
+ unsigned int dims[] = { 4, 1, 1, 1 };
+ std::vector<float> floatWeights{ 1.0f, 2.0f, 3.0f, 4.0f };
+ armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float32), floatWeights);
+
+ // Create simple test network
+ auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
+ input->GetOutputSlot().SetTensorInfo(info);
+
+ auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(armnn::FullyConnectedDescriptor(), "fc");
+ fc->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
+ fc->GetOutputSlot().SetTensorInfo(info);
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
+
+ // Connect up the layers
+ input->GetOutputSlot().Connect(fc->GetInputSlot(0));
+ fc->GetOutputSlot().Connect(output->GetInputSlot(0));
+
+ // Check tensor data type before conversion
+ BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float32);
+
+ // Run the optimizer
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsFloatToHalf()));
+
+ // Check tensor data type after conversion
+ BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float16);
+
+ // Check whether data matches expected fp16 data
+ Half* data = fc->m_Weight->GetTensor<Half>();
+ BOOST_CHECK(data[0] == Half(1.0f));
+ BOOST_CHECK(data[1] == Half(2.0f));
+ BOOST_CHECK(data[2] == Half(3.0f));
+ BOOST_CHECK(data[3] == Half(4.0f));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/ConvertConstantsHalfToFloatTests.cpp b/src/armnn/test/optimizations/ConvertConstantsHalfToFloatTests.cpp
new file mode 100644
index 0000000000..aca58ad113
--- /dev/null
+++ b/src/armnn/test/optimizations/ConvertConstantsHalfToFloatTests.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright © 2017 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(ConvertConstantsHalfToFloatTest)
+{
+ armnn::Graph graph;
+
+ const armnn::TensorInfo info({ 1, 1, 1, 2 }, armnn::DataType::Float32);
+
+ // Create the half precision input data
+ unsigned int dims[] = { 4, 1, 1, 1 };
+ std::vector<float> convWeightsData{ 1.f, 2.f, 3.f, 4.f };
+ std::vector<uint16_t> halfWeights(4);
+ armnnUtils::FloatingPointConverter::ConvertFloat32To16(convWeightsData.data(), convWeightsData.size(),
+ halfWeights.data());
+ armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float16), halfWeights);
+
+ //Create the simple test network
+ auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
+ input->GetOutputSlot().SetTensorInfo(info);
+
+ auto fc = graph.AddLayer<armnn::FullyConnectedLayer>(armnn::FullyConnectedDescriptor(), "fc");
+ fc->m_Weight = std::make_unique<armnn::ScopedCpuTensorHandle>(weights);
+ fc->GetOutputSlot().SetTensorInfo(info);
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
+
+ //Connect up the layers
+ input->GetOutputSlot().Connect(fc->GetInputSlot(0));
+ fc->GetOutputSlot().Connect(output->GetInputSlot(0));
+
+ //Test the tensor info is correct.
+ BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float16);
+
+ // Run the optimizer
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(ConvertConstantsHalfToFloat()));
+
+ //Test the tensor info is correct.
+ BOOST_CHECK(fc->m_Weight->GetTensorInfo().GetDataType() == armnn::DataType::Float32);
+
+ // Now test the data matches float32 data
+ float* data = fc->m_Weight->GetTensor<float>();
+ BOOST_CHECK(1.0f == data[0]);
+ BOOST_CHECK(2.0f == data[1]);
+ BOOST_CHECK(3.0f == data[2]);
+ BOOST_CHECK(4.0f == data[3]);
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/Fp32NetworkToFp16ConverterTests.cpp b/src/armnn/test/optimizations/Fp32NetworkToFp16ConverterTests.cpp
new file mode 100644
index 0000000000..0e47b3f089
--- /dev/null
+++ b/src/armnn/test/optimizations/Fp32NetworkToFp16ConverterTests.cpp
@@ -0,0 +1,45 @@
+//
+// Copyright © 2017 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(Fp32NetworkToFp16OptimizationTest)
+{
+ armnn::Graph graph;
+
+ const armnn::TensorInfo infoFP32({ 2, 2, 1, 3 }, armnn::DataType::Float32);
+
+ // Create the simple test network
+ auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
+ input->GetOutputSlot().SetTensorInfo(infoFP32);
+
+ auto floor = graph.AddLayer<armnn::FloorLayer>("floor");
+ floor->GetOutputSlot().SetTensorInfo(infoFP32);
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
+
+ // Connect up the layers
+ input->GetOutputSlot().Connect(floor->GetInputSlot(0));
+ floor->GetOutputSlot().Connect(output->GetInputSlot(0));
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::FloorLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ // Run the optimizer
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(Fp32NetworkToFp16Converter()));
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>, &IsLayerOfType<armnn::FloorLayer>,
+ &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>, &IsLayerOfType<armnn::OutputLayer>));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/InsertDebugLayerTests.cpp b/src/armnn/test/optimizations/InsertDebugLayerTests.cpp
new file mode 100644
index 0000000000..57cf463931
--- /dev/null
+++ b/src/armnn/test/optimizations/InsertDebugLayerTests.cpp
@@ -0,0 +1,45 @@
+//
+// Copyright © 2017 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(InsertDebugOptimizationTest)
+{
+ armnn::Graph graph;
+
+ const armnn::TensorInfo info({ 2, 2, 1, 3 }, armnn::DataType::Float32);
+
+ // Create the simple test network
+ auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
+ input->GetOutputSlot().SetTensorInfo(info);
+
+ auto floor = graph.AddLayer<armnn::FloorLayer>("floor");
+ floor->GetOutputSlot().SetTensorInfo(info);
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(1, "output");
+
+ // Connect up the layers
+ input->GetOutputSlot().Connect(floor->GetInputSlot(0));
+ floor->GetOutputSlot().Connect(output->GetInputSlot(0));
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::FloorLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ // Run the optimizer
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(InsertDebugLayer()));
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::DebugLayer>, &IsLayerOfType<armnn::FloorLayer>,
+ &IsLayerOfType<armnn::DebugLayer>, &IsLayerOfType<armnn::OutputLayer>));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/MovePermuteUpTests.cpp b/src/armnn/test/optimizations/MovePermuteUpTests.cpp
new file mode 100644
index 0000000000..2c297d65cd
--- /dev/null
+++ b/src/armnn/test/optimizations/MovePermuteUpTests.cpp
@@ -0,0 +1,92 @@
+//
+// Copyright © 2017 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(MovePermuteUpTest)
+{
+ const armnn::TensorInfo info({ 1, 5, 2, 3 }, armnn::DataType::Float32);
+ const armnn::TensorInfo permuted({ 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 permuteLayerName = "original_permute";
+
+ // Insert permute
+ head = graph.InsertNewLayer<armnn::PermuteLayer>(head->GetInputSlot(0), armnn::PermuteDescriptor({ 0, 2, 3, 1 }),
+ permuteLayerName.c_str());
+
+ head->GetOutputHandler().SetTensorInfo(permuted);
+
+ // 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::PermuteLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(MovePermuteUp()));
+
+ // The permute is moved to the top. New permutes for layers with multiple inputs.
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::InputLayer>, &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::PermuteLayer>, &IsLayerOfType<armnn::PermuteLayer>,
+ &IsLayerOfType<armnn::PermuteLayer>, &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 = { permuteLayerName };
+
+ BOOST_TEST(CheckRelatedLayers<armnn::PermuteLayer>(graph, testRelatedLayers));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/OptimizeConsecutiveReshapesTests.cpp b/src/armnn/test/optimizations/OptimizeConsecutiveReshapesTests.cpp
new file mode 100644
index 0000000000..d16b8f7f77
--- /dev/null
+++ b/src/armnn/test/optimizations/OptimizeConsecutiveReshapesTests.cpp
@@ -0,0 +1,80 @@
+//
+// Copyright © 2017 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(OptimizeConsecutiveReshapesTest)
+{
+ armnn::Graph graph;
+
+ const armnn::TensorInfo info0({ 1, 2, 3, 5 }, armnn::DataType::Float32);
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
+ auto input = graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
+
+ input->GetOutputHandler().SetTensorInfo(info0);
+
+ {
+ // Inserts two reshapes.
+ const armnn::TensorInfo info1({ 1, 30, 1, 1 }, armnn::DataType::Float32);
+ const armnn::TensorInfo info2({ 1, 2, 1, 15 }, armnn::DataType::Float32);
+
+ std::string reshape1Name = "reshape1";
+ std::string reshape2Name = "reshape2";
+
+ auto reshape1 = graph.InsertNewLayer<armnn::ReshapeLayer>(
+ output->GetInputSlot(0), armnn::ReshapeDescriptor{ info1.GetShape() }, reshape1Name.c_str());
+ auto reshape2 = graph.InsertNewLayer<armnn::ReshapeLayer>(
+ output->GetInputSlot(0), armnn::ReshapeDescriptor{ info2.GetShape() }, reshape2Name.c_str());
+
+ reshape1->GetOutputHandler().SetTensorInfo(info1);
+ reshape2->GetOutputHandler().SetTensorInfo(info2);
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::ReshapeLayer>, &IsLayerOfType<armnn::ReshapeLayer>,
+ &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeConsecutiveReshapes()));
+
+ auto checkReshape = [&info2](const armnn::Layer* const layer) -> bool {
+ const auto reshapeLayer = static_cast<const armnn::ReshapeLayer*>(layer);
+ return IsLayerOfType<armnn::ReshapeLayer>(layer) &&
+ (reshapeLayer->GetParameters().m_TargetShape == info2.GetShape()) &&
+ (reshapeLayer->GetOutputHandler().GetTensorInfo().GetShape() == info2.GetShape());
+ };
+
+ // The two reshapes are replaced by a single equivalent reshape.
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>, checkReshape,
+ &IsLayerOfType<armnn::OutputLayer>));
+
+ // Check the new reshape layer has the other two reshapes as related layers
+ std::list<std::string> testRelatedLayers = { reshape2Name, reshape1Name };
+
+ BOOST_TEST(CheckRelatedLayers<armnn::ReshapeLayer>(graph, testRelatedLayers));
+ }
+
+ {
+ // Inserts a reshape to the input shape.
+ auto reshapeToIn = graph.InsertNewLayer<armnn::ReshapeLayer>(
+ output->GetInputSlot(0), armnn::ReshapeDescriptor{ info0.GetShape() }, "reshapeToIn");
+
+ reshapeToIn->GetOutputHandler().SetTensorInfo(info0);
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeConsecutiveReshapes()));
+
+ // The two reshapes 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/OptimizeInverseConversionsTests.cpp b/src/armnn/test/optimizations/OptimizeInverseConversionsTests.cpp
new file mode 100644
index 0000000000..130e498b83
--- /dev/null
+++ b/src/armnn/test/optimizations/OptimizeInverseConversionsTests.cpp
@@ -0,0 +1,49 @@
+//
+// Copyright © 2017 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(OptimizeInverseConversionsTest)
+{
+ armnn::Graph graph;
+
+ auto output = graph.AddLayer<armnn::OutputLayer>(0, "output");
+
+ graph.InsertNewLayer<armnn::InputLayer>(output->GetInputSlot(0), 0, "input");
+
+ // Fp32ToFp16 conversion followed by an inverse Fp16ToFp32 conversion
+ graph.InsertNewLayer<armnn::ConvertFp32ToFp16Layer>(output->GetInputSlot(0), "convert1");
+ graph.InsertNewLayer<armnn::ConvertFp16ToFp32Layer>(output->GetInputSlot(0), "convert2");
+
+ graph.InsertNewLayer<armnn::Convolution2dLayer>(output->GetInputSlot(0), Convolution2dDescriptor(), "conv");
+
+ // Fp16ToFp32 conversion followed by an inverse Fp32ToFp16 conversion
+ graph.InsertNewLayer<armnn::ConvertFp16ToFp32Layer>(output->GetInputSlot(0), "convert3");
+ graph.InsertNewLayer<armnn::ConvertFp32ToFp16Layer>(output->GetInputSlot(0), "convert4");
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>,
+ &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>, &IsLayerOfType<armnn::Convolution2dLayer>,
+ &IsLayerOfType<armnn::ConvertFp16ToFp32Layer>,
+ &IsLayerOfType<armnn::ConvertFp32ToFp16Layer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(
+ graph, armnn::MakeOptimizations(OptimizeInverseConversionsFp16(), OptimizeInverseConversionsFp32()));
+
+ // Check that all consecutive inverse conversions are removed
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::Convolution2dLayer>, &IsLayerOfType<armnn::OutputLayer>));
+}
+
+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
new file mode 100644
index 0000000000..dcf955956d
--- /dev/null
+++ b/src/armnn/test/optimizations/OptimizeInversePermutesTests.cpp
@@ -0,0 +1,42 @@
+//
+// Copyright © 2017 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(OptimizeInversePermutesTest)
+{
+ 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::PermuteLayer>(output->GetInputSlot(0), armnn::PermuteDescriptor({ 0, 2, 3, 1 }),
+ "perm0231");
+ graph.InsertNewLayer<armnn::PermuteLayer>(output->GetInputSlot(0), armnn::PermuteDescriptor({ 0, 3, 1, 2 }),
+ "perm0312");
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::PermuteLayer>, &IsLayerOfType<armnn::PermuteLayer>,
+ &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(OptimizeInversePermutes()));
+
+ // 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/PermuteAsReshapeTests.cpp b/src/armnn/test/optimizations/PermuteAsReshapeTests.cpp
new file mode 100644
index 0000000000..b44331c9fc
--- /dev/null
+++ b/src/armnn/test/optimizations/PermuteAsReshapeTests.cpp
@@ -0,0 +1,60 @@
+//
+// Copyright © 2017 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(PermuteAsReshapeTest)
+{
+ armnn::Graph graph;
+
+ std::string permuteLayerName = "permute";
+
+ 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 permute.
+ graph
+ .InsertNewLayer<armnn::PermuteLayer>(output->GetInputSlot(0), armnn::PermuteDescriptor({ 0, 2, 3, 1 }),
+ permuteLayerName.c_str())
+ ->GetOutputHandler()
+ .SetTensorInfo(infoOut);
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::PermuteLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(PermuteAsReshape()));
+
+ // The permute 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 = { permuteLayerName };
+ BOOST_TEST(CheckRelatedLayers<armnn::ReshapeLayer>(graph, testRelatedLayers));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
diff --git a/src/armnn/test/optimizations/SquashEqualSiblingsTests.cpp b/src/armnn/test/optimizations/SquashEqualSiblingsTests.cpp
new file mode 100644
index 0000000000..3fa49ecac7
--- /dev/null
+++ b/src/armnn/test/optimizations/SquashEqualSiblingsTests.cpp
@@ -0,0 +1,74 @@
+//
+// Copyright © 2017 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(SquashEqualSiblingsTest)
+{
+ armnn::Graph graph;
+
+ armnn::LayerBindingId outputId = 0;
+
+ const armnn::TensorInfo info({ 1, 2, 3, 5 }, armnn::DataType::Float32);
+ const armnn::TensorInfo permuted({ 1, 5, 2, 3 }, armnn::DataType::Float32);
+
+ auto input = graph.AddLayer<armnn::InputLayer>(0, "input");
+ input->GetOutputSlot().SetTensorInfo(info);
+
+ // Inserts equal permutes, equal reshapes and something else.
+ const armnn::PermuteDescriptor permDesc({ 0, 2, 3, 1 });
+ const armnn::ReshapeDescriptor reshapeDesc{ { 1, 3, 1, 5 } };
+
+ armnn::Layer* layer;
+
+ layer = graph.AddLayer<armnn::PermuteLayer>(permDesc, "");
+ layer->GetOutputSlot().SetTensorInfo(permuted);
+ layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
+ input->GetOutputSlot().Connect(layer->GetInputSlot(0));
+
+ layer = graph.AddLayer<armnn::ReshapeLayer>(reshapeDesc, "");
+ layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
+ input->GetOutputSlot().Connect(layer->GetInputSlot(0));
+
+ layer = graph.AddLayer<armnn::FloorLayer>("");
+ layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
+ input->GetOutputSlot().Connect(layer->GetInputSlot(0));
+
+ layer = graph.AddLayer<armnn::ReshapeLayer>(reshapeDesc, "");
+ layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
+ input->GetOutputSlot().Connect(layer->GetInputSlot(0));
+
+ layer = graph.AddLayer<armnn::PermuteLayer>(permDesc, "");
+ layer->GetOutputSlot().SetTensorInfo(permuted);
+ layer->GetOutputSlot().Connect(graph.AddLayer<armnn::OutputLayer>(outputId++, "")->GetInputSlot(0));
+ input->GetOutputSlot().Connect(layer->GetInputSlot(0));
+
+ BOOST_TEST(CheckSequence(
+ graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>, &IsLayerOfType<armnn::PermuteLayer>,
+ &IsLayerOfType<armnn::ReshapeLayer>, &IsLayerOfType<armnn::FloorLayer>, &IsLayerOfType<armnn::ReshapeLayer>,
+ &IsLayerOfType<armnn::PermuteLayer>, &IsLayerOfType<armnn::OutputLayer>, &IsLayerOfType<armnn::OutputLayer>,
+ &IsLayerOfType<armnn::OutputLayer>, &IsLayerOfType<armnn::OutputLayer>, &IsLayerOfType<armnn::OutputLayer>));
+
+ armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(SquashEqualPermuteSiblings(), SquashEqualReshapeSiblings()));
+
+ // The permutes and reshapes are squashed.
+
+ BOOST_TEST(CheckSequence(graph.cbegin(), graph.cend(), &IsLayerOfType<armnn::InputLayer>,
+ &IsLayerOfType<armnn::PermuteLayer>, &IsLayerOfType<armnn::ReshapeLayer>,
+ &IsLayerOfType<armnn::FloorLayer>, &IsLayerOfType<armnn::OutputLayer>,
+ &IsLayerOfType<armnn::OutputLayer>, &IsLayerOfType<armnn::OutputLayer>,
+ &IsLayerOfType<armnn::OutputLayer>, &IsLayerOfType<armnn::OutputLayer>));
+}
+
+BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file