大模型微调实践心得与认知深化

描述

以下内容均为个人经验(臆测),不具有指导意义-- 快乐子涵酱。

关于continue

1.pre-train大模型的知识来自于pt阶段,如果你想引入一些新的知识,那CPT是一个不错的选择。

2.但你首先要确保你有足够大量的数据集,至少有几B的token;

3.否则几十条数据的情况我更推荐模型编辑更建议全量微调。

4.不确定lora是不是一个好的选择,后面会展开讲。

5.通常CPT开始的阶段会出现一段时间的loss上升,随后慢慢收敛,所以学习率是一个很重要的参数,这很容易理解:如果lr过大,那loss值收敛会更困难,旧能力损失的会更大;如果lr过小,那可能难以学到新知识。

6.当你数据集比较小(例如100B以下?),那建议使用较小的学习率。例如可以使用pre-train阶段最大学习率的10%。通常7B模型pre-train阶段的学习率大概是3e-4,所以我们可以选择3e-5。

7.记得根据你的batch size做相应缩放。通常lr缩放倍数为batch size倍数的开方。例如batch size增大4倍,学习率对应扩大2倍即可。

8.warmup_ratio也很重要。通常LLM训练的warmup_ratio是epoch * 1%左右。例如pre-train阶段一般只训一个epoch,则ratio是0.01;

9.SFT通常3个epoch,ratio对应为0.03但是如果做CPT,建议warmup_ratio调大一点。如果你的数据集很大,有几百b,那warmup其实不影响最重的模型效果。但通常我们的数据集不会有那么大,所以更小的ratio可以让模型“过渡”得更平滑。

10.我甚至试过3个epoch的训练(SFT),第一个epoch全部用来warmup,结果是work的。这里参考了Qwen-7b的技术报告。

11.所以学习率和warmup_ratio是两个相辅相成的概念,二者通常是成正比的关系。或者说如果你正在用一个较大的学习率,那你或许可以同时尝试增加warmup来防止模型“烂掉”。

12.这几点不只适用于CPT,对一些特殊情况下的SFT阶段同样适用。

13.这里吐槽一下Trainer,到现在都不支持最小lr参数。

关于SFT

1.请勿迷信3个epoch的训练,实测1个epoch就能对话。当然,更多的epoch确实会让模型的评测效果更佳。

2.但如果你资源严重受限,跑一轮也能用~尤其当你从一个SFT模型启动(如chatGLM)时,尝试小点的epoch,防止灾难性遗忘。

3.如果数据量比较小,如只有1k,可以尝试更多的epoch。无他,人为过拟合而已。

关于continue

1.pre-train+SFT首先提出一个问题,假设你想做一个领域模型,并且你的领域模型和通用chatBot的输出内容、格式都区别很大;此外你还期望要通过CPT来注入一定的知识,那可用的技术路线有哪些呢?

从pre-train模型开始SFT训练,先做CPT,SFT数据使用你的领域数据
会得到一个只能解领域问题的模型,丢失掉通用对话能力,如果完全不考虑通用对话能力可以,否则不推荐

从pre-train模型开始SFT训练,先做CPT,SFT数据选用通用SFT数据+领域SFT数据
  如果你的领域数据和通用能力很接近,如医疗问答,那这是一个非常不错的技术路线,推荐

对于2,如果你的新任务和通用任务差别很大,甚至输出格式都完全不一样甚至冲突
虽然可行,但直觉上一些通用SFT数据的answer会对你的任务目标造成一定程度的负向影响

从pre-train模型开始SFT训练,先做CPT,再做通用SFT,再做领域SFT
 这会导致你的任务目标(最后阶段)和你的知识注入阶段(CPT阶段)中间存在一个阶段的gap,可能不是最佳路线

从sft模型开始训练,先做CPT,再做领域SFT
与4同理,任务目标(最后阶段)和通用对话能力阶段隔了一个阶段,仿佛也不够优雅

2.思来想去,好像所有现有常见的技术路线都不太work~所以可能要试一些非常规的方法。

3.一个很有意思的问题是,过去我们都被GPT论文的三个阶段束缚,老老实实串行跑三个阶段:PT->SFT>RLHF

4.但是越来越多人尝试SFT+DPO混合训练,看上去也是work的。

