diff options
Diffstat (limited to 'src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp')
-rw-r--r-- | src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp b/src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp new file mode 100644 index 0000000000..9c095d627f --- /dev/null +++ b/src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp @@ -0,0 +1,123 @@ +// +// Copyright © 2022 Arm Ltd and Contributors. All rights reserved. +// SPDX-License-Identifier: MIT +// + +#include "Conv2dOperator.hpp" + +TosaSerializationBasicBlock* ConvertConv2dToTosaOperator(const Layer* layer, + const std::vector<const TensorInfo*>& inputs, + const std::vector<const TensorInfo*>& outputs, + const Convolution2dDescriptor* conv2dDescriptor) +{ + std::vector<std::string> inputNames; + std::string outputName = std::string("output0_"); + std::string blockName = std::string("Op_CONV2D_block_") + GetUniqueTosaMappingID(); + + // Set input names for validation purposes only. + if(layer == nullptr) + { + inputNames.emplace_back("input0_"); + inputNames.emplace_back("input1_"); + if(conv2dDescriptor->m_BiasEnabled) + { + inputNames.emplace_back("input2_"); + } + } + else + { + // If a layer is present then the block will be used for execution, so input and output names need to be + // determined using the previous and following layers so the graph is connected correctly. + // For validation this doesn't matter. + for (uint32_t i = 0; i < inputs.size(); ++i) + { + // Get the layer connected to the input slot and determine unique layer name. + Layer& connectedLayer = layer->GetInputSlot(i).GetConnectedOutputSlot()->GetOwningLayer(); + + std::string inputName = GenerateUniqueName(connectedLayer, i); + inputNames.push_back(inputName); + } + + // Get the layer connected to the output slot and determine unique layer name. + Layer& connectedLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer(); + + outputName = GenerateUniqueName(connectedLayer, 0); + } + + std::vector<TosaSerializationTensor*> tensors; + std::vector<TosaSerializationOperator*> operators; + + // Setup input Tensor + std::vector<int32_t> inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); + DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(inputNames[0], inputShape0, inputDType0, {})); + + // Only add input tensors if weights and bias are not constant or if running validation. + // Constant tensors will be created in the ConvertConstantToTosaOperator function. + if(!inputs[1]->IsConstant() || layer == nullptr) + { + std::vector<int32_t> inputShape1 = GetTosaTensorShape(inputs[1]->GetShape()); + DType inputDType1 = ArmNNToDType(inputs[1]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(inputNames[1], inputShape1, inputDType1, {})); + } + + if(conv2dDescriptor->m_BiasEnabled) + { + if(!inputs[2]->IsConstant() || layer == nullptr) + { + std::vector<int32_t> inputShape2 = GetTosaTensorShape(inputs[2]->GetShape()); + DType inputDType2 = ArmNNToDType(inputs[2]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(inputNames[2], inputShape2, inputDType2, {})); + } + } + else + { + // If bias is disabled, create a constant bias of 0 as three inputs are required. + std::string constantName = std::string("constant_") + GetUniqueTosaMappingID(); + + operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {constantName})); + + std::vector<uint8_t> uint8Data; + std::vector<float> data = { 0.0 }; + + TosaSerializationHandler::ConvertF32toU8(data, uint8Data); + + tensors.push_back(new TosaSerializationTensor(constantName, {1}, DType_FP32, uint8Data)); + inputNames.emplace_back(constantName); + } + + // Setup Output Tensor + std::vector<int32_t> outputShape0 = GetTosaTensorShape(outputs[0]->GetShape()); + DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {})); + + // Set up CONV2D operator + std::vector<int> pad = {static_cast<int>(conv2dDescriptor->m_PadTop), + static_cast<int>(conv2dDescriptor->m_PadBottom), + static_cast<int>(conv2dDescriptor->m_PadLeft), + static_cast<int>(conv2dDescriptor->m_PadRight)}; + std::vector<int> stride = {static_cast<int>(conv2dDescriptor->m_StrideY), + static_cast<int>(conv2dDescriptor->m_StrideX)}; + std::vector<int> dilation = {static_cast<int>(conv2dDescriptor->m_DilationY), + static_cast<int>(conv2dDescriptor->m_DilationX)}; + TosaConvAttribute attribute(pad, dilation, stride, 0, 0, ArmNNToDType(inputs[0]->GetDataType())); + + auto* op = new TosaSerializationOperator(Op_CONV2D, + Attribute_ConvAttribute, + &attribute, + inputNames, + {outputName}); + operators.push_back(op); + + // operatorInputNames/operatorOutputNames ends up being the same as + // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings + return new TosaSerializationBasicBlock(blockName, // name + operators, // operators + tensors, // tensors + inputNames, // inputs + {outputName}); // outputs +}
\ No newline at end of file |