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重命名即可。
代码解读
- 加载模型
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.dmax−self.dmin没有严格求
m
i
n
min
min和
m
a
x
max
max操作,处理的对象是0-1的浮点数,因此
m
a
x
−
m
i
n
=
1
max-min= 1
max−min=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.qmax−self.qmin表示无符号数,所以为
2
8
−
1
{2^8-1}
28−1。
目前的疑惑点
output = self.round(output / scale)* scale # 量化/反量化
以上为QuantConv2d的quant_input,正常代码为self.round(output / scale) ,公式中为啥最后* scale ,输入的仍然是浮点数,并没有起到量化效果。
输入input
quant_input