5.同理,我相信很多国内大模型的大厂,或多或少可能都在PT模型里偷偷掺了一些SFT数据,这会让模型的性能有一定程度的提升。

6.很久以前也有人在SFT阶段掺杂一些PT数据,来防止灾难性遗忘。

7.此外,不管是SFT还是PT,任务目标其实都一样,都是基于teacher forcing的自回归任务,next token predict而已,唯一的不同只是数据格式不一样。

8.那么我们可不可以认为,其实这不同阶段的区别其实没有那么大?是不是可以CPT+SFT混合训练,不再区分阶段。

9.例如我们可以在CPT阶段加入大量SFT对话数据(同样mask掉question),这个SFT数据甚至可以是海量的、未经清洗的、低质量的数据,仅训练1个epoch即可;接下来我们使用通用SFT数据(少而精的)+领域SFT数据,混合训练1个epoch;最后1个epoch我们只用领域数据做微调。

10.可以根据数据集大小、重要程度,修改各阶段epoch轮次,或在某个阶段内扩大某数据集的倍数。

11.至此,CPT数据共训练1个epoch,通用SFT数据2个,领域数据2个。

12.个人使用这种技术路线,感觉还是比较work的。由于CPT成本太大,未设置更多的消融实验。那除此以外是否有其他技术路线呢?答案或许是Lora?

关于Lora

1.个人对lora使用得不多,之前仅仅是了解原理+会用,没有深入探索过一些参数。最近尝试理解一下。

2.lora真的没省多少GPU也没省多少训练时长,所以我真的不太爱用它。(包大人备注:其实是很省显存的,但不太省训练时长)

3.lora更像是一个能力插件,可以帮助模型学到一些新的输出格式/领域话题,但对新知识或新能力的注入可能不太擅长。

4.对于能力注入,当前的认知是:pre-train > full SFT > lora。

5.所以用lora来进行pretrain可能不是一个最优解,还是更推荐用全参数。

6.但是对于领域任务,lora好像天然适合?

7.第2、3点没有经过实验论证,近期会跑个实验,有结论会做补充。

8.lora_rank是一个很重要的参数,它影响旁路矩阵的大小。

9.如果你的数据量比较小,那推荐用比较小的rank就可以了,我记得原论文里8和32区别不大(懒得翻论文了,全凭记忆,如果有错误请指正)

10.如果你数据量较大,那建议用更大的rank,来得到一个更大的旁路矩阵,它显然可以记住更多的东西。

11.与此同时,除了q_proj,v_proj,强烈建议再试一下把所有的线性层都上lora,如k_proj, up_proj, down_proj这些。

12.此外lora_alpha也很重要,它通常和lora_rank是正比关系,表示一个缩放系数。alpha越大,表示新建的旁路矩阵影响力越大、新数据学得越“猛”;alpha越小,表示原始模型参数对结果的影响力越大。

13.很多人喜欢设置alpha是rank的2倍,其实可以二者1: 1跑个baseline看看效果。

网友补充:

1、SFT和pretrain的任务在有些大模型例如ChatGLM是不一样的,对于把pretrain放到SFT来保持所谓的防止遗忘并没有感觉到明显差异。

2、对于小数据集,设置一个好的prefix,在很多epoch(大于100)的情况仍然保持不错的提升。

3、lora对显存的节约是很明显的,只是很多代码类似zero的思想并不契合lora(把模型切分放到最后,认为是最不占用显存的,然而lora相反)。

4、lora的效果和全量在我做的实验下是有明显差距的(例如在某些指标上经常>4%绝对值的差距),和论文中的理想情况不同,并且lora比较吃分层学习率,程度和crf比较接近了

5、lora的秩的值设置在1-16上还是存在不小的区别,从16到128上经常只是一些收敛上的差异,例如128可能n个epoch收敛到x,16可能要2n,但并不绝对,而且r大时间久,一般16-32是比较推荐的

6、DPO和RLHF根据个人理解,对chosen-rejected数据的质量需求是不同的,选择RLHF仍然是更好的选择,对于显存不够的部分人来说,可以例如lora,将actor和ref共用一个,critic和reward共用一个,把显存从4x降低为2x。宁可这样也尽量把显存尽可能用来提高critic模型的参数量

网友:暂时先写这么多,可能过俩月再看又是一篇漏洞百出的想法,

但总是要在摸索中前进吧~

审核编辑:黄飞

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分