blob: e24055371f223fb4fa2cb508058c90551ca865e9 [file] [log] [blame]
//
// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
// SPDX-License-Identifier: MIT
//
#pragma once
#include <Layer.hpp>
#include <tosaCommon/TosaMappings.hpp>
#include <tosaCommon/operatorMappings/TosaOperatorUtils.hpp>
#include <doctest/doctest.h>
#include <numeric>
using namespace armnn;
using namespace tosa;
inline void VerifyTosaAttribute(const BaseDescriptor& descriptor,
const TosaAttributeBase* attribute,
std::vector<int32_t> inputShape,
std::vector<int32_t> outputShape,
LayerType type,
uint32_t mappingOpNumber = 0)
{
switch (type)
{
case LayerType::Convolution2d:
{
auto conv2dDesc = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor);
std::vector<int> pad = {static_cast<int>(conv2dDesc->m_PadTop),
static_cast<int>(conv2dDesc->m_PadBottom),
static_cast<int>(conv2dDesc->m_PadLeft),
static_cast<int>(conv2dDesc->m_PadRight)};
std::vector<int> dilation = {static_cast<int>(conv2dDesc->m_DilationY),
static_cast<int>(conv2dDesc->m_DilationX)};
std::vector<int> stride = {static_cast<int>(conv2dDesc->m_StrideY),
static_cast<int>(conv2dDesc->m_StrideX)};
TosaConvAttribute convAttribute(attribute);
CHECK(pad == convAttribute.pad());
CHECK(dilation == convAttribute.dilation());
CHECK(stride == convAttribute.stride());
break;
}
case LayerType::Pooling2d:
{
auto poolDesc = PolymorphicDowncast<const Pooling2dDescriptor*>(&descriptor);
std::vector<int> pad = {static_cast<int>(poolDesc->m_PadTop),
static_cast<int>(poolDesc->m_PadBottom),
static_cast<int>(poolDesc->m_PadLeft),
static_cast<int>(poolDesc->m_PadRight)};
bool avgPoolIgnoreValue =
(poolDesc->m_PoolType == PoolingAlgorithm::Average) &&
(poolDesc->m_PaddingMethod == PaddingMethod::IgnoreValue);
if (avgPoolIgnoreValue)
{
if (mappingOpNumber == 0)
{
if (poolDesc->m_DataLayout == DataLayout::NHWC)
{
pad = {0,
0,
static_cast<int>(poolDesc->m_PadTop),
static_cast<int>(poolDesc->m_PadBottom),
static_cast<int>(poolDesc->m_PadLeft),
static_cast<int>(poolDesc->m_PadRight),
0,
0
};
}
else
{
pad = {0,
0,
0,
0,
static_cast<int>(poolDesc->m_PadTop),
static_cast<int>(poolDesc->m_PadBottom),
static_cast<int>(poolDesc->m_PadLeft),
static_cast<int>(poolDesc->m_PadRight)
};
}
TosaPadAttribute padAttribute(attribute);
CHECK(pad == padAttribute.padding());
CHECK(0.0f == padAttribute.pad_const_fp());
CHECK(0 == padAttribute.pad_const_int());
break;
}
pad = {0, 0, 0, 0};
}
std::vector<int> kernel = {static_cast<int>(poolDesc->m_PoolHeight),
static_cast<int>(poolDesc->m_PoolWidth)};
std::vector<int> stride = {static_cast<int>(poolDesc->m_StrideY),
static_cast<int>(poolDesc->m_StrideX)};
TosaPoolAttribute poolAttribute(attribute);
CHECK(pad == poolAttribute.pad());
CHECK(kernel == poolAttribute.kernel());
CHECK(stride == poolAttribute.stride());
break;
}
case LayerType::Reshape:
{
auto reshapeDesc = PolymorphicDowncast<const ReshapeDescriptor*>(&descriptor);
TosaReshapeAttribute reshapeAttribute(attribute);
std::vector<int32_t> shapeAttrib = reshapeAttribute.new_shape();
CHECK(GetTosaTensorShape(reshapeDesc->m_TargetShape) == shapeAttrib);
CHECK(outputShape == shapeAttrib);
auto numInputElements = std::accumulate(std::begin(inputShape),
std::end(inputShape),
1,
std::multiplies<int32_t>());
auto numAttributeShapeElements = std::accumulate(std::begin(shapeAttrib),
std::end(shapeAttrib),
1,
std::multiplies<int32_t>());
CHECK(numInputElements == numAttributeShapeElements);
break;
}
case LayerType::Slice:
{
auto sliceDesc = PolymorphicDowncast<const SliceDescriptor*>(&descriptor);
TosaSliceAttribute reshapeAttribute(attribute);
std::vector<int32_t> begin(sliceDesc->m_Begin.begin(), sliceDesc->m_Begin.end());
std::vector<int32_t> size(sliceDesc->m_Size.begin(), sliceDesc->m_Size.end());
CHECK(begin == reshapeAttribute.start());
CHECK(size == reshapeAttribute.size());
CHECK(begin.size() == inputShape.size());
CHECK(size.size() == inputShape.size());
CHECK(begin.size() == outputShape.size());
CHECK(size.size() == outputShape.size());
break;
}
case LayerType::TransposeConvolution2d:
{
auto transposeConv2dDesc = PolymorphicDowncast<const TransposeConvolution2dDescriptor*>(&descriptor);
std::vector<int> outPad = {-static_cast<int>(transposeConv2dDesc->m_PadTop),
-static_cast<int>(transposeConv2dDesc->m_PadBottom),
-static_cast<int>(transposeConv2dDesc->m_PadLeft),
-static_cast<int>(transposeConv2dDesc->m_PadRight)};
std::vector<int> stride = {static_cast<int>(transposeConv2dDesc->m_StrideY),
static_cast<int>(transposeConv2dDesc->m_StrideX)};
TosaTransposeConvAttribute transposeConvAttribute(attribute);
CHECK(outPad == transposeConvAttribute.out_pad());
CHECK(stride == transposeConvAttribute.stride());
break;
}
case LayerType::Transpose:
{
auto transposeDesc = PolymorphicDowncast<const TransposeDescriptor*>(&descriptor);
std::vector<int> outPerm(transposeDesc->m_DimMappings.begin(), transposeDesc->m_DimMappings.end());
TosaTransposeAttribute transposeAttribute(attribute);
CHECK(outPerm == transposeAttribute.perms());
break;
}
default:
break;
}
return;
}
inline void AssertTosaOneToOneMappingBasicBlock(TosaSerializationBasicBlock* basicBlock,
std::vector<std::vector<int32_t>> inputShape,
std::vector<std::vector<int32_t>> outputShape,
Op tosaOp,
Attribute tosaAttribute,
const BaseDescriptor& descriptor,
LayerType type,
DType dataType = DType_FP32)
{
uint32_t numInputs = static_cast<uint32_t>(inputShape.size());
uint32_t numInputTensors = static_cast<uint32_t>(inputShape.size());
uint32_t numOutputs = static_cast<uint32_t>(outputShape.size());
std::string operatorString = TosaOpToString(tosaOp);
// The number of tensors in the block can be different if there are constant layers, as they are created separately.
if(type == LayerType::Convolution2d)
{
numInputTensors = PolymorphicDowncast<const Convolution2dDescriptor*>(&descriptor)->m_BiasEnabled ? 3 : 2;
}
std::string blockStr = operatorString + "_block_";
CHECK(basicBlock->GetName().find(blockStr) != std::string::npos);
CHECK(basicBlock->GetInputs().size() == numInputTensors);
CHECK(basicBlock->GetOutputs().size() == numOutputs);
CHECK(basicBlock->GetOperators().size() == 1);
CHECK(basicBlock->GetTensors().size() == (numInputs + numOutputs));
TosaSerializationOperator* op = basicBlock->GetOperators().at(0);
CHECK(op->GetInputTensorNames().size() == numInputTensors);
CHECK(op->GetOutputTensorNames().size() == numOutputs);
for (uint32_t i = 0; i < numInputs; i++)
{
std::basic_string<char> blockInputName = basicBlock->GetInputs()[i];
std::basic_string<char> operatorInputName = op->GetInputTensorNames()[i];
std::basic_string<char> tensorName = basicBlock->GetTensors()[i]->GetName();
std::string opStr = "input" + std::to_string(i) + "_";
CHECK(blockInputName == operatorInputName);
CHECK(tensorName == operatorInputName);
CHECK(blockInputName.find(opStr) != std::string::npos);
}
for (uint32_t i = 0; i < numOutputs; i++)
{
std::basic_string<char> blockOutputName = basicBlock->GetOutputs()[i];
std::basic_string<char> operatorOutputName = op->GetOutputTensorNames()[i];
std::basic_string<char> tensorName = basicBlock->GetTensors()[numInputs + i]->GetName();
std::string opStr = "output" + std::to_string(i) + "_";
if (tosaOp == Op_CONST)
{
opStr = "constant_";
}
CHECK(blockOutputName == operatorOutputName);
CHECK(tensorName == operatorOutputName);
CHECK(blockOutputName.find(opStr) != std::string::npos);
}
CHECK(op->GetAttributeType() == tosaAttribute);
CHECK(op->GetOp() == tosaOp);
for (uint32_t i = 0; i < numInputs; i++)
{
TosaSerializationTensor* tensor = basicBlock->GetTensors()[i];
CHECK(tensor->GetDtype() == dataType);
CHECK(tensor->GetData().size() == 0);
CHECK(tensor->GetShape() == inputShape[static_cast<unsigned long int>(i)]);
}
for (uint32_t i = 0; i < numOutputs; i++)
{
TosaSerializationTensor* tensor = basicBlock->GetTensors()[i + inputShape.size()];
CHECK(tensor->GetDtype() == dataType);
CHECK(tensor->GetShape() == outputShape[static_cast<unsigned long int>(i)]);
if (tosaOp != Op_CONST)
{
// Const tensors contain data.
CHECK(tensor->GetData().size() == 0);
}
}
std::vector<int32_t> input = {};
std::vector<int32_t> output = {};
if (!inputShape.empty())
{
input = inputShape[0];
}
if (!outputShape.empty())
{
output = outputShape[0];
}
VerifyTosaAttribute(descriptor,
op->GetAttribute(),
input,
output,
type);
}