mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-29 20:14:01 +00:00
Fix output range for int8_t QuantizeLinear op (#3445)
This commit is contained in:
parent
aabf47b107
commit
de60a14c16
4 changed files with 83 additions and 94 deletions
|
|
@ -420,24 +420,15 @@ MlasNchwcUpsample(
|
|||
// Linear quantization routines.
|
||||
//
|
||||
|
||||
template<typename OutputType>
|
||||
void
|
||||
MLASCALL
|
||||
MlasQuantizeLinear(
|
||||
const float* Input,
|
||||
uint8_t* Output,
|
||||
OutputType* Output,
|
||||
size_t N,
|
||||
float Scale,
|
||||
uint8_t ZeroPoint
|
||||
);
|
||||
|
||||
void
|
||||
MLASCALL
|
||||
MlasQuantizeLinear(
|
||||
const float* Input,
|
||||
int8_t* Output,
|
||||
size_t N,
|
||||
float Scale,
|
||||
int8_t ZeroPoint
|
||||
OutputType ZeroPoint
|
||||
);
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -130,17 +130,44 @@ MlasQuantizeLinearPackBytes<int8_t>(
|
|||
|
||||
#endif
|
||||
|
||||
template<typename OutputType, int32_t MinimumValue, int32_t MaximumValue>
|
||||
MLAS_FORCEINLINE
|
||||
template<typename OutputType>
|
||||
void
|
||||
MlasQuantizeLinearKernel(
|
||||
MLASCALL
|
||||
MlasQuantizeLinear(
|
||||
const float* Input,
|
||||
OutputType* Output,
|
||||
size_t N,
|
||||
float Scale,
|
||||
int32_t ZeroPoint
|
||||
OutputType ZeroPoint
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine quantizes the input buffer using the supplied quantization
|
||||
parameters.
|
||||
|
||||
Arguments:
|
||||
|
||||
Input - Supplies the input buffer.
|
||||
|
||||
Output - Supplies the output buffer.
|
||||
|
||||
N - Supplies the number of elements to process.
|
||||
|
||||
Scale - Supplies the quantization scale.
|
||||
|
||||
ZeroPoint - Supplies the quantization zero point value.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
constexpr int32_t MinimumValue = std::numeric_limits<OutputType>::min();
|
||||
constexpr int32_t MaximumValue = std::numeric_limits<OutputType>::max();
|
||||
|
||||
auto ScaleVector = MlasBroadcastFloat32x4(Scale);
|
||||
auto MinimumValueVector = MlasBroadcastFloat32x4(float(MinimumValue - ZeroPoint));
|
||||
auto MaximumValueVector = MlasBroadcastFloat32x4(float(MaximumValue - ZeroPoint));
|
||||
|
|
@ -189,17 +216,44 @@ MlasQuantizeLinearKernel(
|
|||
// QuantizeLinear implementation using the C++ runtime.
|
||||
//
|
||||
|
||||
template<typename OutputType, int32_t MinimumValue, int32_t MaximumValue>
|
||||
MLAS_FORCEINLINE
|
||||
template<typename OutputType>
|
||||
void
|
||||
MlasQuantizeLinearKernel(
|
||||
MLASCALL
|
||||
MlasQuantizeLinear(
|
||||
const float* Input,
|
||||
OutputType* Output,
|
||||
size_t N,
|
||||
float Scale,
|
||||
int32_t ZeroPoint
|
||||
OutputType ZeroPoint
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine quantizes the input buffer using the supplied quantization
|
||||
parameters.
|
||||
|
||||
Arguments:
|
||||
|
||||
Input - Supplies the input buffer.
|
||||
|
||||
Output - Supplies the output buffer.
|
||||
|
||||
N - Supplies the number of elements to process.
|
||||
|
||||
Scale - Supplies the quantization scale.
|
||||
|
||||
ZeroPoint - Supplies the quantization zero point value.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
constexpr int32_t MinimumValue = std::numeric_limits<OutputType>::min();
|
||||
constexpr int32_t MaximumValue = std::numeric_limits<OutputType>::max();
|
||||
|
||||
for (size_t n = 0; n < N; n++) {
|
||||
|
||||
float FloatValue = std::nearbyintf(Input[n] / Scale) + float(ZeroPoint);
|
||||
|
|
@ -211,79 +265,27 @@ MlasQuantizeLinearKernel(
|
|||
|
||||
#endif
|
||||
|
||||
template
|
||||
void
|
||||
MLASCALL
|
||||
MlasQuantizeLinear(
|
||||
const float* Input,
|
||||
uint8_t* Output,
|
||||
size_t N,
|
||||
float Scale,
|
||||
uint8_t ZeroPoint
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine quantizes the input buffer using the supplied quantization
|
||||
parameters.
|
||||
|
||||
Arguments:
|
||||
|
||||
Input - Supplies the input buffer.
|
||||
|
||||
Output - Supplies the output buffer.
|
||||
|
||||
N - Supplies the number of elements to process.
|
||||
|
||||
Scale - Supplies the quantization scale.
|
||||
|
||||
ZeroPoint - Supplies the quantization zero point value.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
return MlasQuantizeLinearKernel<uint8_t, 0, 255>(Input, Output, N, Scale, ZeroPoint);
|
||||
}
|
||||
|
||||
void
|
||||
MLASCALL
|
||||
MlasQuantizeLinear(
|
||||
MlasQuantizeLinear<int8_t>(
|
||||
const float* Input,
|
||||
int8_t* Output,
|
||||
size_t N,
|
||||
float Scale,
|
||||
int8_t ZeroPoint
|
||||
)
|
||||
/*++
|
||||
);
|
||||
|
||||
Routine Description:
|
||||
|
||||
This routine quantizes the input buffer using the supplied quantization
|
||||
parameters.
|
||||
|
||||
Arguments:
|
||||
|
||||
Input - Supplies the input buffer.
|
||||
|
||||
Output - Supplies the output buffer.
|
||||
|
||||
N - Supplies the number of elements to process.
|
||||
|
||||
Scale - Supplies the quantization scale.
|
||||
|
||||
ZeroPoint - Supplies the quantization zero point value.
|
||||
|
||||
Return Value:
|
||||
|
||||
None.
|
||||
|
||||
--*/
|
||||
{
|
||||
return MlasQuantizeLinearKernel<int8_t, -127, 127>(Input, Output, N, Scale, ZeroPoint);
|
||||
}
|
||||
template
|
||||
void
|
||||
MLASCALL
|
||||
MlasQuantizeLinear<uint8_t>(
|
||||
const float* Input,
|
||||
uint8_t* Output,
|
||||
size_t N,
|
||||
float Scale,
|
||||
uint8_t ZeroPoint
|
||||
);
|
||||
|
||||
#if defined(MLAS_SSE2_INTRINSICS)
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ __global__ void QuantizeLinearKernel(const float* input, int8_t* output, const f
|
|||
for (int i = 0; i < NumElementsPerThread; i++) {
|
||||
if (id < N) {
|
||||
int value = __float2int_rn(input[id] / (*scale)) + *zero_point;
|
||||
output[id] = static_cast<int8_t>(max(-127, min(127, value)));
|
||||
output[id] = static_cast<int8_t>(max(-128, min(127, value)));
|
||||
id += NumThreadsPerBlock;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,10 +75,8 @@ TEST(QuantizeLinearOpTest, QuantizeLinear_int8_NegativeZeroPoint) {
|
|||
test.AddInput<float>("x", dims, {0, 2, 3, 5, 6, -2, -5, -6});
|
||||
test.AddInput<float>("y_scale", {}, {.039215686f});
|
||||
test.AddInput<int8_t>("y_zero_point", {}, {-23});
|
||||
test.AddOutput<int8_t>("y", dims, {-23, 28, 53, 104, 127, -74, -127, -127});
|
||||
// TODO: nGraph returns a range of [-128,127] but the default CPU provider
|
||||
// returns a range of [-127,127]. Resolve this difference in behavior later.
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider});
|
||||
test.AddOutput<int8_t>("y", dims, {-23, 28, 53, 104, 127, -74, -128, -128});
|
||||
test.Run();
|
||||
}
|
||||
|
||||
// quantize with scalar zero point and scale
|
||||
|
|
@ -88,10 +86,8 @@ TEST(QuantizeLinearOpTest, QuantizeLinear_int8_PositiveZeroPoint) {
|
|||
test.AddInput<float>("x", dims, {0, 2, 3, 5, 6, -2, -5, -6});
|
||||
test.AddInput<float>("y_scale", {}, {.039215686f});
|
||||
test.AddInput<int8_t>("y_zero_point", {}, {23});
|
||||
test.AddOutput<int8_t>("y", dims, {23, 74, 99, 127, 127, -28, -104, -127});
|
||||
// TODO: nGraph returns a range of [-128,127] but the default CPU provider
|
||||
// returns a range of [-127,127]. Resolve this difference in behavior later.
|
||||
test.Run(OpTester::ExpectResult::kExpectSuccess, "", {kNGraphExecutionProvider});
|
||||
test.AddOutput<int8_t>("y", dims, {23, 74, 99, 127, 127, -28, -104, -128});
|
||||
test.Run();
|
||||
}
|
||||
|
||||
// quantize with 2D data
|
||||
|
|
|
|||
Loading…
Reference in a new issue