Thanks for your reply. I’m checking histogram observer recently. But I wonder, is the norm computation correct? Why there are 3 norms computed ?



 jerryzh168:

We do not have per_tensor_symmetric tensor in the backend actually since per_tensor_symmetric can be represented by per_tensor_affine tensor, e.g. a torch.per_tensor_symmetric, torch.qint8 tensor with a scale would be the same as a torch.per_tensor_symmetric, torch.qint8 with the same scale and a zero_point of 0. You can use per_tensor_symmetric in observers though.


def _compute_quantization_error(self, next_start_bin: int, next_end_bin: int):
    r"""
    Compute the quantization error if we use start_bin to end_bin as the
    min and max to do the quantization.
    """
    # print('at _compute_quantization_error, next_start, next_end', next_start_bin, next_end_bin)

    bin_width = (self.max_val.item() - self.min_val.item()) / self.bins

    # compute new bin_width
    dst_bin_width = bin_width * (next_end_bin - next_start_bin + 1) / self.dst_nbins      # divided by 256, quantized range is [-128, 127]
    if dst_bin_width == 0.0:
        return 0.0

    src_bin = torch.arange(self.bins).to(self.device)
    # distances from the beginning of first dst_bin to the beginning and
    # end of src_bin
    src_bin_begin = (src_bin - next_start_bin) * bin_width
    src_bin_end = src_bin_begin + bin_width

    # which dst_bins the beginning and end of src_bin belong to?
    dst_bin_of_begin = torch.clamp(src_bin_begin // dst_bin_width, 0, self.dst_nbins - 1)
    dst_bin_of_begin_center = (dst_bin_of_begin + 0.5) * dst_bin_width

    dst_bin_of_end = torch.clamp(src_bin_end // dst_bin_width, 0, self.dst_nbins - 1)
    dst_bin_of_end_center = (dst_bin_of_end + 0.5) * dst_bin_width

    density = self.histogram / bin_width

    norm = torch.zeros(self.bins)

    delta_begin = src_bin_begin - dst_bin_of_begin_center
    delta_end = dst_bin_width / 2
    # print('type of delta_begin, delta_end', type(delta_begin), type(delta_end))

    delta_begin= delta_begin.to(self.device)

    ## compute norm from 3 parts: begin of each new bin, center of each new bin, end of each new bin
    norm += self._get_norm(delta_begin, torch.ones(self.bins) * delta_end, density)

    norm += (dst_bin_of_end - dst_bin_of_begin - 1) * self._get_norm(
        torch.tensor(-dst_bin_width / 2), torch.tensor(dst_bin_width / 2), density
    )

    dst_bin_of_end_center = (
        dst_bin_of_end * dst_bin_width + dst_bin_width / 2
    )

    delta_begin = -dst_bin_width / 2
    delta_end = src_bin_end - dst_bin_of_end_center
    norm += self._get_norm(torch.tensor(delta_begin), delta_end, density)

    return norm.sum().item()