Also, I did look into the code. I found the qat conv module calling fake quant before doing convolution.

  

      github.com
  

  
    pytorch/pytorch/blob/master/torch/nn/qat/modules/conv.py#L36 3



      
      
              factory_kwargs = {'device': device, 'dtype': dtype}
              super().__init__(in_channels, out_channels, kernel_size,
                               stride=stride, padding=padding, dilation=dilation,
                               groups=groups, bias=bias, padding_mode=padding_mode,
                               **factory_kwargs)
              assert qconfig, 'qconfig must be provided for QAT module'
              self.qconfig = qconfig
              self.weight_fake_quant = qconfig.weight(factory_kwargs=factory_kwargs)
          
          
def forward(self, input):
              return self._conv_forward(input, self.weight_fake_quant(self.weight), self.bias)
          
          
@classmethod
          def from_float(cls, mod):
              r"""Create a qat module from a float module or qparams_dict
          
          
        Args: `mod` a float module, either produced by torch.quantization utilities
                  or directly from user
              """
              assert type(mod) == cls._FLOAT_MODULE, 'qat.' + cls.__name__ + '.from_float only works for ' + \
                  cls._FLOAT_MODULE.__name__
      
    
  


  

  
    
    
  

  



  

      github.com
  

  
    pytorch/pytorch/blob/master/torch/quantization/fake_quantize.py#L141 1



      
      
                  _scale, _zero_point = self.calculate_qparams()
                  _scale, _zero_point = _scale.to(self.scale.device), _zero_point.to(self.zero_point.device)
                  if self.scale.shape != _scale.shape:
                      self.scale.resize_(_scale.shape)
                      self.zero_point.resize_(_zero_point.shape)
                  self.scale.copy_(_scale)
                  self.zero_point.copy_(_zero_point)
          
          
    if self.fake_quant_enabled[0] == 1:
                  if self.is_per_channel:
                      X = torch.fake_quantize_per_channel_affine(
                          X, self.scale, self.zero_point,
                          self.ch_axis, self.quant_min, self.quant_max)
                  else:
                      X = torch.fake_quantize_per_tensor_affine(
                          X, float(self.scale), int(self.zero_point),
                          self.quant_min, self.quant_max)
              return X
          
          
@torch.jit.export
          def extra_repr(self):
      
    
  


  

  
    
    
  

  


And, the fake quant calls a fake quantize affine function, for example the fake_quantize_per_tensor_affine function in pytorch/torch/onnx/symbolic_opset10.py
I print the output of self.weight_fake_quant(self.weight) and see all quanted and requanted floating point numbers. My question is that the convolution seems using the floating point r instead of the integers q from the formula in the QAT’s paper r = S*(q - Z)?