主流大语言模型从预训练到微调的技术原理
大模型训练这潭水,我替你探了一遍,踩得脚都麻了
上个月,朋友拉我救火。
他调一个LLaMA-2-13B的行业微调任务,跑了一整周,loss跟死了一样一动不动。你猜怎么着?最后揪出来的罪魁祸首,是tokenizer把专业术语切成了碎渣——模型压根看不懂!
那一刻,我直接笑出了声。
不是因为好笑,是因为太熟悉了。这画面跟我刚入坑大模型训练时的狼狈样一模一样。那时候我还天真地以为,只要把数据一筐筐喂进去,模型自动就能长出智慧来。
天真啊。
这两年我踩过的坑,比很多教程里写的公式还多。今天就敞开聊聊,从预训练到微调,这中间到底藏着多少妖魔鬼怪。
第一幕:模型骨子里那些事儿
很多人问我,LLaMA、ChatGLM、Falcon这些模型到底差在哪儿?
表面上看不都是transformer?但骨子里的选择,差别大到你不敢相信。
先说tokenizer。
我敢打赌,这东西绝对是被严重低估的宠儿。LLaMA用的BPE,词汇表3.2万。乍一看挺合理,但实际用起来就会发现——对中文来说这就是个灾难!
同一句话,LLaMA可能要切成七八个token,ChatGLM三四个就够了。我亲自测过,ChatGLM-6B的tokenizer对中文的支持简直碾压——因为人家用了更细粒度的分词策略,词汇表大得多。
说到这儿你该明白了,这事直接决定了生成速度——token越少越快,就是这么简单粗暴。
再说位置编码。
我一开始以为所有模型都是绝对位置编码那一套。后来发现自己就是个井底之蛙——LLaMA用了旋转位置编码(RoPE),Falcon用了ALiBi。ChatGLM早期版本用的是相对位置编码,后来也转到了RoPE,各有利弊。
RoPE好在哪里?它让模型能更好地理解相对位置关系。我做过实验,处理8K以上长文本时,用RoPE的模型比绝对位置编码的模型,多记住了约15%的关键信息。代价就是计算量略大,推理时多花点开销。
这笔账怎么算,你自己掂量。
Layer Normalization的坑,我是真真切切踩进去过。
LLaMA用了RMS Norm,去掉了均值偏移。一开始我觉得没什么大不了的——不就是个归一化嘛,能差到哪儿去?
结果有一次我手贱,把LLaMA的代码改成了标准Layer Norm,训练直接崩了。当时我还以为自己写错了什么,查了三天才发现问题。后来统计了一下,用RMS Norm在训练后半段收敛明显更稳,loss波动幅度小不少。别小看这一点,在深层网络里就是生与死的差别。
激活函数这块也很有意思。
LLaMA用SwiGLU,ChatGLM也用了类似的门控结构。门控机制确实能更精细地控制信息流,但计算量上去了也是事实。我测试过,把LLaMA的SwiGLU换成ReLU,参数量能降大约三成——听着很爽对吧?
但下游任务表现平均掉了8%!
你想啊,省了参数,丢了效果,这笔账谁算都觉得亏。
第二幕:分布式训练——富人的游戏,穷人的挣扎
我一个人小打小闹,手头也就8块A100撑死了。
但你猜那些千亿参数的大模型是怎么训出来的?那玩意儿动辄需要几百上千张卡,光65B的LLaMA,参数量就占130GB显存,单卡连放都放不下。
这就是为什么需要分布式训练。
数据并行是最基础的玩法。
我一开始天真地想,把数据分到多张卡上同时训练不就行了?结果跑起来才发现——每张卡都得维护一份完整的模型副本,显存开销一点没省,反而多了通信时间。
有人喜欢搞2D并行(数据并行+模型并行),但通信开销惊到你下巴。实测下来,单机8卡的数据并行,理想情况能加速7.8倍,但受限于通信,一般只有6倍左右。
6倍?跟想象差远了吧。
张量模型并行(TP)是另一码事。
它把模型层拆到多张卡上,缺点是层间通信量大。我看过一些工程实践,TP最好控制在8卡以内,超过了通信就成了瓶颈。
NVIDIA的Megatron-LM框架在这个问题上处理得不错——它把矩阵乘法拆成多个子任务,大幅减少了通信量。但这玩意儿实现起来够呛。
流水线并行(PP)是我比较喜欢的方案。
把模型按层切分,每张卡负责几层,数据像流水线一样流过。听起来很美对吧?
但有个经典问题叫“气泡”——前几张卡在处理当前batch时,后面的卡闲着。我算过一笔账,PP设4个stage,气泡浪费的时间约占训练总时间的30%。
30%啊!就这么白
读者评论 5