blob: 7e7631dcefbe80214329578689aa1e0a7d53679f [file] [log] [blame]
Cathal Corbettbd18eab2022-11-15 12:56:16 +00001//
2// Copyright © 2022 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5
6#include "Pooling2DOperator.hpp"
7
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +00008TosaSerializationBasicBlock* ConvertAvgPool2DIgnoreValueToTosaOperator(const Layer* layer,
9 const std::vector<const TensorInfo*>& inputs,
Cathal Corbettbd18eab2022-11-15 12:56:16 +000010 const std::vector<const TensorInfo*>& outputs,
Cathal Corbettbd18eab2022-11-15 12:56:16 +000011 const Pooling2dDescriptor* poolDescriptor)
12{
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +000013 std::string padInputName = std::string("input0_");
14 std::string padOutputName = std::string("intermediate0_") + GetUniqueTosaMappingID();
15 std::string poolOutputName = std::string("output0_");
16 std::string blockName = std::string("Op_AVG_POOL2D_block_") + GetUniqueTosaMappingID();
Cathal Corbettbd18eab2022-11-15 12:56:16 +000017
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +000018 // If a layer is present then the block will be used for execution, so input and output names need to be determined
19 // using the previous and following layers so the graph is connected correctly. For validation this doesn't matter.
20 if(layer != nullptr)
Cathal Corbettbd18eab2022-11-15 12:56:16 +000021 {
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +000022 // Get the layers connected to the input slots and determine unique layer names.
23 Layer& connectedInputLayer = layer->GetInputSlot(0).GetConnectedOutputSlot()->GetOwningLayer();
24 padInputName = GenerateUniqueName(connectedInputLayer, 0);
25
26 // Get the layer connected to the output slot and determine unique layer name.
27 Layer& connectedOutputLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer();
28 poolOutputName = GenerateUniqueName(connectedOutputLayer, 0);
Cathal Corbettbd18eab2022-11-15 12:56:16 +000029 }
30
31 std::vector<int> paddings;
32 if (poolDescriptor->m_DataLayout == DataLayout::NHWC)
33 {
34 paddings = {0,
35 0,
36 static_cast<int>(poolDescriptor->m_PadTop),
37 static_cast<int>(poolDescriptor->m_PadBottom),
38 static_cast<int>(poolDescriptor->m_PadLeft),
39 static_cast<int>(poolDescriptor->m_PadRight),
40 0,
41 0
42 };
43 }
44 else
45 {
46 paddings = {0,
47 0,
48 0,
49 0,
50 static_cast<int>(poolDescriptor->m_PadTop),
51 static_cast<int>(poolDescriptor->m_PadBottom),
52 static_cast<int>(poolDescriptor->m_PadLeft),
53 static_cast<int>(poolDescriptor->m_PadRight)
54 };
55 }
56
57 TosaPadAttribute padAttribute(paddings, 0, 0.0f);
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +000058 auto* opPad = new TosaSerializationOperator(Op_PAD,
59 Attribute_PadAttribute,
60 &padAttribute,
61 {padInputName},
62 {padOutputName});
Cathal Corbettbd18eab2022-11-15 12:56:16 +000063
64 std::vector<int> pad = {0, 0, 0, 0};
65 std::vector<int> kernel = {static_cast<int>(poolDescriptor->m_PoolHeight),
66 static_cast<int>(poolDescriptor->m_PoolWidth)};
67 std::vector<int> stride = {static_cast<int>(poolDescriptor->m_StrideY),
68 static_cast<int>(poolDescriptor->m_StrideX)};
69 TosaPoolAttribute poolAttribute(pad, kernel, stride, 0, 0, ArmNNToDType(inputs[0]->GetDataType()));
70
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +000071 auto* opPool = new TosaSerializationOperator(Op_AVG_POOL2D,
72 Attribute_PoolAttribute,
73 &poolAttribute,
74 {padOutputName},
75 {poolOutputName});
Cathal Corbettbd18eab2022-11-15 12:56:16 +000076
77 std::vector<int32_t> inputShape = GetTosaTensorShape(inputs[0]->GetShape());
78 DType inputDType = ArmNNToDType(inputs[0]->GetDataType());
79
80 std::vector<int32_t> outputShape = GetTosaTensorShape(outputs[0]->GetShape());
81 DType outputDType = ArmNNToDType(outputs[0]->GetDataType());
82
83 std::vector<int32_t> intermediateShape;
84 if (poolDescriptor->m_DataLayout == DataLayout::NHWC)
85 {
86 intermediateShape = {inputShape[0],
87 inputShape[1] + paddings[2] + paddings[3],
88 inputShape[2] + paddings[4] + paddings[5],
89 inputShape[3]};
90 }
91 else
92 {
93 intermediateShape = {inputShape[0],
94 inputShape[1],
95 inputShape[2] + paddings[4] + paddings[5],
96 inputShape[3] + paddings[6] + paddings[7]};
97 }
98
Matthew Sloyanc5fe6e72022-11-25 16:10:00 +000099 auto* inputTensor = new TosaSerializationTensor(padInputName, inputShape, inputDType, {});
100 auto* intermediateTensor = new TosaSerializationTensor(padOutputName, intermediateShape, inputDType, {});
101 auto* outputTensor = new TosaSerializationTensor(poolOutputName, outputShape, outputDType, {});
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000102
103 // operatorInputNames/operatorOutputNames ends up being the same as
Cathal Corbettb30e6552022-12-07 11:50:50 +0000104 // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings
Cathal Corbettbd18eab2022-11-15 12:56:16 +0000105 return new TosaSerializationBasicBlock(blockName, // name
106 {opPad, opPool}, // operators
107 {inputTensor, intermediateTensor, outputTensor}, // tensors
108 {padInputName}, // inputs
109 {poolOutputName}); // outputs
110}