为什么需要 QLoRA
随着 LLM 参数量不断攀升,全量微调所需的显存越来越大。所以出现了 LoRA,它的思路是:冻结主模型权重,只训练少量的低秩适配器。这样虽然需要加载整个模型到显卡,但是由于只需要训练 LoRA 的 $A$ 和 $B$ 两个权重矩阵,所以优化器的参数非常少,并且中间激活值的占用也大幅度减小,所以显存需求大幅降低。
前面我们已经进行了预训练,得到了一个只会续写的模型。这是因为我们预训练数据集的文本都是简单的一句话,然后通过加工我们得到了类似 “<|im_start|> 秦始皇的功绩包括统一货币、文字” 的文本,通过 Teacher-Forcing 它只能做到预测下一个 token,或者说只会机械接龙,不会对话。
今天看了一下源码和官方文档,梳理过后会发现其实也不是很复杂,简单理解就两条:
ModelOutput(transformers.utils.ModelOutput)是所有模型输出的基类。简单理解它就是一个字典,在模型的 forward函数里把原本的输出做了一下封装而已,方便用户能直观地知道输出是什么。例如CausalLMOutput顾名思义就是用于像 GPT 这样自回归模型的输出。PreTrainedModel (transformers.modeling_utils.PretrainedModel) 是所有模型的基类。所以你如果看到一个模型取名为LlamaForCausalLM,那你就可以知道这个模型的输出格式大概率就是自回归输出,即前面提到的CausalLMOutput。为什么说大概率呢,因为自回归输出还有蛮多种的,赶时间的朋友看到这就可以切换到其他文章了,至此你应该也能了解 transformers 最核心的模块了。感兴趣的可以继续往下看,下面做一个简单的总结和介绍。前面已经介绍过了,ModelOutput是所有模型输出的基类。下面是其源码核心部分,一些具体实现代码删除了,不过不影响理解。
这一章我们需要设计一个脚本来验证大模型的对话能力
我们预训练是让模型学会说话的能力,或者说词语接龙的能力,给他一个 prompt 它可以接着说下去。因此我们在处理 prompt 时候需要稍加处理:
预训练我们采用的是 Teacher-Forcing,所以需要的数据格式应该是偏移的
input_ids和labels。
__getitem__ 方法有几个需要注意的地方:
forward 里面规定了:训练模式下将 logits 和 labels 进行偏移,所以在 Dataset 里面返回的 x 和 y 就不用额外的进行 shift 了。F.cross_entropy(...,ignore_index=-100) 一致。