【量化学习3】Micronet代码学习

Micronet代码学习

浮点数和矩阵的量化已经学完,下面要考虑,在神经网络的操作:卷积、reRU、FC,量化究竟是如何执行的。
参考Micronet代码,我们来看看。
Micronet代码:https://github.com/666DZY666/micronet

调试代码

…\micronet\compression\quantization\wqaq\dorefa\main.py
PS:一开始遇到了各种问题,后来发现是程序中的test()方法会导致
Pycharm跑程序会自动进入测试模式,继而引发一系列错误。
修改方法:根据https://blog.csdn.net/qq_60874095/article/details/133743703改配置或者将test重命名即可。

代码解读

  1. 加载模型
model = nin.Net()

nin模型在项目models里
2. 模型量化具体步骤,主要调用quantize.py进行量化的各项操作。
1)quantize.prepare进行模型的预处理,如将Conv2d替换为QuantConv2d等。
2)替换后形成新模型quant_model。
3. 正常训练和测试模型。

train(epoch)
test()

模型替换

经过quantize.prepare,根据下图看看模型发生的什么变化?

在这里插入图片描述

Conv2d替换为QuantConv2d,其中权重进行了WeightQuantizer操作,
relu操作前,先执行了ActivationQuantizer操作。

    def forward(self, input):
        quant_input = self.activation_quantizer(input)#原值乘0.1,经历了量化反量化,0.四位有效数字
        if not self.quant_inference:
            quant_weight = self.weight_quantizer(self.weight)
        else:
            quant_weight = self.weight
        output = F.conv2d(
            quant_input,#将input和weight量化后再进行conv操作
            quant_weight,
            self.bias,
            self.stride,
            self.padding,
            self.dilation,
            self.groups,
        )
        return output

其本质就是将input和weight量化后再进行conv操作。

QuantLinear操作同上。

    def forward(self, input):
        quant_input = self.activation_quantizer(input)
        if not self.quant_inference:
            quant_weight = self.weight_quantizer(self.weight)
        else:
            quant_weight = self.weight
        output = F.conv_transpose2d(
            quant_input,#将input和weight量化后再进行conv操作
            quant_weight,
            self.bias,
            self.stride,
            self.padding,
            self.output_padding,
            self.groups,
            self.dilation,
        )
        return output

量化操作

# A(特征)量化
class ActivationQuantizer(nn.Module):
    def __init__(self, a_bits):
        super(ActivationQuantizer, self).__init__()
        self.a_bits = a_bits

    # 取整(ste)
    def round(self, input):
        output = Round.apply(input)
        return output

    # 量化/反量化
    def forward(self, input):
        if self.a_bits == 32:
            output = input
        elif self.a_bits == 1:
            print("!Binary quantization is not supported !")
            assert self.a_bits != 1
        else:
            output = torch.clamp(input * 0.1, 0, 1)  # 特征A截断前先进行缩放(* 0.1),以减小截断误差
            scale = 1 / float(2 ** self.a_bits - 1)  # scale
            output = self.round(output / scale) * scale  # 量化/反量化
        return output

之前在https://blog.csdn.net/Ashley_huo/article/details/135696842?spm=1001.2014.3001.5502里提到的均匀放射量化。
基本操作为:

self.scale = (self.d_max - self.d_min) / (self.q_max - self.q_min)

这里, s e l f . d m a x − s e l f . d m i n self.d_{max} - self.d_{min} self.dmaxself.dmin没有严格求 m i n min min m a x max max操作,处理的对象是0-1的浮点数,因此 m a x − m i n = 1 max-min= 1 maxmin=1
此外,由于abits为8, s e l f . q m a x − s e l f . q m i n self.q_{max} - self.q_{min} self.qmaxself.qmin表示无符号数,所以为 2 8 − 1 {2^8-1} 281

目前的疑惑点

output = self.round(output / scale)* scale # 量化/反量化
以上为QuantConv2d的quant_input,正常代码为self.round(output / scale) ,公式中为啥最后* scale ,输入的仍然是浮点数,并没有起到量化效果。
输入input
在这里插入图片描述

quant_input
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值