背景

与 pretrain 的区别

sft pretrain
数据长度 每条数据原本多长就是多长 每条数据都是满编 4K/8K
特殊标记 引入 pretrain 阶段未见过的 special_token 无特殊_token
eos_token 能见到最重要的 eos_token 没见过,无法停止生成
语料角色 标配 system、user、assistant、function 等,可根据业务需求有“背景”、“旁白”、“事件”等 无特定角色划分
prompt 的 loss sft 的 prompt 不做 loss,但这并不是说它不能做 loss。主要原因是 prompt 的同质化比较严重,不做 loss_mask 的话,同样的一句话会被翻来覆去的学,但如果你能保证你的每条 prompt 都是独一无二的,就完全可以省去 prompt 的 loss_mask 环节。session 数据需考虑是每一个 answer 算 loss 还是只对最后一轮 answer 算 loss 无提及
训练目的 做题,学习指令 follow 能力,不能强行知识注入,知识注入应采用 continue - pretrain 思路 背书,纯粹学习知识

切勿在 sft 阶段强行给模型做知识注入,比如训个 50W 条的 code 数据,所有的知识注入工作应该采用 continue-pretrain 的思路进行,否则都会使得模型的通用能力掉点明显(sft 做知识注入基本上是 100% 某个知识,但 continue-pretrain 做知识注入会控制在 10% ~ 20% 左右的比例)。

有些同学在第一次训 sft 模型的时候,模型停不下来。这一般是超参数没设置好导致eos没学到,lr=1e-5,epoch=3一般可以解决,不然就epoch=5多训一下。

Special Token

pretrain 阶段完全没见过的 token,在sft 阶段会被赋予全新的语义。主要用于标注对话的角色: user、assistant、system 这些。

此外,special_token 可以用来“构造知识”,比如"<special_token_1>喜欢<sepcail_token_2>"这种知识一定是 sft 阶段才会见到的,可以剔除掉 pretrain 先验知识的影响,用来验证 sft 的训练情况,比如会不会过拟合。

我默认大家都知道怎么用 special_token 去拼 prompt,如果不熟悉,看下 tokenizer_config.json 里的"chat_template"这个字段也就懂了。

耗时问题

模型的预测时间可以近似理解为: y=kx+b ,其中 b 是首个 token 的耗时,k 是后续每个 token 的耗时,x 是生成 token 的总数量。更具体的,b 会是 k 的十几倍或更多,和 prompt 的长度几乎呈正相关。这个耗时的近似估算和 KV_cache 机制有关,不熟悉的可以自行搜索。

这也就是为什么众人都知 cot 效果好,众人又都不使用 cot,因为我们可以几乎下断言“模型的生成速度和生成 token 数量呈正相关”,而 cot 恰恰又引入了大量的生成 token。

此外,prompt 的长度也并非无所谓,尽量不要在 prompt 中写那么多废话,它毕竟和首包耗时呈正相关,在生成 token 不是特别多的情况下,是影响模型耗时的主要因素。

幻觉问题

什么是幻觉?

广义的幻觉指的就是模型回答错误,一本正经的胡说八道;

狭义的幻觉指的是模型本身具备某个知识,但是经过 alignment 处理后就开始回答不对了。

如何解决幻觉?

广义的幻觉在 decode-only transformer 下无解。唯一的优化点可能是通过 sft / rlhf 让模型知道什么时候拒绝回复,但也仅限于训过的同类型 case 能拒绝,没训过的 case 依旧胡说八道,泛化效果很差。