介绍
以ChatGLM-6B ptuning提供的微调代码来进行测试,整体代码在此。
训练和推理
训练就直接使用官方代码啦,推理也是滴,整体流程跑通都很顺畅,整体是采用quantization_bit=4
,所以单卡(5~6G显存)就能跑的起来。
记录几个有意思的点。
1. p-tuning
这个是众多Parameter Efficient fine-tune实现方式之一,其发展历程简单理解有两个阶段,一是人工构造template,二是机器自己学习一个template。
比如一开始做分类,例如“这个沙发怎么样”,那就在这句话前面(当然也可以放到后面)加上一个template,比如情感分析,这个沙发怎么样
,你觉得这句话是正向还是负向:这个沙发怎么样
,那训练时只对这个template进行微调,因为微调seq_len很少,所以速度杠杠滴。不过另外还有一个比较重要的点,贴和预训练模型任务。比如bert采用了mask方式来做预训练,但是你这里明明后面接个二分类,咋说也说不通啊,那为了贴和预训练任务,构造也可以这样:情感分析,这个沙发怎么样<mask>
,那由bert来预测<mask>
位置的值,比如“好”或者“坏”,或者设置一堆和“好”或者“坏”同义的词(amaze、bad)。但是这个呢,又不能解决通用,比如NER任务,“张三和李四谁更漂亮?”,那总不能先知道几个<mask>
吧,以及bert的<mask>
是字粒度的。
emmmm,扯远了,总结来说第一个阶段的peft可理解为人工构造一个template,但是呢,它是显性的,谁知道哪个template会更好。所以咱也不猜了,让模型自己去学去吧。
所以这里引入了第二个阶段:模型自己来学习合适的template。
p-tuning v2采用引入一个pre_seq_len,也就是PrefixEncoder,比如2, 8, 16(只要不超长都可以),那只对这一部分进行微调,bert本身不参与微调哦,从而达成了不自己抓脑袋想一个有效的template,从而也完成了一个通用的目的。
关于p-tuning v2实现,可以参考这里。
2. 速度
这个真是牙痒痒,明明已经使用p-tuning了,明明也量化到4bit了,明明还使用了GPU,还这么慢,不得提前吐槽一下。。。
关于速度慢,一个点是更长的上下文计算attention不可能不慢,新的技术flash-attention(torch2已经原生支持了哦,现在很多大模型都在torch2上跑了哦)更为有效解决这个问题,不过这个不是在算法本身做了优化,所以跳过。
建议使用v2或v3, 如果非用这个,建议推理时采用stream_chat,或是采用Lora微调。
3. 效果
比如采用下面脚本看微调后的效果,会遇到几个比较值得注意的点。
1 | from transformers import set_seed, AutoConfig, AutoModel, AutoTokenizer |
1. 出现<UNK>
和重复
1 | 一件<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>,<UNK>, |
按理说这6B大模型不应该啊!!按理说即使不做超参调整或者说generate时做重复惩罚,也应该效果好是不是~~~
2. 灾难性遗忘
首先这是一个现象,其issue里也讨论了蛮多关于这个话题。有人说p-tuning不就干这个的嘛,你推理时都加了p-tuning这部分参数,那肯定的啊。还有人说Lora虽然也有这个现象,但是比p-tuning要好的多。反正婆说婆有理。
官方给的improve,比如在官方示例前面添加描述性文本”请根据以下标签为商品编写一段广告\n“,最终训练数据类似下面这样:
1 | 请根据以下标签为商品编写一段广告\n类型#裤*版型#显瘦*颜色#黑色*风格#简约*裤长#九分裤 |
但是我训练完还是会这样。
也有人说把学习率调的更低一些,还有说官方给了10几w的训练样本,只用1~2k试试。
这个本身还是有方法可以解决的,比如base大模型不动,可以在上面添加很多的prefx_encoder嘛~~~
总结
多来点A100~