关于模型量化

量化的目的:是为了减少计算时间和计算能耗 。在一些场景下对能耗和时间的要求,要高于模型的指标,所以在这种情况下量化是一个必然的选择。

模型量化方法: 训练后量化(PTQ)和量化感知训练(QAT)。PTQ方法,是将已经训练好的模型进行量化,同时只需要很少的数据或者不需要数据,少部分需要手动调整的超参数以及不需要端到端训练。这使得PTQ成为一种工程实现简单并且不需要大量计算成本的量化方法。QAT,它依赖神经网络在训练过程中进行模拟量化。虽然QAT需要进行重新训练以及调整超参数,但是在低bit时却可以比PTQ获得更接近全精度的效果

量化方法:

对称量化

1. 量化卷积核权重:量化的目的是为了把原来的 float32 位的卷积操作,转换为 int8 的卷积操作,这样计算就变为原来的 1/4,但是访存并没有变少哈,因为我们是在 kernel 里面才把 float32 变为 int8 进行计算的

比如说 float32 位的变量 a=6.238561919405008,可以通过 scale=23.242536 映射到 int8 空间上到整数 a*scale=145

如上所示,这个 scale 是根据最大的权重绝对值 thresh 决定的,然后计算 127 与它的比值,便得到了 scale 值。

可以看到我们是按照通道对卷机层进行切片的。

def quantize_weight(self):
    """
    对该层的卷积核权重进行量化, 计算出 scale
    """
    weights = self.layer.weight.cpu().detach().numpy()      # 剥离每一层的卷积权重
    group_weights = np.array_split(weights, self.channels)  # 将卷积权重按通道划分

    for i, group_weight in enumerate(group_weights):        # 对每个通道的卷积权重进行遍历
        max_val = np.max(group_weight)
        min_val = np.min(group_weight)

        thresh  = max(abs(max_val), abs(min_val))           # 求出阈值 thresh 从而求出 scale
        if thresh < 0.0001:
            self.weight_scales[i] = 0.
        else:
            self.weight_scales[i] = 127 / thresh            # int8: -127 ~ 127

由于卷积运算是卷积核(weights)和数据流(blob)之间乘加操作,因此光对卷积核量化是不够的,还需要对数据流进行量化!

int8推理过程:

整个 INT8 推理过程可以简述为:输入流 x 在喂入每层卷积之前,需要先乘以 blob_scale 映射为 int8 类型数据,然后得到 int8 类型的卷积结果 x。由于卷积层的偏置 bias 没有被量化,它仍然是 float32 类型,因此我们需要将卷积结果 x 再映射回 float32,然后再与偏置 bias 相加。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值