LLM Quantizaiton 101
2023/11/7
一代人有一代人的量化要看(大嘘)
- gen_act_stat.py
- 这里的trainloader是一个长度为nsamples(1024)的list,其中每个元素是一个长度为2的tuple,每个tuple元素都是个长度为(1, 2048)的tensor;
[ ] 在写hook的时候只对Linear层的权重和output挂了hook,意思是只量化了linear层? - (和pytorch hook可能有关的性质)在forward hook的scope下,有m, x, y三个传入参数,分别是当前的module,当前module的输入,当前module的输出:
- 例如,可以写一个hook函数:
def stat_input_hook(m, x, y, name): if isinstance(x, tuple): x = x[0] stat_tensor(name, x) stat_weight(name, m.weight)入参里的m, x, y似乎是固定的;在推理前注册这个hook:
for name, m in model.named_modules(): if isinstance(m, nn.Linear): hooks.append( m.register_forward_hook( functools.partial(stat_input_hook, name=name)) )在推理结束后再删除这个hook:
for h in hooks: h.remove()在hook里打断点观察,发现y就是m(x)。
- 例如,可以写一个hook函数:
- 这里是统计一个module 输入tensor和权重的最大最小值,并更新到一个dict里存下来。
- 一个很蠢但还是犯了的错误:在统计输入tensor的最大最小值的时候,是按照(-1, hidden_dim)展开后在dim=0处记录的最大最小值以及std(一个例子是,如果一个(bs, token, hidden_dim)是(16, 4, 8)的dummy输入,统计结果的尺寸是(1, 8)),看起来统计出来的结果是per-channel的,进一步加工可以得到per-tensor的; [ ] 一个没想清楚的问题是,在不动态量化的前提下per-token量化其实就是per-tensor吧,统计各个channel上历史最大最小值,还不是等于在整个tensor上去算最值?
- 出于上述原因,weight的统计方式和tensor的一样,都是在dim=0处统计,所得结果就是(1, w_out_dim)尺寸的,后面可以很自然地做成per-channel或者per-tensor量化;
- 一个很蠢但还是犯了的错误:在统计输入tensor的最大最小值的时候,是按照(-1, hidden_dim)展开后在dim=0处记录的最大最小值以及std(一个例子是,如果一个(bs, token, hidden_dim)是(16, 4, 8)的dummy输入,统计结果的尺寸是(1, 8)),看起来统计出来的结果是per-channel的,进一步加工可以得到per-tensor的; [ ] 一个没想清楚的问题是,在不动态量化的前提下per-token量化其实就是per-tensor吧,统计各个channel上历史最大最小值,还不是等于在整个tensor上去算最值?
- 这里的trainloader是一个长度为nsamples(1024)的list,其中每个元素是一个长度为2的tuple,每个tuple元素都是个长度为(1, 2048)的tensor;
- ./config/opt-1.3b_w4a4.yaml
- qkvfc_cluster是啥意思?(cluster?意思是分组大小吗?)
- a_q_method和w_q_method里的'mix'又是啥意思?
- a_q_mode的's_woz'是什么意思?
- main_opt_w4a4.py
- 算了一个std的kmeans(完全不懂这么分有什么意义)
- ./group_methods/kmeans.py
- max_std_kmeans
- 输入是一个(576, 2048)的tensor(576=(3+3)*96, 2048是hidden_dim);
- 输出是一个(8, 576)的centroid和(1, 2048)的label,看起来是在每个2048的维度做了8个聚类中心的聚类,看描述可能只有里面的std有意义;(但是为什么要这么聚类呢?)
- max_std_kmeans
- ./group_methods/kmeans.py
- 做了一个smooth_lm:
预计是把scale吸收到LN里;- 订正,是smoothquant的w/a smooth;
- ./quantize/smooth.py
[ ] smooth的scale的具体计算方式没有记住,需要再ck;- 一个细节:在LN中做scale的系数中的weight部分是根据Q/K/V权重的最大值来确定的,这个目前还没想清楚(straight-forward来想好像也有点道理)
- 另一个细节,这个scale是在output_channel维度乘上去的;
- 还有一个没想清楚但是似乎很简单的问题,为什么output_scale是作用在fc1上而不是fc2上的?似乎和输入输出通道有关,回头再想吧。
- 还有还有一个没想清楚但是又似乎很简单的问题,为什么在LN和weight上做完scale后没有去修改act_stat和weight_stat?
- 算了一个std的kmeans(完全不懂这么分有什么意义)
TODO
[ ] 没看dataset里具体是怎么load数据的,看起来是直接采样了几个东西
[ ] 为什么在初始化tokenizer和model后要再搞个lm_model?这个是干什么的?