blob: f54ac9f9cb7066228289984ba08bc6689411b7ec [file] [log] [blame]
//
// Copyright © 2022-2023 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#include "LayersFwd.hpp"
#include <Network.hpp>
#include <TestUtils.hpp>
#include <doctest/doctest.h>
#include <armnn/backends/TensorHandle.hpp>
#include <Optimizer.hpp>
TEST_SUITE("Optimizer")
{
using namespace armnn;
using namespace armnn::optimizations;
// Helpers for testing
auto checkConstantFloat32 = [](const armnn::Layer *const layer)
{
return IsLayerOfType<ConstantLayer>(layer) && (layer->GetDataType() == DataType::Float32);
};
auto checkConstantFloat16 = [](const armnn::Layer *const layer)
{
return IsLayerOfType<ConstantLayer>(layer) && (layer->GetDataType() == DataType::Float16);
};
auto checkConstantQAsymmS8 = [](const armnn::Layer *const layer)
{
return IsLayerOfType<ConstantLayer>(layer) && (layer->GetDataType() == DataType::QAsymmS8);
};
auto checkPadFoldedIntoConv2d = [](const Layer* const layer)
{
const auto conv2dLayer = static_cast<const Convolution2dLayer*>(layer);
const auto conv2dLayerParams = conv2dLayer->GetParameters();
return IsLayerOfType<Convolution2dLayer>(layer) &&
(layer->GetNameStr() == "folded-pad-into-conv2d") &&
(conv2dLayerParams.m_PadLeft == 2) &&
(conv2dLayerParams.m_PadRight == 2) &&
(conv2dLayerParams.m_PadTop == 2) &&
(conv2dLayerParams.m_PadBottom == 2) &&
(conv2dLayerParams.m_StrideX == 1) &&
(conv2dLayerParams.m_StrideY == 1) &&
(conv2dLayerParams.m_BiasEnabled == false) &&
(conv2dLayerParams.m_DataLayout == DataLayout::NHWC);
};
TEST_CASE("ConvertConstFloat16DequantizeToConstFloat32")
{
Graph graph;
const unsigned int shape[] = {1, 2, 2, 3};
const TensorInfo constTensorInfo(4, shape, DataType::Float16, 1.0, 0, true);
const TensorInfo outputDequantizeInfo(4, shape, DataType::Float32, 1.0, 0, true);
auto constantLayer = graph.AddLayer<ConstantLayer>("constant");
std::vector<float> constantValues(constTensorInfo.GetNumElements(), 4.5f);
ConstTensor constTensor(constTensorInfo, constantValues.data());
constantLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
constantLayer->GetOutputSlot().SetTensorInfo(constTensorInfo);
auto dequantizeLayer = graph.AddLayer<DequantizeLayer>("dequantize");
dequantizeLayer->GetOutputSlot().SetTensorInfo(outputDequantizeInfo);
auto output = graph.AddLayer<OutputLayer>(0, "output");
// Connect up constant -> dequantize -> output
constantLayer->GetOutputSlot().Connect(dequantizeLayer->GetInputSlot(0));
dequantizeLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
CHECK(CheckSequence(graph.cbegin(), graph.cend(),
checkConstantFloat16,
&IsLayerOfType<DequantizeLayer>,
&IsLayerOfType<OutputLayer>));
armnn::Optimizer::Pass(graph, MakeOptimizations(ConvertConstDequantisationLayersToConstLayers()));
CHECK(CheckSequence(graph.cbegin(), graph.cend(),
checkConstantFloat32,
&IsLayerOfType<OutputLayer>));
}
TEST_CASE("ConvertConstFloat16DequantizeToConstFloat32PlusFusePadWithConv2d")
{
Graph graph;
const unsigned int shape[] = {1, 2, 2, 3};
const TensorInfo constTensorInfo(4, shape, DataType::Float16, 1.0, 0, true);
const TensorInfo outputDequantizeInfo(4, shape, DataType::Float32, 1.0, 0, true);
auto constantLayer = graph.AddLayer<ConstantLayer>("constant");
std::vector<float> constantValues(constTensorInfo.GetNumElements(), 4.5f);
ConstTensor constTensor(constTensorInfo, constantValues.data());
constantLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
constantLayer->GetOutputSlot().SetTensorInfo(constTensorInfo);
auto dequantizeLayer = graph.AddLayer<DequantizeLayer>("dequantize");
dequantizeLayer->GetOutputSlot().SetTensorInfo(outputDequantizeInfo);
auto output = graph.AddLayer<OutputLayer>(0, "output");
Convolution2dDescriptor convolution2dDescriptor;
convolution2dDescriptor.m_BiasEnabled = false;
convolution2dDescriptor.m_StrideX = 1;
convolution2dDescriptor.m_StrideY = 1;
convolution2dDescriptor.m_DataLayout = DataLayout::NHWC;
auto conv2d = graph.AddLayer<Convolution2dLayer>(convolution2dDescriptor, "conv2d");
auto inputLayer = graph.AddLayer<InputLayer>(0, "input");
PadDescriptor padDescriptor({{0, 0},
{2, 2},
{2, 2},
{0, 0}});
const unsigned int paddedShape[] = {1, 6, 6, 3};
TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
auto padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
// Connect up:
// input -> pad -> conv2d -> output
// constant -> dequantize ->
constantLayer->GetOutputSlot().Connect(dequantizeLayer->GetInputSlot(0));
dequantizeLayer->GetOutputSlot().Connect(conv2d->GetInputSlot(1));
inputLayer->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
padLayer->GetOutputSlot().Connect(conv2d->GetInputSlot(0));
conv2d->GetOutputSlot().Connect(output->GetInputSlot(0));
CHECK(CheckSequence(graph.cbegin(), graph.cend(),
&IsLayerOfType<InputLayer>,
checkConstantFloat16,
&IsLayerOfType<DequantizeLayer>,
&IsLayerOfType<Convolution2dLayer>,
&IsLayerOfType<PadLayer>,
&IsLayerOfType<OutputLayer>));
armnn::Optimizer::Pass(graph, MakeOptimizations(ConvertConstDequantisationLayersToConstLayers()));
armnn::Optimizer::Pass(graph, MakeOptimizations(FoldPadIntoConvolution2d()));
// Ensure that the const and dequantize are now constant of type fp32
// Ensure pad and conv2d are now just convolution
CHECK(CheckSequence(graph.cbegin(), graph.cend(),
&IsLayerOfType<InputLayer>,
checkConstantFloat32,
checkPadFoldedIntoConv2d,
&IsLayerOfType<OutputLayer>));
}
TEST_CASE("ConvertConstInt8DequantizeToConstFloat32")
{
Graph graph;
const unsigned int shape[] = {1, 2, 2, 3};
const TensorInfo constTensorInfo(4, shape, DataType::QAsymmS8, 1.0, 0, true);
const TensorInfo outputDequantizeInfo(4, shape, DataType::Float32, 1.0, 0, true);
auto constantLayer = graph.AddLayer<ConstantLayer>("constant");
std::vector<int8_t> constantValues(constTensorInfo.GetNumElements(), 5);
ConstTensor constTensor(constTensorInfo, constantValues.data());
constantLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
constantLayer->GetOutputSlot().SetTensorInfo(constTensorInfo);
auto dequantizeLayer = graph.AddLayer<DequantizeLayer>("dequantize");
dequantizeLayer->GetOutputSlot().SetTensorInfo(outputDequantizeInfo);
auto output = graph.AddLayer<OutputLayer>(0, "output");
// Connect up constant -> dequantize -> output
constantLayer->GetOutputSlot().Connect(dequantizeLayer->GetInputSlot(0));
dequantizeLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
CHECK(CheckSequence(graph.cbegin(), graph.cend(),
checkConstantQAsymmS8,
&IsLayerOfType<DequantizeLayer>,
&IsLayerOfType<OutputLayer>));
armnn::Optimizer::Pass(graph, MakeOptimizations(ConvertConstDequantisationLayersToConstLayers()));
CHECK(CheckSequence(graph.cbegin(), graph.cend(),
checkConstantFloat32,
&IsLayerOfType<OutputLayer>));
}
}