set zero point to 0 if all value are 0.0 (#12470)

* set zero point to 0 if all value are 0.0

* fix bug: lower version of numpy.finfo doesn't have smallest_subnormal

* check scale to make sure it is not subnormal
This commit is contained in:
Yufeng Li 2022-08-07 21:34:58 -07:00 committed by GitHub
parent ddea1e48df
commit bdd6b00c9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 4 deletions

View file

@ -119,8 +119,7 @@ def quantize_nparray(qType, arr, scale, zero_point, low=None, high=None):
def compute_scale_zp(rmin, rmax, qmin, qmax, symmetric=False):
"""
Calculate the scale s and zero point z for the quantization relation
"""Calculate the scale s and zero point z for the quantization relation
r = s(q-z), where r are the original values and q are the corresponding
quantized values.
@ -138,6 +137,9 @@ def compute_scale_zp(rmin, rmax, qmin, qmax, symmetric=False):
"""
if qmin > 0 or qmax < 0:
raise ValueError(f"qmin and qmax must meet requirement: qmin <= 0 <= qmax while qmin:{qmin}, qmmax:{qmax}")
# Adjust rmin and rmax such that 0 is included in the range. This is
# required to make sure zero can be represented by the quantization data
# type (i.e. to make sure qmin <= zero_point <= qmax)
@ -149,8 +151,12 @@ def compute_scale_zp(rmin, rmax, qmin, qmax, symmetric=False):
rmin = -absmax
rmax = +absmax
scale = (rmax - rmin) / float(qmax - qmin) if rmax != rmin else 1.0
zero_point = round(qmin - rmin / scale)
scale = (rmax - rmin) / float(qmax - qmin)
if scale < numpy.finfo(numpy.float32).tiny:
scale = 1.0
zero_point = 0
else:
zero_point = round(qmin - rmin / scale)
return [zero_point, scale]

View file

@ -0,0 +1,35 @@
#!/usr/bin/env python
# coding: utf-8
# -------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for
# license information.
# --------------------------------------------------------------------------
import unittest
import numpy
from onnxruntime.quantization.quant_utils import compute_scale_zp
class TestQuantUtil(unittest.TestCase):
def test_compute_scale_zp(self):
self.assertEqual(compute_scale_zp(0.0, 0.0, -127, 127, symmetric=True), [0, 1.0])
self.assertEqual(compute_scale_zp(1.0, -1.0, -127, 127, symmetric=True), [0, 1.0])
self.assertEqual(compute_scale_zp(0.0, 0.0, 0, 255, symmetric=True), [0, 1.0])
self.assertEqual(compute_scale_zp(1.0, -1.0, 0, 255, symmetric=True), [0, 1.0])
self.assertEqual(compute_scale_zp(-1.0, 2.0, -127, 127, symmetric=True), [0, 2.0 / 127])
self.assertEqual(compute_scale_zp(-1.0, 2.0, -127, 127, symmetric=False), [-42, 3.0 / 254])
self.assertEqual(compute_scale_zp(-1.0, 2.0, 0, 255, symmetric=True), [128, 4.0 / 255])
self.assertEqual(compute_scale_zp(-1.0, 2.0, 0, 255, symmetric=False), [85, 3.0 / 255])
tiny_float = numpy.float32(numpy.finfo(numpy.float32).tiny * 0.1)
self.assertEqual(compute_scale_zp(-tiny_float, tiny_float, 0, 255, symmetric=True), [0, 1.0])
self.assertEqual(compute_scale_zp(-tiny_float, 0.0, 0, 255, symmetric=False), [0, 1.0])
if __name__ == "__main__":
unittest.main()