Repository: pytorch
Issue: fx qat symmetric config zero_point not zero
Labels: oncall: quantization

### 🐛 Describe the bug

import torch
import torch.nn as nn
import torch.optim as optim
import torchvision.transforms as transforms
import torchvision.datasets as datasets
from torchvision.models import resnet18
from torch.ao.quantization import (
  get_default_qconfig_mapping,
  get_default_qat_qconfig_mapping,
  QConfigMapping,
)
from torch.ao.quantization.qconfig_mapping import _get_symmetric_qnnpack_qat_qconfig_mapping
import torch.ao.quantization.quantize_fx as quantize_fx

from torch.ao.quantization import QConfig, default_observer, default_per_channel_weight_observer
from torch.ao.quantization.observer import (
    MinMaxObserver,
    MovingAverageMinMaxObserver,
    MovingAveragePerChannelMinMaxObserver,
    _PartialWrapper,
    default_fixed_qparams_range_0to1_observer,
    default_fixed_qparams_range_neg1to1_observer,
    default_weight_observer,
    default_placeholder_observer,
        )
from torch.ao.quantization.fake_quantize import (
            FusedMovingAvgObsFakeQuantize,
            default_weight_fake_quant,
            FixedQParamsFakeQuantize,
        )
import onnx
import copy
from torch.ao.quantization.backend_config import (
            BackendConfig,
            BackendPatternConfig,
            DTypeConfig,
            ObservationType,
            get_qnnpack_backend_config,
        )
from torch.ao.quantization.qconfig import (
            default_reuse_input_qconfig,
            default_per_channel_symmetric_qnnpack_qat_qconfig,
            QConfigAny
        )

from typing import Any, Callable, Dict, Tuple, Union, List
from tqdm import tqdm


#build model, using ResNet18 on CIFAR10 Dataset
class CIFAR10ResNet(nn.Module):
    def __init__(self, num_classes=10):
        super(CIFAR10ResNet, self).__init__()

        resnet = resnet18(pretrained=True)

        resnet.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)

        resnet.fc = nn.Linear(resnet.fc.in_features, num_classes)
        self.resnet = resnet

    def forward(self, x):
        return self.resnet(x)


#build dataset
transform = transforms.Compose([
    transforms.Resize((32, 32)),
    transforms.ToTensor(),
    transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
])
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)


model = CIFAR10ResNet()


#build example input
dummy_input = torch.randn(1, 3, 32, 32)
for i, (image, _) in tqdm(enumerate(train_loader), total= 1):
    dummy_input = image.cuda()
    if i >= 1:
        break



model_to_quantize = copy.deepcopy(model)


#get backend, it is just the default backend config, I did not change anything
backend_config_s = get_qnnpack_backend_config()



#get qconfig_mapping, I wan to use _get_symmetric_qnnpack_qat_qconfig_mapping because I do not want quint8, I need int8
qconfig_mapping = _get_symmetric_qnnpack_qat_qconfig_mapping()



#model_prepared
model_prepared = quantize_fx.prepare_qat_fx(model_to_quantize, qconfig_mapping, dummy_input, backend_config = backend_config_s)


#training
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model_prepared = model_prepared.to(device)  
model_prepared.train()
optimizer = optim.SGD(model_prepared.parameters(), lr=0.01, momentum=0.9)
criterion = nn.CrossEntropyLoss()
epochs = 2
for epoch in range(epochs):
    for inputs, labels in train_loader:
        inputs = inputs.to(device)
        labels = labels.to(device)
        optimizer.zero_grad()
        outputs = model_prepared(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
    print(f'Epoch {epoch+1}, Loss: {loss.item()}')


#convert to onnx
device = torch.device( "cpu")
model_prepared = model_prepared.to(device)  
model_quantized = quantize_fx.convert_fx(model_prepared)
dummy_input = dummy_input.to(device)
model_quantized.eval()
torch.onnx.export(model_quantized, dummy_input, "quantized_model.onnx",
    verbose = False, 
    input_names = ['input'],
    output_names = ['output'],
    )

### Versions

absl-py                  2.1.0
albucore                 0.0.13
albumentations           1.3.1
annotated-types          0.7.0
certifi                  2024.7.4
charset-normalizer       3.3.2
coloredlogs              15.0.1
contourpy                1.1.1
cycler                   0.12.1
eval_type_backport       0.2.0
filelock                 3.13.1
flatbuffers              24.3.25
fonttools                4.53.1
fsspec                   2024.2.0
humanfriendly            10.0
idna                     3.7
imageio                  2.34.2
imgaug                   0.4.0
importlib_resources      6.4.0
Jinja2                   3.1.3
joblib                   1.4.2
jsonpatch                1.33
jsonpointer              3.0.0
kiwisolver               1.4.5
lazy_loader              0.4
Mako                     1.3.5
markdown-it-py           3.0.0
MarkupSafe               2.1.5
matplotlib               3.7.5
mdurl                    0.1.2
mpmath                   1.3.0
munch                    4.0.0
networkx                 3.0
numpy                    1.24.4
nvidia-cublas-cu11       11.11.3.6
nvidia-cuda-cupti-cu11   11.8.87
nvidia-cuda-nvrtc-cu11   11.8.89
nvidia-cuda-runtime-cu11 11.8.89
nvidia-cuda-runtime-cu12 12.6.37
nvidia-cudnn-cu11        9.1.0.70
nvidia-cufft-cu11        10.9.0.58
nvidia-curand-cu11       10.3.0.86
nvidia-cusolver-cu11     11.4.1.48
nvidia-cusparse-cu11     11.7.5.86
nvidia-nccl-cu11         2.20.5
nvidia-nvtx-cu11         11.8.86
nvidia-pyindex           1.0.9
onnx                     1.16.2
onnxruntime              1.18.1
onnxruntime-gpu          1.18.1
onnxsim                  0.4.36
opencv-python            4.10.0.84
opencv-python-headless   4.10.0.84
packaging                24.1
pillow                   10.2.0
pip                      24.0
platformdirs             4.2.2
pretrainedmodels         0.7.4
prettytable              3.11.0
protobuf                 5.27.3
pycuda                   2024.1.2
pydantic                 2.8.2
pydantic_core            2.20.1
Pygments                 2.18.0
pyparsing                3.1.2
python-dateutil          2.9.0.post0
pytools                  2024.1.13
pytorch-quantization     2.1.3
PyWavelets               1.4.1
PyYAML                   6.0.2
qudida                   0.0.4
requests                 2.32.3
rich                     13.7.1
scikit-image             0.21.0
scikit-learn             1.3.2
scipy                    1.10.1
setuptools               72.1.0
shapely                  2.0.5
six                      1.16.0
sphinx_glpi_theme        0.6
sympy                    1.12
tensorrt                 10.3.0
tensorrt-cu12            10.3.0
tensorrt-cu12-bindings   10.3.0
tensorrt-cu12-libs       10.3.0
threadpoolctl            3.5.0
tifffile                 2023.7.10
tomli                    2.0.1
torch                    2.4.0+cu118
torch2trt                0.5.0
torchaudio               2.4.0+cu118
torchnet                 0.0.4
torchvision              0.19.0+cu118
tornado                  6.4.1
tqdm                     4.66.5
triton                   3.0.0
typing_extensions        4.12.2
urllib3                  2.2.2
visdom                   0.2.4
wcwidth                  0.2.13
websocket-client         1.8.0
wheel                    0.43.0
zipp                     3.19.2

cc @jerryzh168 @jianyuh @raghuramank100 @jamesr66a @vkuzo @jgong5 @Xia-Weiwen @leslie-fang-intel @msaroufim