本节,我们模拟下全连接层实现量化,原理上为了方便计算,全连接矩阵采用动态量化的方法,而输入由于不断在变化,我们采用静态量化的方法,直接给出代码:
import torch
import numpy as np
import math
#静态量化
def fix_quantize_tensor(array, highB, lowB, num_bits=8):rangeB = highB - lowBshiftDist = -(highB + lowB) / 2qmax = 2.**num_bits - 1.zero_point = shiftDist / rangeB * qmax;qmaxp = 2.**(num_bits - 1) - 1.qminp = -2.**(num_bits - 1)zero_point = math.floor(zero_point)scale = rangeB / qmaxq_x = array/scale + zero_pointq_x = q_x.round().int()q_x[q_x > qmaxp] = qmaxpq_x[q_x < qminp] = qminpreturn q_x, zero_point, scale
#动态量化
def quantize_tensor(array, num_bits=8):highB = array.max()lowB = array.min()rangeB = highB - lowBshiftDist = -(highB + lowB) / 2qmax = 2.**num_bits - 1.zero_point = shiftDist / rangeB * qmax;qmaxp = 2.**(num_bits - 1) - 1.qminp = -2.**(num_bits - 1)zero_point = zero_point.floor().int()scale = rangeB / qmaxq_x = array/scale + zero_pointq_x = q_x.round().int()q_x[q_x > qmaxp] = qmaxpq_x[q_x < qminp] = qminpreturn q_x, zero_point, scale
#输入信号
x1 = torch.randn(1, 10, dtype=torch.float32) * 0.1
#权重矩阵
W = torch.randn(10, 10, dtype=torch.float32) * 0.1
#偏置
mbias = torch.randn(1, 10, dtype=torch.float32) * 0.1print('************quantize value**************')
q2, z2, s2 = quantize_tensor(W)m_range = 0.5
print(x1)
#静态量化输入信号,且输入信号量化范围对称
q1, z1, s1 = fix_quantize_tensor(x1, m_range, -m_range)
print(q1, z1, s1)print(mbias)
#偏置的量化和输入信号要一致,这样可以减少运算复杂度
qb, zb, sb = fix_quantize_tensor(mbias, m_range, -m_range)
print(qb, zb, sb)print('************quantize matrix multiply*************')
########### s1(q1-z1)q2+qb #############
#通过*2^16+移位的方式来实现浮点乘运算
M0 = int(s2 * (2**16))
qresult = (torch.matmul(q1 - z1, q2) * M0) >> 16
qresult = qresult.round().int() + qb
print(qresult)
print('************quant result***********************')
print(qresult * s1)
print('************real result*************************')
print(torch.matmul(x1, W) + mbias)
结果:
************quantize value**************
tensor([[ 0.1819, 0.0145, -0.2078, -0.0485, -0.0212, -0.0677, -0.0572, 0.0349,0.1925, -0.0266]])
tensor([[ 46, 4, -53, -12, -5, -17, -15, 9, 49, -7]], dtype=torch.int32) 0 0.00392156862745098
tensor([[ 0.0032, 0.0095, -0.1825, -0.1033, -0.0582, -0.1757, -0.0893, 0.0119,0.0336, -0.0487]])
tensor([[ 1, 2, -47, -26, -15, -45, -23, 3, 9, -12]], dtype=torch.int32) 0 0.00392156862745098
************quantize matrix multiply*************
tensor([[ -1, -1, -44, -38, -15, -53, -31, 9, 4, -15]], dtype=torch.int32)
************quant result***********************
tensor([[-0.0039, -0.0039, -0.1725, -0.1490, -0.0588, -0.2078, -0.1216, 0.0353,0.0157, -0.0588]])
************real result*************************
tensor([[-0.0041, -0.0049, -0.1688, -0.1506, -0.0592, -0.2056, -0.1213, 0.0356,0.0133, -0.0617]])
注意结果是随机的,需要注意,我们对于输入信号和偏置的量化采用的是相同的量化参数,且zero_point为0,这是常用的一种方法,可以简化操作流程,得到的结果就是按照这个量化参数量化的结果(s1和z1),对于神经网络下一级可以继续按照这样的量化信号继续下一级运算,