Jermmy / pytorch-quantization-demo

A simple network quantization demo using pytorch from scratch.
Apache License 2.0
497 stars 96 forks source link

想请教一些问题 #12

Closed neesetifa closed 2 years ago

neesetifa commented 2 years ago

您好, 我有两个问题想请教一下: (模型和训练MNIST的代码直接使用, 没做改动)

  1. 做完QAT后获得的权重, 我发现在经过scale变换后, 仍然不是一个很贴近整数的浮点数, round()之后就会产生不小误差。 请问这是因为QAT算法无法实现的效果, 还是说无所谓能不能变成一个很贴近整数的浮点数?

    >>> new_weight.shape
    torch.Size([40, 1, 3, 3])
    >>> new_weight[0]
    tensor([[[ 0.6816, -0.6561, -0.1549],
         [ 0.5218, -1.5822,  0.5984],
         [-0.1848,  0.4262,  0.2918]]], device='cuda:0')
    >>> new_weight[0]/qat['qconv1.qw.scale']
    tensor([[[  54.2636,  -52.2335,  -12.3310],
         [  41.5433, -125.9577,   47.6389],
         [ -14.7157,   33.9326,   23.2337]]], device='cuda:0')
    >>> (new_weight[0]/qat['qconv1.qw.scale']).round()
    tensor([[[  54.,  -52.,  -12.],
         [  42., -126.,   48.],
         [ -15.,   34.,   23.]]], device='cuda:0')

    2.我在quantization_aware_training.py最后加了以下代码, 在做完QAT之后, 想比较模型“freeze前使用直接inference“以及”freeze后使用quantize_inference()“的结果

    # test_loader set batch_size = 1
    miss_cnt = 0
    result = torch.zeros(10).cuda()
    correct_freeze=0
    correct_before_freeze=0
    for i, (data, target) in enumerate(test_loader, 1):
        data, target = data.to(device), target.to(device)
        with torch.no_grad():
            output1 = model_freeze.quantize_inference(data)[0]
            output2 = model_before_freeze(data)[0]
        result+=(output1-output2).abs()
        pred1 = output1.argmax().item()
        pred2 = output2.argmax().item()
        miss_cnt += not(pred1==pred2)
        correct_freeze += pred1==target.item()
        correct_before_freeze += pred2==target.item()
    
    result=result/len(test_loader.dataset)
    print(f'qat model correct {correct_freeze}\nori model correct {correct_before_freeze}')
    print(f'qat miss ori {miss_cnt}')
    print(f'diff {result}')
    qat model correct 9881
    ori model correct 9880
    qat miss ori 7
    diff tensor([0.0587, 0.0569, 0.0789, 0.0846, 0.0658, 0.0600, 0.0645, 0.0644, 0.0987, 0.0617], device='cuda:0')

    我发现两者的output差距并不小, 请问这么比较有意义吗?或者说我是否应该期望量化后的模型和原始模型在最后数值的输出上也要很接近?

Jermmy commented 2 years ago

您好,您的邮件已收到,我会尽快查看。

Jermmy commented 2 years ago

@neesetifa 你好,

  1. 数值不接近整数并不能说明什么。因为训练的时候就已经加了round误差,在这个误差下,模型训练得到的权重是这样,说明在当前的任务难度下,目前weight的数值已经足够拟合数据集了。
  2. model_before_freeze是经过量化训练得到的吗?如果要比较freeze前的效果,那应该调用quantize_forward函数,因为此时模型是经过量化训练的,权重已经修改了,所以必须用伪量化的forward来跑。然后,正常来说,当然是量化后的精度和量化前越接近越好,但通常来说,量化都会伴随精度损失。你这个结果里面,只能对比分类准确率的差异,直接看模型输出的差异是没有意义的,因为量化后的模型,其实数值分布(domain)已经和原来的模型不一致了,加上训练的损失函数只是分类损失,并不会对模型输出的一致性进行约束,所以对比模型输出是没意义的。
neesetifa commented 2 years ago

了解。非常感谢如此详细的解答!