def __add__(self, other): if isinstance(other, QuantTensor) and self.is_not_none and other.is_not_none: self.check_scaling_factors_same(other) self.check_zero_points_same(other) output_value = self.value + other.value output_scale = (self.scale + other.scale) / 2 output_zero_point = (self.zero_point + other.zero_point) / 2 max_val = max_int(signed=self.signed, narrow_range=False, bit_width=self.bit_width) max_val += max_int(signed=other.signed, narrow_range=False, bit_width=other.bit_width) min_val = min_int(signed=self.signed, narrow_range=False, bit_width=self.bit_width) min_val += min_int(signed=other.signed, narrow_range=False, bit_width=other.bit_width) output_bit_width = ceil_ste(torch.log2(max_val - min_val)) output_signed = self.signed or other.signed output_training = self.training or other.training output = QuantTensor(value=output_value, scale=output_scale, zero_point=output_zero_point, bit_width=output_bit_width, signed=output_signed, training=output_training) elif isinstance(other, QuantTensor): output = QuantTensor(self.value + other.value) else: output = QuantTensor(self.value + other) return output
def test_IntQuant(x, narrow_range, signed, bit_width, scale, int_scale, float_to_int_impl, scale_multiplier): float_to_int_impl_mock = Mock() tensor_clamp_impl = TensorClamp() value = torch.tensor(x) bit_width = torch.tensor(bit_width, dtype=torch.float) scale = torch.tensor(scale) int_scale = torch.tensor(int_scale) tol = scale * scale_multiplier float_to_int_impl_mock.side_effect = float_to_int_impl() obj = IntQuant(narrow_range=narrow_range, signed=signed, float_to_int_impl=float_to_int_impl_mock, tensor_clamp_impl=tensor_clamp_impl) output = obj(scale, int_scale, bit_width, value) min_value = int(min_int(signed, narrow_range, bit_width)) max_value = int(max_int(signed, bit_width)) admissible_values = [x for x in range(min_value, max_value + 1)] value = (value / scale) * int_scale expected_output = tensor_clamp(value, min_val=min_int(signed, narrow_range, bit_width), max_val=max_int(signed, bit_width)) expected_output = (expected_output / int_scale) * scale int_output = obj.to_int(scale, int_scale, bit_width, value) # The assert is performed internally check_admissible_values check_admissible_values(int_output, admissible_values) assert torch.allclose(expected_output, output, RTOL, tol)
def min_int(self, bit_width): return min_int(self.signed, self.narrow_range, bit_width)
def forward(self, bit_width): if self.signed: return - min_int(self.signed, self.narrow_range, bit_width) else: return max_int(self.signed, bit_width)
def forward(self, bit_width): return -min_int(self.signed, self.narrow_range, bit_width)