ArmNN
 25.11
Loading...
Searching...
No Matches
ReluOperator.cpp
Go to the documentation of this file.
1//
2// Copyright © 2024 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5//
6// Copyright © 2020 The TensorFlow Authors. All Rights Reserved.
7// SPDX-License-Identifier: Apache-2.0
8//
9
10#include "LeakyReluOperator.hpp"
12
14
15// This function is paraphrased from:
16// tensorflow/compiler/mlir/tosa/transforms/legalize_tfl.cc from function ConvertTFLReluOp
17TosaSerializationBasicBlock* ConvertReluToTosaOperator(const Layer* layer,
18 const std::vector<const TensorInfo*>& inputs,
19 const std::vector<const TensorInfo*>& outputs,
20 const ActivationDescriptor* desc)
21{
22 if (inputs.size() != 1)
23 {
24 throw armnn::Exception("ConvertReluToTosaOperator: 1 input tensors required.");
25 }
26
27 if (outputs.size() != 1)
28 {
29 throw armnn::Exception("ConvertReluToTosaOperator: 1 output tensor required.");
30 }
31
32 std::string inputName = std::string("input_");
33 std::string outputName = std::string("output0_");
34 std::string blockName = std::string("Op_RELU_block_") + GetUniqueTosaMappingID();
35
36 // If a layer is present then the block will be used for execution, so input and output names need to be determined
37 // using the previous and following layers so the graph is connected correctly. For validation this doesn't matter.
38 if (layer != nullptr)
39 {
40 inputName = GenerateUniqueInputName(layer->GetInputSlot(0));
41 outputName = GenerateUniqueOutputName(*layer);
42 }
43
44 std::vector<TosaSerializationTensor*> tensors;
45 std::vector<TosaSerializationOperator*> operators;
46
47 // Only add input tensors if connected layer is an input layer.
48 // As intermediate or constant tensors will be created separately.
49 // There also can't be duplicate tensor.
50 std::vector<int32_t> inputShape0 = GetTosaTensorShape(inputs[0]->GetShape());
51 DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType());
52 if(inputName.find("input_") != std::string::npos)
53 {
54 tensors.push_back(new TosaSerializationTensor(inputName, inputShape0, inputDType0, {}));
55 }
56
57 std::vector<int32_t> outputShape0 = GetTosaTensorShape(outputs[0]->GetShape());
58 DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType());
59 tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
60
61 int32_t clamp_min = 0;
62 int32_t clamp_max = 0;
63 float float_max = 0.0f;
64 switch (desc->m_Function)
65 {
66 case ActivationFunction::ReLu:
67 {
68 clamp_max = std::numeric_limits<int32_t>::max();
69 float_max = std::numeric_limits<float>::max();
70 break;
71 }
72 case ActivationFunction::BoundedReLu:
73 {
74 clamp_max = static_cast<int32_t>(desc->m_A);
75 float_max = desc->m_A;
76 break;
77 }
78 case ActivationFunction::LeakyReLu:
79 {
80 throw Exception("LeakyRelu TOSA mappings are performed in ConvertLeakyReluToTosaOperator().");
81 }
82 default:
83 {
84 throw Exception("Activation function is not supported in ConvertReluToTosaOperator().");
85 }
86 }
87
88 std::string clampInputNameStr = inputName;
89 if (inputDType0 == tosa::DType::DType_INT8 || inputDType0 == tosa::DType::DType_INT16)
90 {
91 std::string outputNameRescale = std::string("layer_intermediate0_") + GetUniqueTosaMappingID();
92 clampInputNameStr = outputNameRescale;
93
94 double scale = inputs[0]->GetQuantizationScale() / outputs[0]->GetQuantizationScale();
95 int32_t input_zp = inputs[0]->GetQuantizationOffset();
96 int32_t output_zp = outputs[0]->GetQuantizationOffset();
97
98 clamp_min = output_zp;
99
100 if (desc->m_Function == ActivationFunction::BoundedReLu)
101 {
102 clamp_max = static_cast<int32_t>(std::round(desc->m_A / outputs[0]->GetQuantizationScale())) + output_zp;
103 }
104
105 if (inputDType0 == tosa::DType::DType_INT8)
106 {
107 clamp_min =
108 clamp_min < std::numeric_limits<int8_t>::min() ? std::numeric_limits<int8_t>::min() : clamp_min;
109 clamp_max =
110 clamp_max > std::numeric_limits<int8_t>::max() ? std::numeric_limits<int8_t>::max() : clamp_max;
111 }
112 else
113 {
114 clamp_min =
115 clamp_min < std::numeric_limits<int16_t>::min() ? std::numeric_limits<int16_t>::min() : clamp_min;
116 clamp_max =
117 clamp_max > std::numeric_limits<int16_t>::max() ? std::numeric_limits<int16_t>::max() : clamp_max;
118 }
119
120 TosaSerializationOperator* rescaleOp = nullptr;
122 outputNameRescale,
123 scale,
124 input_zp,
125 output_zp,
126 false, //input unsigned
127 false, //output unsigned
128 false,
129 true,
130 &rescaleOp);
131 operators.push_back(rescaleOp);
132 tensors.push_back(new TosaSerializationTensor(outputNameRescale,
133 inputShape0,
134 inputDType0,
135 {}));
136 }
137 TosaClampAttribute attribute(clamp_min, clamp_max, 0, float_max);
138 auto* clamp_op = new TosaSerializationOperator(Op_CLAMP,
139 Attribute_ClampAttribute,
140 &attribute,
141 {clampInputNameStr},
142 {outputName});
143 operators.push_back(clamp_op);
144
145 // operatorInputNames/operatorOutputNames ends up being the same as
146 // blockInputNames/blockOutputNames for one-to-one ArmNN to Tosa mappings
147 return new TosaSerializationBasicBlock(blockName, // name
148 mainName, // region name
149 operators, // operators
150 tensors, // tensors
151 {inputName}, // inputs
152 {outputName}); // outputs
153}
TosaSerializationBasicBlock * ConvertReluToTosaOperator(const Layer *layer, const std::vector< const TensorInfo * > &inputs, const std::vector< const TensorInfo * > &outputs, const ActivationDescriptor *desc)
std::string GenerateUniqueOutputName(const Layer &layer, uint32_t layerSlot=0)
const std::string mainName
DType ArmNNToDType(const DataType &type)
std::string GenerateUniqueInputName(const armnn::InputSlot &slot)
std::string GetUniqueTosaMappingID()
std::vector< int32_t > GetTosaTensorShape(const TensorShape &shape)
void CreateRescaleTosaOperator(const std::string &inputName, const std::string &outputName, double scale, int32_t input_zp, int32_t output_zp, bool input_unsigned, bool output_unsigned, bool double_round, bool scale32, TosaSerializationOperator **op)
Creates a Tosa rescale operator.
Base class for all ArmNN exceptions so that users can filter to just those.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
Definition Layer.hpp:337
An ActivationDescriptor for the ActivationLayer.
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH,...
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu,...