在本篇文章中,我们将深入探讨Fine-tuning的概念、原理以及如何在实际项目中运用它,以此为初学者提供一份入门级的指南。
ChatGPT大模型今年可谓是大火,在正式介绍大模型微调技术之前,为了方便大家理解,我们先对大模型做一个直观的抽象。
本质上,现在的大模型要解决的问题,就是一个序列数据转换的问题:
输入序列 X = [x1, x2, ..., xm], 输出序列Y = [y1, y2, …, yn],X和Y之间的关系是:Y = WX。
我们所说的“大模型”这个词:“大”是指用于训练模型的参数非常多,多达千亿、万亿;而“模型”指的就是上述公式中的矩阵W。
在这里,矩阵W就是通过机器学习,得出的用来将X序列,转换成Y序列的权重参数组成的矩阵。
需要特别说明:这里为了方便理解,做了大量的简化。在实际的模型中,会有多个用于不同目的的权重参数矩阵,也还有一些其它参数。
Fine-tuning源于对已经训练好的模型进行微调的概念。传统的机器学习模型需要通过大量数据进行训练,而Fine-tuning则利用了在庞大数据集上训练好的大型深度学习模型。这些预训练模型,如ChatGPT大模型,已经通过数以亿计的文本数据学到了庞大的知识库。
在预训练模型的基础上进行额外训练,使其适应特定任务或领域。这一过程包括选择预训练模型,准备目标任务的数据,调整模型结构,进行微调训练,以及评估和部署。
微调的优点在于节省时间和资源,提高性能,但也存在过拟合风险和模型选择与调整的复杂性。总体而言,它是一种强大的技术,特别适用于数据受限或计算资源有限的情况。
在 OpenAI 发布的 ChatGPT应用中,就主要应用了大模型微调技术,从而获得了惊艳全世界的效果。
而随着ChatGPT的火热,parameter-efficient fine-tuning和prompt-tuning技术似乎也有替代传统fine-tuning的趋势,本篇论文将简单描述预训练模型领域这三种微调技术及其差别。
大模型全量微调通过在预训练的大型模型基础上调整所有层和参数,使其适应特定任务。这一过程使用较小的学习率和特定任务的数据进行,可以充分利用预训练模型的通用特征,但可能需要更多的计算资源。
PEFT技术旨在通过最小化微调参数的数量和计算复杂度,来提高预训练模型在新任务上的性能,从而缓解大型预训练模型的训练成本。
Prompt Tuning的出发点,是基座模型(Foundation Model)的参数不变,为每个特定任务,训练一个少量参数的小模型,在具体执行特定任务的时候按需调用。
Prompt Tuning的基本原理是在输入序列X之前,增加一些特定长度的特殊Token,以增大生成期望序列的概率。
具体来说,就是将X = [x1, x2, ..., xm]变成,X` = [x`1, x`2, ..., x`k; x1, x2, ..., xm], Y = WX`。
如果将大模型比做一个函数:Y=f(X),那么Prompt Tuning就是在保证函数本身不变的前提下,在X前面加上了一些特定的内容,而这些内容可以影响X生成期望中Y的概率。
Prefix Tuning的灵感来源是,基于Prompt Engineering的实践表明,在不改变大模型的前提下,在Prompt上下文中添加适当的条件,可以引导大模型有更加出色的表现。
Prefix Tuning的出发点,跟Prompt Tuning的是类似的,只不过它们的具体实现上有一些差异。
而Prefix Tuning是在Transformer的Encoder和Decoder的网络中都加了一些特定的前缀。
具体来说,就是将Y=WX中的W,变成W` = [Wp; W],Y=W`X。
Prefix Tuning也保证了基座模型本身是没有变的,只是在推理的过程中,按需要在W前面拼接一些参数。
LoRA是跟Prompt Tuning和Prefix Tuning完全不相同的另一条技术路线。
LoRA背后有一个假设:我们现在看到的这些大语言模型,它们都是被过度参数化的。而过度参数化的大模型背后,都有一个低维的本质模型。
通俗讲人话:大模型参数很多,但并不是所有的参数都是发挥同样作用的;大模型中有其中一部分参数,是非常重要的,是影响大模型生成结果的关键参数,这部分关键参数就是上面提到的低维的本质模型。
首先, 要适配特定的下游任务,要训练一个特定的模型,将Y=WX变成Y=(W+?W)X,这里面?W主是我们要微调得到的结果;
其次,将?W进行低维分解?W=AB (?W为m * n维,A为m * r维,B为r * n维,r就是上述假设中的低维);
接下来,用特定的训练数据,训练出A和B即可得到?W,在推理的过程中直接将?W加到W上去,再没有额外的成本。
另外,如果要用LoRA适配不同的场景,切换也非常方便,做简单的矩阵加法即可:(W + ?W) - ?W + ?W`。
备注:预训练模型是指在庞大的数据集上进行训练得到的模型。这些数据集通常是通过无监督学习或其他任务进行训练的。简单来说就是“模型的母体”。
备注:微调数据集是指在模型微调过程中所使用的数据集,比如原有大模型是识别动物类的大模型,现在我们准备了全部是猫狗的图片数据集,迁移模型的识别到识别猫狗上。
备注:本质上,就是调节模型识别的标签,比如原来识别的猫,现在让识别成狗,就是调整模型的标签输入
备注:损失函数就好比你在玩打靶游戏,目标是尽量靠近靶心。当你射击命中靶心时,你会得到一个很小的损失分数,代表你的射击非常准确;而当你偏离靶心时,损失分数会相应增加,代表你离目标更远了。
在机器学习中,损失函数类似于靶心,我们的模型的预测结果就类比为射击的结果。损失函数衡量了模型预测值与真实值之间的差距,我们的目标是尽量减小这种差距,即尽量减小损失函数的值。
备注:冻结部分模型可以用一个简单的例子来解释。假设你正在准备一道复杂的菜肴,这个菜需要煎牛排、炒蔬菜和做汁料。你已经有了一个非常熟练的牛排煎得恰到好处的步骤,这是你多年的经验总结出来的。但是你对于炒蔬菜和做汁料的处理方法还不是很熟悉。
那么在这个情况下,你可以决定冻结(保持不变)你熟练的牛排煎的步骤,因为你已经能够很好地完成它。你只需要专注于学习和改进炒蔬菜和做汁料的步骤,以充分利用你的努力。
我们可以将机器学习模型的参数调整过程类比为学生学习的过程。学习过程中,学生需要根据老师的指导不断调整学习策略,使得自己的学习效果越来越好。
优化器就像是学生的学习策略,它决定了如何根据反馈信息来更新模型的参数。不同的优化器有不同的策略,比如一些优化器会根据参数的梯度(导数)大小来调整参数的更新步长,而另一些优化器则会考虑参数的历史更新情况来调整步长。这些策略旨在使模型更好地逼近最优解,就像学生通过不断调整学习策略来提高学习效果一样。
学习率则类似于学生的学习步长,它决定了每次参数更新的幅度。如果学习率很小,那么参数更新的幅度会很小,学习过程会比较稳定但可能会收敛得比较慢;如果学习率很大,那么参数更新的幅度会很大,学习过程可能会比较震荡但可能会收敛得较快。选择合适的学习率可以帮助模型更快地找到最优解,就像选择合适的学习步长可以帮助学生更快地掌握知识一样。
备注:评估模型性能就好比是给学生考试一样,我们想知道学生掌握知识的程度。在考试中,我们通过评估学生的答题情况来得出一个分数,这个分数反映了学生在掌握知识方面的能力。
作者后来将各种大模型的高效微调,统一到了一个项目里:https://github.com/hiyouga/LLaMA-Factory(opens new window)
href="https://github.com/baichuan-inc/Baichuan-13B" Baichuan | |||
总的来说,这些微调方式都是为了让模型更好地适应新的任务或数据,但它们的策略和重点略有不同。选择合适的微调方式可以帮助我们更快地实现模型性能的提升,就好比选择合适的训练方式可以让我们更好地提高学习效果一样。