12 #include <gemmlowp/fixedpoint.h>
16 static void quantizeMultiplier(
double doubleMultiplier, int32_t* quantizedMultiplier,
int* shift)
18 if (doubleMultiplier == 0.)
20 *quantizedMultiplier = 0;
25 const double q = std::frexp(doubleMultiplier, shift);
26 auto qFixed =
static_cast<int64_t
>(std::round(q * (1LL << 31)));
30 if (qFixed == (1LL << 31))
44 *quantizedMultiplier =
static_cast<int32_t
>(qFixed);
49 static int16_t saturatingDoublingHighMul(int16_t a, int16_t b)
51 bool overflow = (a == b && a == std::numeric_limits<int16_t>::min());
54 return std::numeric_limits<int16_t>::max();
59 int32_t ab32 = a32 * b32;
60 int16_t abX2High16 =
static_cast<int16_t
>((ab32) / (1 << 15));
67 static void downScaleInt32ToInt16Multiplier(int32_t multiplierInt32, int16_t* multiplierInt16)
71 static constexpr int32_t kRoundingOffset = 1 << 15;
72 if (multiplierInt32 >= std::numeric_limits<int32_t>::max() - kRoundingOffset)
74 *multiplierInt16 = std::numeric_limits<int16_t>::max();
78 const int32_t result = (multiplierInt32 + kRoundingOffset) >> 16;
83 *multiplierInt16 =
static_cast<int16_t
>(result);
95 const float hiresInputScale = (1.0f / 128.0f) * inputScale;
96 const float outputMultiplier = hiresInputScale / outputScale;
97 int outputMultiplierExponent;
98 int16_t outputMultiplierFixedpointInt16;
99 int32_t outputMultiplierFixedpointInt32;
101 quantizeMultiplier(outputMultiplier, &outputMultiplierFixedpointInt32, &outputMultiplierExponent);
102 downScaleInt32ToInt16Multiplier(outputMultiplierFixedpointInt32, &outputMultiplierFixedpointInt16);
106 const float reluishScale = 3.0f / 32768.0f;
107 const float reluishMultiplier = hiresInputScale / reluishScale;
108 int reluishMultiplierExponent;
109 int16_t reluishMultiplierFixedpointInt16;
110 int32_t reluishMultiplierFixedpointInt32;
112 quantizeMultiplier(reluishMultiplier, &reluishMultiplierFixedpointInt32, &reluishMultiplierExponent);
113 downScaleInt32ToInt16Multiplier(reluishMultiplierFixedpointInt32, &reluishMultiplierFixedpointInt16);
115 std::vector<int16_t> table;
117 for (int32_t i = -128; i < 128; i++)
119 const int16_t inputValue =
static_cast<int16_t
>(i - inputZp);
120 const int16_t inputValueHiresInputScale =
static_cast<int16_t
>(inputValue * (1 << 7));
122 int16_t reluishValue = inputValueHiresInputScale;
123 if (reluishMultiplierExponent > 0)
125 reluishValue = gemmlowp::ShiftLeft(reluishValue, reluishMultiplierExponent - 1);
128 reluishValue = gemmlowp::SaturatingRoundingDoublingHighMul(reluishValue, reluishMultiplierFixedpointInt16);
130 if (reluishMultiplierExponent > 0)
132 reluishValue = gemmlowp::ShiftLeft(reluishValue, 1);
134 else if (reluishMultiplierExponent < 0)
136 reluishValue = gemmlowp::RoundingDivideByPOT(reluishValue, -reluishMultiplierExponent);
139 reluishValue =
static_cast<int16_t
>((reluishValue + (1 << 15)) >> 1);
141 const int16_t inputValPreshiftOutputScale =
142 gemmlowp::SaturatingRoundingDoublingHighMul(inputValueHiresInputScale, outputMultiplierFixedpointInt16);
144 const int16_t preshiftOutputValue = saturatingDoublingHighMul(reluishValue, inputValPreshiftOutputScale);
146 int16_t outputValue = gemmlowp::RoundingDivideByPOT(preshiftOutputValue, -outputMultiplierExponent);
148 outputValue =
static_cast<int16_t
>(outputValue + outputZp);
149 outputValue = std::min<int16_t>(outputValue, std::numeric_limits<int8_t>::max());
150 outputValue = std::max<int16_t>(outputValue, std::numeric_limits<int8_t>::min());
152 table.push_back(outputValue);
161 const std::vector<const TensorInfo*>& inputs,
162 const std::vector<const TensorInfo*>& outputs,
165 if (inputs.size() != 1)
167 throw armnn::Exception(
"ConvertHardSwishToTosaOperator: 1 input tensors required.");
170 if (outputs.size() != 1)
172 throw armnn::Exception(
"ConvertHardSwishToTosaOperator: 1 output tensor required.");
175 if (desc->
m_Function != ActivationFunction::HardSwish)
177 throw armnn::Exception(
"ConvertHardSwishToTosaOperator ActivationDescriptor only supports function HardSwish.");
180 std::string inputName = std::string(
"input_");
181 std::string outputName = std::string(
"output0_");
186 if (layer !=
nullptr)
192 std::vector<TosaSerializationTensor*> tensors;
193 std::vector<TosaSerializationOperator*> operators;
195 DataType inputDType = inputs[0]->GetDataType();
197 bool isInt8 = (inputDType == DataType::QAsymmS8 || inputDType == DataType::QSymmS8);
200 float inputScale = inputs[0]->GetQuantizationScale();
201 float outputScale = outputs[0]->GetQuantizationScale();
202 int32_t inputZp = inputs[0]->GetQuantizationOffset();
203 int32_t outputZp = outputs[0]->GetQuantizationOffset();
205 TosaTableAttribute attribute(
207 operators.push_back(
new TosaSerializationOperator(tosa::Op_TABLE,
208 Attribute_TableAttribute,
215 throw Exception(
"ConvertHardSwishToTosaOperator() type currently unimplemented.");
221 std::vector<int32_t> inputShape0;
222 DType inputDType0 =
ArmNNToDType(inputs[0]->GetDataType());
223 if(inputName.find(
"input_") != std::string::npos)
226 tensors.push_back(
new TosaSerializationTensor(inputName, inputShape0, inputDType0, {}));
230 DType outputDType0 =
ArmNNToDType(outputs[0]->GetDataType());
231 tensors.push_back(
new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}));
235 return new TosaSerializationBasicBlock(blockName,
#define ARMNN_THROW_INVALIDARG_IF_FALSE(_cond)
std::vector< int16_t > getTosaConstHardSwish8bitTable(float inputScale, int32_t inputZp, float outputScale, int32_t outputZp)
TosaSerializationBasicBlock * ConvertHardSwishToTosaOperator(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::vector< int32_t > GetTosaTensorShape(const TensorShape &shape)
std::string GenerateUniqueInputName(const armnn::InputSlot &slot)
std::string GetUniqueTosaMappingID()
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.
An ActivationDescriptor for the ActivationLayer.
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu,...