【深度学习】DeepL基础知识
+【深度学习】DeepL|LLM基础知识
- Last updated on March 14, 2024 am + Last updated on March 24, 2024 pm
@@ -1571,7 +1571,7 @@(4)进制转换
(4)进制转换
(4)进制转换
【深度学习】大语言模型简介
+【大语言模型】基础模型概念
- Last updated on March 14, 2024 pm + Last updated on March 24, 2024 pm
@@ -760,8 +760,8 @@3.1
3.2
BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
-3.3BERT用的是transformer里面的encoder还是decoder?
+3.3 +BERT用的是transformer里面的encoder还是decoder?
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
@@ -851,7 +851,7 @@3.8
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
https://lihaibineric.github.io/2024/03/08/dl_llm_model/
@@ -870,7 +870,7 @@ 3.8
Updated on
- March 14, 2024
+ March 24, 2024
@@ -901,12 +901,18 @@ 3.8
+
+
+ 【大语言模型】有监督微调
+ Previous
+
+
-
- 【深度学习】DeepL基础知识
+
+ 【深度学习】DeepL|LLM基础知识
Next
diff --git a/2024/03/24/dl-llm-ft/index.html b/2024/03/24/dl-llm-ft/index.html
new file mode 100644
index 0000000..2d81ca1
--- /dev/null
+++ b/2024/03/24/dl-llm-ft/index.html
@@ -0,0 +1,1512 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调 - LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 26k words
+
+
+
+
+
+
+
+
+
+
+ 220 mins
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调
+
+
+
+
+ Last updated on March 24, 2024 pm
+
+
+
+
+
+
+
+
+大语言模型微调
+1. 大模型微调简介
+1.1 微调方法定义
+微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
+下面是一般的微调步骤:
+
+- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。
+- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。
+- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specific
+head)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。
+- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。
+- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。
+- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。
+- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。
+- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。
+
+微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
+1.2 为什么需要 PEFT
+Parameter-Efficient
+Fine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trained
+language models
+)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
+PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
+参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
+参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
+高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Soft
+prompts)两个小类。
+
+
+Scaling Down to Scale Up: A Guide to Parameter-Efficient
+Fine-Tuning
+
+1.3
+微调和参数高效微调之间的区别
+微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
+微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
+另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
+1.4 PEFT 有什么优点
+在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
+
+- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本
+- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。
+- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。
+- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。
+- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。
+
+1.5 多种不同的高效微调方法对比
+参数有效策略可能涉及多种技术:
+
+- 选择性层调整(Selective Layer
+Tuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。
+- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。
+- 稀疏微调(Sparse
+Fine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。
+- 低秩近似(Low-Rank
+Approximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。
+- 正则化技术(Regularization
+Techniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。
+- 任务特定的头(Task-specific
+Heads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。
+
+1.6
+当前高效微调技术存在的一些问题
+当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
+
+- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。
+Ladder-side
+Tuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。
+- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。
+- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。
+- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用git
+fork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。
+
+1.7 PEFT技术实践
+针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
+
+- 明确指出参数数量类型。
+- 使用不同大小的模型进行评估。
+- 和类似方法进行比较。
+- 标准化PEFT测量基准。
+- 重视代码清晰度,以最小化进行实现。
+
+2. 微调Fine-Tune
+2.1 为什么SFT之后感觉LLM傻了?
+在进行Supervised
+Fine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
+
+- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。
+- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。
+- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。
+- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。
+
+为了解决这些问题,可以尝试以下方法:
+
+- 收集更多的训练数据,以增加数据的多样性和覆盖范围。
+- 仔细检查微调数据集的标注,确保标签的准确性和一致性。
+- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。
+- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。
+- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。
+
+通过这些方法,可以尽量减少Supervised
+Fine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
+2.2 SFT 指令微调数据 如何构建?
+构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
+
+- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。
+- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。
+- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。
+- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。
+- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。
+- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。
+- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。
+
+2.3 如何训练自己的大模型?
+
+- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。
+- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。
+- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。
+- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。
+- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。
+- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。
+- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。
+
+2.4 指令微调的好处?
+指令微调(Instruction
+Fine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
+
+- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。
+- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。
+- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。
+- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。
+- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。
+
+请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
+2.5 多轮对话任务微调调型
+在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
+
+- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。
+- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。
+- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。
+- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
+
+- 初始化模型参数:将预训练模型的参数加载到模型中。
+- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。
+- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。
+- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。
+
+- 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。
+- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。
+
+需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
+2.6 微调后的模型出现能力劣化
+灾难性遗忘(Catastrophic
+Forgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
+在微调大语言模型时,灾难性遗忘可能出现的原因包括:
+
+- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。
+- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。
+
+为了解决灾难性遗忘问题,可以尝试以下方法:
+
+- 经验回放(Replay
+Buffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。
+- 弹性权重共享(Elastic Weight
+Consolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。
+- 增量学习(Incremental
+Learning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。
+- 多任务学习(Multi-Task
+Learning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。
+
+综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
+2.7 预训练和SFT操作有什么不同
+大语言模型的预训练和有监督微调(Supervised
+Fine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
+目标:
+
+- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(Masked
+Language Model,MLM)或下一句预测(Next Sentence
+Prediction,NSP)等,来训练模型。
+- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。
+
+数据:
+
+- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。
+- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。
+
+训练方式:
+
+- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。
+- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。
+
+总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
+2.8 大模型LLM进行SFT
+如何对样本进行优化?
+对于大语言模型进行有监督微调(Supervised
+Fine-Tuning)时,可以采用以下几种方式对样本进行优化:
+
+- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。
+- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。
+- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。
+- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。
+- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。
+- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。
+- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。
+
+总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
+3. 预训练
+3.1 为什么要增量预训练?
+预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
+3.2
+进行增量预训练需要做哪些准备工作?
+
+- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。
+- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是
+TB 级别的。
+- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。
+
+3.3
+增量预训练训练流程是怎么样?
+
+- 数据预处理:参考 LLaMA
+的预训练长度,也把数据处理成2048长度(如果不够,做补全)。
+- 分词器:如果使用 LLaMA
+可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。
+- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选
+Chat 模型。
+- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。
+- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。
+- 模型测试:简单测试下续写能力,验证下模型是否正常。
+
+4. Prompting工程
+4.1 BitFit
+4.1.1 背景
+虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署,
+特别是随着任务数量的增加,很难维护。
+理想状况下,我们希望有一种满足以下条件的高效微调方法:
+
+- 到达能够匹配全量微调的效果。
+- 仅更改一小部分模型参数。
+- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。
+- 改变的参数在不同下游任务中是一致的。
+
+上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
+虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
+4.1.2 技术原理
+BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuning
+or Transformer-based Masked
+Language-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
+对于Transformer模型而言,冻结大部分 transformer-encoder
+参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
+在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了
+BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
+
+同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言,
+只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
+同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
+
+4.2 Prefix Tuning
+4.2.1 背景
+在Prefix
+Tuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
+除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
+基于上述两点,Prefix
+Tuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,
+这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的Virtual
+Token(Soft Prompt/Continuous
+Prompt),相比离散的Token,更好优化,效果更好。
+
+4.2.2 技术原理
+Prefix Tuning(论文:Prefix-Tuning: Optimizing Continuous
+Prompts for
+Generation),在输入token之前构造一段任务相关的virtual
+tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
+针对不同的模型结构,需要构造不同的Prefix。
+
+- 针对自回归架构模型:在句子前面添加前缀,得到
+
z = [PREFIX; x; y]
,合适的上文能够在固定 LM
+的情况下去引导生成下文(比如:GPT3的上下文学习)。
+- 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
+
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder
+端增加前缀是为了引导后续token的生成。
+
+
+该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
+
+除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
+
+另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为
+[PREFIX; x; y]
,Infix-tuning形式为
+[x; INFIX; y]
。
+4.3 Prompt Tuning
+4.3.1 背景
+大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
+基于此,作者提出了Prompt
+Tuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,
+训练完以后,用同一个模型可以做多任务推理。
+4.3.2 技术原理
+Prompt Tuning(论文:The Power of Scale for
+Parameter-Efficient Prompt Tuning),该方法可以看作是Prefix
+Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompt
+tokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
+
+通过实验发现,随着预训练模型参数量的增加,Prompt
+Tuning的方法会逼近全参数微调的结果。
+
+同时,Prompt Tuning 还提出了 Prompt
+Ensembling,也就是在一个批次(Batch)里同时训练同一个任务的不同
+prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
+
+4.4 P-Tuning
+4.4.1 背景
+该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(in
+context
+learning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
+同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtual
+token(同Prefix-Tuning类似)。
+
+4.4.2 技术原理
+P-Tuning(论文:GPT Understands,
+Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。
+
+相比Prefix Tuning,P-Tuning加入的可微的virtual
+token,但仅限于输入层,没有在每一层都加;另外,virtual
+token的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtual
+token。
+经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual
+token,容易优化到局部最优值,而这些virtual
+token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt
+encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual
+token以后,再输入到模型。
+从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
+并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
+4.5 P-Tuning v2
+4.5.1 背景
+之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
+第一,缺乏模型参数规模和任务通用性。
+
+- 缺乏规模通用性:Prompt
+Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
+- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些
+NLU
+基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。
+
+第二,缺少深度提示优化,在Prompt
+Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
+
+- 由于序列长度的限制,可调参数的数量是有限的。
+- 输入embedding对模型预测只有相对间接的影响。
+
+考虑到这些问题,作者提出了Ptuning
+v2,它利用深度提示优化(如:Prefix Tuning),对Prompt
+Tuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
+4.5.2 技术原理
+P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can Be
+Comparable to Fine-tuning Universally Across Scales and
+Tasks),该方法在每一层都加入了Prompts
+tokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
+
+- 更多可学习的参数(从P-tuning和Prompt
+Tuning的0.01%增加到0.1%-3%),同时也足够参数高效。
+- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。
+
+
+具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix
+Tuning技术适配到NLU任务中,然后做了一些改进:
+
+- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2
+中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
+- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。
+- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuning
+v2的有益补充。
+- 回归传统的分类标签范式,而不是映射器。标签词映射器(Label
+Word
+Verbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuning
+v2回归传统的CLS标签分类范式,采用随机初始化的分类头(Classification
+Head)应用于tokens之上,以增强通用性,可以适配到序列标注任务。
+
+论文中展示了P-tuning
+v2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),Prompt
+Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuning
+v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning
+v2在RTE中的表现明显优于微调,特别是在BERT中。
+5. Adapter-Tuning
+5.1 Adapter Tuning
+5.1.1 背景
+预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
+基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题
+Adapter
+在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
+5.1.2 技术原理
+Adapter Tuning(论文:Parameter-Efficient Transfer Learning
+for
+NLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的
+==Adapter 结构和 Layer Norm
+层==进行微调,从而保证了训练的高效性。
+每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
+
+5.1.3 具体细节
+每个 Adapter
+模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skip
+connection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便
+Adapter 一开始的参数初始化接近0,Adapter也由于skip
+connection的设置而接近于一个恒等映射,从而确保训练的有效性。
+\[
+h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p}
+\]
+通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
+总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
+5.2 AdapterFusion
+5.2.1 背景
+为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequential
+fine-tuning)或者多任务学习(multi-task
+learning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
+而之前的工作,Adapter
+Tuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter
+的参数某种程度上就表达了解决这个任务需要的知识。
+作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了
+AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
+5.2.2 技术原理
+Adapter Fusion(论文:AdapterFusion:Non-Destructive Task
+Composition for Transfer
+Learning),一种融合多任务信息的Adapter的变体,在
+Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+
+- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
+- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。
+
+
+对于第一阶段,有两种训练方式,分别如下:
+
+- Single-Task
+Adapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。
+- Multi-Task
+Adapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。
+
+对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
+5.2.3 AdapterFusion结构
+AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,
+value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
+
+通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
+总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
+5.3 AdapterDrop
+5.3.1 背景
+近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
+作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
+基于此,作者提出了AdapterDrop方法缓解该问题。
+5.3.2 技术原理
+AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters in
+Transformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+
+实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。
+例如,将前五个Transformer层中的Adapter丢弃,在对 8
+个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop
+也能保持良好的结果。
+除此之外,作者还研究了对
+AdapterFusion中的Adapter进行剪枝后的效果。
+
+通过实验表明可以移除 AdapterFusion
+中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整
+AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
+因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。
+这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
+总之,AdapterDrop
+通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+5.4 MAM Adapter
+5.4.1 背景
+近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
+下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,Prefix
+Tuning和LoRA都是性能比较好的方法。
+
+为什么看起来Adapter、Prefix
+Tuning、LoRA(在结构上和公式上)都不太一样,尤其是Prefix
+Tuning,但是这三种方法有近似的效果?
+基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、Prefix
+Tuning和LoRA)的设计,并提出了一种新方法MAM
+Adapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
+
+首先,作者通过对Prefix Tuning变换,发现Prefix
+Tuning和Adapters的公式高度相似。
+然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体)
+Parallel Adapter、 Scaled PA的结构。
+
+下表展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体在新增可训练参数结构形式(functional
+form)、结构插入形式(Insertion
+form)、新增结构在PLM修改的具体位置(modified
+representation)、新增结构与PLM的组合函数(composition
+function)。其中,新增可训练参数结构形式为需要学习的部分(注:Prefix
+Tuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
+
+5.4.2 技术原理
+MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT
+TRANSFER LEARNING),一个在Adapter、Prefix
+Tuning和LoRA之间建立联系的统一方法。
+作者对Adapter的放置和软提示(soft
+prompt)进行了详细的调查。得出如下结论:
+
+- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN
+并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。
+- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。
+
+然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用
+FFN 层的并行Adapter和软提示的组合。
+通过最终的实验结果,可以看到 MAM Adapter
+在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于
+BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
+5.5 UniPELT
+5.5.1 背景
+近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
+基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+5.5.2 技术原理
+UniPELT(论文: UNIPELT: A Unified Framework for Parameter-Efficient
+Language Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
+更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,Prefix
+Tuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。
+对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括
+LoRA 矩阵
+WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
+
+UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter
+和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT
+的性能与这些方法相当或更好。
+实验还对不同 PELT 方法训练时间和推理时间进行了分析。
+
+- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围,
+- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。
+- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。
+
+6. lora
+6.1 LoRA
+6.1.1 背景
+神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsic
+rank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
+6.1.2 技术原理
+LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE
+MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsic
+rank)。
+
+可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
+
+在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
+\[
+h=W_{0} x+\Delta W x=W_{0} x+B A x
+\]
+在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
+此外,Transformer的权重矩阵包括Attention模块里用于计算query
,
+key
,
+value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整
+Wq 和 Wv 会产生最佳结果。
+实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
+6.2 AdaLoRA
+6.2.1 背景
+在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
+
+- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。
+- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。
+
+为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
+
+- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adapter
+tuning、Prefix tuning、Prompt
+Tuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adapter
+tuning引入了推理延时;Prefix tuning或Prompt
+tuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。
+- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diff
+pruning、LoRA等,
+此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diff
+pruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。
+LoRA则需要预先指定每个增量矩阵的本征秩 r
+相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。
+
+基于以上问题进行总结:
+
+- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。
+- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。
+
+为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
+6.2.2 技术原理
+AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FOR
+PARAMETEREFFICIENT
+FINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
+
+- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。
+
+\[
+W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q
+\]
+
+- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。
+
+通过实验证明,AdaLoRA
+实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。
+例如,当参数预算为 0.3M 时,AdaLoRA
+在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
+
+6.3 QLoRA
+6.3.1 背景
+微调大型语言模型 (LLM)
+是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以
+LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU
+内存。
+虽然最近的量化方法可以减少 LLM
+的内存占用,但此类技术仅适用于推理场景。
+基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为
+4 bit的模型。
+6.3.2 技术原理
+QLoRA(论文: QLORA: Efficient Finetuning of Quantized
+LLMs),使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA
+有一种低精度存储数据类型(4
+bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用
+QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16
+位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bit
+NormalFloat(NF4)
+量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
+
+- 4bit
+NormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比
+4 bit整数和 4bit 浮点数更好的实证结果。
+- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。
+- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的
+GPU 处理。该功能的工作方式类似于 CPU
+内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在
+GPU 内存不足时将其自动卸载到 CPU
+内存,并在优化器更新步骤需要时将其加载回 GPU 内存。
+
+
+实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
+7. 微调方法总结
+7.1
+当前高效微调技术的简述
+之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
+7.2 BitFit
+对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
+特点:
+
+- 训练参数量极小(约0.1%)。
+- 在大部分任务上效果会差于LoRA、Adapter等方法。
+
+7.3 Prefix Tuning
+在每一个Transformer层都带上一些virtual
+token作为前缀,以适应不同的任务。
+特点:
+
+- 前缀Token会占用序列长度,有一定的额外计算开销。
+- Prefix Tuning的线性插值是比较复杂的。
+
+7.4 Prompt Tuning
+该方法可以看着是Prefix
+Tuning的简化版本,针对不同的任务,仅在输入层引入virtual
+token形式的软提示(soft prompt)。
+特点:
+
+- 相对于Prefix
+Tuning,参与训练的参数量和改变的参数量更小,更节省显存。
+- 对一些简单的NLU
+任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。
+
+7.5 P-Tuning
+将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtual
+token;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
+特点:
+
+- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtual
+token的相互依赖会收敛更快,效果更好。
+
+7.6 P-Tuning v2
+该方法在每一个Transformer层都加入了prompt
+token作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
+特点:
+
+- 解决了Prompt Tuning无法在小模型上有效提升的问题。
+- 移除了对模型效果改进较小的重参数化的编码器(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM)。
+- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。
+
+7.7 Adapter Tuning
+该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和Layer
+Norm 层进行微调。
+特点:
+
+- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。
+
+7.8 AdapterFusion
+一种融合多任务信息的Adapter的变体,在 Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+7.9 AdapterDrop
+该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+特点:
+
+- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+
+7.10 LoRA
+该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+特点:
+
+- 将BA加到W上可以消除推理延迟。
+- 可以通过可插拔的形式切换到不同的任务。
+- 设计的比较好,简单且效果好。
+
+7.11 AdaLoRA
+对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+7.12 QLoRA
+使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
+特点:
+
+- 使用 QLoRA
+微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。
+
+7.13 MAM Adapter
+一种在 Adapter、Prefix Tuning 和 LoRA
+之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter
+和 软提示的组合。
+特点:
+
+- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。
+
+7.14 UniPELT
+一种将不同的PELT方法LoRA、Prefix
+Tuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+特点:
+
+- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。
+- 多种 PELT 方法的混合涉及PLM
+的不同部分对模型有效性和鲁棒性都有好处
+
+7.15 总结
+本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
+
+- 增加额外参数,如:Prefix Tuning、Prompt Tuning、Adapter
+Tuning及其变体。
+- 选取一部分参数更新,如:BitFit。
+- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。
+- 混合高效微调,如:MAM Adapter、UniPELT。
+
+并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调
+ https://lihaibineric.github.io/2024/03/24/dl-llm-ft/
+
+
+
+
+ Author
+ Haibin Li
+
+
+
+
+ Posted on
+ March 24, 2024
+
+
+
+
+ Updated on
+ March 24, 2024
+
+
+
+
+ Licensed under
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】基础模型概念
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html
index 7a34a5d..816d579 100644
--- a/archives/2023/10/index.html
+++ b/archives/2023/10/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2023/11/index.html b/archives/2023/11/index.html
index 7842f5a..be3c6c6 100644
--- a/archives/2023/11/index.html
+++ b/archives/2023/11/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html
index 092c79f..bcb7a34 100644
--- a/archives/2023/12/index.html
+++ b/archives/2023/12/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2023/index.html b/archives/2023/index.html
index 2dd443e..00a9f5f 100644
--- a/archives/2023/index.html
+++ b/archives/2023/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2024/01/index.html b/archives/2024/01/index.html
index 84e676d..9a09053 100644
--- a/archives/2024/01/index.html
+++ b/archives/2024/01/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2024/02/index.html b/archives/2024/02/index.html
index b9e819b..a800db7 100644
--- a/archives/2024/02/index.html
+++ b/archives/2024/02/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2024/03/index.html b/archives/2024/03/index.html
index 45df041..e6980a4 100644
--- a/archives/2024/03/index.html
+++ b/archives/2024/03/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
diff --git a/archives/2024/index.html b/archives/2024/index.html
index 15e05e8..0579f1a 100644
--- a/archives/2024/index.html
+++ b/archives/2024/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -263,12 +269,6 @@
【深度学习】推荐系统基础知识
-
-
-
- 【深度学习】图神经网络
-
-
diff --git a/archives/2024/page/2/index.html b/archives/2024/page/2/index.html
index 49e38fd..c7a7b0b 100644
--- a/archives/2024/page/2/index.html
+++ b/archives/2024/page/2/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,6 +210,12 @@
2024
+
+
+ 【深度学习】图神经网络
+
+
+
【算法题】LeetCode算法汇总
diff --git a/archives/index.html b/archives/index.html
index 8bf5389..4f12518 100644
--- a/archives/index.html
+++ b/archives/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -263,18 +269,12 @@
【深度学习】推荐系统基础知识
-
-
-
- 【深度学习】图神经网络
-
-
diff --git a/archives/page/2/index.html b/archives/page/2/index.html
index ad7bca9..3b5a50b 100644
--- a/archives/page/2/index.html
+++ b/archives/page/2/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,6 +210,12 @@
2024
+
+
+ 【深度学习】图神经网络
+
+
+
【算法题】LeetCode算法汇总
@@ -266,18 +272,12 @@
【多智能体强化学习】Pymarl环境配置
-
-
-
- 【自动驾驶】RSS Model for Autonomous Driving
-
-
diff --git a/archives/page/3/index.html b/archives/page/3/index.html
new file mode 100644
index 0000000..2ee7fb6
--- /dev/null
+++ b/archives/page/3/index.html
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Archives - LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/categories/index.html b/categories/index.html
index d955284..2e1be46 100644
--- a/categories/index.html
+++ b/categories/index.html
@@ -224,7 +224,7 @@
- 8
+ 9
- 【深度学习】大语言模型简介
+ 【大语言模型】有监督微调
-
- 【深度学习】DeepL基础知识
+ 【大语言模型】基础模型概念
+
+
+
+
+
+
+ 【深度学习】DeepL|LLM基础知识
diff --git "a/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html" "b/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
index 70e9371..616604f 100644
--- "a/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
+++ "b/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
@@ -202,7 +202,7 @@
- 8 posts in total
+ 9 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
diff --git a/index.html b/index.html
index ade9136..27b81af 100644
--- a/index.html
+++ b/index.html
@@ -202,6 +202,69 @@
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调
+
+
+
+
+
+
+ 大语言模型微调 1. 大模型微调简介 1.1 微调方法定义 微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。 下面是一般的微调步骤: 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。
+
+
+
+
+
+
+
@@ -209,7 +272,7 @@
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
@@ -272,7 +335,7 @@
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -769,72 +832,11 @@
-
-
-
-
-
-
-
- 【深度学习】图神经网络
-
-
-
-
-
-
- 图神经网络 GNN全称----图神经网络,它是一种直接作用于图结构上的神经网络。我们可以把图中的每一个节点 \(V\) 当作个体对象,而每一条边 \(E\) 当作个体与个体间的某种联系,所有节点组成的关系网就是最后的图 \(U\) GNN的输入一般是每个节点的起始特征向量和表示节点间关系的邻接矩阵,有了这两个输入信息,接下来就是聚合操作了。所谓的聚合,其实就是将周边与节点 V i ViVi 有关
-
-
-
-
-
-
-
diff --git a/local-search.xml b/local-search.xml
index bd4e79c..7ff96c3 100644
--- a/local-search.xml
+++ b/local-search.xml
@@ -4,11 +4,38 @@
- 【深度学习】大语言模型简介
+ 【大语言模型】有监督微调
+
+ /2024/03/24/dl-llm-ft/
+
+ 大语言模型微调
1. 大模型微调简介
1.1 微调方法定义
微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
下面是一般的微调步骤:
- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。
- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。
- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specifichead)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。
- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。
- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。
- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。
- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。
- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。
微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
1.2 为什么需要 PEFT
Parameter-EfficientFine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trainedlanguage models)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Softprompts)两个小类。
Scaling Down to Scale Up: A Guide to Parameter-EfficientFine-Tuning
1.3微调和参数高效微调之间的区别
微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
1.4 PEFT 有什么优点
在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本
- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。
- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。
- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。
- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。
1.5 多种不同的高效微调方法对比
参数有效策略可能涉及多种技术:
- 选择性层调整(Selective LayerTuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。
- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。
- 稀疏微调(SparseFine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。
- 低秩近似(Low-RankApproximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。
- 正则化技术(RegularizationTechniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。
- 任务特定的头(Task-specificHeads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。
1.6当前高效微调技术存在的一些问题
当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。Ladder-sideTuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。
- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。
- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。
- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用gitfork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。
1.7 PEFT技术实践
针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
- 明确指出参数数量类型。
- 使用不同大小的模型进行评估。
- 和类似方法进行比较。
- 标准化PEFT测量基准。
- 重视代码清晰度,以最小化进行实现。
2. 微调Fine-Tune
2.1 为什么SFT之后感觉LLM傻了?
在进行SupervisedFine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。
- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。
- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。
- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。
为了解决这些问题,可以尝试以下方法:
- 收集更多的训练数据,以增加数据的多样性和覆盖范围。
- 仔细检查微调数据集的标注,确保标签的准确性和一致性。
- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。
- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。
- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。
通过这些方法,可以尽量减少SupervisedFine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
2.2 SFT 指令微调数据 如何构建?
构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。
- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。
- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。
- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。
- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。
- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。
- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。
2.3 如何训练自己的大模型?
- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。
- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。
- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。
- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。
- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。
- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。
- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。
2.4 指令微调的好处?
指令微调(InstructionFine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。
- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。
- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。
- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。
- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。
请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
2.5 多轮对话任务微调调型
在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。
- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。
- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。
- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
- 初始化模型参数:将预训练模型的参数加载到模型中。
- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。
- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。
- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。
- 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。
- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。
需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
2.6 微调后的模型出现能力劣化
灾难性遗忘(CatastrophicForgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
在微调大语言模型时,灾难性遗忘可能出现的原因包括:
- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。
- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。
为了解决灾难性遗忘问题,可以尝试以下方法:
- 经验回放(ReplayBuffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。
- 弹性权重共享(Elastic WeightConsolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。
- 增量学习(IncrementalLearning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。
- 多任务学习(Multi-TaskLearning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。
综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
2.7 预训练和SFT操作有什么不同
大语言模型的预训练和有监督微调(SupervisedFine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
目标:
- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(MaskedLanguage Model,MLM)或下一句预测(Next SentencePrediction,NSP)等,来训练模型。
- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。
数据:
- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。
- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。
训练方式:
- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。
- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。
总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
2.8 大模型LLM进行SFT如何对样本进行优化?
对于大语言模型进行有监督微调(SupervisedFine-Tuning)时,可以采用以下几种方式对样本进行优化:
- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。
- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。
- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。
- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。
- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。
- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。
- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。
总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
3. 预训练
3.1 为什么要增量预训练?
预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
3.2进行增量预训练需要做哪些准备工作?
- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。
- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是TB 级别的。
- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。
3.3增量预训练训练流程是怎么样?
- 数据预处理:参考 LLaMA的预训练长度,也把数据处理成2048长度(如果不够,做补全)。
- 分词器:如果使用 LLaMA可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。
- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选Chat 模型。
- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。
- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。
- 模型测试:简单测试下续写能力,验证下模型是否正常。
4. Prompting工程
4.1 BitFit
4.1.1 背景
虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署,特别是随着任务数量的增加,很难维护。
理想状况下,我们希望有一种满足以下条件的高效微调方法:
- 到达能够匹配全量微调的效果。
- 仅更改一小部分模型参数。
- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。
- 改变的参数在不同下游任务中是一致的。
上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
4.1.2 技术原理
BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuningor Transformer-based MaskedLanguage-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
对于Transformer模型而言,冻结大部分 transformer-encoder参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言,只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
4.2 Prefix Tuning
4.2.1 背景
在PrefixTuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
基于上述两点,PrefixTuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的VirtualToken(Soft Prompt/ContinuousPrompt),相比离散的Token,更好优化,效果更好。
4.2.2 技术原理
Prefix Tuning(论文:Prefix-Tuning: Optimizing ContinuousPrompts forGeneration),在输入token之前构造一段任务相关的virtualtokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
针对不同的模型结构,需要构造不同的Prefix。
- 针对自回归架构模型:在句子前面添加前缀,得到
z = [PREFIX; x; y]
,合适的上文能够在固定 LM的情况下去引导生成下文(比如:GPT3的上下文学习)。 - 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder端增加前缀是为了引导后续token的生成。
该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为[PREFIX; x; y]
,Infix-tuning形式为[x; INFIX; y]
。
4.3 Prompt Tuning
4.3.1 背景
大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
基于此,作者提出了PromptTuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,训练完以后,用同一个模型可以做多任务推理。
4.3.2 技术原理
Prompt Tuning(论文:The Power of Scale forParameter-Efficient Prompt Tuning),该方法可以看作是PrefixTuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompttokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
通过实验发现,随着预训练模型参数量的增加,PromptTuning的方法会逼近全参数微调的结果。
同时,Prompt Tuning 还提出了 PromptEnsembling,也就是在一个批次(Batch)里同时训练同一个任务的不同prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
4.4 P-Tuning
4.4.1 背景
该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(incontextlearning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtualtoken(同Prefix-Tuning类似)。
4.4.2 技术原理
P-Tuning(论文:GPT Understands,Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对PromptEmbedding进行一层处理。
相比Prefix Tuning,P-Tuning加入的可微的virtualtoken,但仅限于输入层,没有在每一层都加;另外,virtualtoken的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtualtoken。
经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtualtoken,容易优化到局部最优值,而这些virtualtoken理论是应该有相关关联的。因此,作者通过实验发现用一个promptencoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtualtoken以后,再输入到模型。
从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
4.5 P-Tuning v2
4.5.1 背景
之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
第一,缺乏模型参数规模和任务通用性。
- 缺乏规模通用性:PromptTuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些NLU基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。
第二,缺少深度提示优化,在PromptTuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
- 由于序列长度的限制,可调参数的数量是有限的。
- 输入embedding对模型预测只有相对间接的影响。
考虑到这些问题,作者提出了Ptuningv2,它利用深度提示优化(如:Prefix Tuning),对PromptTuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
4.5.2 技术原理
P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can BeComparable to Fine-tuning Universally Across Scales andTasks),该方法在每一层都加入了Promptstokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
- 更多可学习的参数(从P-tuning和PromptTuning的0.01%增加到0.1%-3%),同时也足够参数高效。
- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。
具体做法基本同Prefix Tuning,可以看作是将文本生成的PrefixTuning技术适配到NLU任务中,然后做了一些改进:
- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:PrefixTuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。
- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuningv2的有益补充。
- 回归传统的分类标签范式,而不是映射器。标签词映射器(LabelWordVerbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuningv2回归传统的CLS标签分类范式,采用随机初始化的分类头(ClassificationHead)应用于tokens之上,以增强通用性,可以适配到序列标注任务。
论文中展示了P-tuningv2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),PromptTuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuningv2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuningv2在RTE中的表现明显优于微调,特别是在BERT中。
5. Adapter-Tuning
5.1 Adapter Tuning
5.1.1 背景
预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题Adapter在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
5.1.2 技术原理
Adapter Tuning(论文:Parameter-Efficient Transfer LearningforNLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的==Adapter 结构和 Layer Norm层==进行微调,从而保证了训练的高效性。
每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
5.1.3 具体细节
每个 Adapter模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skipconnection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便Adapter 一开始的参数初始化接近0,Adapter也由于skipconnection的设置而接近于一个恒等映射,从而确保训练的有效性。
\[h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p}\]
通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
5.2 AdapterFusion
5.2.1 背景
为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequentialfine-tuning)或者多任务学习(multi-tasklearning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
而之前的工作,AdapterTuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter的参数某种程度上就表达了解决这个任务需要的知识。
作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
5.2.2 技术原理
Adapter Fusion(论文:AdapterFusion:Non-Destructive TaskComposition for TransferLearning),一种融合多任务信息的Adapter的变体,在Adapter的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。
对于第一阶段,有两种训练方式,分别如下:
- Single-TaskAdapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。
- Multi-TaskAdapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。
对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
5.2.3 AdapterFusion结构
AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
5.3 AdapterDrop
5.3.1 背景
近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
基于此,作者提出了AdapterDrop方法缓解该问题。
5.3.2 技术原理
AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters inTransformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。例如,将前五个Transformer层中的Adapter丢弃,在对 8个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop也能保持良好的结果。
除此之外,作者还研究了对AdapterFusion中的Adapter进行剪枝后的效果。
通过实验表明可以移除 AdapterFusion中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
总之,AdapterDrop通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
5.4 MAM Adapter
5.4.1 背景
近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,PrefixTuning和LoRA都是性能比较好的方法。
为什么看起来Adapter、PrefixTuning、LoRA(在结构上和公式上)都不太一样,尤其是PrefixTuning,但是这三种方法有近似的效果?
基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、PrefixTuning和LoRA)的设计,并提出了一种新方法MAMAdapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
首先,作者通过对Prefix Tuning变换,发现PrefixTuning和Adapters的公式高度相似。
然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、PrefixTuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体)Parallel Adapter、 Scaled PA的结构。
下表展示了高效微调方法Adapter、PrefixTuning、LoRA以及新变体在新增可训练参数结构形式(functionalform)、结构插入形式(Insertionform)、新增结构在PLM修改的具体位置(modifiedrepresentation)、新增结构与PLM的组合函数(compositionfunction)。其中,新增可训练参数结构形式为需要学习的部分(注:PrefixTuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
5.4.2 技术原理
MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENTTRANSFER LEARNING),一个在Adapter、PrefixTuning和LoRA之间建立联系的统一方法。
作者对Adapter的放置和软提示(softprompt)进行了详细的调查。得出如下结论:
- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。
- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。
然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用FFN 层的并行Adapter和软提示的组合。
通过最终的实验结果,可以看到 MAM Adapter在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
5.5 UniPELT
5.5.1 背景
近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
5.5.2 技术原理
UniPELT(论文: UNIPELT: A Unified Framework for Parameter-EfficientLanguage Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,PrefixTuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括LoRA 矩阵WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT的性能与这些方法相当或更好。
实验还对不同 PELT 方法训练时间和推理时间进行了分析。
- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围,
- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。
- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。
6. lora
6.1 LoRA
6.1.1 背景
神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsicrank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
6.1.2 技术原理
LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGEMODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsicrank)。
可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
\[h=W_{0} x+\Delta W x=W_{0} x+B A x\]
在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
此外,Transformer的权重矩阵包括Attention模块里用于计算query
,key
,value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整Wq 和 Wv 会产生最佳结果。
实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
6.2 AdaLoRA
6.2.1 背景
在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。
- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。
为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adaptertuning、Prefix tuning、PromptTuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adaptertuning引入了推理延时;Prefix tuning或Prompttuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。
- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diffpruning、LoRA等,此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diffpruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。LoRA则需要预先指定每个增量矩阵的本征秩 r相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。
基于以上问题进行总结:
- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。
- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。
为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
6.2.2 技术原理
AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FORPARAMETEREFFICIENTFINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。
\[W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q\]
- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。
通过实验证明,AdaLoRA实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。例如,当参数预算为 0.3M 时,AdaLoRA在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
6.3 QLoRA
6.3.1 背景
微调大型语言模型 (LLM)是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU内存。
虽然最近的量化方法可以减少 LLM的内存占用,但此类技术仅适用于推理场景。
基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为4 bit的模型。
6.3.2 技术原理
QLoRA(论文: QLORA: Efficient Finetuning of QuantizedLLMs),使用一种新颖的高精度技术将预训练模型量化为 4bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA有一种低精度存储数据类型(4bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bitNormalFloat(NF4)量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
- 4bitNormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比4 bit整数和 4bit 浮点数更好的实证结果。
- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。
- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的GPU 处理。该功能的工作方式类似于 CPU内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在GPU 内存不足时将其自动卸载到 CPU内存,并在优化器更新步骤需要时将其加载回 GPU 内存。
实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
7. 微调方法总结
7.1当前高效微调技术的简述
之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
7.2 BitFit
对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
特点:
- 训练参数量极小(约0.1%)。
- 在大部分任务上效果会差于LoRA、Adapter等方法。
7.3 Prefix Tuning
在每一个Transformer层都带上一些virtualtoken作为前缀,以适应不同的任务。
特点:
- 前缀Token会占用序列长度,有一定的额外计算开销。
- Prefix Tuning的线性插值是比较复杂的。
7.4 Prompt Tuning
该方法可以看着是PrefixTuning的简化版本,针对不同的任务,仅在输入层引入virtualtoken形式的软提示(soft prompt)。
特点:
- 相对于PrefixTuning,参与训练的参数量和改变的参数量更小,更节省显存。
- 对一些简单的NLU任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。
7.5 P-Tuning
将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对PromptEmbedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtualtoken;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
特点:
- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtualtoken的相互依赖会收敛更快,效果更好。
7.6 P-Tuning v2
该方法在每一个Transformer层都加入了prompttoken作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
特点:
- 解决了Prompt Tuning无法在小模型上有效提升的问题。
- 移除了对模型效果改进较小的重参数化的编码器(如:PrefixTuning中的MLP、P-Tuning中的LSTM)。
- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。
7.7 Adapter Tuning
该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和LayerNorm 层进行微调。
特点:
- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。
7.8 AdapterFusion
一种融合多任务信息的Adapter的变体,在 Adapter的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
7.9 AdapterDrop
该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
特点:
- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
7.10 LoRA
该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
特点:
- 将BA加到W上可以消除推理延迟。
- 可以通过可插拔的形式切换到不同的任务。
- 设计的比较好,简单且效果好。
7.11 AdaLoRA
对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
7.12 QLoRA
使用一种新颖的高精度技术将预训练模型量化为 4bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
特点:
- 使用 QLoRA微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。
7.13 MAM Adapter
一种在 Adapter、Prefix Tuning 和 LoRA之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter和 软提示的组合。
特点:
- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。
7.14 UniPELT
一种将不同的PELT方法LoRA、PrefixTuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
特点:
- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。
- 多种 PELT 方法的混合涉及PLM的不同部分对模型有效性和鲁棒性都有好处
7.15 总结
本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
- 增加额外参数,如:Prefix Tuning、Prompt Tuning、AdapterTuning及其变体。
- 选取一部分参数更新,如:BitFit。
- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。
- 混合高效微调,如:MAM Adapter、UniPELT。
并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
]]>
+
+
+
+
+ 深度学习
+
+
+
+
+
+
+ 深度学习
+
+ 大语言模型
+
+
+
+
+
+
+
+
+ 【大语言模型】基础模型概念
/2024/03/08/dl_llm_model/
- 大语言模型简介
1.llm概念
1.1 主流的开源模型体系
目前主流的开源LLM(语言模型)模型体系包括以下几个:
- GPT(Generative Pre-trainedTransformer)系列:由OpenAI发布的一系列基于Transformer架构的语言模型,包括GPT、GPT-2、GPT-3等。GPT模型通过在大规模无标签文本上进行预训练,然后在特定任务上进行微调,具有很强的生成能力和语言理解能力。
- BERT(Bidirectional Encoder Representations fromTransformers):由Google发布的一种基于Transformer架构的双向预训练语言模型。BERT模型通过在大规模无标签文本上进行预训练,然后在下游任务上进行微调,具有强大的语言理解能力和表征能力。
- XLNet:由CMU和GoogleBrain发布的一种基于Transformer架构的自回归预训练语言模型。XLNet模型通过自回归方式预训练,可以建模全局依赖关系,具有更好的语言建模能力和生成能力。
- RoBERTa:由Facebook发布的一种基于Transformer架构的预训练语言模型。RoBERTa模型在BERT的基础上进行了改进,通过更大规模的数据和更长的训练时间,取得了更好的性能。
- T5(Text-to-Text TransferTransformer):由Google发布的一种基于Transformer架构的多任务预训练语言模型。T5模型通过在大规模数据集上进行预训练,可以用于多种自然语言处理任务,如文本分类、机器翻译、问答等。
这些模型在自然语言处理领域取得了显著的成果,并被广泛应用于各种任务和应用中。
1.2 prefix LM 和 causal LM区别是什么?
Prefix LM(前缀语言模型)和CausalLM(因果语言模型)是两种不同类型的语言模型,它们的区别在于生成文本的方式和训练目标。
- PrefixLM:前缀语言模型是一种生成模型,它在生成每个词时都可以考虑之前的上下文信息。在生成时,前缀语言模型会根据给定的前缀(即部分文本序列)预测下一个可能的词。这种模型可以用于文本生成、机器翻译等任务。
- CausalLM:因果语言模型是一种自回归模型,它只能根据之前的文本生成后续的文本,而不能根据后续的文本生成之前的文本。在训练时,因果语言模型的目标是预测下一个词的概率,给定之前的所有词作为上下文。这种模型可以用于文本生成、语言建模等任务。
总结来说,前缀语言模型可以根据给定的前缀生成后续的文本,而因果语言模型只能根据之前的文本生成后续的文本。它们的训练目标和生成方式略有不同,适用于不同的任务和应用场景。
1.3 大模型LLM的训练目标
大型语言模型(Large LanguageModels,LLM)的训练目标通常是最大似然估计(Maximum LikelihoodEstimation,MLE)。最大似然估计是一种统计方法,用于从给定数据中估计概率模型的参数。
在LLM的训练过程中,使用的数据通常是大量的文本语料库。训练目标是最大化模型生成训练数据中观察到的文本序列的概率。具体来说,对于每个文本序列,模型根据前面的上下文生成下一个词的条件概率分布,并通过最大化生成的词序列的概率来优化模型参数。
为了最大化似然函数,可以使用梯度下降等优化算法来更新模型参数,使得模型生成的文本序列的概率逐步提高。在训练过程中,通常会使用批量训练(batchtraining)的方法,通过每次处理一小批数据样本来进行参数更新。
1.4 涌现能力是啥原因?
大语言模型的涌现能力:现象与解释- 知乎 (zhihu.com)
涌现能力(EmergentAbility)是指模型在训练过程中能够生成出令人惊喜、创造性和新颖的内容或行为。这种能力使得模型能够超出其训练数据所提供的内容,并产生出具有创造性和独特性的输出。
涌现能力的产生可以归因于以下几个原因:
- 任务的评价指标不够平滑:因为很多任务的评价指标不够平滑,导致我们现在看到的涌现现象。如果评价指标要求很严格,要求一字不错才算对,那么Emoji_movie任务我们就会看到涌现现象的出现。但是,如果我们把问题形式换成多选题,就是给出几个候选答案,让LLM选,那么随着模型不断增大,任务效果在持续稳定变好,但涌现现象消失,如上图图右所示。这说明评价指标不够平滑,起码是一部分任务看到涌现现象的原因。
- 复杂任务 vs子任务:展现出涌现现象的任务有一个共性,就是任务往往是由多个子任务构成的复杂任务。也就是说,最终任务过于复杂,如果仔细分析,可以看出它由多个子任务构成,这时候,子任务效果往往随着模型增大,符合Scaling Law,而最终任务则体现为涌现现象。
- 用 Grokking(顿悟)来解释涌现:对于某个任务T,尽管我们看到的预训练数据总量是巨大的,但是与T相关的训练数据其实数量很少。当我们推大模型规模的时候,往往会伴随着增加预训练数据的数据量操作,这样,当模型规模达到某个点的时候,与任务T相关的数据量,突然就达到了最小要求临界点,于是我们就看到了这个任务产生了Grokking现象。
尽管涌现能力为模型带来了创造性和独特性,但也需要注意其生成的内容可能存在偏差、错误或不完整性。因此,在应用和使用涌现能力强的模型时,需要谨慎评估和验证生成的输出,以确保其质量和准确性。
1.5为何现在的大模型大部分是Decoder only结构
- 自回归生成:Decoder-only结构适用于自回归生成任务,其中模型根据先前的输入生成下一个输出。这种结构在自然语言处理任务中非常有用,如文本生成、机器翻译和对话生成等。Decoder-only结构能够利用上下文信息来生成连续的输出序列,使得生成的结果更加准确和连贯。
- 生成多样性:Decoder-only结构可以通过在训练期间使用不同的解码策略来生成多样化的结果。例如,在生成文本时,可以使用不同的采样策略(如贪婪采样或随机采样)或温度参数来调整生成的多样性。这种能力对于一些任务(如对话生成)非常重要,因为它可以产生更加有趣和多样化的回复。
- 模型训练和推理的一致性:Decoder-only结构使得模型的训练和推理过程更加一致。在训练期间,模型可以使用教师强制(teacherforcing)策略,即将真实的目标输出作为输入传递给解码器。而在推理期间,模型可以逐步生成输出,将前一个时间步的输出作为输入传递给下一个时间步。这种一致性有助于更好地控制模型的生成过程,并提高模型的稳定性和可靠性。
1.6 大模型架构介绍
LLM(Large LanguageModel,大型语言模型)是指基于大规模数据和参数量的语言模型。具体的架构可以有多种选择,以下是一种常见的大模型LLM的架构介绍:
- Transformer架构:大模型LLM常使用Transformer架构,它是一种基于自注意力机制的序列模型。Transformer架构由多个编码器层和解码器层组成,每个层都包含多头自注意力机制和前馈神经网络。这种架构可以捕捉长距离的依赖关系和语言结构,适用于处理大规模语言数据。
- 自注意力机制(Self-Attention):自注意力机制是Transformer架构的核心组件之一。它允许模型在生成每个词时,根据输入序列中的其他词来计算该词的表示。自注意力机制能够动态地为每个词分配不同的权重,从而更好地捕捉上下文信息。
- 多头注意力(Multi-HeadAttention):多头注意力是自注意力机制的一种扩展形式。它将自注意力机制应用多次,每次使用不同的权重矩阵进行计算,得到多个注意力头。多头注意力可以提供更丰富的上下文表示,增强模型的表达能力。
- 前馈神经网络(Feed-ForwardNetwork):在Transformer架构中,每个注意力层后面都有一个前馈神经网络。前馈神经网络由两个全连接层组成,通过非线性激活函数(如ReLU)进行变换。它可以对注意力层输出的表示进行进一步的映射和调整。
- 预训练和微调:大模型LLM通常采用预训练和微调的方法进行训练。预训练阶段使用大规模无标签数据,通过自监督学习等方法进行训练,使模型学习到丰富的语言知识。微调阶段使用有标签的特定任务数据,如文本生成、机器翻译等,通过有监督学习进行模型的微调和优化。
需要注意的是,大模型LLM的具体架构可能会因不同的研究和应用而有所不同。上述介绍的是一种常见的架构,但实际应用中可能会有一些变体或改进。
1.7 LLMs复读机问题
1.7.1 什么是 LLMs 复读机问题?
LLMs复读机问题(LLMs ParrotingProblem)是指大型语言模型在生成文本时过度依赖输入文本的复制,而缺乏创造性和独特性。当面对一个问题或指令时,模型可能会简单地复制输入文本的一部分或全部内容,并将其作为生成的输出,而不是提供有意义或新颖的回应。
1.7.2 为什么会出现 LLMs复读机问题?
- 数据偏差:大型语言模型通常是通过预训练阶段使用大规模无标签数据进行训练的。如果训练数据中存在大量的重复文本或者某些特定的句子或短语出现频率较高,模型在生成文本时可能会倾向于复制这些常见的模式。
- 训练目标的限制:大型语言模型的训练通常是基于自监督学习的方法,通过预测下一个词或掩盖词来学习语言模型。这样的训练目标可能使得模型更倾向于生成与输入相似的文本,导致复读机问题的出现。
- 缺乏多样性的训练数据:虽然大型语言模型可以处理大规模的数据,但如果训练数据中缺乏多样性的语言表达和语境,模型可能无法学习到足够的多样性和创造性,导致复读机问题的出现。
- 模型结构和参数设置:大型语言模型的结构和参数设置也可能对复读机问题产生影响。例如,模型的注意力机制和生成策略可能导致模型更倾向于复制输入的文本。
1.7.3 如何缓解 LLMs 复读机问题?
为了缓解LLMs复读机问题,可以尝试以下方法:
- 多样性训练数据:在训练阶段,使用多样性的语料库来训练模型,避免数据偏差和重复文本的问题。这可以包括从不同领域、不同来源和不同风格的文本中获取数据。
- 引入噪声:在生成文本时,引入一些随机性或噪声,例如通过采样不同的词或短语,或者引入随机的变换操作,以增加生成文本的多样性。这可以通过在生成过程中对模型的输出进行采样或添加随机性来实现。
- 温度参数调整:温度参数是用来控制生成文本的多样性的一个参数。通过调整温度参数的值,可以控制生成文本的独创性和多样性。较高的温度值会增加随机性,从而减少复读机问题的出现。
- Beam搜索调整:在生成文本时,可以调整Beam搜索算法的参数。Beam搜索是一种常用的生成策略,它在生成过程中维护了一个候选序列的集合。通过调整Beam大小和搜索宽度,可以控制生成文本的多样性和创造性。
- 后处理和过滤:对生成的文本进行后处理和过滤,去除重复的句子或短语,以提高生成文本的质量和多样性。可以使用文本相似度计算方法或规则来检测和去除重复的文本。
- 人工干预和控制:对于关键任务或敏感场景,可以引入人工干预和控制机制,对生成的文本进行审查和筛选,确保生成结果的准确性和多样性。
需要注意的是,缓解LLMs复读机问题是一个复杂的任务,没有一种通用的解决方案。不同的方法可能适用于不同的场景和任务,需要根据具体情况进行选择和调整。此外,解决复读机问题还需要综合考虑数据、训练目标、模型架构和生成策略等多个因素,需要进一步的研究和实践来提高大型语言模型的生成文本多样性和创造性。
1.8LLMs输入句子长度理论上可以无限长吗?
理论上来说,LLMs(大型语言模型)可以处理任意长度的输入句子,但实际上存在一些限制和挑战。下面是一些相关的考虑因素:
- 计算资源:生成长句子需要更多的计算资源,包括内存和计算时间。由于LLMs通常是基于神经网络的模型,计算长句子可能会导致内存不足或计算时间过长的问题。
- 模型训练和推理:训练和推理长句子可能会面临一些挑战。在训练阶段,处理长句子可能会导致梯度消失或梯度爆炸的问题,影响模型的收敛性和训练效果。在推理阶段,生成长句子可能会增加模型的错误率和生成时间。
- 上下文建模:LLMs是基于上下文建模的模型,长句子的上下文可能会更加复杂和深层。模型需要能够捕捉长句子中的语义和语法结构,以生成准确和连贯的文本。
1.9如何让大模型处理更长的文本?
要让大模型处理更长的文本,可以考虑以下几个方法:
- 分块处理:将长文本分割成较短的片段,然后逐个片段输入模型进行处理。这样可以避免长文本对模型内存和计算资源的压力。在处理分块文本时,可以使用重叠的方式,即将相邻片段的一部分重叠,以保持上下文的连贯性。
- 层次建模:通过引入层次结构,将长文本划分为更小的单元。例如,可以将文本分为段落、句子或子句等层次,然后逐层输入模型进行处理。这样可以减少每个单元的长度,提高模型处理长文本的能力。
- 部分生成:如果只需要模型生成文本的一部分,而不是整个文本,可以只输入部分文本作为上下文,然后让模型生成所需的部分。例如,输入前一部分文本,让模型生成后续的内容。
- 注意力机制:注意力机制可以帮助模型关注输入中的重要部分,可以用于处理长文本时的上下文建模。通过引入注意力机制,模型可以更好地捕捉长文本中的关键信息。
- 模型结构优化:通过优化模型结构和参数设置,可以提高模型处理长文本的能力。例如,可以增加模型的层数或参数量,以增加模型的表达能力。还可以使用更高效的模型架构,如Transformer等,以提高长文本的处理效率。
需要注意的是,处理长文本时还需考虑计算资源和时间的限制。较长的文本可能需要更多的内存和计算时间,因此在实际应用中需要根据具体情况进行权衡和调整。
2.LLama系列模型
2.1LLama
2.1.1 简介
LLaMA 所采用的 Transformer 结构和细节,与标准的 Transformer架构不同的地方包括采用了前置层归一化(Pre-normalization)并使用RMSNorm 归一化函数 (NormalizingFunction)、激活函数更换为SwiGLU,并使用了旋转位置嵌入(RoP),整体Transformer 架构与 GPT-2 类似。
2.1.2 RMSNorm归一化函数
为了使得模型训练过程更加稳定,GPT-2 相较于 GPT就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了RMSNorm 归一化函数。 针对输入向量a,RMSNorm 函数计算公式如下 \[R M S(a)=\sqrt{\frac{1}{n} \sum_{i=1}^{n} a_{i}^{2}}\]
\[\bar{a}_{i}=\frac{a_{i}}{R M S(\boldsymbol{a})}\]
此外,RMSNorm 还可以引入可学习的缩放因子 $ g_ i $和偏移参数 \(b_i\),从而得到 \(\bar{a}_{i}=\frac{a_{i}}{\operatorname{RMS}(\boldsymbol{a})}g_{i}+b_{i}\)。 RMSNorm 在 HuggingFace Transformer库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class LlamaRMSNorm(nn.Module):
def __init__(self, hidden_size, eps=1e-6):
"""
LlamaRMSNorm is equivalent to T5LayerNorm
"""
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.variance_epsilon = eps # eps 防止取倒数之后分母为 0
def forward(self, hidden_states):
input_dtype = hidden_states.dtype
variance = hidden_states.to(torch.float32).pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) # weight 是末尾乘的可训练参数, 即 g_i
return (self.weight * hidden_states).to(input_dtype)
为什么要用RMSNorm优势在哪里?
不用计算均值,直接算一次就能得到结果
2.1.3 SwiGLU激活函数
SwiGLU激活函数是相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA中全连接层使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-ForwardNetwork)的计算公式如下:
\[\operatorname{FFN}_{\text {SwiGLU }}\left(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V},\boldsymbol{W}_{2}\right)=\operatorname{SwiGLU}(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V}) \boldsymbol{W}_{2}\]
\[\operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W},\boldsymbol{V})=\operatorname{Swish}_{\beta}(x \boldsymbol{W}) \otimes\boldsymbol{x} \boldsymbol{V}\]
\[\operatorname{Swish}_{\beta}(\boldsymbol{x})=\boldsymbol{x}\sigma(\boldsymbol{\beta} \boldsymbol{x})\]
其中,\(σ(x)\) 是 Sigmoid函数。下图给出了 Swish 激活函数在参数 \(β\) 不同取值下的形状。可以看 到当 \(β\) 趋近于 0 时,Swish 函数趋近于线性函数\(y = x\),当 $ β \(趋近于无穷大时,Swish 函数趋近于 ReLU函数,\)β$ 取值为 1 时,Swish 函数是光滑且非单调。在 HuggingFace的 Transformer 库中 Swish1 函数使用 silu 函数代替。
LLaMA中直接将FFN中的ReLU替换为SwiGLU,并将维度放缩为\((2/3) ⋅ 4d\)
2.1.4 旋转位置嵌入(RoPE)
在位置编码上,使用旋转位置嵌入(Rotary PositionalEmbeddings,RoPE)代替原有的绝对位置编码。RoPE借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给q
,k
添加绝对位置信息:
\[\tilde{\boldsymbol{q}}_{m}=f(\boldsymbol{q}, m),\tilde{\boldsymbol{k}}_{n}=f(\boldsymbol{k}, n)\]
经过上述操作后,\(\tilde{\boldsymbol{q}}_{m}\)和\(\tilde{\boldsymbol{k}}_{n}\)就带有位置m和n的绝对位置信息。
最终可以得到二维情况下用复数表示的 RoPE:
\[f(\boldsymbol{q}, m)=R_{f}(\boldsymbol{q}, m) e^{i\Theta_{f}(\boldsymbol{q}, m)}=\|\boldsymbol{q}\|e^{i(\Theta(\boldsymbol{q})+m \theta)}=\boldsymbol{q} e^{i m \theta}\]
根据复数乘法的几何意义,上述变换实际上是对应向量旋转,所以位置向量称为“旋转式位置编码”。还可以使用矩阵形式表示
\[f(\boldsymbol{q}, m)=\left(\begin{array}{cc}\cos m \theta & -\sin\cos m \theta \\ \sin m \theta & \cos m\theta\end{array}\right)\left(\begin{array}{l}\boldsymbol{q}_{0} \\\boldsymbol{q}_{1}\end{array}\right)\]
根据内积满足线性叠加的性质,任意偶数维的RoPE,都可以表示为二维情形的拼接,即:
\[f(\boldsymbol{q}, m)=\underbrace{\left(\begin{array}{ccccccc}\cos m\theta_{0} & -\sin m \theta_{0} & 0 & 0 & \cdots & 0& 0 \\ \sin m \theta_{0} & \cos m \theta_{0} & 0 & 0& \cdots & 0 & 0 \\ 0 & 0 & \cos m \theta_{1} &-\sin m \theta_{1} & \cdots & 0 & 0 \\ 0 & 0 & \sinm \theta_{1} & \cos m \theta_{1} & \cdots & 0 & 0 \\\cdots & \cdots & \cdots & \cdots & \ddots & \cdots& \cdots \\ 0 & 0 & 0 & 0 & \cdots & \cos m\theta_{d / 2-1} & -\sin m \theta_{d / 2-1} \\ 0 & 0 & 0& 0 & \cdots & \sin m \theta_{d / 2-1} & \cos m\theta_{d /2-1}\end{array}\right)}_{\boldsymbol{R}_{d}}\left(\begin{array}{c}\boldsymbol{q}_{0}\\ \boldsymbol{q}_{1} \\ \boldsymbol{q}_{2} \\ \boldsymbol{q}_{3} \\\cdots \\ \boldsymbol{q}_{d-2} \\ \boldsymbol{q}_{d-1}\end{array}\right)\]
RoPE 在 HuggingFace Transformer 库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import torch
def precompute_freqs_cis(dim: int, end: int, constant: float = 10000.0):
'''
计算cos和sin的值,cos值在实部,sin值在虚部,类似于 cosx+j*sinx
:param dim: q,k,v的最后一维,一般为emb_dim/head_num
:param end: 句长length
:param constant: 这里指10000
:return:
复数计算 torch.polar(a, t)输出, a*(cos(t)+j*sin(t))
'''
# freqs: 计算 1/(10000^(2i/d) ),将结果作为参数theta
# 形式化为 [theta_0, theta_1, ..., theta_(d/2-1)]
freqs = 1.0 / (constant ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) # [d/2]
# 计算m
t = torch.arange(end, device=freqs.device) # [length]
# 计算m*theta
freqs = torch.outer(t, freqs).float() # [length, d/2]
# freqs形式化为 [m*theta_0, m*theta_1, ..., m*theta_(d/2-1)],其中 m=0,1,...,length-1
# 计算cos(m*theta)+j*sin(m*theta)
freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64
# freqs_cis: [cos(m*theta_0)+j*sin(m*theta_0), cos(m*theta_1)+j*sin(m*theta_1),), ..., cos(m*theta_(d/2-1))+j*sin(m*theta_(d/2-1))]
# 其中j为虚数单位, m=0,1,...,length-1
return freqs_cis # [length, d/2]
def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
ndim = x.ndim
assert 0 <= 1 < ndim
assert freqs_cis.shape == (x.shape[1], x.shape[-1])
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] # (1, length, 1, d/2)
return freqs_cis.view(*shape) # [1, length, 1, d/2]
def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor,):
# 先将xq维度变为[bs, length, head, d/2, 2], 利用torch.view_as_complex转变为复数
# xq:[q0, q1, .., q(d-1)] 转变为 xq_: [q0+j*q1, q2+j*q3, ..., q(d-2)+j*q(d-1)]
xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [bs, length, head, d/2]
# 同样的,xk_:[k0+j*k1, k2+j*k3, ..., k(d-2)+j*k(d-1)]
xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
freqs_cis = reshape_for_broadcast(freqs_cis, xq_) # [1, length, 1, d/2]
# 下式xq_ * freqs_cis形式化输出,以第一个为例, 如下
# (q0+j*q1)(cos(m*theta_0)+j*sin(m*theta_0)) = q0*cos(m*theta_0)-q1*sin(m*theta_0) + j*(q1*cos(m*theta_0)+q0*sin(m*theta_0))
# 上式的实部为q0*cos(m*theta_0)-q1*sin(m*theta_0),虚部为q1*cos(m*theta_0)+q0*sin(m*theta_0)
# 然后通过torch.view_as_real函数,取出实部和虚部,维度由[bs, length, head, d/2]变为[bs, length, head, d/2, 2],最后一维放实部与虚部
# 最后经flatten函数将维度拉平,即[bs, length, head, d]
# 此时xq_out形式化为 [实部0,虚部0,实部1,虚部1,..., 实部(d/2-1), 虚部(d/2-1)]
xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3) # [bs, length, head, d]
# 即为新生成的q
xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
return xq_out.type_as(xq), xk_out.type_as(xk)
if __name__=='__main__':
# (bs, length, head, d)
q = torch.randn((2, 10, 12, 32)) # q=[q0, q1, .., qd-1]
k = torch.randn((2, 10, 12, 32))
v = torch.randn((2, 10, 12, 32))
freqs_cis= precompute_freqs_cis(dim=32, end=10, constant= 10000.0)
# print(freqs_cis.detach().numpy())
q_new, k_new = apply_rotary_emb(xq=q, xk=k, freqs_cis=freqs_cis)
print()
1.2 Alpaca
1.2.1 简介
Stanford Alpaca: An Instruction-following LLaMA Model
Alpaca是在LLaMA基础上使用52K指令数据精调的预训练模型,作者只用了不到600美元的成本训练出了该模型(数据$500+ 机器$100)。初步实验结果表明Alpaca可以达到与OpenAItext-davinci-003相匹敌的效果
1.2.2 微调方法
- 第一步:构造175条self-instruct 种子示例任务
- 第二步:基于上述种子任务,利 用text-davinci-003爬取指令数据
- 第三步:使用爬取下来的52K指令 数据在LLaMA上进行精调,最终得到Alpaca
1.2.3 Self-instruct数据构造
首先由人工构造175条种子数据
1
2
3
4
5
6
7
{
"id": "seed_task_25",
"name": "perfect_numbers",
"instruction": "Find the four smallest perfect numbers.",
"instances": [{ "input": "", "output": "6, 28, 496, and 8128”}],
"is_classification": false
}
将“爬取要求”和种子数据进行适当组合,送入textdavinci-003,要求生成类似的指令数据。要求包括:提升指令多样性、包含真实数据、字数要求、语言要求、拒绝不合适指令等
1.2.4 指令数据格式
instruction
: 描述模型需要执行的指令内容input
(可选):任务上下文或输入信息,例如当指令是“对文章进行总结”,则input是文章内容output
: 由text-davinci-003生成的针对指令的回复
1.3.Llama-2
1.3.1 简介
Llama 2: Open Foundation and Fine-Tuned Chat Models
2023年7月,Meta推出了Llama-2开源大模型,并且推出了Llama-2-Chat对话模型
与一代LLaMA主要区别体现在更多的训练数据、更⻓的上下文窗口、GQA技术等
二次分发是什么?
模型结构的变动主要是体现在GQA和FFN缩放上
- MHA改成GQA:整体参数量会有减少
- FFN模块矩阵维度有扩充:增强泛化能力,整体参数量增加
- 上下文长度是llama两倍(长度从2048->4096)训练语料增加约 40%,体现在1.4T->2.0T的Tokensllama2-34B和llama2-70B使用了GQA,加速模型训练和推理速度
1.3.2 GQA
GQA和MQA都是注意力的变体,其中多个查询头关注相同的键和值头,以减少推理过程中KV 缓存的大小,并可以显著提高推理吞吐量。
MHA、GQA、MQA的区别和联系,具体的优点如下:
Mutil-Head Attention
因为自回归模型生成回答时,需要前面生成的KV缓存起来,来加速计算。Multi-Query Attention
多个头之间可以共享KV对,因此速度上非常有优势,实验验证大约减少30-40%吞吐。Group Query Attention
没有像MQA那么极端,将query分组,组内共享KV,效果接近MQA,速度上与MQA可比较。
Llama-2中使用了8个KV映射,即GQA-8,GQA在多数任务上与MHA效果相当,且平均效果优于MQA;GQA和MQA均比MHA有更好的吞吐量
1.3.3 源码
2.ChatGLM
2.1 背景
主流的预训练框架主要有三种:
- autoregressive自回归模型(AR模型):代表作GPT。本质上是一个left-to-right的语言模型。通常用于生成式任务,在长文本生成方面取得了巨大的成功,比如自然语言生成(NLG)领域的任务:摘要、翻译或抽象问答。当扩展到十亿级别参数时,表现出了少样本学习能力。缺点是单向注意力机制,在NLU任务中,无法完全捕捉上下文的依赖关系。
- autoencoding自编码模型(AE模型):代表作BERT。是通过某个降噪目标(比如MLM)训练的双向文本编码器。编码器会产出适用于NLU任务的上下文表示,但无法直接用于文本生成。
- encoder-decoder(Seq2seq模型):代表作T5。采用双向注意力机制,通常用于条件生成任务,比如文本摘要、机器翻译等。
三种预训练框架各有利弊,没有一种框架在以下三种领域的表现最佳:自然语言理解(NLU)、无条件生成以及条件生成。T5曾经尝试使用MTL的方式统一上述框架,然而自编码和自回归目标天然存在差异,简单的融合自然无法继承各个框架的优点。
在这个天下三分的僵持局面下,GLM诞生了。
GLM模型基于autoregressive blankinfilling方法,结合了上述三种预训练模型的思想。
2.2 GLM预训练框架
GLM特点
- 自编码思想:在输入文本中,随机删除连续的tokens。
- 自回归思想:顺序重建连续tokens。在使用自回归方式预测缺失tokens时,模型既可以访问corrupted文本,又可以访问之前已经被预测的spans。
- span shuffling + 二维位置编码技术。
- 通过改变缺失spans的数量和长度,自回归空格填充目标可以为条件生成以及无条件生成任务预训练语言模型。
2.2.1 自回归空格填充任务
给定一个输入文本\(x=\left[x_{1}, \ldotsx_{n}\right]\),可以采样得到多个文本spans \(\left\{s_{1}, \ldotss_{m}\right\}\)。为了充分捕捉各spans之间的相互依赖关系,可以对spans的顺序进行随机排列,得到所有可能的排列集合\(Z_m\),其中:\(S_{z<i}=\left[s_{z_{1}}, \ldots,s_{z_{i-1}}\right]\)。所以预训练目标很清晰:
\[\max _{\theta} \mathbb{E}_{\boldsymbol{z} \simZ_{m}}\left[\sum_{i=1}^{m} \log p_{\theta}\left(\boldsymbol{s}_{z_{i}}\mid \boldsymbol{x}_{\text {corrupt }},\boldsymbol{s}_{\boldsymbol{z}_{<i}}\right)\right]\]
GLM自回归空格填充任务的技术细节:
- 输入\(x\)可以被分成两部分:PartA是被mask的文本 \(x_{\text {corrupt}}\),Part B由masked spans组成。假设原始输入文本是
\([x1, x2, x3, x4, x5,x6]\),采样的两个文本片段是\([x3]\)以及\([x5,x6]\)。那么mask后的文本序列是:\(x1,x2, [M], x4, [M]\),即Part A;同时我们需要对PartB的片段进行shuffle。每个片段使用[S]
填充在开头作为输入,使用[E]
填充在末尾作为输出。 - 二维位置编码:Transformer使用位置编码来标记tokens中的绝对和相对位置。在GLM中,使用二维位置编码,第一个位置id用来标记PartA中的位置,第二个位置id用来表示跨度内部的相对位置。这两个位置id会通过embedding表被投影为两个向量,最终都会被加入到输入token的embedding表达中。
- 观察GLM中自定义attention mask的设计,非常巧妙:
- Part A中的tokens彼此可见,但是不可见B中的任意tokens。
- Part B tokens可见Part A。
- Part B tokens可见B中过去的tokens,不可见B中未来的tokens。
- 采样方式:文本片段的采样遵循泊松分布,重复采样,直到原始tokens中有15%被mask。
- 总结:模型可以自动学习双向encoder(Part A)以及单向decoder(PartB)。
2.2.2 多目标预训练
上述方法适合于NLU任务。作者希望可以训练一个既可以解决NLU任务,又具备文本生成能力的模型。因此除了空格填充目标之外,还需要增加一个生成长文本目标的任务。具体包含以下两个目标:
- 文档级别。从文档中采样一个文本片段进行mask,且片段长度为文档长度的50%~100%。这个目标用于长文本生成。
- 句子级别。限制被mask的片段必须是完整句子。多个片段需覆盖原始tokens的15%。这个目标是用于预测完整句子或者段落的seq2seq任务。
2.2.3 模型结构
GLM在原始single Transformer的基础上进行了一些修改:
- 重组了LN和残差连接的顺序;
- 使用单个线性层对输出token进行预测;
- 激活函数从ReLU换成了GeLUS。
但我觉得这部分的修改比较简单常见。核心和亮点还是空格填充任务的设计。
2.2.4 GLM微调
对于下游NLU任务来说,通常会将预训练模型产出的序列或tokens表达作为输入,使用线性分类器预测label。所以预训练与微调之间存在天然不一致。
作者按照PET的方式,将下游NLU任务重新表述为空白填充的生成任务。具体来说,比如给定一个已标注样本(x,y),将输入的文本x转换成一个包含masktoken的完形填空问题。比如,情感分类任务可以表述为:"{SENTENCE}. It’sreally [MASK]"。输出label y也同样会被映射到完形填空的答案中。“positive”和 “negative” 对应的标签就是“good” 和 “bad。
其实,预训练时,对较长的文本片段进行mask,以确保GLM的文本生成能力。但是在微调的时候,相当于将NLU任务也转换成了生成任务,这样其实是为了适应预训练的目标。但难免有一些牵强。
2.3 ChatGLM-2
2.3.1 主要创新
- 更长的上下文:基于
FlashAttention**技术,将基座模型的上下文长度(Context Length)由 ChatGLM-6B 的2K 扩展到了 32K**,并在对话阶段使用 8K的上下文长度训练。对于更长的上下文,发布了 ChatGLM2-6B-32K 模型。LongBench的测评结果表明,在等量级的开源模型中,ChatGLM2-6B-32K有着较为明显的竞争优势。 - 更强大的性能:基于 ChatGLM初代模型的开发经验,全面升级了 ChatGLM2-6B 的基座模型。ChatGLM2-6B使用了 GLM** 的混合目标函数**,经过了 1.4T中英标识符的预训练与人类偏好对齐训练,
评测结果显示,相比于初代模型,ChatGLM2-6B 在MMLU(+23%)、CEval(+33%)、GSM8K(+571%)、BBH(+60%)等数据集上的性能取得了大幅度的提升,在同尺寸开源模型中具有较强的竞争力。 - 更高效的推理:基于
Multi-Query Attention技术,ChatGLM2-6B有更高效的推理速度和更低的显存占用:在官方的模型实现下,推理速度相比初代提升了42%,INT4 量化下,6G 显存支持的对话长度由 1K 提升到了 8K。 - 更开放的协议:ChatGLM2-6B权重对学术研究完全开放,在填写
问卷进行登记后亦允许免费商业使用。
2.3.2 与ChatGLM的变化
- 使用了RoPE替换二维位置编码。这也是GLM中提出的亮点设计之一。但是目前大部分主流的LLMs都在使用RoPE,所以大势所趋。当前版本仍然采用了最初的RoPE设计,事实上现在的RoPE经过了xPOS→线性内插→NTK-AwareScaled RoPE→…若干次进化。
- Multi-QueryAttention:这是一种共享机制的Attention,相比Multi-HeadAttention,其Query部分没有区别,Key和Value可以只用一个Head。计算时,对Key和Value进行expand或者repeat操作,使它们填充到与Query一样的维度,后续计算就与Multi-HeadAttention没区别。
- Attention Mask: V1的attention mask分了2部分,PartA和Part B,Part A部分是双向Attention(代码中的
prefix_attention_mask),PartB部分是CausalAttention(原代码文件中的get_masks函数)。在V2版本,全部换成了CausalAttention,不再区分是Part A还是PartB,完全变成了decoder-only的架构。 - 多目标任务:Chat版本主要还是用的gMask生成式任务,但是在V1版本的代码还能看到mask、gMask等字样,V2已经摒弃了这些特殊token,原因与AttentionMask一致,均因为变成了decoder-only的架构,不再需要区分Part A和PartB。
2.3.3 ChatGLM-3
省流:ChatGLM2与ChatGLM3模型架构是完全一致的,ChatGLM与后继者结构不同。可见ChatGLM3相对于ChatGLM2没有模型架构上的改进。
相对于ChatGLM,ChatGLM2、ChatGLM3模型上的变化:
- 词表的大小从ChatGLM的150528缩小为65024(一个直观的体验是ChatGLM2、3加载比ChatGLM快不少)
- 位置编码从每个GLMBlock一份提升为全局一份
- SelfAttention之后的前馈网络有不同。ChatGLM用GELU(GaussianError LinearUnit)做激活;ChatGLM用Swish-1做激活。而且ChatGLM2、3应该是修正了之前的一个bug,因为GLU(GatedLinearUnit)本质上一半的入参是用来做门控制的,不需要输出到下层,所以ChatGLM2、3看起来前后维度不一致(27392->13696)反而是正确的。
3.BERT
3.1BERT用字粒度和词粒度的优缺点有哪些?
BERT可以使用字粒度(character-level)和词粒度(word-level)两种方式来进行文本表示,它们各自有优缺点:
字粒度(Character-level):
- 优点:处理未登录词(Out-of-Vocabulary,OOV):字粒度可以处理任意字符串,包括未登录词,不需要像词粒度那样遇到未登录词就忽略或使用特殊标记。对于少见词和低频词,字粒度可以学习更丰富的字符级别表示,使得模型能够更好地捕捉词汇的细粒度信息。
- 缺点:计算复杂度高:使用字粒度会导致输入序列的长度大大增加,进而增加模型的计算复杂度和内存消耗。需要更多的训练数据:字粒度模型对于少见词和低频词需要更多的训练数据来学习有效的字符级别表示,否则可能会导致过拟合。
词粒度(Word-level):
- 优点:计算效率高:使用词粒度可以大大减少输入序列的长度,从而降低模型的计算复杂度和内存消耗。学习到更加稳定的词级别表示:词粒度模型可以学习到更加稳定的词级别表示,特别是对于高频词和常见词,有更好的表示能力。
- 缺点:处理未登录词(OOV):词粒度模型无法处理未登录词,遇到未登录词时需要采用特殊处理(如使用未登录词的特殊标记或直接忽略)。对于多音字等形态复杂的词汇,可能无法准确捕捉其细粒度的信息。
3.2BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
3.3BERT用的是transformer里面的encoder还是decoder?BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
3.4为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?
BERT选择mask掉15%的词是一种经验性的选择,是原论文中的一种选择,并没有一个固定的理论依据,实际中当然可以尝试不同的比例,15%的比例是由BERT的作者在原始论文中提出,并在实验中发现对于BERT的训练效果是有效的
3.5为什么BERT在第一句前会加一个[CLS] 标志?
BERT在第一句前会加一个 [CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。为什么选它?因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。而[CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。
3.6 BERT非线性的来源在哪里?
主要来自两个地方:前馈层的gelu激活函数和self-attention。
前馈神经网络层:在BERT的Encoder中,每个自注意力层之后都跟着一个前馈神经网络层。前馈神经网络层是全连接的神经网络,通常包括一个线性变换和一个非线性的激活函数,如gelu。这样的非线性激活函数引入了非线性变换,使得模型能够学习更加复杂的特征表示。
self-attentionlayer:在自注意力层中,查询(Query)、键(Key)、值(Value)之间的点积得分会经过softmax操作,形成注意力权重,然后将这些权重与值向量相乘得到每个位置的自注意输出。这个过程中涉及了softmax操作,使得模型的计算是非线性的。
3.7BERT训练时使用的学习率 warm-up策略是怎样的?为什么要这么做?在BERT的训练中,使用了学习率warm-up策略,这是为了在训练的早期阶段增加学习率,以提高训练的稳定性和加快模型收敛。
学习率warm-up策略的具体做法是,在训练开始的若干个步骤(通常是一小部分训练数据的迭代次数)内,将学习率逐渐从一个较小的初始值增加到预定的最大学习率。在这个过程中,学习率的变化是线性的,即学习率在warm-up阶段的每个步骤按固定的步幅逐渐增加。学习率warm-up的目的是为了解决BERT在训练初期的两个问题:
- 不稳定性:在训练初期,由于模型参数的随机初始化以及模型的复杂性,模型可能处于一个较不稳定的状态。此时使用较大的学习率可能导致模型的参数变动太大,使得模型很难收敛,学习率warm-up可以在这个阶段将学习率保持较小,提高模型训练的稳定性。
- 避免过拟合:BERT模型往往需要较长的训练时间来获得高质量的表示。如果在训练的早期阶段就使用较大的学习率,可能会导致模型在训练初期就过度拟合训练数据,降低模型的泛化能力。通过学习率warm-up,在训练初期使用较小的学习率,可以避免过度拟合,等模型逐渐稳定后再使用较大的学习率进行更快的收敛。
3.8在BERT应用中,如何解决长文本问题?
在BERT应用中,处理长文本问题有以下几种常见的解决方案:
- 截断与填充:将长文本截断为固定长度或者进行填充。BERT模型的输入是一个固定长度的序列,因此当输入的文本长度超过模型的最大输入长度时,需要进行截断或者填充。通常,可以根据任务的要求,选择适当的最大长度,并对文本进行截断或者填充,使其满足模型输入的要求。
- SlidingWindow:将长文本分成多个短文本,然后分别输入BERT模型。这种方法被称为SlidingWindow技术。具体来说,将长文本按照固定的步长切分成多个片段,然后分别输入BERT模型进行处理。每个片段的输出可以进行进一步的汇总或者融合,得到最终的表示。
- HierarchicalModel:使用分层模型来处理长文本,其中底层模型用于处理短文本片段,然后将不同片段的表示进行汇总或者融合得到整个长文本的表示。这样的分层模型可以充分利用BERT模型的表示能力,同时处理长文本。
- Longformer、BigBird等模型:使用专门针对长文本的模型,如Longformer和BigBird。这些模型采用了不同的注意力机制,以处理超长序列,并且通常在处理长文本时具有更高的效率。
- Document-LevelModel:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
]]>
+ 大语言模型简介
1.llm概念
1.1 主流的开源模型体系
目前主流的开源LLM(语言模型)模型体系包括以下几个:
- GPT(Generative Pre-trainedTransformer)系列:由OpenAI发布的一系列基于Transformer架构的语言模型,包括GPT、GPT-2、GPT-3等。GPT模型通过在大规模无标签文本上进行预训练,然后在特定任务上进行微调,具有很强的生成能力和语言理解能力。
- BERT(Bidirectional Encoder Representations fromTransformers):由Google发布的一种基于Transformer架构的双向预训练语言模型。BERT模型通过在大规模无标签文本上进行预训练,然后在下游任务上进行微调,具有强大的语言理解能力和表征能力。
- XLNet:由CMU和GoogleBrain发布的一种基于Transformer架构的自回归预训练语言模型。XLNet模型通过自回归方式预训练,可以建模全局依赖关系,具有更好的语言建模能力和生成能力。
- RoBERTa:由Facebook发布的一种基于Transformer架构的预训练语言模型。RoBERTa模型在BERT的基础上进行了改进,通过更大规模的数据和更长的训练时间,取得了更好的性能。
- T5(Text-to-Text TransferTransformer):由Google发布的一种基于Transformer架构的多任务预训练语言模型。T5模型通过在大规模数据集上进行预训练,可以用于多种自然语言处理任务,如文本分类、机器翻译、问答等。
这些模型在自然语言处理领域取得了显著的成果,并被广泛应用于各种任务和应用中。
1.2 prefix LM 和 causal LM区别是什么?
Prefix LM(前缀语言模型)和CausalLM(因果语言模型)是两种不同类型的语言模型,它们的区别在于生成文本的方式和训练目标。
- PrefixLM:前缀语言模型是一种生成模型,它在生成每个词时都可以考虑之前的上下文信息。在生成时,前缀语言模型会根据给定的前缀(即部分文本序列)预测下一个可能的词。这种模型可以用于文本生成、机器翻译等任务。
- CausalLM:因果语言模型是一种自回归模型,它只能根据之前的文本生成后续的文本,而不能根据后续的文本生成之前的文本。在训练时,因果语言模型的目标是预测下一个词的概率,给定之前的所有词作为上下文。这种模型可以用于文本生成、语言建模等任务。
总结来说,前缀语言模型可以根据给定的前缀生成后续的文本,而因果语言模型只能根据之前的文本生成后续的文本。它们的训练目标和生成方式略有不同,适用于不同的任务和应用场景。
1.3 大模型LLM的训练目标
大型语言模型(Large LanguageModels,LLM)的训练目标通常是最大似然估计(Maximum LikelihoodEstimation,MLE)。最大似然估计是一种统计方法,用于从给定数据中估计概率模型的参数。
在LLM的训练过程中,使用的数据通常是大量的文本语料库。训练目标是最大化模型生成训练数据中观察到的文本序列的概率。具体来说,对于每个文本序列,模型根据前面的上下文生成下一个词的条件概率分布,并通过最大化生成的词序列的概率来优化模型参数。
为了最大化似然函数,可以使用梯度下降等优化算法来更新模型参数,使得模型生成的文本序列的概率逐步提高。在训练过程中,通常会使用批量训练(batchtraining)的方法,通过每次处理一小批数据样本来进行参数更新。
1.4 涌现能力是啥原因?
大语言模型的涌现能力:现象与解释- 知乎 (zhihu.com)
涌现能力(EmergentAbility)是指模型在训练过程中能够生成出令人惊喜、创造性和新颖的内容或行为。这种能力使得模型能够超出其训练数据所提供的内容,并产生出具有创造性和独特性的输出。
涌现能力的产生可以归因于以下几个原因:
- 任务的评价指标不够平滑:因为很多任务的评价指标不够平滑,导致我们现在看到的涌现现象。如果评价指标要求很严格,要求一字不错才算对,那么Emoji_movie任务我们就会看到涌现现象的出现。但是,如果我们把问题形式换成多选题,就是给出几个候选答案,让LLM选,那么随着模型不断增大,任务效果在持续稳定变好,但涌现现象消失,如上图图右所示。这说明评价指标不够平滑,起码是一部分任务看到涌现现象的原因。
- 复杂任务 vs子任务:展现出涌现现象的任务有一个共性,就是任务往往是由多个子任务构成的复杂任务。也就是说,最终任务过于复杂,如果仔细分析,可以看出它由多个子任务构成,这时候,子任务效果往往随着模型增大,符合Scaling Law,而最终任务则体现为涌现现象。
- 用 Grokking(顿悟)来解释涌现:对于某个任务T,尽管我们看到的预训练数据总量是巨大的,但是与T相关的训练数据其实数量很少。当我们推大模型规模的时候,往往会伴随着增加预训练数据的数据量操作,这样,当模型规模达到某个点的时候,与任务T相关的数据量,突然就达到了最小要求临界点,于是我们就看到了这个任务产生了Grokking现象。
尽管涌现能力为模型带来了创造性和独特性,但也需要注意其生成的内容可能存在偏差、错误或不完整性。因此,在应用和使用涌现能力强的模型时,需要谨慎评估和验证生成的输出,以确保其质量和准确性。
1.5为何现在的大模型大部分是Decoder only结构
- 自回归生成:Decoder-only结构适用于自回归生成任务,其中模型根据先前的输入生成下一个输出。这种结构在自然语言处理任务中非常有用,如文本生成、机器翻译和对话生成等。Decoder-only结构能够利用上下文信息来生成连续的输出序列,使得生成的结果更加准确和连贯。
- 生成多样性:Decoder-only结构可以通过在训练期间使用不同的解码策略来生成多样化的结果。例如,在生成文本时,可以使用不同的采样策略(如贪婪采样或随机采样)或温度参数来调整生成的多样性。这种能力对于一些任务(如对话生成)非常重要,因为它可以产生更加有趣和多样化的回复。
- 模型训练和推理的一致性:Decoder-only结构使得模型的训练和推理过程更加一致。在训练期间,模型可以使用教师强制(teacherforcing)策略,即将真实的目标输出作为输入传递给解码器。而在推理期间,模型可以逐步生成输出,将前一个时间步的输出作为输入传递给下一个时间步。这种一致性有助于更好地控制模型的生成过程,并提高模型的稳定性和可靠性。
1.6 大模型架构介绍
LLM(Large LanguageModel,大型语言模型)是指基于大规模数据和参数量的语言模型。具体的架构可以有多种选择,以下是一种常见的大模型LLM的架构介绍:
- Transformer架构:大模型LLM常使用Transformer架构,它是一种基于自注意力机制的序列模型。Transformer架构由多个编码器层和解码器层组成,每个层都包含多头自注意力机制和前馈神经网络。这种架构可以捕捉长距离的依赖关系和语言结构,适用于处理大规模语言数据。
- 自注意力机制(Self-Attention):自注意力机制是Transformer架构的核心组件之一。它允许模型在生成每个词时,根据输入序列中的其他词来计算该词的表示。自注意力机制能够动态地为每个词分配不同的权重,从而更好地捕捉上下文信息。
- 多头注意力(Multi-HeadAttention):多头注意力是自注意力机制的一种扩展形式。它将自注意力机制应用多次,每次使用不同的权重矩阵进行计算,得到多个注意力头。多头注意力可以提供更丰富的上下文表示,增强模型的表达能力。
- 前馈神经网络(Feed-ForwardNetwork):在Transformer架构中,每个注意力层后面都有一个前馈神经网络。前馈神经网络由两个全连接层组成,通过非线性激活函数(如ReLU)进行变换。它可以对注意力层输出的表示进行进一步的映射和调整。
- 预训练和微调:大模型LLM通常采用预训练和微调的方法进行训练。预训练阶段使用大规模无标签数据,通过自监督学习等方法进行训练,使模型学习到丰富的语言知识。微调阶段使用有标签的特定任务数据,如文本生成、机器翻译等,通过有监督学习进行模型的微调和优化。
需要注意的是,大模型LLM的具体架构可能会因不同的研究和应用而有所不同。上述介绍的是一种常见的架构,但实际应用中可能会有一些变体或改进。
1.7 LLMs复读机问题
1.7.1 什么是 LLMs 复读机问题?
LLMs复读机问题(LLMs ParrotingProblem)是指大型语言模型在生成文本时过度依赖输入文本的复制,而缺乏创造性和独特性。当面对一个问题或指令时,模型可能会简单地复制输入文本的一部分或全部内容,并将其作为生成的输出,而不是提供有意义或新颖的回应。
1.7.2 为什么会出现 LLMs复读机问题?
- 数据偏差:大型语言模型通常是通过预训练阶段使用大规模无标签数据进行训练的。如果训练数据中存在大量的重复文本或者某些特定的句子或短语出现频率较高,模型在生成文本时可能会倾向于复制这些常见的模式。
- 训练目标的限制:大型语言模型的训练通常是基于自监督学习的方法,通过预测下一个词或掩盖词来学习语言模型。这样的训练目标可能使得模型更倾向于生成与输入相似的文本,导致复读机问题的出现。
- 缺乏多样性的训练数据:虽然大型语言模型可以处理大规模的数据,但如果训练数据中缺乏多样性的语言表达和语境,模型可能无法学习到足够的多样性和创造性,导致复读机问题的出现。
- 模型结构和参数设置:大型语言模型的结构和参数设置也可能对复读机问题产生影响。例如,模型的注意力机制和生成策略可能导致模型更倾向于复制输入的文本。
1.7.3 如何缓解 LLMs 复读机问题?
为了缓解LLMs复读机问题,可以尝试以下方法:
- 多样性训练数据:在训练阶段,使用多样性的语料库来训练模型,避免数据偏差和重复文本的问题。这可以包括从不同领域、不同来源和不同风格的文本中获取数据。
- 引入噪声:在生成文本时,引入一些随机性或噪声,例如通过采样不同的词或短语,或者引入随机的变换操作,以增加生成文本的多样性。这可以通过在生成过程中对模型的输出进行采样或添加随机性来实现。
- 温度参数调整:温度参数是用来控制生成文本的多样性的一个参数。通过调整温度参数的值,可以控制生成文本的独创性和多样性。较高的温度值会增加随机性,从而减少复读机问题的出现。
- Beam搜索调整:在生成文本时,可以调整Beam搜索算法的参数。Beam搜索是一种常用的生成策略,它在生成过程中维护了一个候选序列的集合。通过调整Beam大小和搜索宽度,可以控制生成文本的多样性和创造性。
- 后处理和过滤:对生成的文本进行后处理和过滤,去除重复的句子或短语,以提高生成文本的质量和多样性。可以使用文本相似度计算方法或规则来检测和去除重复的文本。
- 人工干预和控制:对于关键任务或敏感场景,可以引入人工干预和控制机制,对生成的文本进行审查和筛选,确保生成结果的准确性和多样性。
需要注意的是,缓解LLMs复读机问题是一个复杂的任务,没有一种通用的解决方案。不同的方法可能适用于不同的场景和任务,需要根据具体情况进行选择和调整。此外,解决复读机问题还需要综合考虑数据、训练目标、模型架构和生成策略等多个因素,需要进一步的研究和实践来提高大型语言模型的生成文本多样性和创造性。
1.8LLMs输入句子长度理论上可以无限长吗?
理论上来说,LLMs(大型语言模型)可以处理任意长度的输入句子,但实际上存在一些限制和挑战。下面是一些相关的考虑因素:
- 计算资源:生成长句子需要更多的计算资源,包括内存和计算时间。由于LLMs通常是基于神经网络的模型,计算长句子可能会导致内存不足或计算时间过长的问题。
- 模型训练和推理:训练和推理长句子可能会面临一些挑战。在训练阶段,处理长句子可能会导致梯度消失或梯度爆炸的问题,影响模型的收敛性和训练效果。在推理阶段,生成长句子可能会增加模型的错误率和生成时间。
- 上下文建模:LLMs是基于上下文建模的模型,长句子的上下文可能会更加复杂和深层。模型需要能够捕捉长句子中的语义和语法结构,以生成准确和连贯的文本。
1.9如何让大模型处理更长的文本?
要让大模型处理更长的文本,可以考虑以下几个方法:
- 分块处理:将长文本分割成较短的片段,然后逐个片段输入模型进行处理。这样可以避免长文本对模型内存和计算资源的压力。在处理分块文本时,可以使用重叠的方式,即将相邻片段的一部分重叠,以保持上下文的连贯性。
- 层次建模:通过引入层次结构,将长文本划分为更小的单元。例如,可以将文本分为段落、句子或子句等层次,然后逐层输入模型进行处理。这样可以减少每个单元的长度,提高模型处理长文本的能力。
- 部分生成:如果只需要模型生成文本的一部分,而不是整个文本,可以只输入部分文本作为上下文,然后让模型生成所需的部分。例如,输入前一部分文本,让模型生成后续的内容。
- 注意力机制:注意力机制可以帮助模型关注输入中的重要部分,可以用于处理长文本时的上下文建模。通过引入注意力机制,模型可以更好地捕捉长文本中的关键信息。
- 模型结构优化:通过优化模型结构和参数设置,可以提高模型处理长文本的能力。例如,可以增加模型的层数或参数量,以增加模型的表达能力。还可以使用更高效的模型架构,如Transformer等,以提高长文本的处理效率。
需要注意的是,处理长文本时还需考虑计算资源和时间的限制。较长的文本可能需要更多的内存和计算时间,因此在实际应用中需要根据具体情况进行权衡和调整。
2.LLama系列模型
2.1LLama
2.1.1 简介
LLaMA 所采用的 Transformer 结构和细节,与标准的 Transformer架构不同的地方包括采用了前置层归一化(Pre-normalization)并使用RMSNorm 归一化函数 (NormalizingFunction)、激活函数更换为SwiGLU,并使用了旋转位置嵌入(RoP),整体Transformer 架构与 GPT-2 类似。
2.1.2 RMSNorm归一化函数
为了使得模型训练过程更加稳定,GPT-2 相较于 GPT就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了RMSNorm 归一化函数。 针对输入向量a,RMSNorm 函数计算公式如下 \[R M S(a)=\sqrt{\frac{1}{n} \sum_{i=1}^{n} a_{i}^{2}}\]
\[\bar{a}_{i}=\frac{a_{i}}{R M S(\boldsymbol{a})}\]
此外,RMSNorm 还可以引入可学习的缩放因子 $ g_ i $和偏移参数 \(b_i\),从而得到 \(\bar{a}_{i}=\frac{a_{i}}{\operatorname{RMS}(\boldsymbol{a})}g_{i}+b_{i}\)。 RMSNorm 在 HuggingFace Transformer库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class LlamaRMSNorm(nn.Module):
def __init__(self, hidden_size, eps=1e-6):
"""
LlamaRMSNorm is equivalent to T5LayerNorm
"""
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.variance_epsilon = eps # eps 防止取倒数之后分母为 0
def forward(self, hidden_states):
input_dtype = hidden_states.dtype
variance = hidden_states.to(torch.float32).pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) # weight 是末尾乘的可训练参数, 即 g_i
return (self.weight * hidden_states).to(input_dtype)
为什么要用RMSNorm优势在哪里?
不用计算均值,直接算一次就能得到结果
2.1.3 SwiGLU激活函数
SwiGLU激活函数是相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA中全连接层使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-ForwardNetwork)的计算公式如下:
\[\operatorname{FFN}_{\text {SwiGLU }}\left(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V},\boldsymbol{W}_{2}\right)=\operatorname{SwiGLU}(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V}) \boldsymbol{W}_{2}\]
\[\operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W},\boldsymbol{V})=\operatorname{Swish}_{\beta}(x \boldsymbol{W}) \otimes\boldsymbol{x} \boldsymbol{V}\]
\[\operatorname{Swish}_{\beta}(\boldsymbol{x})=\boldsymbol{x}\sigma(\boldsymbol{\beta} \boldsymbol{x})\]
其中,\(σ(x)\) 是 Sigmoid函数。下图给出了 Swish 激活函数在参数 \(β\) 不同取值下的形状。可以看 到当 \(β\) 趋近于 0 时,Swish 函数趋近于线性函数\(y = x\),当 $ β \(趋近于无穷大时,Swish 函数趋近于 ReLU函数,\)β$ 取值为 1 时,Swish 函数是光滑且非单调。在 HuggingFace的 Transformer 库中 Swish1 函数使用 silu 函数代替。
LLaMA中直接将FFN中的ReLU替换为SwiGLU,并将维度放缩为\((2/3) ⋅ 4d\)
2.1.4 旋转位置嵌入(RoPE)
在位置编码上,使用旋转位置嵌入(Rotary PositionalEmbeddings,RoPE)代替原有的绝对位置编码。RoPE借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给q
,k
添加绝对位置信息:
\[\tilde{\boldsymbol{q}}_{m}=f(\boldsymbol{q}, m),\tilde{\boldsymbol{k}}_{n}=f(\boldsymbol{k}, n)\]
经过上述操作后,\(\tilde{\boldsymbol{q}}_{m}\)和\(\tilde{\boldsymbol{k}}_{n}\)就带有位置m和n的绝对位置信息。
最终可以得到二维情况下用复数表示的 RoPE:
\[f(\boldsymbol{q}, m)=R_{f}(\boldsymbol{q}, m) e^{i\Theta_{f}(\boldsymbol{q}, m)}=\|\boldsymbol{q}\|e^{i(\Theta(\boldsymbol{q})+m \theta)}=\boldsymbol{q} e^{i m \theta}\]
根据复数乘法的几何意义,上述变换实际上是对应向量旋转,所以位置向量称为“旋转式位置编码”。还可以使用矩阵形式表示
\[f(\boldsymbol{q}, m)=\left(\begin{array}{cc}\cos m \theta & -\sin\cos m \theta \\ \sin m \theta & \cos m\theta\end{array}\right)\left(\begin{array}{l}\boldsymbol{q}_{0} \\\boldsymbol{q}_{1}\end{array}\right)\]
根据内积满足线性叠加的性质,任意偶数维的RoPE,都可以表示为二维情形的拼接,即:
\[f(\boldsymbol{q}, m)=\underbrace{\left(\begin{array}{ccccccc}\cos m\theta_{0} & -\sin m \theta_{0} & 0 & 0 & \cdots & 0& 0 \\ \sin m \theta_{0} & \cos m \theta_{0} & 0 & 0& \cdots & 0 & 0 \\ 0 & 0 & \cos m \theta_{1} &-\sin m \theta_{1} & \cdots & 0 & 0 \\ 0 & 0 & \sinm \theta_{1} & \cos m \theta_{1} & \cdots & 0 & 0 \\\cdots & \cdots & \cdots & \cdots & \ddots & \cdots& \cdots \\ 0 & 0 & 0 & 0 & \cdots & \cos m\theta_{d / 2-1} & -\sin m \theta_{d / 2-1} \\ 0 & 0 & 0& 0 & \cdots & \sin m \theta_{d / 2-1} & \cos m\theta_{d /2-1}\end{array}\right)}_{\boldsymbol{R}_{d}}\left(\begin{array}{c}\boldsymbol{q}_{0}\\ \boldsymbol{q}_{1} \\ \boldsymbol{q}_{2} \\ \boldsymbol{q}_{3} \\\cdots \\ \boldsymbol{q}_{d-2} \\ \boldsymbol{q}_{d-1}\end{array}\right)\]
RoPE 在 HuggingFace Transformer 库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import torch
def precompute_freqs_cis(dim: int, end: int, constant: float = 10000.0):
'''
计算cos和sin的值,cos值在实部,sin值在虚部,类似于 cosx+j*sinx
:param dim: q,k,v的最后一维,一般为emb_dim/head_num
:param end: 句长length
:param constant: 这里指10000
:return:
复数计算 torch.polar(a, t)输出, a*(cos(t)+j*sin(t))
'''
# freqs: 计算 1/(10000^(2i/d) ),将结果作为参数theta
# 形式化为 [theta_0, theta_1, ..., theta_(d/2-1)]
freqs = 1.0 / (constant ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) # [d/2]
# 计算m
t = torch.arange(end, device=freqs.device) # [length]
# 计算m*theta
freqs = torch.outer(t, freqs).float() # [length, d/2]
# freqs形式化为 [m*theta_0, m*theta_1, ..., m*theta_(d/2-1)],其中 m=0,1,...,length-1
# 计算cos(m*theta)+j*sin(m*theta)
freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64
# freqs_cis: [cos(m*theta_0)+j*sin(m*theta_0), cos(m*theta_1)+j*sin(m*theta_1),), ..., cos(m*theta_(d/2-1))+j*sin(m*theta_(d/2-1))]
# 其中j为虚数单位, m=0,1,...,length-1
return freqs_cis # [length, d/2]
def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
ndim = x.ndim
assert 0 <= 1 < ndim
assert freqs_cis.shape == (x.shape[1], x.shape[-1])
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] # (1, length, 1, d/2)
return freqs_cis.view(*shape) # [1, length, 1, d/2]
def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor,):
# 先将xq维度变为[bs, length, head, d/2, 2], 利用torch.view_as_complex转变为复数
# xq:[q0, q1, .., q(d-1)] 转变为 xq_: [q0+j*q1, q2+j*q3, ..., q(d-2)+j*q(d-1)]
xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [bs, length, head, d/2]
# 同样的,xk_:[k0+j*k1, k2+j*k3, ..., k(d-2)+j*k(d-1)]
xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
freqs_cis = reshape_for_broadcast(freqs_cis, xq_) # [1, length, 1, d/2]
# 下式xq_ * freqs_cis形式化输出,以第一个为例, 如下
# (q0+j*q1)(cos(m*theta_0)+j*sin(m*theta_0)) = q0*cos(m*theta_0)-q1*sin(m*theta_0) + j*(q1*cos(m*theta_0)+q0*sin(m*theta_0))
# 上式的实部为q0*cos(m*theta_0)-q1*sin(m*theta_0),虚部为q1*cos(m*theta_0)+q0*sin(m*theta_0)
# 然后通过torch.view_as_real函数,取出实部和虚部,维度由[bs, length, head, d/2]变为[bs, length, head, d/2, 2],最后一维放实部与虚部
# 最后经flatten函数将维度拉平,即[bs, length, head, d]
# 此时xq_out形式化为 [实部0,虚部0,实部1,虚部1,..., 实部(d/2-1), 虚部(d/2-1)]
xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3) # [bs, length, head, d]
# 即为新生成的q
xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
return xq_out.type_as(xq), xk_out.type_as(xk)
if __name__=='__main__':
# (bs, length, head, d)
q = torch.randn((2, 10, 12, 32)) # q=[q0, q1, .., qd-1]
k = torch.randn((2, 10, 12, 32))
v = torch.randn((2, 10, 12, 32))
freqs_cis= precompute_freqs_cis(dim=32, end=10, constant= 10000.0)
# print(freqs_cis.detach().numpy())
q_new, k_new = apply_rotary_emb(xq=q, xk=k, freqs_cis=freqs_cis)
print()
1.2 Alpaca
1.2.1 简介
Stanford Alpaca: An Instruction-following LLaMA Model
Alpaca是在LLaMA基础上使用52K指令数据精调的预训练模型,作者只用了不到600美元的成本训练出了该模型(数据$500+ 机器$100)。初步实验结果表明Alpaca可以达到与OpenAItext-davinci-003相匹敌的效果
1.2.2 微调方法
- 第一步:构造175条self-instruct 种子示例任务
- 第二步:基于上述种子任务,利 用text-davinci-003爬取指令数据
- 第三步:使用爬取下来的52K指令 数据在LLaMA上进行精调,最终得到Alpaca
1.2.3 Self-instruct数据构造
首先由人工构造175条种子数据
1
2
3
4
5
6
7
{
"id": "seed_task_25",
"name": "perfect_numbers",
"instruction": "Find the four smallest perfect numbers.",
"instances": [{ "input": "", "output": "6, 28, 496, and 8128”}],
"is_classification": false
}
将“爬取要求”和种子数据进行适当组合,送入textdavinci-003,要求生成类似的指令数据。要求包括:提升指令多样性、包含真实数据、字数要求、语言要求、拒绝不合适指令等
1.2.4 指令数据格式
instruction
: 描述模型需要执行的指令内容input
(可选):任务上下文或输入信息,例如当指令是“对文章进行总结”,则input是文章内容output
: 由text-davinci-003生成的针对指令的回复
1.3.Llama-2
1.3.1 简介
Llama 2: Open Foundation and Fine-Tuned Chat Models
2023年7月,Meta推出了Llama-2开源大模型,并且推出了Llama-2-Chat对话模型
与一代LLaMA主要区别体现在更多的训练数据、更⻓的上下文窗口、GQA技术等
二次分发是什么?
模型结构的变动主要是体现在GQA和FFN缩放上
- MHA改成GQA:整体参数量会有减少
- FFN模块矩阵维度有扩充:增强泛化能力,整体参数量增加
- 上下文长度是llama两倍(长度从2048->4096)训练语料增加约 40%,体现在1.4T->2.0T的Tokensllama2-34B和llama2-70B使用了GQA,加速模型训练和推理速度
1.3.2 GQA
GQA和MQA都是注意力的变体,其中多个查询头关注相同的键和值头,以减少推理过程中KV 缓存的大小,并可以显著提高推理吞吐量。
MHA、GQA、MQA的区别和联系,具体的优点如下:
Mutil-Head Attention
因为自回归模型生成回答时,需要前面生成的KV缓存起来,来加速计算。Multi-Query Attention
多个头之间可以共享KV对,因此速度上非常有优势,实验验证大约减少30-40%吞吐。Group Query Attention
没有像MQA那么极端,将query分组,组内共享KV,效果接近MQA,速度上与MQA可比较。
Llama-2中使用了8个KV映射,即GQA-8,GQA在多数任务上与MHA效果相当,且平均效果优于MQA;GQA和MQA均比MHA有更好的吞吐量
1.3.3 源码
2.ChatGLM
2.1 背景
主流的预训练框架主要有三种:
- autoregressive自回归模型(AR模型):代表作GPT。本质上是一个left-to-right的语言模型。通常用于生成式任务,在长文本生成方面取得了巨大的成功,比如自然语言生成(NLG)领域的任务:摘要、翻译或抽象问答。当扩展到十亿级别参数时,表现出了少样本学习能力。缺点是单向注意力机制,在NLU任务中,无法完全捕捉上下文的依赖关系。
- autoencoding自编码模型(AE模型):代表作BERT。是通过某个降噪目标(比如MLM)训练的双向文本编码器。编码器会产出适用于NLU任务的上下文表示,但无法直接用于文本生成。
- encoder-decoder(Seq2seq模型):代表作T5。采用双向注意力机制,通常用于条件生成任务,比如文本摘要、机器翻译等。
三种预训练框架各有利弊,没有一种框架在以下三种领域的表现最佳:自然语言理解(NLU)、无条件生成以及条件生成。T5曾经尝试使用MTL的方式统一上述框架,然而自编码和自回归目标天然存在差异,简单的融合自然无法继承各个框架的优点。
在这个天下三分的僵持局面下,GLM诞生了。
GLM模型基于autoregressive blankinfilling方法,结合了上述三种预训练模型的思想。
2.2 GLM预训练框架
GLM特点
- 自编码思想:在输入文本中,随机删除连续的tokens。
- 自回归思想:顺序重建连续tokens。在使用自回归方式预测缺失tokens时,模型既可以访问corrupted文本,又可以访问之前已经被预测的spans。
- span shuffling + 二维位置编码技术。
- 通过改变缺失spans的数量和长度,自回归空格填充目标可以为条件生成以及无条件生成任务预训练语言模型。
2.2.1 自回归空格填充任务
给定一个输入文本\(x=\left[x_{1}, \ldotsx_{n}\right]\),可以采样得到多个文本spans \(\left\{s_{1}, \ldotss_{m}\right\}\)。为了充分捕捉各spans之间的相互依赖关系,可以对spans的顺序进行随机排列,得到所有可能的排列集合\(Z_m\),其中:\(S_{z<i}=\left[s_{z_{1}}, \ldots,s_{z_{i-1}}\right]\)。所以预训练目标很清晰:
\[\max _{\theta} \mathbb{E}_{\boldsymbol{z} \simZ_{m}}\left[\sum_{i=1}^{m} \log p_{\theta}\left(\boldsymbol{s}_{z_{i}}\mid \boldsymbol{x}_{\text {corrupt }},\boldsymbol{s}_{\boldsymbol{z}_{<i}}\right)\right]\]
GLM自回归空格填充任务的技术细节:
- 输入\(x\)可以被分成两部分:PartA是被mask的文本 \(x_{\text {corrupt}}\),Part B由masked spans组成。假设原始输入文本是
\([x1, x2, x3, x4, x5,x6]\),采样的两个文本片段是\([x3]\)以及\([x5,x6]\)。那么mask后的文本序列是:\(x1,x2, [M], x4, [M]\),即Part A;同时我们需要对PartB的片段进行shuffle。每个片段使用[S]
填充在开头作为输入,使用[E]
填充在末尾作为输出。 - 二维位置编码:Transformer使用位置编码来标记tokens中的绝对和相对位置。在GLM中,使用二维位置编码,第一个位置id用来标记PartA中的位置,第二个位置id用来表示跨度内部的相对位置。这两个位置id会通过embedding表被投影为两个向量,最终都会被加入到输入token的embedding表达中。
- 观察GLM中自定义attention mask的设计,非常巧妙:
- Part A中的tokens彼此可见,但是不可见B中的任意tokens。
- Part B tokens可见Part A。
- Part B tokens可见B中过去的tokens,不可见B中未来的tokens。
- 采样方式:文本片段的采样遵循泊松分布,重复采样,直到原始tokens中有15%被mask。
- 总结:模型可以自动学习双向encoder(Part A)以及单向decoder(PartB)。
2.2.2 多目标预训练
上述方法适合于NLU任务。作者希望可以训练一个既可以解决NLU任务,又具备文本生成能力的模型。因此除了空格填充目标之外,还需要增加一个生成长文本目标的任务。具体包含以下两个目标:
- 文档级别。从文档中采样一个文本片段进行mask,且片段长度为文档长度的50%~100%。这个目标用于长文本生成。
- 句子级别。限制被mask的片段必须是完整句子。多个片段需覆盖原始tokens的15%。这个目标是用于预测完整句子或者段落的seq2seq任务。
2.2.3 模型结构
GLM在原始single Transformer的基础上进行了一些修改:
- 重组了LN和残差连接的顺序;
- 使用单个线性层对输出token进行预测;
- 激活函数从ReLU换成了GeLUS。
但我觉得这部分的修改比较简单常见。核心和亮点还是空格填充任务的设计。
2.2.4 GLM微调
对于下游NLU任务来说,通常会将预训练模型产出的序列或tokens表达作为输入,使用线性分类器预测label。所以预训练与微调之间存在天然不一致。
作者按照PET的方式,将下游NLU任务重新表述为空白填充的生成任务。具体来说,比如给定一个已标注样本(x,y),将输入的文本x转换成一个包含masktoken的完形填空问题。比如,情感分类任务可以表述为:"{SENTENCE}. It’sreally [MASK]"。输出label y也同样会被映射到完形填空的答案中。“positive”和 “negative” 对应的标签就是“good” 和 “bad。
其实,预训练时,对较长的文本片段进行mask,以确保GLM的文本生成能力。但是在微调的时候,相当于将NLU任务也转换成了生成任务,这样其实是为了适应预训练的目标。但难免有一些牵强。
2.3 ChatGLM-2
2.3.1 主要创新
- 更长的上下文:基于
FlashAttention**技术,将基座模型的上下文长度(Context Length)由 ChatGLM-6B 的2K 扩展到了 32K**,并在对话阶段使用 8K的上下文长度训练。对于更长的上下文,发布了 ChatGLM2-6B-32K 模型。LongBench的测评结果表明,在等量级的开源模型中,ChatGLM2-6B-32K有着较为明显的竞争优势。 - 更强大的性能:基于 ChatGLM初代模型的开发经验,全面升级了 ChatGLM2-6B 的基座模型。ChatGLM2-6B使用了 GLM** 的混合目标函数**,经过了 1.4T中英标识符的预训练与人类偏好对齐训练,
评测结果显示,相比于初代模型,ChatGLM2-6B 在MMLU(+23%)、CEval(+33%)、GSM8K(+571%)、BBH(+60%)等数据集上的性能取得了大幅度的提升,在同尺寸开源模型中具有较强的竞争力。 - 更高效的推理:基于
Multi-Query Attention技术,ChatGLM2-6B有更高效的推理速度和更低的显存占用:在官方的模型实现下,推理速度相比初代提升了42%,INT4 量化下,6G 显存支持的对话长度由 1K 提升到了 8K。 - 更开放的协议:ChatGLM2-6B权重对学术研究完全开放,在填写
问卷进行登记后亦允许免费商业使用。
2.3.2 与ChatGLM的变化
- 使用了RoPE替换二维位置编码。这也是GLM中提出的亮点设计之一。但是目前大部分主流的LLMs都在使用RoPE,所以大势所趋。当前版本仍然采用了最初的RoPE设计,事实上现在的RoPE经过了xPOS→线性内插→NTK-AwareScaled RoPE→…若干次进化。
- Multi-QueryAttention:这是一种共享机制的Attention,相比Multi-HeadAttention,其Query部分没有区别,Key和Value可以只用一个Head。计算时,对Key和Value进行expand或者repeat操作,使它们填充到与Query一样的维度,后续计算就与Multi-HeadAttention没区别。
- Attention Mask: V1的attention mask分了2部分,PartA和Part B,Part A部分是双向Attention(代码中的
prefix_attention_mask),PartB部分是CausalAttention(原代码文件中的get_masks函数)。在V2版本,全部换成了CausalAttention,不再区分是Part A还是PartB,完全变成了decoder-only的架构。 - 多目标任务:Chat版本主要还是用的gMask生成式任务,但是在V1版本的代码还能看到mask、gMask等字样,V2已经摒弃了这些特殊token,原因与AttentionMask一致,均因为变成了decoder-only的架构,不再需要区分Part A和PartB。
2.3.3 ChatGLM-3
省流:ChatGLM2与ChatGLM3模型架构是完全一致的,ChatGLM与后继者结构不同。可见ChatGLM3相对于ChatGLM2没有模型架构上的改进。
相对于ChatGLM,ChatGLM2、ChatGLM3模型上的变化:
- 词表的大小从ChatGLM的150528缩小为65024(一个直观的体验是ChatGLM2、3加载比ChatGLM快不少)
- 位置编码从每个GLMBlock一份提升为全局一份
- SelfAttention之后的前馈网络有不同。ChatGLM用GELU(GaussianError LinearUnit)做激活;ChatGLM用Swish-1做激活。而且ChatGLM2、3应该是修正了之前的一个bug,因为GLU(GatedLinearUnit)本质上一半的入参是用来做门控制的,不需要输出到下层,所以ChatGLM2、3看起来前后维度不一致(27392->13696)反而是正确的。
3.BERT
3.1BERT用字粒度和词粒度的优缺点有哪些?
BERT可以使用字粒度(character-level)和词粒度(word-level)两种方式来进行文本表示,它们各自有优缺点:
字粒度(Character-level):
- 优点:处理未登录词(Out-of-Vocabulary,OOV):字粒度可以处理任意字符串,包括未登录词,不需要像词粒度那样遇到未登录词就忽略或使用特殊标记。对于少见词和低频词,字粒度可以学习更丰富的字符级别表示,使得模型能够更好地捕捉词汇的细粒度信息。
- 缺点:计算复杂度高:使用字粒度会导致输入序列的长度大大增加,进而增加模型的计算复杂度和内存消耗。需要更多的训练数据:字粒度模型对于少见词和低频词需要更多的训练数据来学习有效的字符级别表示,否则可能会导致过拟合。
词粒度(Word-level):
- 优点:计算效率高:使用词粒度可以大大减少输入序列的长度,从而降低模型的计算复杂度和内存消耗。学习到更加稳定的词级别表示:词粒度模型可以学习到更加稳定的词级别表示,特别是对于高频词和常见词,有更好的表示能力。
- 缺点:处理未登录词(OOV):词粒度模型无法处理未登录词,遇到未登录词时需要采用特殊处理(如使用未登录词的特殊标记或直接忽略)。对于多音字等形态复杂的词汇,可能无法准确捕捉其细粒度的信息。
3.2BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
3.3BERT用的是transformer里面的encoder还是decoder?
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
3.4为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?
BERT选择mask掉15%的词是一种经验性的选择,是原论文中的一种选择,并没有一个固定的理论依据,实际中当然可以尝试不同的比例,15%的比例是由BERT的作者在原始论文中提出,并在实验中发现对于BERT的训练效果是有效的
3.5为什么BERT在第一句前会加一个[CLS] 标志?
BERT在第一句前会加一个 [CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。为什么选它?因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。而[CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。
3.6 BERT非线性的来源在哪里?
主要来自两个地方:前馈层的gelu激活函数和self-attention。
前馈神经网络层:在BERT的Encoder中,每个自注意力层之后都跟着一个前馈神经网络层。前馈神经网络层是全连接的神经网络,通常包括一个线性变换和一个非线性的激活函数,如gelu。这样的非线性激活函数引入了非线性变换,使得模型能够学习更加复杂的特征表示。
self-attentionlayer:在自注意力层中,查询(Query)、键(Key)、值(Value)之间的点积得分会经过softmax操作,形成注意力权重,然后将这些权重与值向量相乘得到每个位置的自注意输出。这个过程中涉及了softmax操作,使得模型的计算是非线性的。
3.7BERT训练时使用的学习率 warm-up策略是怎样的?为什么要这么做?在BERT的训练中,使用了学习率warm-up策略,这是为了在训练的早期阶段增加学习率,以提高训练的稳定性和加快模型收敛。
学习率warm-up策略的具体做法是,在训练开始的若干个步骤(通常是一小部分训练数据的迭代次数)内,将学习率逐渐从一个较小的初始值增加到预定的最大学习率。在这个过程中,学习率的变化是线性的,即学习率在warm-up阶段的每个步骤按固定的步幅逐渐增加。学习率warm-up的目的是为了解决BERT在训练初期的两个问题:
- 不稳定性:在训练初期,由于模型参数的随机初始化以及模型的复杂性,模型可能处于一个较不稳定的状态。此时使用较大的学习率可能导致模型的参数变动太大,使得模型很难收敛,学习率warm-up可以在这个阶段将学习率保持较小,提高模型训练的稳定性。
- 避免过拟合:BERT模型往往需要较长的训练时间来获得高质量的表示。如果在训练的早期阶段就使用较大的学习率,可能会导致模型在训练初期就过度拟合训练数据,降低模型的泛化能力。通过学习率warm-up,在训练初期使用较小的学习率,可以避免过度拟合,等模型逐渐稳定后再使用较大的学习率进行更快的收敛。
3.8在BERT应用中,如何解决长文本问题?
在BERT应用中,处理长文本问题有以下几种常见的解决方案:
- 截断与填充:将长文本截断为固定长度或者进行填充。BERT模型的输入是一个固定长度的序列,因此当输入的文本长度超过模型的最大输入长度时,需要进行截断或者填充。通常,可以根据任务的要求,选择适当的最大长度,并对文本进行截断或者填充,使其满足模型输入的要求。
- SlidingWindow:将长文本分成多个短文本,然后分别输入BERT模型。这种方法被称为SlidingWindow技术。具体来说,将长文本按照固定的步长切分成多个片段,然后分别输入BERT模型进行处理。每个片段的输出可以进行进一步的汇总或者融合,得到最终的表示。
- HierarchicalModel:使用分层模型来处理长文本,其中底层模型用于处理短文本片段,然后将不同片段的表示进行汇总或者融合得到整个长文本的表示。这样的分层模型可以充分利用BERT模型的表示能力,同时处理长文本。
- Longformer、BigBird等模型:使用专门针对长文本的模型,如Longformer和BigBird。这些模型采用了不同的注意力机制,以处理超长序列,并且通常在处理长文本时具有更高的效率。
- Document-LevelModel:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
]]>
@@ -31,7 +58,7 @@
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
/2024/03/05/dl_llm_basic/
diff --git a/page/2/index.html b/page/2/index.html
index 9f0a906..1032d0f 100644
--- a/page/2/index.html
+++ b/page/2/index.html
@@ -202,6 +202,67 @@
+
+
+
+
+
+
+
+ 【深度学习】图神经网络
+
+
+
+
+
+
+ 图神经网络 GNN全称----图神经网络,它是一种直接作用于图结构上的神经网络。我们可以把图中的每一个节点 \(V\) 当作个体对象,而每一条边 \(E\) 当作个体与个体间的某种联系,所有节点组成的关系网就是最后的图 \(U\) GNN的输入一般是每个节点的起始特征向量和表示节点间关系的邻接矩阵,有了这两个输入信息,接下来就是聚合操作了。所谓的聚合,其实就是将周边与节点 V i ViVi 有关
+
+
+
+
+
+
+
@@ -765,74 +826,11 @@
-
-
-
-
-
-
-
- 【自动驾驶】RSS Model for Autonomous Driving
-
-
-
-
-
-
- RSS Model for Autonomous Driving 论文:《On a Formal Model of Safe and Scalable Self-driving Cars》 Contribution: Safety (RSS model) Reasonable care, Responsibility, agile driving policy Semantic (Semant
-
-
-
-
-
-
-
diff --git a/page/3/index.html b/page/3/index.html
new file mode 100644
index 0000000..abdef70
--- /dev/null
+++ b/page/3/index.html
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/search.xml b/search.xml
index a42b258..fb121df 100644
--- a/search.xml
+++ b/search.xml
@@ -7748,7 +7748,7 @@ href="https://so.csdn.net/so/search?q=conda&spm=1001.2101.3001.7020">conda
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
/2024/03/05/dl_llm_basic/
深度学习&LLM基础
@@ -9010,7 +9010,7 @@ alt="进制转换的示意图" />
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
/2024/03/08/dl_llm_model/
大语言模型简介
@@ -9498,8 +9498,8 @@ BERT用字粒度和词粒度的优缺点有哪些?
3.2
BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
-3.3BERT用的是transformer里面的encoder还是decoder?
+3.3
+BERT用的是transformer里面的encoder还是decoder?
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
@@ -9542,6 +9542,826 @@ Model:使用分层模型来处理长文本,其中底层模型用于
Document-Level
Model:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
+]]>
+
+ 深度学习
+
+
+ 深度学习
+ 大语言模型
+
+
+
+ 【大语言模型】有监督微调
+ /2024/03/24/dl-llm-ft/
+
+大语言模型微调
+1. 大模型微调简介
+1.1 微调方法定义
+微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
+下面是一般的微调步骤:
+
+- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。
+- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。
+- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specific
+head)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。
+- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。
+- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。
+- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。
+- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。
+- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。
+
+微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
+1.2 为什么需要 PEFT
+Parameter-Efficient
+Fine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trained
+language models
+)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
+PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
+参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
+参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
+高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Soft
+prompts)两个小类。
+
+
+Scaling Down to Scale Up: A Guide to Parameter-Efficient
+Fine-Tuning
+
+1.3
+微调和参数高效微调之间的区别
+微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
+微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
+另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
+1.4 PEFT 有什么优点
+在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
+
+- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本
+- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。
+- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。
+- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。
+- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。
+
+1.5 多种不同的高效微调方法对比
+参数有效策略可能涉及多种技术:
+
+- 选择性层调整(Selective Layer
+Tuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。
+- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。
+- 稀疏微调(Sparse
+Fine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。
+- 低秩近似(Low-Rank
+Approximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。
+- 正则化技术(Regularization
+Techniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。
+- 任务特定的头(Task-specific
+Heads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。
+
+1.6
+当前高效微调技术存在的一些问题
+当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
+
+- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。
+Ladder-side
+Tuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。
+- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。
+- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。
+- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用git
+fork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。
+
+1.7 PEFT技术实践
+针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
+
+- 明确指出参数数量类型。
+- 使用不同大小的模型进行评估。
+- 和类似方法进行比较。
+- 标准化PEFT测量基准。
+- 重视代码清晰度,以最小化进行实现。
+
+2. 微调Fine-Tune
+2.1 为什么SFT之后感觉LLM傻了?
+在进行Supervised
+Fine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
+
+- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。
+- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。
+- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。
+- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。
+
+为了解决这些问题,可以尝试以下方法:
+
+- 收集更多的训练数据,以增加数据的多样性和覆盖范围。
+- 仔细检查微调数据集的标注,确保标签的准确性和一致性。
+- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。
+- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。
+- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。
+
+通过这些方法,可以尽量减少Supervised
+Fine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
+2.2 SFT 指令微调数据 如何构建?
+构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
+
+- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。
+- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。
+- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。
+- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。
+- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。
+- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。
+- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。
+
+2.3 如何训练自己的大模型?
+
+- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。
+- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。
+- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。
+- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。
+- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。
+- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。
+- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。
+
+2.4 指令微调的好处?
+指令微调(Instruction
+Fine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
+
+- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。
+- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。
+- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。
+- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。
+- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。
+
+请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
+2.5 多轮对话任务微调调型
+在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
+
+- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。
+- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。
+- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。
+- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
+
+- 初始化模型参数:将预训练模型的参数加载到模型中。
+- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。
+- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。
+- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。
+
+- 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。
+- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。
+
+需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
+2.6 微调后的模型出现能力劣化
+灾难性遗忘(Catastrophic
+Forgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
+在微调大语言模型时,灾难性遗忘可能出现的原因包括:
+
+- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。
+- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。
+
+为了解决灾难性遗忘问题,可以尝试以下方法:
+
+- 经验回放(Replay
+Buffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。
+- 弹性权重共享(Elastic Weight
+Consolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。
+- 增量学习(Incremental
+Learning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。
+- 多任务学习(Multi-Task
+Learning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。
+
+综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
+2.7 预训练和SFT操作有什么不同
+大语言模型的预训练和有监督微调(Supervised
+Fine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
+目标:
+
+- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(Masked
+Language Model,MLM)或下一句预测(Next Sentence
+Prediction,NSP)等,来训练模型。
+- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。
+
+数据:
+
+- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。
+- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。
+
+训练方式:
+
+- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。
+- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。
+
+总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
+2.8 大模型LLM进行SFT
+如何对样本进行优化?
+对于大语言模型进行有监督微调(Supervised
+Fine-Tuning)时,可以采用以下几种方式对样本进行优化:
+
+- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。
+- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。
+- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。
+- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。
+- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。
+- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。
+- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。
+
+总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
+3. 预训练
+3.1 为什么要增量预训练?
+预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
+3.2
+进行增量预训练需要做哪些准备工作?
+
+- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。
+- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是
+TB 级别的。
+- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。
+
+3.3
+增量预训练训练流程是怎么样?
+
+- 数据预处理:参考 LLaMA
+的预训练长度,也把数据处理成2048长度(如果不够,做补全)。
+- 分词器:如果使用 LLaMA
+可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。
+- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选
+Chat 模型。
+- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。
+- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。
+- 模型测试:简单测试下续写能力,验证下模型是否正常。
+
+4. Prompting工程
+4.1 BitFit
+4.1.1 背景
+虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署,
+特别是随着任务数量的增加,很难维护。
+理想状况下,我们希望有一种满足以下条件的高效微调方法:
+
+- 到达能够匹配全量微调的效果。
+- 仅更改一小部分模型参数。
+- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。
+- 改变的参数在不同下游任务中是一致的。
+
+上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
+虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
+4.1.2 技术原理
+BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuning
+or Transformer-based Masked
+Language-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
+对于Transformer模型而言,冻结大部分 transformer-encoder
+参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
+在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了
+BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
+
+同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言,
+只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
+同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
+
+4.2 Prefix Tuning
+4.2.1 背景
+在Prefix
+Tuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
+除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
+基于上述两点,Prefix
+Tuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,
+这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的Virtual
+Token(Soft Prompt/Continuous
+Prompt),相比离散的Token,更好优化,效果更好。
+
+4.2.2 技术原理
+Prefix Tuning(论文:Prefix-Tuning: Optimizing Continuous
+Prompts for
+Generation),在输入token之前构造一段任务相关的virtual
+tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
+针对不同的模型结构,需要构造不同的Prefix。
+
+- 针对自回归架构模型:在句子前面添加前缀,得到
+
z = [PREFIX; x; y]
,合适的上文能够在固定 LM
+的情况下去引导生成下文(比如:GPT3的上下文学习)。
+- 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
+
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder
+端增加前缀是为了引导后续token的生成。
+
+
+该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
+
+除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
+
+另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为
+[PREFIX; x; y]
,Infix-tuning形式为
+[x; INFIX; y]
。
+4.3 Prompt Tuning
+4.3.1 背景
+大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
+基于此,作者提出了Prompt
+Tuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,
+训练完以后,用同一个模型可以做多任务推理。
+4.3.2 技术原理
+Prompt Tuning(论文:The Power of Scale for
+Parameter-Efficient Prompt Tuning),该方法可以看作是Prefix
+Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompt
+tokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
+
+通过实验发现,随着预训练模型参数量的增加,Prompt
+Tuning的方法会逼近全参数微调的结果。
+
+同时,Prompt Tuning 还提出了 Prompt
+Ensembling,也就是在一个批次(Batch)里同时训练同一个任务的不同
+prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
+
+4.4 P-Tuning
+4.4.1 背景
+该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(in
+context
+learning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
+同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtual
+token(同Prefix-Tuning类似)。
+
+4.4.2 技术原理
+P-Tuning(论文:GPT Understands,
+Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。
+
+相比Prefix Tuning,P-Tuning加入的可微的virtual
+token,但仅限于输入层,没有在每一层都加;另外,virtual
+token的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtual
+token。
+经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual
+token,容易优化到局部最优值,而这些virtual
+token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt
+encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual
+token以后,再输入到模型。
+从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
+并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
+4.5 P-Tuning v2
+4.5.1 背景
+之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
+第一,缺乏模型参数规模和任务通用性。
+
+- 缺乏规模通用性:Prompt
+Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
+- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些
+NLU
+基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。
+
+第二,缺少深度提示优化,在Prompt
+Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
+
+- 由于序列长度的限制,可调参数的数量是有限的。
+- 输入embedding对模型预测只有相对间接的影响。
+
+考虑到这些问题,作者提出了Ptuning
+v2,它利用深度提示优化(如:Prefix Tuning),对Prompt
+Tuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
+4.5.2 技术原理
+P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can Be
+Comparable to Fine-tuning Universally Across Scales and
+Tasks),该方法在每一层都加入了Prompts
+tokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
+
+- 更多可学习的参数(从P-tuning和Prompt
+Tuning的0.01%增加到0.1%-3%),同时也足够参数高效。
+- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。
+
+
+具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix
+Tuning技术适配到NLU任务中,然后做了一些改进:
+
+- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2
+中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
+- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。
+- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuning
+v2的有益补充。
+- 回归传统的分类标签范式,而不是映射器。标签词映射器(Label
+Word
+Verbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuning
+v2回归传统的CLS标签分类范式,采用随机初始化的分类头(Classification
+Head)应用于tokens之上,以增强通用性,可以适配到序列标注任务。
+
+论文中展示了P-tuning
+v2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),Prompt
+Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuning
+v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning
+v2在RTE中的表现明显优于微调,特别是在BERT中。
+5. Adapter-Tuning
+5.1 Adapter Tuning
+5.1.1 背景
+预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
+基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题
+Adapter
+在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
+5.1.2 技术原理
+Adapter Tuning(论文:Parameter-Efficient Transfer Learning
+for
+NLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的
+==Adapter 结构和 Layer Norm
+层==进行微调,从而保证了训练的高效性。
+每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
+
+5.1.3 具体细节
+每个 Adapter
+模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skip
+connection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便
+Adapter 一开始的参数初始化接近0,Adapter也由于skip
+connection的设置而接近于一个恒等映射,从而确保训练的有效性。
+\[
+h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p}
+\]
+通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
+总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
+5.2 AdapterFusion
+5.2.1 背景
+为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequential
+fine-tuning)或者多任务学习(multi-task
+learning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
+而之前的工作,Adapter
+Tuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter
+的参数某种程度上就表达了解决这个任务需要的知识。
+作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了
+AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
+5.2.2 技术原理
+Adapter Fusion(论文:AdapterFusion:Non-Destructive Task
+Composition for Transfer
+Learning),一种融合多任务信息的Adapter的变体,在
+Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+
+- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
+- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。
+
+
+对于第一阶段,有两种训练方式,分别如下:
+
+- Single-Task
+Adapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。
+- Multi-Task
+Adapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。
+
+对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
+5.2.3 AdapterFusion结构
+AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,
+value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
+
+通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
+总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
+5.3 AdapterDrop
+5.3.1 背景
+近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
+作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
+基于此,作者提出了AdapterDrop方法缓解该问题。
+5.3.2 技术原理
+AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters in
+Transformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+
+实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。
+例如,将前五个Transformer层中的Adapter丢弃,在对 8
+个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop
+也能保持良好的结果。
+除此之外,作者还研究了对
+AdapterFusion中的Adapter进行剪枝后的效果。
+
+通过实验表明可以移除 AdapterFusion
+中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整
+AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
+因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。
+这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
+总之,AdapterDrop
+通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+5.4 MAM Adapter
+5.4.1 背景
+近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
+下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,Prefix
+Tuning和LoRA都是性能比较好的方法。
+
+为什么看起来Adapter、Prefix
+Tuning、LoRA(在结构上和公式上)都不太一样,尤其是Prefix
+Tuning,但是这三种方法有近似的效果?
+基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、Prefix
+Tuning和LoRA)的设计,并提出了一种新方法MAM
+Adapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
+
+首先,作者通过对Prefix Tuning变换,发现Prefix
+Tuning和Adapters的公式高度相似。
+然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体)
+Parallel Adapter、 Scaled PA的结构。
+
+下表展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体在新增可训练参数结构形式(functional
+form)、结构插入形式(Insertion
+form)、新增结构在PLM修改的具体位置(modified
+representation)、新增结构与PLM的组合函数(composition
+function)。其中,新增可训练参数结构形式为需要学习的部分(注:Prefix
+Tuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
+
+5.4.2 技术原理
+MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT
+TRANSFER LEARNING),一个在Adapter、Prefix
+Tuning和LoRA之间建立联系的统一方法。
+作者对Adapter的放置和软提示(soft
+prompt)进行了详细的调查。得出如下结论:
+
+- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN
+并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。
+- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。
+
+然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用
+FFN 层的并行Adapter和软提示的组合。
+通过最终的实验结果,可以看到 MAM Adapter
+在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于
+BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
+5.5 UniPELT
+5.5.1 背景
+近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
+基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+5.5.2 技术原理
+UniPELT(论文: UNIPELT: A Unified Framework for Parameter-Efficient
+Language Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
+更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,Prefix
+Tuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。
+对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括
+LoRA 矩阵
+WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
+
+UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter
+和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT
+的性能与这些方法相当或更好。
+实验还对不同 PELT 方法训练时间和推理时间进行了分析。
+
+- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围,
+- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。
+- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。
+
+6. lora
+6.1 LoRA
+6.1.1 背景
+神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsic
+rank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
+6.1.2 技术原理
+LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE
+MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsic
+rank)。
+
+可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
+
+在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
+\[
+h=W_{0} x+\Delta W x=W_{0} x+B A x
+\]
+在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
+此外,Transformer的权重矩阵包括Attention模块里用于计算query
,
+key
,
+value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整
+Wq 和 Wv 会产生最佳结果。
+实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
+6.2 AdaLoRA
+6.2.1 背景
+在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
+
+- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。
+- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。
+
+为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
+
+- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adapter
+tuning、Prefix tuning、Prompt
+Tuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adapter
+tuning引入了推理延时;Prefix tuning或Prompt
+tuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。
+- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diff
+pruning、LoRA等,
+此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diff
+pruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。
+LoRA则需要预先指定每个增量矩阵的本征秩 r
+相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。
+
+基于以上问题进行总结:
+
+- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。
+- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。
+
+为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
+6.2.2 技术原理
+AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FOR
+PARAMETEREFFICIENT
+FINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
+
+- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。
+
+\[
+W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q
+\]
+
+- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。
+
+通过实验证明,AdaLoRA
+实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。
+例如,当参数预算为 0.3M 时,AdaLoRA
+在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
+
+6.3 QLoRA
+6.3.1 背景
+微调大型语言模型 (LLM)
+是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以
+LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU
+内存。
+虽然最近的量化方法可以减少 LLM
+的内存占用,但此类技术仅适用于推理场景。
+基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为
+4 bit的模型。
+6.3.2 技术原理
+QLoRA(论文: QLORA: Efficient Finetuning of Quantized
+LLMs),使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA
+有一种低精度存储数据类型(4
+bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用
+QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16
+位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bit
+NormalFloat(NF4)
+量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
+
+- 4bit
+NormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比
+4 bit整数和 4bit 浮点数更好的实证结果。
+- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。
+- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的
+GPU 处理。该功能的工作方式类似于 CPU
+内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在
+GPU 内存不足时将其自动卸载到 CPU
+内存,并在优化器更新步骤需要时将其加载回 GPU 内存。
+
+
+实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
+7. 微调方法总结
+7.1
+当前高效微调技术的简述
+之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
+7.2 BitFit
+对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
+特点:
+
+- 训练参数量极小(约0.1%)。
+- 在大部分任务上效果会差于LoRA、Adapter等方法。
+
+7.3 Prefix Tuning
+在每一个Transformer层都带上一些virtual
+token作为前缀,以适应不同的任务。
+特点:
+
+- 前缀Token会占用序列长度,有一定的额外计算开销。
+- Prefix Tuning的线性插值是比较复杂的。
+
+7.4 Prompt Tuning
+该方法可以看着是Prefix
+Tuning的简化版本,针对不同的任务,仅在输入层引入virtual
+token形式的软提示(soft prompt)。
+特点:
+
+- 相对于Prefix
+Tuning,参与训练的参数量和改变的参数量更小,更节省显存。
+- 对一些简单的NLU
+任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。
+
+7.5 P-Tuning
+将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtual
+token;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
+特点:
+
+- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtual
+token的相互依赖会收敛更快,效果更好。
+
+7.6 P-Tuning v2
+该方法在每一个Transformer层都加入了prompt
+token作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
+特点:
+
+- 解决了Prompt Tuning无法在小模型上有效提升的问题。
+- 移除了对模型效果改进较小的重参数化的编码器(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM)。
+- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。
+
+7.7 Adapter Tuning
+该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和Layer
+Norm 层进行微调。
+特点:
+
+- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。
+
+7.8 AdapterFusion
+一种融合多任务信息的Adapter的变体,在 Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+7.9 AdapterDrop
+该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+特点:
+
+- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+
+7.10 LoRA
+该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+特点:
+
+- 将BA加到W上可以消除推理延迟。
+- 可以通过可插拔的形式切换到不同的任务。
+- 设计的比较好,简单且效果好。
+
+7.11 AdaLoRA
+对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+7.12 QLoRA
+使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
+特点:
+
+- 使用 QLoRA
+微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。
+
+7.13 MAM Adapter
+一种在 Adapter、Prefix Tuning 和 LoRA
+之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter
+和 软提示的组合。
+特点:
+
+- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。
+
+7.14 UniPELT
+一种将不同的PELT方法LoRA、Prefix
+Tuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+特点:
+
+- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。
+- 多种 PELT 方法的混合涉及PLM
+的不同部分对模型有效性和鲁棒性都有好处
+
+7.15 总结
+本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
+
+- 增加额外参数,如:Prefix Tuning、Prompt Tuning、Adapter
+Tuning及其变体。
+- 选取一部分参数更新,如:BitFit。
+- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。
+- 混合高效微调,如:MAM Adapter、UniPELT。
+
+并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
]]>
深度学习
diff --git a/tags/index.html b/tags/index.html
index 09b5b82..8d3b766 100644
--- a/tags/index.html
+++ b/tags/index.html
@@ -202,7 +202,7 @@
diff --git "a/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html" "b/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html"
index d1b80e6..144b637 100644
--- "a/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html"
+++ "b/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html"
@@ -202,7 +202,7 @@
- 1 posts in total
+ 2 posts in total
@@ -210,9 +210,15 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
diff --git "a/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html" "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
index 04bf2b4..41f4f1e 100644
--- "a/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
+++ "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
@@ -202,7 +202,7 @@
- 10 posts in total
+ 11 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -266,15 +272,15 @@
【深度学习】PyTorch使用手册
-
-
-
- 【多智能体强化学习】Pymarl环境配置
-
-
+
+
diff --git "a/tags/\346\267\261\345\272\246\345\255\246\344\271\240/page/2/index.html" "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/page/2/index.html"
new file mode 100644
index 0000000..0ec8797
--- /dev/null
+++ "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/page/2/index.html"
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tags - 深度学习 - LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
3.8
Updated on
- March 14, 2024
+ March 24, 2024
@@ -901,12 +901,18 @@ 3.8
+
+
+ 【大语言模型】有监督微调
+ Previous
+
+
-
- 【深度学习】DeepL基础知识
+
+ 【深度学习】DeepL|LLM基础知识
Next
diff --git a/2024/03/24/dl-llm-ft/index.html b/2024/03/24/dl-llm-ft/index.html
new file mode 100644
index 0000000..2d81ca1
--- /dev/null
+++ b/2024/03/24/dl-llm-ft/index.html
@@ -0,0 +1,1512 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调 - LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 26k words
+
+
+
+
+
+
+
+
+
+
+ 220 mins
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调
+
+
+
+
+ Last updated on March 24, 2024 pm
+
+
+
+
+
+
+
+
+大语言模型微调
+1. 大模型微调简介
+1.1 微调方法定义
+微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
+下面是一般的微调步骤:
+
+- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。
+- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。
+- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specific
+head)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。
+- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。
+- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。
+- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。
+- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。
+- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。
+
+微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
+1.2 为什么需要 PEFT
+Parameter-Efficient
+Fine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trained
+language models
+)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
+PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
+参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
+参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
+高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Soft
+prompts)两个小类。
+
+
+Scaling Down to Scale Up: A Guide to Parameter-Efficient
+Fine-Tuning
+
+1.3
+微调和参数高效微调之间的区别
+微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
+微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
+另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
+1.4 PEFT 有什么优点
+在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
+
+- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本
+- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。
+- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。
+- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。
+- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。
+
+1.5 多种不同的高效微调方法对比
+参数有效策略可能涉及多种技术:
+
+- 选择性层调整(Selective Layer
+Tuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。
+- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。
+- 稀疏微调(Sparse
+Fine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。
+- 低秩近似(Low-Rank
+Approximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。
+- 正则化技术(Regularization
+Techniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。
+- 任务特定的头(Task-specific
+Heads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。
+
+1.6
+当前高效微调技术存在的一些问题
+当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
+
+- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。
+Ladder-side
+Tuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。
+- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。
+- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。
+- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用git
+fork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。
+
+1.7 PEFT技术实践
+针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
+
+- 明确指出参数数量类型。
+- 使用不同大小的模型进行评估。
+- 和类似方法进行比较。
+- 标准化PEFT测量基准。
+- 重视代码清晰度,以最小化进行实现。
+
+2. 微调Fine-Tune
+2.1 为什么SFT之后感觉LLM傻了?
+在进行Supervised
+Fine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
+
+- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。
+- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。
+- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。
+- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。
+
+为了解决这些问题,可以尝试以下方法:
+
+- 收集更多的训练数据,以增加数据的多样性和覆盖范围。
+- 仔细检查微调数据集的标注,确保标签的准确性和一致性。
+- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。
+- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。
+- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。
+
+通过这些方法,可以尽量减少Supervised
+Fine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
+2.2 SFT 指令微调数据 如何构建?
+构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
+
+- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。
+- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。
+- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。
+- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。
+- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。
+- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。
+- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。
+
+2.3 如何训练自己的大模型?
+
+- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。
+- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。
+- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。
+- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。
+- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。
+- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。
+- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。
+
+2.4 指令微调的好处?
+指令微调(Instruction
+Fine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
+
+- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。
+- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。
+- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。
+- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。
+- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。
+
+请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
+2.5 多轮对话任务微调调型
+在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
+
+- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。
+- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。
+- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。
+- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
+
+- 初始化模型参数:将预训练模型的参数加载到模型中。
+- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。
+- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。
+- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。
+
+- 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。
+- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。
+
+需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
+2.6 微调后的模型出现能力劣化
+灾难性遗忘(Catastrophic
+Forgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
+在微调大语言模型时,灾难性遗忘可能出现的原因包括:
+
+- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。
+- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。
+
+为了解决灾难性遗忘问题,可以尝试以下方法:
+
+- 经验回放(Replay
+Buffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。
+- 弹性权重共享(Elastic Weight
+Consolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。
+- 增量学习(Incremental
+Learning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。
+- 多任务学习(Multi-Task
+Learning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。
+
+综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
+2.7 预训练和SFT操作有什么不同
+大语言模型的预训练和有监督微调(Supervised
+Fine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
+目标:
+
+- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(Masked
+Language Model,MLM)或下一句预测(Next Sentence
+Prediction,NSP)等,来训练模型。
+- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。
+
+数据:
+
+- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。
+- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。
+
+训练方式:
+
+- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。
+- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。
+
+总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
+2.8 大模型LLM进行SFT
+如何对样本进行优化?
+对于大语言模型进行有监督微调(Supervised
+Fine-Tuning)时,可以采用以下几种方式对样本进行优化:
+
+- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。
+- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。
+- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。
+- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。
+- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。
+- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。
+- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。
+
+总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
+3. 预训练
+3.1 为什么要增量预训练?
+预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
+3.2
+进行增量预训练需要做哪些准备工作?
+
+- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。
+- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是
+TB 级别的。
+- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。
+
+3.3
+增量预训练训练流程是怎么样?
+
+- 数据预处理:参考 LLaMA
+的预训练长度,也把数据处理成2048长度(如果不够,做补全)。
+- 分词器:如果使用 LLaMA
+可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。
+- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选
+Chat 模型。
+- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。
+- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。
+- 模型测试:简单测试下续写能力,验证下模型是否正常。
+
+4. Prompting工程
+4.1 BitFit
+4.1.1 背景
+虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署,
+特别是随着任务数量的增加,很难维护。
+理想状况下,我们希望有一种满足以下条件的高效微调方法:
+
+- 到达能够匹配全量微调的效果。
+- 仅更改一小部分模型参数。
+- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。
+- 改变的参数在不同下游任务中是一致的。
+
+上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
+虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
+4.1.2 技术原理
+BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuning
+or Transformer-based Masked
+Language-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
+对于Transformer模型而言,冻结大部分 transformer-encoder
+参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
+在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了
+BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
+
+同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言,
+只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
+同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
+
+4.2 Prefix Tuning
+4.2.1 背景
+在Prefix
+Tuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
+除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
+基于上述两点,Prefix
+Tuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,
+这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的Virtual
+Token(Soft Prompt/Continuous
+Prompt),相比离散的Token,更好优化,效果更好。
+
+4.2.2 技术原理
+Prefix Tuning(论文:Prefix-Tuning: Optimizing Continuous
+Prompts for
+Generation),在输入token之前构造一段任务相关的virtual
+tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
+针对不同的模型结构,需要构造不同的Prefix。
+
+- 针对自回归架构模型:在句子前面添加前缀,得到
+
z = [PREFIX; x; y]
,合适的上文能够在固定 LM
+的情况下去引导生成下文(比如:GPT3的上下文学习)。
+- 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
+
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder
+端增加前缀是为了引导后续token的生成。
+
+
+该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
+
+除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
+
+另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为
+[PREFIX; x; y]
,Infix-tuning形式为
+[x; INFIX; y]
。
+4.3 Prompt Tuning
+4.3.1 背景
+大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
+基于此,作者提出了Prompt
+Tuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,
+训练完以后,用同一个模型可以做多任务推理。
+4.3.2 技术原理
+Prompt Tuning(论文:The Power of Scale for
+Parameter-Efficient Prompt Tuning),该方法可以看作是Prefix
+Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompt
+tokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
+
+通过实验发现,随着预训练模型参数量的增加,Prompt
+Tuning的方法会逼近全参数微调的结果。
+
+同时,Prompt Tuning 还提出了 Prompt
+Ensembling,也就是在一个批次(Batch)里同时训练同一个任务的不同
+prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
+
+4.4 P-Tuning
+4.4.1 背景
+该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(in
+context
+learning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
+同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtual
+token(同Prefix-Tuning类似)。
+
+4.4.2 技术原理
+P-Tuning(论文:GPT Understands,
+Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。
+
+相比Prefix Tuning,P-Tuning加入的可微的virtual
+token,但仅限于输入层,没有在每一层都加;另外,virtual
+token的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtual
+token。
+经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual
+token,容易优化到局部最优值,而这些virtual
+token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt
+encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual
+token以后,再输入到模型。
+从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
+并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
+4.5 P-Tuning v2
+4.5.1 背景
+之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
+第一,缺乏模型参数规模和任务通用性。
+
+- 缺乏规模通用性:Prompt
+Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
+- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些
+NLU
+基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。
+
+第二,缺少深度提示优化,在Prompt
+Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
+
+- 由于序列长度的限制,可调参数的数量是有限的。
+- 输入embedding对模型预测只有相对间接的影响。
+
+考虑到这些问题,作者提出了Ptuning
+v2,它利用深度提示优化(如:Prefix Tuning),对Prompt
+Tuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
+4.5.2 技术原理
+P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can Be
+Comparable to Fine-tuning Universally Across Scales and
+Tasks),该方法在每一层都加入了Prompts
+tokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
+
+- 更多可学习的参数(从P-tuning和Prompt
+Tuning的0.01%增加到0.1%-3%),同时也足够参数高效。
+- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。
+
+
+具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix
+Tuning技术适配到NLU任务中,然后做了一些改进:
+
+- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2
+中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
+- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。
+- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuning
+v2的有益补充。
+- 回归传统的分类标签范式,而不是映射器。标签词映射器(Label
+Word
+Verbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuning
+v2回归传统的CLS标签分类范式,采用随机初始化的分类头(Classification
+Head)应用于tokens之上,以增强通用性,可以适配到序列标注任务。
+
+论文中展示了P-tuning
+v2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),Prompt
+Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuning
+v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning
+v2在RTE中的表现明显优于微调,特别是在BERT中。
+5. Adapter-Tuning
+5.1 Adapter Tuning
+5.1.1 背景
+预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
+基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题
+Adapter
+在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
+5.1.2 技术原理
+Adapter Tuning(论文:Parameter-Efficient Transfer Learning
+for
+NLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的
+==Adapter 结构和 Layer Norm
+层==进行微调,从而保证了训练的高效性。
+每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
+
+5.1.3 具体细节
+每个 Adapter
+模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skip
+connection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便
+Adapter 一开始的参数初始化接近0,Adapter也由于skip
+connection的设置而接近于一个恒等映射,从而确保训练的有效性。
+\[
+h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p}
+\]
+通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
+总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
+5.2 AdapterFusion
+5.2.1 背景
+为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequential
+fine-tuning)或者多任务学习(multi-task
+learning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
+而之前的工作,Adapter
+Tuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter
+的参数某种程度上就表达了解决这个任务需要的知识。
+作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了
+AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
+5.2.2 技术原理
+Adapter Fusion(论文:AdapterFusion:Non-Destructive Task
+Composition for Transfer
+Learning),一种融合多任务信息的Adapter的变体,在
+Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+
+- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
+- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。
+
+
+对于第一阶段,有两种训练方式,分别如下:
+
+- Single-Task
+Adapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。
+- Multi-Task
+Adapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。
+
+对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
+5.2.3 AdapterFusion结构
+AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,
+value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
+
+通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
+总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
+5.3 AdapterDrop
+5.3.1 背景
+近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
+作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
+基于此,作者提出了AdapterDrop方法缓解该问题。
+5.3.2 技术原理
+AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters in
+Transformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+
+实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。
+例如,将前五个Transformer层中的Adapter丢弃,在对 8
+个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop
+也能保持良好的结果。
+除此之外,作者还研究了对
+AdapterFusion中的Adapter进行剪枝后的效果。
+
+通过实验表明可以移除 AdapterFusion
+中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整
+AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
+因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。
+这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
+总之,AdapterDrop
+通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+5.4 MAM Adapter
+5.4.1 背景
+近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
+下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,Prefix
+Tuning和LoRA都是性能比较好的方法。
+
+为什么看起来Adapter、Prefix
+Tuning、LoRA(在结构上和公式上)都不太一样,尤其是Prefix
+Tuning,但是这三种方法有近似的效果?
+基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、Prefix
+Tuning和LoRA)的设计,并提出了一种新方法MAM
+Adapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
+
+首先,作者通过对Prefix Tuning变换,发现Prefix
+Tuning和Adapters的公式高度相似。
+然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体)
+Parallel Adapter、 Scaled PA的结构。
+
+下表展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体在新增可训练参数结构形式(functional
+form)、结构插入形式(Insertion
+form)、新增结构在PLM修改的具体位置(modified
+representation)、新增结构与PLM的组合函数(composition
+function)。其中,新增可训练参数结构形式为需要学习的部分(注:Prefix
+Tuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
+
+5.4.2 技术原理
+MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT
+TRANSFER LEARNING),一个在Adapter、Prefix
+Tuning和LoRA之间建立联系的统一方法。
+作者对Adapter的放置和软提示(soft
+prompt)进行了详细的调查。得出如下结论:
+
+- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN
+并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。
+- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。
+
+然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用
+FFN 层的并行Adapter和软提示的组合。
+通过最终的实验结果,可以看到 MAM Adapter
+在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于
+BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
+5.5 UniPELT
+5.5.1 背景
+近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
+基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+5.5.2 技术原理
+UniPELT(论文: UNIPELT: A Unified Framework for Parameter-Efficient
+Language Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
+更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,Prefix
+Tuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。
+对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括
+LoRA 矩阵
+WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
+
+UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter
+和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT
+的性能与这些方法相当或更好。
+实验还对不同 PELT 方法训练时间和推理时间进行了分析。
+
+- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围,
+- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。
+- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。
+
+6. lora
+6.1 LoRA
+6.1.1 背景
+神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsic
+rank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
+6.1.2 技术原理
+LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE
+MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsic
+rank)。
+
+可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
+
+在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
+\[
+h=W_{0} x+\Delta W x=W_{0} x+B A x
+\]
+在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
+此外,Transformer的权重矩阵包括Attention模块里用于计算query
,
+key
,
+value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整
+Wq 和 Wv 会产生最佳结果。
+实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
+6.2 AdaLoRA
+6.2.1 背景
+在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
+
+- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。
+- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。
+
+为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
+
+- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adapter
+tuning、Prefix tuning、Prompt
+Tuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adapter
+tuning引入了推理延时;Prefix tuning或Prompt
+tuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。
+- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diff
+pruning、LoRA等,
+此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diff
+pruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。
+LoRA则需要预先指定每个增量矩阵的本征秩 r
+相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。
+
+基于以上问题进行总结:
+
+- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。
+- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。
+
+为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
+6.2.2 技术原理
+AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FOR
+PARAMETEREFFICIENT
+FINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
+
+- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。
+
+\[
+W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q
+\]
+
+- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。
+
+通过实验证明,AdaLoRA
+实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。
+例如,当参数预算为 0.3M 时,AdaLoRA
+在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
+
+6.3 QLoRA
+6.3.1 背景
+微调大型语言模型 (LLM)
+是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以
+LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU
+内存。
+虽然最近的量化方法可以减少 LLM
+的内存占用,但此类技术仅适用于推理场景。
+基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为
+4 bit的模型。
+6.3.2 技术原理
+QLoRA(论文: QLORA: Efficient Finetuning of Quantized
+LLMs),使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA
+有一种低精度存储数据类型(4
+bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用
+QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16
+位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bit
+NormalFloat(NF4)
+量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
+
+- 4bit
+NormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比
+4 bit整数和 4bit 浮点数更好的实证结果。
+- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。
+- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的
+GPU 处理。该功能的工作方式类似于 CPU
+内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在
+GPU 内存不足时将其自动卸载到 CPU
+内存,并在优化器更新步骤需要时将其加载回 GPU 内存。
+
+
+实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
+7. 微调方法总结
+7.1
+当前高效微调技术的简述
+之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
+7.2 BitFit
+对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
+特点:
+
+- 训练参数量极小(约0.1%)。
+- 在大部分任务上效果会差于LoRA、Adapter等方法。
+
+7.3 Prefix Tuning
+在每一个Transformer层都带上一些virtual
+token作为前缀,以适应不同的任务。
+特点:
+
+- 前缀Token会占用序列长度,有一定的额外计算开销。
+- Prefix Tuning的线性插值是比较复杂的。
+
+7.4 Prompt Tuning
+该方法可以看着是Prefix
+Tuning的简化版本,针对不同的任务,仅在输入层引入virtual
+token形式的软提示(soft prompt)。
+特点:
+
+- 相对于Prefix
+Tuning,参与训练的参数量和改变的参数量更小,更节省显存。
+- 对一些简单的NLU
+任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。
+
+7.5 P-Tuning
+将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtual
+token;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
+特点:
+
+- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtual
+token的相互依赖会收敛更快,效果更好。
+
+7.6 P-Tuning v2
+该方法在每一个Transformer层都加入了prompt
+token作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
+特点:
+
+- 解决了Prompt Tuning无法在小模型上有效提升的问题。
+- 移除了对模型效果改进较小的重参数化的编码器(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM)。
+- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。
+
+7.7 Adapter Tuning
+该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和Layer
+Norm 层进行微调。
+特点:
+
+- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。
+
+7.8 AdapterFusion
+一种融合多任务信息的Adapter的变体,在 Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+7.9 AdapterDrop
+该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+特点:
+
+- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+
+7.10 LoRA
+该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+特点:
+
+- 将BA加到W上可以消除推理延迟。
+- 可以通过可插拔的形式切换到不同的任务。
+- 设计的比较好,简单且效果好。
+
+7.11 AdaLoRA
+对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+7.12 QLoRA
+使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
+特点:
+
+- 使用 QLoRA
+微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。
+
+7.13 MAM Adapter
+一种在 Adapter、Prefix Tuning 和 LoRA
+之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter
+和 软提示的组合。
+特点:
+
+- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。
+
+7.14 UniPELT
+一种将不同的PELT方法LoRA、Prefix
+Tuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+特点:
+
+- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。
+- 多种 PELT 方法的混合涉及PLM
+的不同部分对模型有效性和鲁棒性都有好处
+
+7.15 总结
+本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
+
+- 增加额外参数,如:Prefix Tuning、Prompt Tuning、Adapter
+Tuning及其变体。
+- 选取一部分参数更新,如:BitFit。
+- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。
+- 混合高效微调,如:MAM Adapter、UniPELT。
+
+并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调
+ https://lihaibineric.github.io/2024/03/24/dl-llm-ft/
+
+
+
+
+ Author
+ Haibin Li
+
+
+
+
+ Posted on
+ March 24, 2024
+
+
+
+
+ Updated on
+ March 24, 2024
+
+
+
+
+ Licensed under
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 【大语言模型】基础模型概念
+ Next
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html
index 7a34a5d..816d579 100644
--- a/archives/2023/10/index.html
+++ b/archives/2023/10/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2023/11/index.html b/archives/2023/11/index.html
index 7842f5a..be3c6c6 100644
--- a/archives/2023/11/index.html
+++ b/archives/2023/11/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html
index 092c79f..bcb7a34 100644
--- a/archives/2023/12/index.html
+++ b/archives/2023/12/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2023/index.html b/archives/2023/index.html
index 2dd443e..00a9f5f 100644
--- a/archives/2023/index.html
+++ b/archives/2023/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2024/01/index.html b/archives/2024/01/index.html
index 84e676d..9a09053 100644
--- a/archives/2024/01/index.html
+++ b/archives/2024/01/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2024/02/index.html b/archives/2024/02/index.html
index b9e819b..a800db7 100644
--- a/archives/2024/02/index.html
+++ b/archives/2024/02/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
diff --git a/archives/2024/03/index.html b/archives/2024/03/index.html
index 45df041..e6980a4 100644
--- a/archives/2024/03/index.html
+++ b/archives/2024/03/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
diff --git a/archives/2024/index.html b/archives/2024/index.html
index 15e05e8..0579f1a 100644
--- a/archives/2024/index.html
+++ b/archives/2024/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -263,12 +269,6 @@
【深度学习】推荐系统基础知识
-
-
-
- 【深度学习】图神经网络
-
-
diff --git a/archives/2024/page/2/index.html b/archives/2024/page/2/index.html
index 49e38fd..c7a7b0b 100644
--- a/archives/2024/page/2/index.html
+++ b/archives/2024/page/2/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,6 +210,12 @@
2024
+
+
+ 【深度学习】图神经网络
+
+
+
【算法题】LeetCode算法汇总
diff --git a/archives/index.html b/archives/index.html
index 8bf5389..4f12518 100644
--- a/archives/index.html
+++ b/archives/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -263,18 +269,12 @@
【深度学习】推荐系统基础知识
-
-
-
- 【深度学习】图神经网络
-
-
diff --git a/archives/page/2/index.html b/archives/page/2/index.html
index ad7bca9..3b5a50b 100644
--- a/archives/page/2/index.html
+++ b/archives/page/2/index.html
@@ -202,7 +202,7 @@
- 20 posts in total
+ 21 posts in total
@@ -210,6 +210,12 @@
2024
+
+
+ 【深度学习】图神经网络
+
+
+
【算法题】LeetCode算法汇总
@@ -266,18 +272,12 @@
【多智能体强化学习】Pymarl环境配置
-
-
-
- 【自动驾驶】RSS Model for Autonomous Driving
-
-
diff --git a/archives/page/3/index.html b/archives/page/3/index.html
new file mode 100644
index 0000000..2ee7fb6
--- /dev/null
+++ b/archives/page/3/index.html
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Archives - LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/categories/index.html b/categories/index.html
index d955284..2e1be46 100644
--- a/categories/index.html
+++ b/categories/index.html
@@ -224,7 +224,7 @@
- 8
+ 9
- 【深度学习】大语言模型简介
+ 【大语言模型】有监督微调
-
- 【深度学习】DeepL基础知识
+ 【大语言模型】基础模型概念
+
+
+
+
+
+
+ 【深度学习】DeepL|LLM基础知识
diff --git "a/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html" "b/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
index 70e9371..616604f 100644
--- "a/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
+++ "b/categories/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
@@ -202,7 +202,7 @@
- 8 posts in total
+ 9 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
diff --git a/index.html b/index.html
index ade9136..27b81af 100644
--- a/index.html
+++ b/index.html
@@ -202,6 +202,69 @@
+
+
+
+
+
+
+
+ 【大语言模型】有监督微调
+
+
+
+
+
+
+ 大语言模型微调 1. 大模型微调简介 1.1 微调方法定义 微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。 下面是一般的微调步骤: 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。
+
+
+
+
+
+
+
@@ -209,7 +272,7 @@
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
@@ -272,7 +335,7 @@
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -769,72 +832,11 @@
-
-
-
-
-
-
-
- 【深度学习】图神经网络
-
-
-
-
-
-
- 图神经网络 GNN全称----图神经网络,它是一种直接作用于图结构上的神经网络。我们可以把图中的每一个节点 \(V\) 当作个体对象,而每一条边 \(E\) 当作个体与个体间的某种联系,所有节点组成的关系网就是最后的图 \(U\) GNN的输入一般是每个节点的起始特征向量和表示节点间关系的邻接矩阵,有了这两个输入信息,接下来就是聚合操作了。所谓的聚合,其实就是将周边与节点 V i ViVi 有关
-
-
-
-
-
-
-
diff --git a/local-search.xml b/local-search.xml
index bd4e79c..7ff96c3 100644
--- a/local-search.xml
+++ b/local-search.xml
@@ -4,11 +4,38 @@
- 【深度学习】大语言模型简介
+ 【大语言模型】有监督微调
+
+ /2024/03/24/dl-llm-ft/
+
+ 大语言模型微调
1. 大模型微调简介
1.1 微调方法定义
微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
下面是一般的微调步骤:
- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。
- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。
- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specifichead)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。
- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。
- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。
- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。
- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。
- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。
微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
1.2 为什么需要 PEFT
Parameter-EfficientFine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trainedlanguage models)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Softprompts)两个小类。
Scaling Down to Scale Up: A Guide to Parameter-EfficientFine-Tuning
1.3微调和参数高效微调之间的区别
微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
1.4 PEFT 有什么优点
在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本
- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。
- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。
- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。
- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。
1.5 多种不同的高效微调方法对比
参数有效策略可能涉及多种技术:
- 选择性层调整(Selective LayerTuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。
- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。
- 稀疏微调(SparseFine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。
- 低秩近似(Low-RankApproximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。
- 正则化技术(RegularizationTechniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。
- 任务特定的头(Task-specificHeads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。
1.6当前高效微调技术存在的一些问题
当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。Ladder-sideTuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。
- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。
- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。
- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用gitfork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。
1.7 PEFT技术实践
针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
- 明确指出参数数量类型。
- 使用不同大小的模型进行评估。
- 和类似方法进行比较。
- 标准化PEFT测量基准。
- 重视代码清晰度,以最小化进行实现。
2. 微调Fine-Tune
2.1 为什么SFT之后感觉LLM傻了?
在进行SupervisedFine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。
- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。
- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。
- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。
为了解决这些问题,可以尝试以下方法:
- 收集更多的训练数据,以增加数据的多样性和覆盖范围。
- 仔细检查微调数据集的标注,确保标签的准确性和一致性。
- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。
- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。
- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。
通过这些方法,可以尽量减少SupervisedFine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
2.2 SFT 指令微调数据 如何构建?
构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。
- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。
- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。
- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。
- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。
- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。
- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。
2.3 如何训练自己的大模型?
- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。
- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。
- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。
- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。
- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。
- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。
- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。
2.4 指令微调的好处?
指令微调(InstructionFine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。
- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。
- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。
- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。
- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。
请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
2.5 多轮对话任务微调调型
在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。
- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。
- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。
- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
- 初始化模型参数:将预训练模型的参数加载到模型中。
- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。
- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。
- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。
- 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。
- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。
需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
2.6 微调后的模型出现能力劣化
灾难性遗忘(CatastrophicForgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
在微调大语言模型时,灾难性遗忘可能出现的原因包括:
- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。
- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。
为了解决灾难性遗忘问题,可以尝试以下方法:
- 经验回放(ReplayBuffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。
- 弹性权重共享(Elastic WeightConsolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。
- 增量学习(IncrementalLearning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。
- 多任务学习(Multi-TaskLearning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。
综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
2.7 预训练和SFT操作有什么不同
大语言模型的预训练和有监督微调(SupervisedFine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
目标:
- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(MaskedLanguage Model,MLM)或下一句预测(Next SentencePrediction,NSP)等,来训练模型。
- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。
数据:
- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。
- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。
训练方式:
- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。
- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。
总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
2.8 大模型LLM进行SFT如何对样本进行优化?
对于大语言模型进行有监督微调(SupervisedFine-Tuning)时,可以采用以下几种方式对样本进行优化:
- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。
- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。
- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。
- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。
- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。
- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。
- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。
总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
3. 预训练
3.1 为什么要增量预训练?
预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
3.2进行增量预训练需要做哪些准备工作?
- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。
- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是TB 级别的。
- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。
3.3增量预训练训练流程是怎么样?
- 数据预处理:参考 LLaMA的预训练长度,也把数据处理成2048长度(如果不够,做补全)。
- 分词器:如果使用 LLaMA可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。
- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选Chat 模型。
- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。
- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。
- 模型测试:简单测试下续写能力,验证下模型是否正常。
4. Prompting工程
4.1 BitFit
4.1.1 背景
虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署,特别是随着任务数量的增加,很难维护。
理想状况下,我们希望有一种满足以下条件的高效微调方法:
- 到达能够匹配全量微调的效果。
- 仅更改一小部分模型参数。
- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。
- 改变的参数在不同下游任务中是一致的。
上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
4.1.2 技术原理
BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuningor Transformer-based MaskedLanguage-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
对于Transformer模型而言,冻结大部分 transformer-encoder参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言,只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
4.2 Prefix Tuning
4.2.1 背景
在PrefixTuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
基于上述两点,PrefixTuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的VirtualToken(Soft Prompt/ContinuousPrompt),相比离散的Token,更好优化,效果更好。
4.2.2 技术原理
Prefix Tuning(论文:Prefix-Tuning: Optimizing ContinuousPrompts forGeneration),在输入token之前构造一段任务相关的virtualtokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
针对不同的模型结构,需要构造不同的Prefix。
- 针对自回归架构模型:在句子前面添加前缀,得到
z = [PREFIX; x; y]
,合适的上文能够在固定 LM的情况下去引导生成下文(比如:GPT3的上下文学习)。 - 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder端增加前缀是为了引导后续token的生成。
该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为[PREFIX; x; y]
,Infix-tuning形式为[x; INFIX; y]
。
4.3 Prompt Tuning
4.3.1 背景
大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
基于此,作者提出了PromptTuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,训练完以后,用同一个模型可以做多任务推理。
4.3.2 技术原理
Prompt Tuning(论文:The Power of Scale forParameter-Efficient Prompt Tuning),该方法可以看作是PrefixTuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompttokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
通过实验发现,随着预训练模型参数量的增加,PromptTuning的方法会逼近全参数微调的结果。
同时,Prompt Tuning 还提出了 PromptEnsembling,也就是在一个批次(Batch)里同时训练同一个任务的不同prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
4.4 P-Tuning
4.4.1 背景
该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(incontextlearning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtualtoken(同Prefix-Tuning类似)。
4.4.2 技术原理
P-Tuning(论文:GPT Understands,Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对PromptEmbedding进行一层处理。
相比Prefix Tuning,P-Tuning加入的可微的virtualtoken,但仅限于输入层,没有在每一层都加;另外,virtualtoken的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtualtoken。
经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtualtoken,容易优化到局部最优值,而这些virtualtoken理论是应该有相关关联的。因此,作者通过实验发现用一个promptencoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtualtoken以后,再输入到模型。
从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
4.5 P-Tuning v2
4.5.1 背景
之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
第一,缺乏模型参数规模和任务通用性。
- 缺乏规模通用性:PromptTuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些NLU基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。
第二,缺少深度提示优化,在PromptTuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
- 由于序列长度的限制,可调参数的数量是有限的。
- 输入embedding对模型预测只有相对间接的影响。
考虑到这些问题,作者提出了Ptuningv2,它利用深度提示优化(如:Prefix Tuning),对PromptTuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
4.5.2 技术原理
P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can BeComparable to Fine-tuning Universally Across Scales andTasks),该方法在每一层都加入了Promptstokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
- 更多可学习的参数(从P-tuning和PromptTuning的0.01%增加到0.1%-3%),同时也足够参数高效。
- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。
具体做法基本同Prefix Tuning,可以看作是将文本生成的PrefixTuning技术适配到NLU任务中,然后做了一些改进:
- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:PrefixTuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。
- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuningv2的有益补充。
- 回归传统的分类标签范式,而不是映射器。标签词映射器(LabelWordVerbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuningv2回归传统的CLS标签分类范式,采用随机初始化的分类头(ClassificationHead)应用于tokens之上,以增强通用性,可以适配到序列标注任务。
论文中展示了P-tuningv2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),PromptTuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuningv2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuningv2在RTE中的表现明显优于微调,特别是在BERT中。
5. Adapter-Tuning
5.1 Adapter Tuning
5.1.1 背景
预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题Adapter在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
5.1.2 技术原理
Adapter Tuning(论文:Parameter-Efficient Transfer LearningforNLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的==Adapter 结构和 Layer Norm层==进行微调,从而保证了训练的高效性。
每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
5.1.3 具体细节
每个 Adapter模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skipconnection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便Adapter 一开始的参数初始化接近0,Adapter也由于skipconnection的设置而接近于一个恒等映射,从而确保训练的有效性。
\[h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p}\]
通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
5.2 AdapterFusion
5.2.1 背景
为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequentialfine-tuning)或者多任务学习(multi-tasklearning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
而之前的工作,AdapterTuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter的参数某种程度上就表达了解决这个任务需要的知识。
作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
5.2.2 技术原理
Adapter Fusion(论文:AdapterFusion:Non-Destructive TaskComposition for TransferLearning),一种融合多任务信息的Adapter的变体,在Adapter的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。
对于第一阶段,有两种训练方式,分别如下:
- Single-TaskAdapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。
- Multi-TaskAdapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。
对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
5.2.3 AdapterFusion结构
AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
5.3 AdapterDrop
5.3.1 背景
近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
基于此,作者提出了AdapterDrop方法缓解该问题。
5.3.2 技术原理
AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters inTransformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。例如,将前五个Transformer层中的Adapter丢弃,在对 8个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop也能保持良好的结果。
除此之外,作者还研究了对AdapterFusion中的Adapter进行剪枝后的效果。
通过实验表明可以移除 AdapterFusion中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
总之,AdapterDrop通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
5.4 MAM Adapter
5.4.1 背景
近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,PrefixTuning和LoRA都是性能比较好的方法。
为什么看起来Adapter、PrefixTuning、LoRA(在结构上和公式上)都不太一样,尤其是PrefixTuning,但是这三种方法有近似的效果?
基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、PrefixTuning和LoRA)的设计,并提出了一种新方法MAMAdapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
首先,作者通过对Prefix Tuning变换,发现PrefixTuning和Adapters的公式高度相似。
然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、PrefixTuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体)Parallel Adapter、 Scaled PA的结构。
下表展示了高效微调方法Adapter、PrefixTuning、LoRA以及新变体在新增可训练参数结构形式(functionalform)、结构插入形式(Insertionform)、新增结构在PLM修改的具体位置(modifiedrepresentation)、新增结构与PLM的组合函数(compositionfunction)。其中,新增可训练参数结构形式为需要学习的部分(注:PrefixTuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
5.4.2 技术原理
MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENTTRANSFER LEARNING),一个在Adapter、PrefixTuning和LoRA之间建立联系的统一方法。
作者对Adapter的放置和软提示(softprompt)进行了详细的调查。得出如下结论:
- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。
- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。
然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用FFN 层的并行Adapter和软提示的组合。
通过最终的实验结果,可以看到 MAM Adapter在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
5.5 UniPELT
5.5.1 背景
近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
5.5.2 技术原理
UniPELT(论文: UNIPELT: A Unified Framework for Parameter-EfficientLanguage Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,PrefixTuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括LoRA 矩阵WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT的性能与这些方法相当或更好。
实验还对不同 PELT 方法训练时间和推理时间进行了分析。
- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围,
- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。
- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。
6. lora
6.1 LoRA
6.1.1 背景
神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsicrank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
6.1.2 技术原理
LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGEMODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsicrank)。
可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
\[h=W_{0} x+\Delta W x=W_{0} x+B A x\]
在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
此外,Transformer的权重矩阵包括Attention模块里用于计算query
,key
,value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整Wq 和 Wv 会产生最佳结果。
实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
6.2 AdaLoRA
6.2.1 背景
在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。
- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。
为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adaptertuning、Prefix tuning、PromptTuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adaptertuning引入了推理延时;Prefix tuning或Prompttuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。
- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diffpruning、LoRA等,此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diffpruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。LoRA则需要预先指定每个增量矩阵的本征秩 r相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。
基于以上问题进行总结:
- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。
- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。
为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
6.2.2 技术原理
AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FORPARAMETEREFFICIENTFINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。
\[W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q\]
- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。
通过实验证明,AdaLoRA实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。例如,当参数预算为 0.3M 时,AdaLoRA在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
6.3 QLoRA
6.3.1 背景
微调大型语言模型 (LLM)是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU内存。
虽然最近的量化方法可以减少 LLM的内存占用,但此类技术仅适用于推理场景。
基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为4 bit的模型。
6.3.2 技术原理
QLoRA(论文: QLORA: Efficient Finetuning of QuantizedLLMs),使用一种新颖的高精度技术将预训练模型量化为 4bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA有一种低精度存储数据类型(4bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bitNormalFloat(NF4)量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
- 4bitNormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比4 bit整数和 4bit 浮点数更好的实证结果。
- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。
- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的GPU 处理。该功能的工作方式类似于 CPU内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在GPU 内存不足时将其自动卸载到 CPU内存,并在优化器更新步骤需要时将其加载回 GPU 内存。
实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
7. 微调方法总结
7.1当前高效微调技术的简述
之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
7.2 BitFit
对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
特点:
- 训练参数量极小(约0.1%)。
- 在大部分任务上效果会差于LoRA、Adapter等方法。
7.3 Prefix Tuning
在每一个Transformer层都带上一些virtualtoken作为前缀,以适应不同的任务。
特点:
- 前缀Token会占用序列长度,有一定的额外计算开销。
- Prefix Tuning的线性插值是比较复杂的。
7.4 Prompt Tuning
该方法可以看着是PrefixTuning的简化版本,针对不同的任务,仅在输入层引入virtualtoken形式的软提示(soft prompt)。
特点:
- 相对于PrefixTuning,参与训练的参数量和改变的参数量更小,更节省显存。
- 对一些简单的NLU任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。
7.5 P-Tuning
将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对PromptEmbedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtualtoken;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
特点:
- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtualtoken的相互依赖会收敛更快,效果更好。
7.6 P-Tuning v2
该方法在每一个Transformer层都加入了prompttoken作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
特点:
- 解决了Prompt Tuning无法在小模型上有效提升的问题。
- 移除了对模型效果改进较小的重参数化的编码器(如:PrefixTuning中的MLP、P-Tuning中的LSTM)。
- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。
7.7 Adapter Tuning
该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和LayerNorm 层进行微调。
特点:
- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。
7.8 AdapterFusion
一种融合多任务信息的Adapter的变体,在 Adapter的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
7.9 AdapterDrop
该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
特点:
- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
7.10 LoRA
该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
特点:
- 将BA加到W上可以消除推理延迟。
- 可以通过可插拔的形式切换到不同的任务。
- 设计的比较好,简单且效果好。
7.11 AdaLoRA
对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
7.12 QLoRA
使用一种新颖的高精度技术将预训练模型量化为 4bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
特点:
- 使用 QLoRA微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。
7.13 MAM Adapter
一种在 Adapter、Prefix Tuning 和 LoRA之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter和 软提示的组合。
特点:
- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。
7.14 UniPELT
一种将不同的PELT方法LoRA、PrefixTuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
特点:
- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。
- 多种 PELT 方法的混合涉及PLM的不同部分对模型有效性和鲁棒性都有好处
7.15 总结
本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
- 增加额外参数,如:Prefix Tuning、Prompt Tuning、AdapterTuning及其变体。
- 选取一部分参数更新,如:BitFit。
- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。
- 混合高效微调,如:MAM Adapter、UniPELT。
并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
]]>
+
+
+
+
+ 深度学习
+
+
+
+
+
+
+ 深度学习
+
+ 大语言模型
+
+
+
+
+
+
+
+
+ 【大语言模型】基础模型概念
/2024/03/08/dl_llm_model/
- 大语言模型简介
1.llm概念
1.1 主流的开源模型体系
目前主流的开源LLM(语言模型)模型体系包括以下几个:
- GPT(Generative Pre-trainedTransformer)系列:由OpenAI发布的一系列基于Transformer架构的语言模型,包括GPT、GPT-2、GPT-3等。GPT模型通过在大规模无标签文本上进行预训练,然后在特定任务上进行微调,具有很强的生成能力和语言理解能力。
- BERT(Bidirectional Encoder Representations fromTransformers):由Google发布的一种基于Transformer架构的双向预训练语言模型。BERT模型通过在大规模无标签文本上进行预训练,然后在下游任务上进行微调,具有强大的语言理解能力和表征能力。
- XLNet:由CMU和GoogleBrain发布的一种基于Transformer架构的自回归预训练语言模型。XLNet模型通过自回归方式预训练,可以建模全局依赖关系,具有更好的语言建模能力和生成能力。
- RoBERTa:由Facebook发布的一种基于Transformer架构的预训练语言模型。RoBERTa模型在BERT的基础上进行了改进,通过更大规模的数据和更长的训练时间,取得了更好的性能。
- T5(Text-to-Text TransferTransformer):由Google发布的一种基于Transformer架构的多任务预训练语言模型。T5模型通过在大规模数据集上进行预训练,可以用于多种自然语言处理任务,如文本分类、机器翻译、问答等。
这些模型在自然语言处理领域取得了显著的成果,并被广泛应用于各种任务和应用中。
1.2 prefix LM 和 causal LM区别是什么?
Prefix LM(前缀语言模型)和CausalLM(因果语言模型)是两种不同类型的语言模型,它们的区别在于生成文本的方式和训练目标。
- PrefixLM:前缀语言模型是一种生成模型,它在生成每个词时都可以考虑之前的上下文信息。在生成时,前缀语言模型会根据给定的前缀(即部分文本序列)预测下一个可能的词。这种模型可以用于文本生成、机器翻译等任务。
- CausalLM:因果语言模型是一种自回归模型,它只能根据之前的文本生成后续的文本,而不能根据后续的文本生成之前的文本。在训练时,因果语言模型的目标是预测下一个词的概率,给定之前的所有词作为上下文。这种模型可以用于文本生成、语言建模等任务。
总结来说,前缀语言模型可以根据给定的前缀生成后续的文本,而因果语言模型只能根据之前的文本生成后续的文本。它们的训练目标和生成方式略有不同,适用于不同的任务和应用场景。
1.3 大模型LLM的训练目标
大型语言模型(Large LanguageModels,LLM)的训练目标通常是最大似然估计(Maximum LikelihoodEstimation,MLE)。最大似然估计是一种统计方法,用于从给定数据中估计概率模型的参数。
在LLM的训练过程中,使用的数据通常是大量的文本语料库。训练目标是最大化模型生成训练数据中观察到的文本序列的概率。具体来说,对于每个文本序列,模型根据前面的上下文生成下一个词的条件概率分布,并通过最大化生成的词序列的概率来优化模型参数。
为了最大化似然函数,可以使用梯度下降等优化算法来更新模型参数,使得模型生成的文本序列的概率逐步提高。在训练过程中,通常会使用批量训练(batchtraining)的方法,通过每次处理一小批数据样本来进行参数更新。
1.4 涌现能力是啥原因?
大语言模型的涌现能力:现象与解释- 知乎 (zhihu.com)
涌现能力(EmergentAbility)是指模型在训练过程中能够生成出令人惊喜、创造性和新颖的内容或行为。这种能力使得模型能够超出其训练数据所提供的内容,并产生出具有创造性和独特性的输出。
涌现能力的产生可以归因于以下几个原因:
- 任务的评价指标不够平滑:因为很多任务的评价指标不够平滑,导致我们现在看到的涌现现象。如果评价指标要求很严格,要求一字不错才算对,那么Emoji_movie任务我们就会看到涌现现象的出现。但是,如果我们把问题形式换成多选题,就是给出几个候选答案,让LLM选,那么随着模型不断增大,任务效果在持续稳定变好,但涌现现象消失,如上图图右所示。这说明评价指标不够平滑,起码是一部分任务看到涌现现象的原因。
- 复杂任务 vs子任务:展现出涌现现象的任务有一个共性,就是任务往往是由多个子任务构成的复杂任务。也就是说,最终任务过于复杂,如果仔细分析,可以看出它由多个子任务构成,这时候,子任务效果往往随着模型增大,符合Scaling Law,而最终任务则体现为涌现现象。
- 用 Grokking(顿悟)来解释涌现:对于某个任务T,尽管我们看到的预训练数据总量是巨大的,但是与T相关的训练数据其实数量很少。当我们推大模型规模的时候,往往会伴随着增加预训练数据的数据量操作,这样,当模型规模达到某个点的时候,与任务T相关的数据量,突然就达到了最小要求临界点,于是我们就看到了这个任务产生了Grokking现象。
尽管涌现能力为模型带来了创造性和独特性,但也需要注意其生成的内容可能存在偏差、错误或不完整性。因此,在应用和使用涌现能力强的模型时,需要谨慎评估和验证生成的输出,以确保其质量和准确性。
1.5为何现在的大模型大部分是Decoder only结构
- 自回归生成:Decoder-only结构适用于自回归生成任务,其中模型根据先前的输入生成下一个输出。这种结构在自然语言处理任务中非常有用,如文本生成、机器翻译和对话生成等。Decoder-only结构能够利用上下文信息来生成连续的输出序列,使得生成的结果更加准确和连贯。
- 生成多样性:Decoder-only结构可以通过在训练期间使用不同的解码策略来生成多样化的结果。例如,在生成文本时,可以使用不同的采样策略(如贪婪采样或随机采样)或温度参数来调整生成的多样性。这种能力对于一些任务(如对话生成)非常重要,因为它可以产生更加有趣和多样化的回复。
- 模型训练和推理的一致性:Decoder-only结构使得模型的训练和推理过程更加一致。在训练期间,模型可以使用教师强制(teacherforcing)策略,即将真实的目标输出作为输入传递给解码器。而在推理期间,模型可以逐步生成输出,将前一个时间步的输出作为输入传递给下一个时间步。这种一致性有助于更好地控制模型的生成过程,并提高模型的稳定性和可靠性。
1.6 大模型架构介绍
LLM(Large LanguageModel,大型语言模型)是指基于大规模数据和参数量的语言模型。具体的架构可以有多种选择,以下是一种常见的大模型LLM的架构介绍:
- Transformer架构:大模型LLM常使用Transformer架构,它是一种基于自注意力机制的序列模型。Transformer架构由多个编码器层和解码器层组成,每个层都包含多头自注意力机制和前馈神经网络。这种架构可以捕捉长距离的依赖关系和语言结构,适用于处理大规模语言数据。
- 自注意力机制(Self-Attention):自注意力机制是Transformer架构的核心组件之一。它允许模型在生成每个词时,根据输入序列中的其他词来计算该词的表示。自注意力机制能够动态地为每个词分配不同的权重,从而更好地捕捉上下文信息。
- 多头注意力(Multi-HeadAttention):多头注意力是自注意力机制的一种扩展形式。它将自注意力机制应用多次,每次使用不同的权重矩阵进行计算,得到多个注意力头。多头注意力可以提供更丰富的上下文表示,增强模型的表达能力。
- 前馈神经网络(Feed-ForwardNetwork):在Transformer架构中,每个注意力层后面都有一个前馈神经网络。前馈神经网络由两个全连接层组成,通过非线性激活函数(如ReLU)进行变换。它可以对注意力层输出的表示进行进一步的映射和调整。
- 预训练和微调:大模型LLM通常采用预训练和微调的方法进行训练。预训练阶段使用大规模无标签数据,通过自监督学习等方法进行训练,使模型学习到丰富的语言知识。微调阶段使用有标签的特定任务数据,如文本生成、机器翻译等,通过有监督学习进行模型的微调和优化。
需要注意的是,大模型LLM的具体架构可能会因不同的研究和应用而有所不同。上述介绍的是一种常见的架构,但实际应用中可能会有一些变体或改进。
1.7 LLMs复读机问题
1.7.1 什么是 LLMs 复读机问题?
LLMs复读机问题(LLMs ParrotingProblem)是指大型语言模型在生成文本时过度依赖输入文本的复制,而缺乏创造性和独特性。当面对一个问题或指令时,模型可能会简单地复制输入文本的一部分或全部内容,并将其作为生成的输出,而不是提供有意义或新颖的回应。
1.7.2 为什么会出现 LLMs复读机问题?
- 数据偏差:大型语言模型通常是通过预训练阶段使用大规模无标签数据进行训练的。如果训练数据中存在大量的重复文本或者某些特定的句子或短语出现频率较高,模型在生成文本时可能会倾向于复制这些常见的模式。
- 训练目标的限制:大型语言模型的训练通常是基于自监督学习的方法,通过预测下一个词或掩盖词来学习语言模型。这样的训练目标可能使得模型更倾向于生成与输入相似的文本,导致复读机问题的出现。
- 缺乏多样性的训练数据:虽然大型语言模型可以处理大规模的数据,但如果训练数据中缺乏多样性的语言表达和语境,模型可能无法学习到足够的多样性和创造性,导致复读机问题的出现。
- 模型结构和参数设置:大型语言模型的结构和参数设置也可能对复读机问题产生影响。例如,模型的注意力机制和生成策略可能导致模型更倾向于复制输入的文本。
1.7.3 如何缓解 LLMs 复读机问题?
为了缓解LLMs复读机问题,可以尝试以下方法:
- 多样性训练数据:在训练阶段,使用多样性的语料库来训练模型,避免数据偏差和重复文本的问题。这可以包括从不同领域、不同来源和不同风格的文本中获取数据。
- 引入噪声:在生成文本时,引入一些随机性或噪声,例如通过采样不同的词或短语,或者引入随机的变换操作,以增加生成文本的多样性。这可以通过在生成过程中对模型的输出进行采样或添加随机性来实现。
- 温度参数调整:温度参数是用来控制生成文本的多样性的一个参数。通过调整温度参数的值,可以控制生成文本的独创性和多样性。较高的温度值会增加随机性,从而减少复读机问题的出现。
- Beam搜索调整:在生成文本时,可以调整Beam搜索算法的参数。Beam搜索是一种常用的生成策略,它在生成过程中维护了一个候选序列的集合。通过调整Beam大小和搜索宽度,可以控制生成文本的多样性和创造性。
- 后处理和过滤:对生成的文本进行后处理和过滤,去除重复的句子或短语,以提高生成文本的质量和多样性。可以使用文本相似度计算方法或规则来检测和去除重复的文本。
- 人工干预和控制:对于关键任务或敏感场景,可以引入人工干预和控制机制,对生成的文本进行审查和筛选,确保生成结果的准确性和多样性。
需要注意的是,缓解LLMs复读机问题是一个复杂的任务,没有一种通用的解决方案。不同的方法可能适用于不同的场景和任务,需要根据具体情况进行选择和调整。此外,解决复读机问题还需要综合考虑数据、训练目标、模型架构和生成策略等多个因素,需要进一步的研究和实践来提高大型语言模型的生成文本多样性和创造性。
1.8LLMs输入句子长度理论上可以无限长吗?
理论上来说,LLMs(大型语言模型)可以处理任意长度的输入句子,但实际上存在一些限制和挑战。下面是一些相关的考虑因素:
- 计算资源:生成长句子需要更多的计算资源,包括内存和计算时间。由于LLMs通常是基于神经网络的模型,计算长句子可能会导致内存不足或计算时间过长的问题。
- 模型训练和推理:训练和推理长句子可能会面临一些挑战。在训练阶段,处理长句子可能会导致梯度消失或梯度爆炸的问题,影响模型的收敛性和训练效果。在推理阶段,生成长句子可能会增加模型的错误率和生成时间。
- 上下文建模:LLMs是基于上下文建模的模型,长句子的上下文可能会更加复杂和深层。模型需要能够捕捉长句子中的语义和语法结构,以生成准确和连贯的文本。
1.9如何让大模型处理更长的文本?
要让大模型处理更长的文本,可以考虑以下几个方法:
- 分块处理:将长文本分割成较短的片段,然后逐个片段输入模型进行处理。这样可以避免长文本对模型内存和计算资源的压力。在处理分块文本时,可以使用重叠的方式,即将相邻片段的一部分重叠,以保持上下文的连贯性。
- 层次建模:通过引入层次结构,将长文本划分为更小的单元。例如,可以将文本分为段落、句子或子句等层次,然后逐层输入模型进行处理。这样可以减少每个单元的长度,提高模型处理长文本的能力。
- 部分生成:如果只需要模型生成文本的一部分,而不是整个文本,可以只输入部分文本作为上下文,然后让模型生成所需的部分。例如,输入前一部分文本,让模型生成后续的内容。
- 注意力机制:注意力机制可以帮助模型关注输入中的重要部分,可以用于处理长文本时的上下文建模。通过引入注意力机制,模型可以更好地捕捉长文本中的关键信息。
- 模型结构优化:通过优化模型结构和参数设置,可以提高模型处理长文本的能力。例如,可以增加模型的层数或参数量,以增加模型的表达能力。还可以使用更高效的模型架构,如Transformer等,以提高长文本的处理效率。
需要注意的是,处理长文本时还需考虑计算资源和时间的限制。较长的文本可能需要更多的内存和计算时间,因此在实际应用中需要根据具体情况进行权衡和调整。
2.LLama系列模型
2.1LLama
2.1.1 简介
LLaMA 所采用的 Transformer 结构和细节,与标准的 Transformer架构不同的地方包括采用了前置层归一化(Pre-normalization)并使用RMSNorm 归一化函数 (NormalizingFunction)、激活函数更换为SwiGLU,并使用了旋转位置嵌入(RoP),整体Transformer 架构与 GPT-2 类似。
2.1.2 RMSNorm归一化函数
为了使得模型训练过程更加稳定,GPT-2 相较于 GPT就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了RMSNorm 归一化函数。 针对输入向量a,RMSNorm 函数计算公式如下 \[R M S(a)=\sqrt{\frac{1}{n} \sum_{i=1}^{n} a_{i}^{2}}\]
\[\bar{a}_{i}=\frac{a_{i}}{R M S(\boldsymbol{a})}\]
此外,RMSNorm 还可以引入可学习的缩放因子 $ g_ i $和偏移参数 \(b_i\),从而得到 \(\bar{a}_{i}=\frac{a_{i}}{\operatorname{RMS}(\boldsymbol{a})}g_{i}+b_{i}\)。 RMSNorm 在 HuggingFace Transformer库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class LlamaRMSNorm(nn.Module):
def __init__(self, hidden_size, eps=1e-6):
"""
LlamaRMSNorm is equivalent to T5LayerNorm
"""
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.variance_epsilon = eps # eps 防止取倒数之后分母为 0
def forward(self, hidden_states):
input_dtype = hidden_states.dtype
variance = hidden_states.to(torch.float32).pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) # weight 是末尾乘的可训练参数, 即 g_i
return (self.weight * hidden_states).to(input_dtype)
为什么要用RMSNorm优势在哪里?
不用计算均值,直接算一次就能得到结果
2.1.3 SwiGLU激活函数
SwiGLU激活函数是相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA中全连接层使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-ForwardNetwork)的计算公式如下:
\[\operatorname{FFN}_{\text {SwiGLU }}\left(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V},\boldsymbol{W}_{2}\right)=\operatorname{SwiGLU}(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V}) \boldsymbol{W}_{2}\]
\[\operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W},\boldsymbol{V})=\operatorname{Swish}_{\beta}(x \boldsymbol{W}) \otimes\boldsymbol{x} \boldsymbol{V}\]
\[\operatorname{Swish}_{\beta}(\boldsymbol{x})=\boldsymbol{x}\sigma(\boldsymbol{\beta} \boldsymbol{x})\]
其中,\(σ(x)\) 是 Sigmoid函数。下图给出了 Swish 激活函数在参数 \(β\) 不同取值下的形状。可以看 到当 \(β\) 趋近于 0 时,Swish 函数趋近于线性函数\(y = x\),当 $ β \(趋近于无穷大时,Swish 函数趋近于 ReLU函数,\)β$ 取值为 1 时,Swish 函数是光滑且非单调。在 HuggingFace的 Transformer 库中 Swish1 函数使用 silu 函数代替。
LLaMA中直接将FFN中的ReLU替换为SwiGLU,并将维度放缩为\((2/3) ⋅ 4d\)
2.1.4 旋转位置嵌入(RoPE)
在位置编码上,使用旋转位置嵌入(Rotary PositionalEmbeddings,RoPE)代替原有的绝对位置编码。RoPE借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给q
,k
添加绝对位置信息:
\[\tilde{\boldsymbol{q}}_{m}=f(\boldsymbol{q}, m),\tilde{\boldsymbol{k}}_{n}=f(\boldsymbol{k}, n)\]
经过上述操作后,\(\tilde{\boldsymbol{q}}_{m}\)和\(\tilde{\boldsymbol{k}}_{n}\)就带有位置m和n的绝对位置信息。
最终可以得到二维情况下用复数表示的 RoPE:
\[f(\boldsymbol{q}, m)=R_{f}(\boldsymbol{q}, m) e^{i\Theta_{f}(\boldsymbol{q}, m)}=\|\boldsymbol{q}\|e^{i(\Theta(\boldsymbol{q})+m \theta)}=\boldsymbol{q} e^{i m \theta}\]
根据复数乘法的几何意义,上述变换实际上是对应向量旋转,所以位置向量称为“旋转式位置编码”。还可以使用矩阵形式表示
\[f(\boldsymbol{q}, m)=\left(\begin{array}{cc}\cos m \theta & -\sin\cos m \theta \\ \sin m \theta & \cos m\theta\end{array}\right)\left(\begin{array}{l}\boldsymbol{q}_{0} \\\boldsymbol{q}_{1}\end{array}\right)\]
根据内积满足线性叠加的性质,任意偶数维的RoPE,都可以表示为二维情形的拼接,即:
\[f(\boldsymbol{q}, m)=\underbrace{\left(\begin{array}{ccccccc}\cos m\theta_{0} & -\sin m \theta_{0} & 0 & 0 & \cdots & 0& 0 \\ \sin m \theta_{0} & \cos m \theta_{0} & 0 & 0& \cdots & 0 & 0 \\ 0 & 0 & \cos m \theta_{1} &-\sin m \theta_{1} & \cdots & 0 & 0 \\ 0 & 0 & \sinm \theta_{1} & \cos m \theta_{1} & \cdots & 0 & 0 \\\cdots & \cdots & \cdots & \cdots & \ddots & \cdots& \cdots \\ 0 & 0 & 0 & 0 & \cdots & \cos m\theta_{d / 2-1} & -\sin m \theta_{d / 2-1} \\ 0 & 0 & 0& 0 & \cdots & \sin m \theta_{d / 2-1} & \cos m\theta_{d /2-1}\end{array}\right)}_{\boldsymbol{R}_{d}}\left(\begin{array}{c}\boldsymbol{q}_{0}\\ \boldsymbol{q}_{1} \\ \boldsymbol{q}_{2} \\ \boldsymbol{q}_{3} \\\cdots \\ \boldsymbol{q}_{d-2} \\ \boldsymbol{q}_{d-1}\end{array}\right)\]
RoPE 在 HuggingFace Transformer 库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import torch
def precompute_freqs_cis(dim: int, end: int, constant: float = 10000.0):
'''
计算cos和sin的值,cos值在实部,sin值在虚部,类似于 cosx+j*sinx
:param dim: q,k,v的最后一维,一般为emb_dim/head_num
:param end: 句长length
:param constant: 这里指10000
:return:
复数计算 torch.polar(a, t)输出, a*(cos(t)+j*sin(t))
'''
# freqs: 计算 1/(10000^(2i/d) ),将结果作为参数theta
# 形式化为 [theta_0, theta_1, ..., theta_(d/2-1)]
freqs = 1.0 / (constant ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) # [d/2]
# 计算m
t = torch.arange(end, device=freqs.device) # [length]
# 计算m*theta
freqs = torch.outer(t, freqs).float() # [length, d/2]
# freqs形式化为 [m*theta_0, m*theta_1, ..., m*theta_(d/2-1)],其中 m=0,1,...,length-1
# 计算cos(m*theta)+j*sin(m*theta)
freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64
# freqs_cis: [cos(m*theta_0)+j*sin(m*theta_0), cos(m*theta_1)+j*sin(m*theta_1),), ..., cos(m*theta_(d/2-1))+j*sin(m*theta_(d/2-1))]
# 其中j为虚数单位, m=0,1,...,length-1
return freqs_cis # [length, d/2]
def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
ndim = x.ndim
assert 0 <= 1 < ndim
assert freqs_cis.shape == (x.shape[1], x.shape[-1])
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] # (1, length, 1, d/2)
return freqs_cis.view(*shape) # [1, length, 1, d/2]
def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor,):
# 先将xq维度变为[bs, length, head, d/2, 2], 利用torch.view_as_complex转变为复数
# xq:[q0, q1, .., q(d-1)] 转变为 xq_: [q0+j*q1, q2+j*q3, ..., q(d-2)+j*q(d-1)]
xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [bs, length, head, d/2]
# 同样的,xk_:[k0+j*k1, k2+j*k3, ..., k(d-2)+j*k(d-1)]
xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
freqs_cis = reshape_for_broadcast(freqs_cis, xq_) # [1, length, 1, d/2]
# 下式xq_ * freqs_cis形式化输出,以第一个为例, 如下
# (q0+j*q1)(cos(m*theta_0)+j*sin(m*theta_0)) = q0*cos(m*theta_0)-q1*sin(m*theta_0) + j*(q1*cos(m*theta_0)+q0*sin(m*theta_0))
# 上式的实部为q0*cos(m*theta_0)-q1*sin(m*theta_0),虚部为q1*cos(m*theta_0)+q0*sin(m*theta_0)
# 然后通过torch.view_as_real函数,取出实部和虚部,维度由[bs, length, head, d/2]变为[bs, length, head, d/2, 2],最后一维放实部与虚部
# 最后经flatten函数将维度拉平,即[bs, length, head, d]
# 此时xq_out形式化为 [实部0,虚部0,实部1,虚部1,..., 实部(d/2-1), 虚部(d/2-1)]
xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3) # [bs, length, head, d]
# 即为新生成的q
xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
return xq_out.type_as(xq), xk_out.type_as(xk)
if __name__=='__main__':
# (bs, length, head, d)
q = torch.randn((2, 10, 12, 32)) # q=[q0, q1, .., qd-1]
k = torch.randn((2, 10, 12, 32))
v = torch.randn((2, 10, 12, 32))
freqs_cis= precompute_freqs_cis(dim=32, end=10, constant= 10000.0)
# print(freqs_cis.detach().numpy())
q_new, k_new = apply_rotary_emb(xq=q, xk=k, freqs_cis=freqs_cis)
print()
1.2 Alpaca
1.2.1 简介
Stanford Alpaca: An Instruction-following LLaMA Model
Alpaca是在LLaMA基础上使用52K指令数据精调的预训练模型,作者只用了不到600美元的成本训练出了该模型(数据$500+ 机器$100)。初步实验结果表明Alpaca可以达到与OpenAItext-davinci-003相匹敌的效果
1.2.2 微调方法
- 第一步:构造175条self-instruct 种子示例任务
- 第二步:基于上述种子任务,利 用text-davinci-003爬取指令数据
- 第三步:使用爬取下来的52K指令 数据在LLaMA上进行精调,最终得到Alpaca
1.2.3 Self-instruct数据构造
首先由人工构造175条种子数据
1
2
3
4
5
6
7
{
"id": "seed_task_25",
"name": "perfect_numbers",
"instruction": "Find the four smallest perfect numbers.",
"instances": [{ "input": "", "output": "6, 28, 496, and 8128”}],
"is_classification": false
}
将“爬取要求”和种子数据进行适当组合,送入textdavinci-003,要求生成类似的指令数据。要求包括:提升指令多样性、包含真实数据、字数要求、语言要求、拒绝不合适指令等
1.2.4 指令数据格式
instruction
: 描述模型需要执行的指令内容input
(可选):任务上下文或输入信息,例如当指令是“对文章进行总结”,则input是文章内容output
: 由text-davinci-003生成的针对指令的回复
1.3.Llama-2
1.3.1 简介
Llama 2: Open Foundation and Fine-Tuned Chat Models
2023年7月,Meta推出了Llama-2开源大模型,并且推出了Llama-2-Chat对话模型
与一代LLaMA主要区别体现在更多的训练数据、更⻓的上下文窗口、GQA技术等
二次分发是什么?
模型结构的变动主要是体现在GQA和FFN缩放上
- MHA改成GQA:整体参数量会有减少
- FFN模块矩阵维度有扩充:增强泛化能力,整体参数量增加
- 上下文长度是llama两倍(长度从2048->4096)训练语料增加约 40%,体现在1.4T->2.0T的Tokensllama2-34B和llama2-70B使用了GQA,加速模型训练和推理速度
1.3.2 GQA
GQA和MQA都是注意力的变体,其中多个查询头关注相同的键和值头,以减少推理过程中KV 缓存的大小,并可以显著提高推理吞吐量。
MHA、GQA、MQA的区别和联系,具体的优点如下:
Mutil-Head Attention
因为自回归模型生成回答时,需要前面生成的KV缓存起来,来加速计算。Multi-Query Attention
多个头之间可以共享KV对,因此速度上非常有优势,实验验证大约减少30-40%吞吐。Group Query Attention
没有像MQA那么极端,将query分组,组内共享KV,效果接近MQA,速度上与MQA可比较。
Llama-2中使用了8个KV映射,即GQA-8,GQA在多数任务上与MHA效果相当,且平均效果优于MQA;GQA和MQA均比MHA有更好的吞吐量
1.3.3 源码
2.ChatGLM
2.1 背景
主流的预训练框架主要有三种:
- autoregressive自回归模型(AR模型):代表作GPT。本质上是一个left-to-right的语言模型。通常用于生成式任务,在长文本生成方面取得了巨大的成功,比如自然语言生成(NLG)领域的任务:摘要、翻译或抽象问答。当扩展到十亿级别参数时,表现出了少样本学习能力。缺点是单向注意力机制,在NLU任务中,无法完全捕捉上下文的依赖关系。
- autoencoding自编码模型(AE模型):代表作BERT。是通过某个降噪目标(比如MLM)训练的双向文本编码器。编码器会产出适用于NLU任务的上下文表示,但无法直接用于文本生成。
- encoder-decoder(Seq2seq模型):代表作T5。采用双向注意力机制,通常用于条件生成任务,比如文本摘要、机器翻译等。
三种预训练框架各有利弊,没有一种框架在以下三种领域的表现最佳:自然语言理解(NLU)、无条件生成以及条件生成。T5曾经尝试使用MTL的方式统一上述框架,然而自编码和自回归目标天然存在差异,简单的融合自然无法继承各个框架的优点。
在这个天下三分的僵持局面下,GLM诞生了。
GLM模型基于autoregressive blankinfilling方法,结合了上述三种预训练模型的思想。
2.2 GLM预训练框架
GLM特点
- 自编码思想:在输入文本中,随机删除连续的tokens。
- 自回归思想:顺序重建连续tokens。在使用自回归方式预测缺失tokens时,模型既可以访问corrupted文本,又可以访问之前已经被预测的spans。
- span shuffling + 二维位置编码技术。
- 通过改变缺失spans的数量和长度,自回归空格填充目标可以为条件生成以及无条件生成任务预训练语言模型。
2.2.1 自回归空格填充任务
给定一个输入文本\(x=\left[x_{1}, \ldotsx_{n}\right]\),可以采样得到多个文本spans \(\left\{s_{1}, \ldotss_{m}\right\}\)。为了充分捕捉各spans之间的相互依赖关系,可以对spans的顺序进行随机排列,得到所有可能的排列集合\(Z_m\),其中:\(S_{z<i}=\left[s_{z_{1}}, \ldots,s_{z_{i-1}}\right]\)。所以预训练目标很清晰:
\[\max _{\theta} \mathbb{E}_{\boldsymbol{z} \simZ_{m}}\left[\sum_{i=1}^{m} \log p_{\theta}\left(\boldsymbol{s}_{z_{i}}\mid \boldsymbol{x}_{\text {corrupt }},\boldsymbol{s}_{\boldsymbol{z}_{<i}}\right)\right]\]
GLM自回归空格填充任务的技术细节:
- 输入\(x\)可以被分成两部分:PartA是被mask的文本 \(x_{\text {corrupt}}\),Part B由masked spans组成。假设原始输入文本是
\([x1, x2, x3, x4, x5,x6]\),采样的两个文本片段是\([x3]\)以及\([x5,x6]\)。那么mask后的文本序列是:\(x1,x2, [M], x4, [M]\),即Part A;同时我们需要对PartB的片段进行shuffle。每个片段使用[S]
填充在开头作为输入,使用[E]
填充在末尾作为输出。 - 二维位置编码:Transformer使用位置编码来标记tokens中的绝对和相对位置。在GLM中,使用二维位置编码,第一个位置id用来标记PartA中的位置,第二个位置id用来表示跨度内部的相对位置。这两个位置id会通过embedding表被投影为两个向量,最终都会被加入到输入token的embedding表达中。
- 观察GLM中自定义attention mask的设计,非常巧妙:
- Part A中的tokens彼此可见,但是不可见B中的任意tokens。
- Part B tokens可见Part A。
- Part B tokens可见B中过去的tokens,不可见B中未来的tokens。
- 采样方式:文本片段的采样遵循泊松分布,重复采样,直到原始tokens中有15%被mask。
- 总结:模型可以自动学习双向encoder(Part A)以及单向decoder(PartB)。
2.2.2 多目标预训练
上述方法适合于NLU任务。作者希望可以训练一个既可以解决NLU任务,又具备文本生成能力的模型。因此除了空格填充目标之外,还需要增加一个生成长文本目标的任务。具体包含以下两个目标:
- 文档级别。从文档中采样一个文本片段进行mask,且片段长度为文档长度的50%~100%。这个目标用于长文本生成。
- 句子级别。限制被mask的片段必须是完整句子。多个片段需覆盖原始tokens的15%。这个目标是用于预测完整句子或者段落的seq2seq任务。
2.2.3 模型结构
GLM在原始single Transformer的基础上进行了一些修改:
- 重组了LN和残差连接的顺序;
- 使用单个线性层对输出token进行预测;
- 激活函数从ReLU换成了GeLUS。
但我觉得这部分的修改比较简单常见。核心和亮点还是空格填充任务的设计。
2.2.4 GLM微调
对于下游NLU任务来说,通常会将预训练模型产出的序列或tokens表达作为输入,使用线性分类器预测label。所以预训练与微调之间存在天然不一致。
作者按照PET的方式,将下游NLU任务重新表述为空白填充的生成任务。具体来说,比如给定一个已标注样本(x,y),将输入的文本x转换成一个包含masktoken的完形填空问题。比如,情感分类任务可以表述为:"{SENTENCE}. It’sreally [MASK]"。输出label y也同样会被映射到完形填空的答案中。“positive”和 “negative” 对应的标签就是“good” 和 “bad。
其实,预训练时,对较长的文本片段进行mask,以确保GLM的文本生成能力。但是在微调的时候,相当于将NLU任务也转换成了生成任务,这样其实是为了适应预训练的目标。但难免有一些牵强。
2.3 ChatGLM-2
2.3.1 主要创新
- 更长的上下文:基于
FlashAttention**技术,将基座模型的上下文长度(Context Length)由 ChatGLM-6B 的2K 扩展到了 32K**,并在对话阶段使用 8K的上下文长度训练。对于更长的上下文,发布了 ChatGLM2-6B-32K 模型。LongBench的测评结果表明,在等量级的开源模型中,ChatGLM2-6B-32K有着较为明显的竞争优势。 - 更强大的性能:基于 ChatGLM初代模型的开发经验,全面升级了 ChatGLM2-6B 的基座模型。ChatGLM2-6B使用了 GLM** 的混合目标函数**,经过了 1.4T中英标识符的预训练与人类偏好对齐训练,
评测结果显示,相比于初代模型,ChatGLM2-6B 在MMLU(+23%)、CEval(+33%)、GSM8K(+571%)、BBH(+60%)等数据集上的性能取得了大幅度的提升,在同尺寸开源模型中具有较强的竞争力。 - 更高效的推理:基于
Multi-Query Attention技术,ChatGLM2-6B有更高效的推理速度和更低的显存占用:在官方的模型实现下,推理速度相比初代提升了42%,INT4 量化下,6G 显存支持的对话长度由 1K 提升到了 8K。 - 更开放的协议:ChatGLM2-6B权重对学术研究完全开放,在填写
问卷进行登记后亦允许免费商业使用。
2.3.2 与ChatGLM的变化
- 使用了RoPE替换二维位置编码。这也是GLM中提出的亮点设计之一。但是目前大部分主流的LLMs都在使用RoPE,所以大势所趋。当前版本仍然采用了最初的RoPE设计,事实上现在的RoPE经过了xPOS→线性内插→NTK-AwareScaled RoPE→…若干次进化。
- Multi-QueryAttention:这是一种共享机制的Attention,相比Multi-HeadAttention,其Query部分没有区别,Key和Value可以只用一个Head。计算时,对Key和Value进行expand或者repeat操作,使它们填充到与Query一样的维度,后续计算就与Multi-HeadAttention没区别。
- Attention Mask: V1的attention mask分了2部分,PartA和Part B,Part A部分是双向Attention(代码中的
prefix_attention_mask),PartB部分是CausalAttention(原代码文件中的get_masks函数)。在V2版本,全部换成了CausalAttention,不再区分是Part A还是PartB,完全变成了decoder-only的架构。 - 多目标任务:Chat版本主要还是用的gMask生成式任务,但是在V1版本的代码还能看到mask、gMask等字样,V2已经摒弃了这些特殊token,原因与AttentionMask一致,均因为变成了decoder-only的架构,不再需要区分Part A和PartB。
2.3.3 ChatGLM-3
省流:ChatGLM2与ChatGLM3模型架构是完全一致的,ChatGLM与后继者结构不同。可见ChatGLM3相对于ChatGLM2没有模型架构上的改进。
相对于ChatGLM,ChatGLM2、ChatGLM3模型上的变化:
- 词表的大小从ChatGLM的150528缩小为65024(一个直观的体验是ChatGLM2、3加载比ChatGLM快不少)
- 位置编码从每个GLMBlock一份提升为全局一份
- SelfAttention之后的前馈网络有不同。ChatGLM用GELU(GaussianError LinearUnit)做激活;ChatGLM用Swish-1做激活。而且ChatGLM2、3应该是修正了之前的一个bug,因为GLU(GatedLinearUnit)本质上一半的入参是用来做门控制的,不需要输出到下层,所以ChatGLM2、3看起来前后维度不一致(27392->13696)反而是正确的。
3.BERT
3.1BERT用字粒度和词粒度的优缺点有哪些?
BERT可以使用字粒度(character-level)和词粒度(word-level)两种方式来进行文本表示,它们各自有优缺点:
字粒度(Character-level):
- 优点:处理未登录词(Out-of-Vocabulary,OOV):字粒度可以处理任意字符串,包括未登录词,不需要像词粒度那样遇到未登录词就忽略或使用特殊标记。对于少见词和低频词,字粒度可以学习更丰富的字符级别表示,使得模型能够更好地捕捉词汇的细粒度信息。
- 缺点:计算复杂度高:使用字粒度会导致输入序列的长度大大增加,进而增加模型的计算复杂度和内存消耗。需要更多的训练数据:字粒度模型对于少见词和低频词需要更多的训练数据来学习有效的字符级别表示,否则可能会导致过拟合。
词粒度(Word-level):
- 优点:计算效率高:使用词粒度可以大大减少输入序列的长度,从而降低模型的计算复杂度和内存消耗。学习到更加稳定的词级别表示:词粒度模型可以学习到更加稳定的词级别表示,特别是对于高频词和常见词,有更好的表示能力。
- 缺点:处理未登录词(OOV):词粒度模型无法处理未登录词,遇到未登录词时需要采用特殊处理(如使用未登录词的特殊标记或直接忽略)。对于多音字等形态复杂的词汇,可能无法准确捕捉其细粒度的信息。
3.2BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
3.3BERT用的是transformer里面的encoder还是decoder?BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
3.4为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?
BERT选择mask掉15%的词是一种经验性的选择,是原论文中的一种选择,并没有一个固定的理论依据,实际中当然可以尝试不同的比例,15%的比例是由BERT的作者在原始论文中提出,并在实验中发现对于BERT的训练效果是有效的
3.5为什么BERT在第一句前会加一个[CLS] 标志?
BERT在第一句前会加一个 [CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。为什么选它?因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。而[CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。
3.6 BERT非线性的来源在哪里?
主要来自两个地方:前馈层的gelu激活函数和self-attention。
前馈神经网络层:在BERT的Encoder中,每个自注意力层之后都跟着一个前馈神经网络层。前馈神经网络层是全连接的神经网络,通常包括一个线性变换和一个非线性的激活函数,如gelu。这样的非线性激活函数引入了非线性变换,使得模型能够学习更加复杂的特征表示。
self-attentionlayer:在自注意力层中,查询(Query)、键(Key)、值(Value)之间的点积得分会经过softmax操作,形成注意力权重,然后将这些权重与值向量相乘得到每个位置的自注意输出。这个过程中涉及了softmax操作,使得模型的计算是非线性的。
3.7BERT训练时使用的学习率 warm-up策略是怎样的?为什么要这么做?在BERT的训练中,使用了学习率warm-up策略,这是为了在训练的早期阶段增加学习率,以提高训练的稳定性和加快模型收敛。
学习率warm-up策略的具体做法是,在训练开始的若干个步骤(通常是一小部分训练数据的迭代次数)内,将学习率逐渐从一个较小的初始值增加到预定的最大学习率。在这个过程中,学习率的变化是线性的,即学习率在warm-up阶段的每个步骤按固定的步幅逐渐增加。学习率warm-up的目的是为了解决BERT在训练初期的两个问题:
- 不稳定性:在训练初期,由于模型参数的随机初始化以及模型的复杂性,模型可能处于一个较不稳定的状态。此时使用较大的学习率可能导致模型的参数变动太大,使得模型很难收敛,学习率warm-up可以在这个阶段将学习率保持较小,提高模型训练的稳定性。
- 避免过拟合:BERT模型往往需要较长的训练时间来获得高质量的表示。如果在训练的早期阶段就使用较大的学习率,可能会导致模型在训练初期就过度拟合训练数据,降低模型的泛化能力。通过学习率warm-up,在训练初期使用较小的学习率,可以避免过度拟合,等模型逐渐稳定后再使用较大的学习率进行更快的收敛。
3.8在BERT应用中,如何解决长文本问题?
在BERT应用中,处理长文本问题有以下几种常见的解决方案:
- 截断与填充:将长文本截断为固定长度或者进行填充。BERT模型的输入是一个固定长度的序列,因此当输入的文本长度超过模型的最大输入长度时,需要进行截断或者填充。通常,可以根据任务的要求,选择适当的最大长度,并对文本进行截断或者填充,使其满足模型输入的要求。
- SlidingWindow:将长文本分成多个短文本,然后分别输入BERT模型。这种方法被称为SlidingWindow技术。具体来说,将长文本按照固定的步长切分成多个片段,然后分别输入BERT模型进行处理。每个片段的输出可以进行进一步的汇总或者融合,得到最终的表示。
- HierarchicalModel:使用分层模型来处理长文本,其中底层模型用于处理短文本片段,然后将不同片段的表示进行汇总或者融合得到整个长文本的表示。这样的分层模型可以充分利用BERT模型的表示能力,同时处理长文本。
- Longformer、BigBird等模型:使用专门针对长文本的模型,如Longformer和BigBird。这些模型采用了不同的注意力机制,以处理超长序列,并且通常在处理长文本时具有更高的效率。
- Document-LevelModel:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
]]>
+ 大语言模型简介
1.llm概念
1.1 主流的开源模型体系
目前主流的开源LLM(语言模型)模型体系包括以下几个:
- GPT(Generative Pre-trainedTransformer)系列:由OpenAI发布的一系列基于Transformer架构的语言模型,包括GPT、GPT-2、GPT-3等。GPT模型通过在大规模无标签文本上进行预训练,然后在特定任务上进行微调,具有很强的生成能力和语言理解能力。
- BERT(Bidirectional Encoder Representations fromTransformers):由Google发布的一种基于Transformer架构的双向预训练语言模型。BERT模型通过在大规模无标签文本上进行预训练,然后在下游任务上进行微调,具有强大的语言理解能力和表征能力。
- XLNet:由CMU和GoogleBrain发布的一种基于Transformer架构的自回归预训练语言模型。XLNet模型通过自回归方式预训练,可以建模全局依赖关系,具有更好的语言建模能力和生成能力。
- RoBERTa:由Facebook发布的一种基于Transformer架构的预训练语言模型。RoBERTa模型在BERT的基础上进行了改进,通过更大规模的数据和更长的训练时间,取得了更好的性能。
- T5(Text-to-Text TransferTransformer):由Google发布的一种基于Transformer架构的多任务预训练语言模型。T5模型通过在大规模数据集上进行预训练,可以用于多种自然语言处理任务,如文本分类、机器翻译、问答等。
这些模型在自然语言处理领域取得了显著的成果,并被广泛应用于各种任务和应用中。
1.2 prefix LM 和 causal LM区别是什么?
Prefix LM(前缀语言模型)和CausalLM(因果语言模型)是两种不同类型的语言模型,它们的区别在于生成文本的方式和训练目标。
- PrefixLM:前缀语言模型是一种生成模型,它在生成每个词时都可以考虑之前的上下文信息。在生成时,前缀语言模型会根据给定的前缀(即部分文本序列)预测下一个可能的词。这种模型可以用于文本生成、机器翻译等任务。
- CausalLM:因果语言模型是一种自回归模型,它只能根据之前的文本生成后续的文本,而不能根据后续的文本生成之前的文本。在训练时,因果语言模型的目标是预测下一个词的概率,给定之前的所有词作为上下文。这种模型可以用于文本生成、语言建模等任务。
总结来说,前缀语言模型可以根据给定的前缀生成后续的文本,而因果语言模型只能根据之前的文本生成后续的文本。它们的训练目标和生成方式略有不同,适用于不同的任务和应用场景。
1.3 大模型LLM的训练目标
大型语言模型(Large LanguageModels,LLM)的训练目标通常是最大似然估计(Maximum LikelihoodEstimation,MLE)。最大似然估计是一种统计方法,用于从给定数据中估计概率模型的参数。
在LLM的训练过程中,使用的数据通常是大量的文本语料库。训练目标是最大化模型生成训练数据中观察到的文本序列的概率。具体来说,对于每个文本序列,模型根据前面的上下文生成下一个词的条件概率分布,并通过最大化生成的词序列的概率来优化模型参数。
为了最大化似然函数,可以使用梯度下降等优化算法来更新模型参数,使得模型生成的文本序列的概率逐步提高。在训练过程中,通常会使用批量训练(batchtraining)的方法,通过每次处理一小批数据样本来进行参数更新。
1.4 涌现能力是啥原因?
大语言模型的涌现能力:现象与解释- 知乎 (zhihu.com)
涌现能力(EmergentAbility)是指模型在训练过程中能够生成出令人惊喜、创造性和新颖的内容或行为。这种能力使得模型能够超出其训练数据所提供的内容,并产生出具有创造性和独特性的输出。
涌现能力的产生可以归因于以下几个原因:
- 任务的评价指标不够平滑:因为很多任务的评价指标不够平滑,导致我们现在看到的涌现现象。如果评价指标要求很严格,要求一字不错才算对,那么Emoji_movie任务我们就会看到涌现现象的出现。但是,如果我们把问题形式换成多选题,就是给出几个候选答案,让LLM选,那么随着模型不断增大,任务效果在持续稳定变好,但涌现现象消失,如上图图右所示。这说明评价指标不够平滑,起码是一部分任务看到涌现现象的原因。
- 复杂任务 vs子任务:展现出涌现现象的任务有一个共性,就是任务往往是由多个子任务构成的复杂任务。也就是说,最终任务过于复杂,如果仔细分析,可以看出它由多个子任务构成,这时候,子任务效果往往随着模型增大,符合Scaling Law,而最终任务则体现为涌现现象。
- 用 Grokking(顿悟)来解释涌现:对于某个任务T,尽管我们看到的预训练数据总量是巨大的,但是与T相关的训练数据其实数量很少。当我们推大模型规模的时候,往往会伴随着增加预训练数据的数据量操作,这样,当模型规模达到某个点的时候,与任务T相关的数据量,突然就达到了最小要求临界点,于是我们就看到了这个任务产生了Grokking现象。
尽管涌现能力为模型带来了创造性和独特性,但也需要注意其生成的内容可能存在偏差、错误或不完整性。因此,在应用和使用涌现能力强的模型时,需要谨慎评估和验证生成的输出,以确保其质量和准确性。
1.5为何现在的大模型大部分是Decoder only结构
- 自回归生成:Decoder-only结构适用于自回归生成任务,其中模型根据先前的输入生成下一个输出。这种结构在自然语言处理任务中非常有用,如文本生成、机器翻译和对话生成等。Decoder-only结构能够利用上下文信息来生成连续的输出序列,使得生成的结果更加准确和连贯。
- 生成多样性:Decoder-only结构可以通过在训练期间使用不同的解码策略来生成多样化的结果。例如,在生成文本时,可以使用不同的采样策略(如贪婪采样或随机采样)或温度参数来调整生成的多样性。这种能力对于一些任务(如对话生成)非常重要,因为它可以产生更加有趣和多样化的回复。
- 模型训练和推理的一致性:Decoder-only结构使得模型的训练和推理过程更加一致。在训练期间,模型可以使用教师强制(teacherforcing)策略,即将真实的目标输出作为输入传递给解码器。而在推理期间,模型可以逐步生成输出,将前一个时间步的输出作为输入传递给下一个时间步。这种一致性有助于更好地控制模型的生成过程,并提高模型的稳定性和可靠性。
1.6 大模型架构介绍
LLM(Large LanguageModel,大型语言模型)是指基于大规模数据和参数量的语言模型。具体的架构可以有多种选择,以下是一种常见的大模型LLM的架构介绍:
- Transformer架构:大模型LLM常使用Transformer架构,它是一种基于自注意力机制的序列模型。Transformer架构由多个编码器层和解码器层组成,每个层都包含多头自注意力机制和前馈神经网络。这种架构可以捕捉长距离的依赖关系和语言结构,适用于处理大规模语言数据。
- 自注意力机制(Self-Attention):自注意力机制是Transformer架构的核心组件之一。它允许模型在生成每个词时,根据输入序列中的其他词来计算该词的表示。自注意力机制能够动态地为每个词分配不同的权重,从而更好地捕捉上下文信息。
- 多头注意力(Multi-HeadAttention):多头注意力是自注意力机制的一种扩展形式。它将自注意力机制应用多次,每次使用不同的权重矩阵进行计算,得到多个注意力头。多头注意力可以提供更丰富的上下文表示,增强模型的表达能力。
- 前馈神经网络(Feed-ForwardNetwork):在Transformer架构中,每个注意力层后面都有一个前馈神经网络。前馈神经网络由两个全连接层组成,通过非线性激活函数(如ReLU)进行变换。它可以对注意力层输出的表示进行进一步的映射和调整。
- 预训练和微调:大模型LLM通常采用预训练和微调的方法进行训练。预训练阶段使用大规模无标签数据,通过自监督学习等方法进行训练,使模型学习到丰富的语言知识。微调阶段使用有标签的特定任务数据,如文本生成、机器翻译等,通过有监督学习进行模型的微调和优化。
需要注意的是,大模型LLM的具体架构可能会因不同的研究和应用而有所不同。上述介绍的是一种常见的架构,但实际应用中可能会有一些变体或改进。
1.7 LLMs复读机问题
1.7.1 什么是 LLMs 复读机问题?
LLMs复读机问题(LLMs ParrotingProblem)是指大型语言模型在生成文本时过度依赖输入文本的复制,而缺乏创造性和独特性。当面对一个问题或指令时,模型可能会简单地复制输入文本的一部分或全部内容,并将其作为生成的输出,而不是提供有意义或新颖的回应。
1.7.2 为什么会出现 LLMs复读机问题?
- 数据偏差:大型语言模型通常是通过预训练阶段使用大规模无标签数据进行训练的。如果训练数据中存在大量的重复文本或者某些特定的句子或短语出现频率较高,模型在生成文本时可能会倾向于复制这些常见的模式。
- 训练目标的限制:大型语言模型的训练通常是基于自监督学习的方法,通过预测下一个词或掩盖词来学习语言模型。这样的训练目标可能使得模型更倾向于生成与输入相似的文本,导致复读机问题的出现。
- 缺乏多样性的训练数据:虽然大型语言模型可以处理大规模的数据,但如果训练数据中缺乏多样性的语言表达和语境,模型可能无法学习到足够的多样性和创造性,导致复读机问题的出现。
- 模型结构和参数设置:大型语言模型的结构和参数设置也可能对复读机问题产生影响。例如,模型的注意力机制和生成策略可能导致模型更倾向于复制输入的文本。
1.7.3 如何缓解 LLMs 复读机问题?
为了缓解LLMs复读机问题,可以尝试以下方法:
- 多样性训练数据:在训练阶段,使用多样性的语料库来训练模型,避免数据偏差和重复文本的问题。这可以包括从不同领域、不同来源和不同风格的文本中获取数据。
- 引入噪声:在生成文本时,引入一些随机性或噪声,例如通过采样不同的词或短语,或者引入随机的变换操作,以增加生成文本的多样性。这可以通过在生成过程中对模型的输出进行采样或添加随机性来实现。
- 温度参数调整:温度参数是用来控制生成文本的多样性的一个参数。通过调整温度参数的值,可以控制生成文本的独创性和多样性。较高的温度值会增加随机性,从而减少复读机问题的出现。
- Beam搜索调整:在生成文本时,可以调整Beam搜索算法的参数。Beam搜索是一种常用的生成策略,它在生成过程中维护了一个候选序列的集合。通过调整Beam大小和搜索宽度,可以控制生成文本的多样性和创造性。
- 后处理和过滤:对生成的文本进行后处理和过滤,去除重复的句子或短语,以提高生成文本的质量和多样性。可以使用文本相似度计算方法或规则来检测和去除重复的文本。
- 人工干预和控制:对于关键任务或敏感场景,可以引入人工干预和控制机制,对生成的文本进行审查和筛选,确保生成结果的准确性和多样性。
需要注意的是,缓解LLMs复读机问题是一个复杂的任务,没有一种通用的解决方案。不同的方法可能适用于不同的场景和任务,需要根据具体情况进行选择和调整。此外,解决复读机问题还需要综合考虑数据、训练目标、模型架构和生成策略等多个因素,需要进一步的研究和实践来提高大型语言模型的生成文本多样性和创造性。
1.8LLMs输入句子长度理论上可以无限长吗?
理论上来说,LLMs(大型语言模型)可以处理任意长度的输入句子,但实际上存在一些限制和挑战。下面是一些相关的考虑因素:
- 计算资源:生成长句子需要更多的计算资源,包括内存和计算时间。由于LLMs通常是基于神经网络的模型,计算长句子可能会导致内存不足或计算时间过长的问题。
- 模型训练和推理:训练和推理长句子可能会面临一些挑战。在训练阶段,处理长句子可能会导致梯度消失或梯度爆炸的问题,影响模型的收敛性和训练效果。在推理阶段,生成长句子可能会增加模型的错误率和生成时间。
- 上下文建模:LLMs是基于上下文建模的模型,长句子的上下文可能会更加复杂和深层。模型需要能够捕捉长句子中的语义和语法结构,以生成准确和连贯的文本。
1.9如何让大模型处理更长的文本?
要让大模型处理更长的文本,可以考虑以下几个方法:
- 分块处理:将长文本分割成较短的片段,然后逐个片段输入模型进行处理。这样可以避免长文本对模型内存和计算资源的压力。在处理分块文本时,可以使用重叠的方式,即将相邻片段的一部分重叠,以保持上下文的连贯性。
- 层次建模:通过引入层次结构,将长文本划分为更小的单元。例如,可以将文本分为段落、句子或子句等层次,然后逐层输入模型进行处理。这样可以减少每个单元的长度,提高模型处理长文本的能力。
- 部分生成:如果只需要模型生成文本的一部分,而不是整个文本,可以只输入部分文本作为上下文,然后让模型生成所需的部分。例如,输入前一部分文本,让模型生成后续的内容。
- 注意力机制:注意力机制可以帮助模型关注输入中的重要部分,可以用于处理长文本时的上下文建模。通过引入注意力机制,模型可以更好地捕捉长文本中的关键信息。
- 模型结构优化:通过优化模型结构和参数设置,可以提高模型处理长文本的能力。例如,可以增加模型的层数或参数量,以增加模型的表达能力。还可以使用更高效的模型架构,如Transformer等,以提高长文本的处理效率。
需要注意的是,处理长文本时还需考虑计算资源和时间的限制。较长的文本可能需要更多的内存和计算时间,因此在实际应用中需要根据具体情况进行权衡和调整。
2.LLama系列模型
2.1LLama
2.1.1 简介
LLaMA 所采用的 Transformer 结构和细节,与标准的 Transformer架构不同的地方包括采用了前置层归一化(Pre-normalization)并使用RMSNorm 归一化函数 (NormalizingFunction)、激活函数更换为SwiGLU,并使用了旋转位置嵌入(RoP),整体Transformer 架构与 GPT-2 类似。
2.1.2 RMSNorm归一化函数
为了使得模型训练过程更加稳定,GPT-2 相较于 GPT就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了RMSNorm 归一化函数。 针对输入向量a,RMSNorm 函数计算公式如下 \[R M S(a)=\sqrt{\frac{1}{n} \sum_{i=1}^{n} a_{i}^{2}}\]
\[\bar{a}_{i}=\frac{a_{i}}{R M S(\boldsymbol{a})}\]
此外,RMSNorm 还可以引入可学习的缩放因子 $ g_ i $和偏移参数 \(b_i\),从而得到 \(\bar{a}_{i}=\frac{a_{i}}{\operatorname{RMS}(\boldsymbol{a})}g_{i}+b_{i}\)。 RMSNorm 在 HuggingFace Transformer库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class LlamaRMSNorm(nn.Module):
def __init__(self, hidden_size, eps=1e-6):
"""
LlamaRMSNorm is equivalent to T5LayerNorm
"""
super().__init__()
self.weight = nn.Parameter(torch.ones(hidden_size))
self.variance_epsilon = eps # eps 防止取倒数之后分母为 0
def forward(self, hidden_states):
input_dtype = hidden_states.dtype
variance = hidden_states.to(torch.float32).pow(2).mean(-1, keepdim=True)
hidden_states = hidden_states * torch.rsqrt(variance + self.variance_epsilon) # weight 是末尾乘的可训练参数, 即 g_i
return (self.weight * hidden_states).to(input_dtype)
为什么要用RMSNorm优势在哪里?
不用计算均值,直接算一次就能得到结果
2.1.3 SwiGLU激活函数
SwiGLU激活函数是相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA中全连接层使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-ForwardNetwork)的计算公式如下:
\[\operatorname{FFN}_{\text {SwiGLU }}\left(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V},\boldsymbol{W}_{2}\right)=\operatorname{SwiGLU}(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V}) \boldsymbol{W}_{2}\]
\[\operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W},\boldsymbol{V})=\operatorname{Swish}_{\beta}(x \boldsymbol{W}) \otimes\boldsymbol{x} \boldsymbol{V}\]
\[\operatorname{Swish}_{\beta}(\boldsymbol{x})=\boldsymbol{x}\sigma(\boldsymbol{\beta} \boldsymbol{x})\]
其中,\(σ(x)\) 是 Sigmoid函数。下图给出了 Swish 激活函数在参数 \(β\) 不同取值下的形状。可以看 到当 \(β\) 趋近于 0 时,Swish 函数趋近于线性函数\(y = x\),当 $ β \(趋近于无穷大时,Swish 函数趋近于 ReLU函数,\)β$ 取值为 1 时,Swish 函数是光滑且非单调。在 HuggingFace的 Transformer 库中 Swish1 函数使用 silu 函数代替。
LLaMA中直接将FFN中的ReLU替换为SwiGLU,并将维度放缩为\((2/3) ⋅ 4d\)
2.1.4 旋转位置嵌入(RoPE)
在位置编码上,使用旋转位置嵌入(Rotary PositionalEmbeddings,RoPE)代替原有的绝对位置编码。RoPE借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给q
,k
添加绝对位置信息:
\[\tilde{\boldsymbol{q}}_{m}=f(\boldsymbol{q}, m),\tilde{\boldsymbol{k}}_{n}=f(\boldsymbol{k}, n)\]
经过上述操作后,\(\tilde{\boldsymbol{q}}_{m}\)和\(\tilde{\boldsymbol{k}}_{n}\)就带有位置m和n的绝对位置信息。
最终可以得到二维情况下用复数表示的 RoPE:
\[f(\boldsymbol{q}, m)=R_{f}(\boldsymbol{q}, m) e^{i\Theta_{f}(\boldsymbol{q}, m)}=\|\boldsymbol{q}\|e^{i(\Theta(\boldsymbol{q})+m \theta)}=\boldsymbol{q} e^{i m \theta}\]
根据复数乘法的几何意义,上述变换实际上是对应向量旋转,所以位置向量称为“旋转式位置编码”。还可以使用矩阵形式表示
\[f(\boldsymbol{q}, m)=\left(\begin{array}{cc}\cos m \theta & -\sin\cos m \theta \\ \sin m \theta & \cos m\theta\end{array}\right)\left(\begin{array}{l}\boldsymbol{q}_{0} \\\boldsymbol{q}_{1}\end{array}\right)\]
根据内积满足线性叠加的性质,任意偶数维的RoPE,都可以表示为二维情形的拼接,即:
\[f(\boldsymbol{q}, m)=\underbrace{\left(\begin{array}{ccccccc}\cos m\theta_{0} & -\sin m \theta_{0} & 0 & 0 & \cdots & 0& 0 \\ \sin m \theta_{0} & \cos m \theta_{0} & 0 & 0& \cdots & 0 & 0 \\ 0 & 0 & \cos m \theta_{1} &-\sin m \theta_{1} & \cdots & 0 & 0 \\ 0 & 0 & \sinm \theta_{1} & \cos m \theta_{1} & \cdots & 0 & 0 \\\cdots & \cdots & \cdots & \cdots & \ddots & \cdots& \cdots \\ 0 & 0 & 0 & 0 & \cdots & \cos m\theta_{d / 2-1} & -\sin m \theta_{d / 2-1} \\ 0 & 0 & 0& 0 & \cdots & \sin m \theta_{d / 2-1} & \cos m\theta_{d /2-1}\end{array}\right)}_{\boldsymbol{R}_{d}}\left(\begin{array}{c}\boldsymbol{q}_{0}\\ \boldsymbol{q}_{1} \\ \boldsymbol{q}_{2} \\ \boldsymbol{q}_{3} \\\cdots \\ \boldsymbol{q}_{d-2} \\ \boldsymbol{q}_{d-1}\end{array}\right)\]
RoPE 在 HuggingFace Transformer 库中代码实现如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import torch
def precompute_freqs_cis(dim: int, end: int, constant: float = 10000.0):
'''
计算cos和sin的值,cos值在实部,sin值在虚部,类似于 cosx+j*sinx
:param dim: q,k,v的最后一维,一般为emb_dim/head_num
:param end: 句长length
:param constant: 这里指10000
:return:
复数计算 torch.polar(a, t)输出, a*(cos(t)+j*sin(t))
'''
# freqs: 计算 1/(10000^(2i/d) ),将结果作为参数theta
# 形式化为 [theta_0, theta_1, ..., theta_(d/2-1)]
freqs = 1.0 / (constant ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim)) # [d/2]
# 计算m
t = torch.arange(end, device=freqs.device) # [length]
# 计算m*theta
freqs = torch.outer(t, freqs).float() # [length, d/2]
# freqs形式化为 [m*theta_0, m*theta_1, ..., m*theta_(d/2-1)],其中 m=0,1,...,length-1
# 计算cos(m*theta)+j*sin(m*theta)
freqs_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64
# freqs_cis: [cos(m*theta_0)+j*sin(m*theta_0), cos(m*theta_1)+j*sin(m*theta_1),), ..., cos(m*theta_(d/2-1))+j*sin(m*theta_(d/2-1))]
# 其中j为虚数单位, m=0,1,...,length-1
return freqs_cis # [length, d/2]
def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor):
ndim = x.ndim
assert 0 <= 1 < ndim
assert freqs_cis.shape == (x.shape[1], x.shape[-1])
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)] # (1, length, 1, d/2)
return freqs_cis.view(*shape) # [1, length, 1, d/2]
def apply_rotary_emb(xq: torch.Tensor, xk: torch.Tensor, freqs_cis: torch.Tensor,):
# 先将xq维度变为[bs, length, head, d/2, 2], 利用torch.view_as_complex转变为复数
# xq:[q0, q1, .., q(d-1)] 转变为 xq_: [q0+j*q1, q2+j*q3, ..., q(d-2)+j*q(d-1)]
xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2)) # [bs, length, head, d/2]
# 同样的,xk_:[k0+j*k1, k2+j*k3, ..., k(d-2)+j*k(d-1)]
xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
freqs_cis = reshape_for_broadcast(freqs_cis, xq_) # [1, length, 1, d/2]
# 下式xq_ * freqs_cis形式化输出,以第一个为例, 如下
# (q0+j*q1)(cos(m*theta_0)+j*sin(m*theta_0)) = q0*cos(m*theta_0)-q1*sin(m*theta_0) + j*(q1*cos(m*theta_0)+q0*sin(m*theta_0))
# 上式的实部为q0*cos(m*theta_0)-q1*sin(m*theta_0),虚部为q1*cos(m*theta_0)+q0*sin(m*theta_0)
# 然后通过torch.view_as_real函数,取出实部和虚部,维度由[bs, length, head, d/2]变为[bs, length, head, d/2, 2],最后一维放实部与虚部
# 最后经flatten函数将维度拉平,即[bs, length, head, d]
# 此时xq_out形式化为 [实部0,虚部0,实部1,虚部1,..., 实部(d/2-1), 虚部(d/2-1)]
xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3) # [bs, length, head, d]
# 即为新生成的q
xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
return xq_out.type_as(xq), xk_out.type_as(xk)
if __name__=='__main__':
# (bs, length, head, d)
q = torch.randn((2, 10, 12, 32)) # q=[q0, q1, .., qd-1]
k = torch.randn((2, 10, 12, 32))
v = torch.randn((2, 10, 12, 32))
freqs_cis= precompute_freqs_cis(dim=32, end=10, constant= 10000.0)
# print(freqs_cis.detach().numpy())
q_new, k_new = apply_rotary_emb(xq=q, xk=k, freqs_cis=freqs_cis)
print()
1.2 Alpaca
1.2.1 简介
Stanford Alpaca: An Instruction-following LLaMA Model
Alpaca是在LLaMA基础上使用52K指令数据精调的预训练模型,作者只用了不到600美元的成本训练出了该模型(数据$500+ 机器$100)。初步实验结果表明Alpaca可以达到与OpenAItext-davinci-003相匹敌的效果
1.2.2 微调方法
- 第一步:构造175条self-instruct 种子示例任务
- 第二步:基于上述种子任务,利 用text-davinci-003爬取指令数据
- 第三步:使用爬取下来的52K指令 数据在LLaMA上进行精调,最终得到Alpaca
1.2.3 Self-instruct数据构造
首先由人工构造175条种子数据
1
2
3
4
5
6
7
{
"id": "seed_task_25",
"name": "perfect_numbers",
"instruction": "Find the four smallest perfect numbers.",
"instances": [{ "input": "", "output": "6, 28, 496, and 8128”}],
"is_classification": false
}
将“爬取要求”和种子数据进行适当组合,送入textdavinci-003,要求生成类似的指令数据。要求包括:提升指令多样性、包含真实数据、字数要求、语言要求、拒绝不合适指令等
1.2.4 指令数据格式
instruction
: 描述模型需要执行的指令内容input
(可选):任务上下文或输入信息,例如当指令是“对文章进行总结”,则input是文章内容output
: 由text-davinci-003生成的针对指令的回复
1.3.Llama-2
1.3.1 简介
Llama 2: Open Foundation and Fine-Tuned Chat Models
2023年7月,Meta推出了Llama-2开源大模型,并且推出了Llama-2-Chat对话模型
与一代LLaMA主要区别体现在更多的训练数据、更⻓的上下文窗口、GQA技术等
二次分发是什么?
模型结构的变动主要是体现在GQA和FFN缩放上
- MHA改成GQA:整体参数量会有减少
- FFN模块矩阵维度有扩充:增强泛化能力,整体参数量增加
- 上下文长度是llama两倍(长度从2048->4096)训练语料增加约 40%,体现在1.4T->2.0T的Tokensllama2-34B和llama2-70B使用了GQA,加速模型训练和推理速度
1.3.2 GQA
GQA和MQA都是注意力的变体,其中多个查询头关注相同的键和值头,以减少推理过程中KV 缓存的大小,并可以显著提高推理吞吐量。
MHA、GQA、MQA的区别和联系,具体的优点如下:
Mutil-Head Attention
因为自回归模型生成回答时,需要前面生成的KV缓存起来,来加速计算。Multi-Query Attention
多个头之间可以共享KV对,因此速度上非常有优势,实验验证大约减少30-40%吞吐。Group Query Attention
没有像MQA那么极端,将query分组,组内共享KV,效果接近MQA,速度上与MQA可比较。
Llama-2中使用了8个KV映射,即GQA-8,GQA在多数任务上与MHA效果相当,且平均效果优于MQA;GQA和MQA均比MHA有更好的吞吐量
1.3.3 源码
2.ChatGLM
2.1 背景
主流的预训练框架主要有三种:
- autoregressive自回归模型(AR模型):代表作GPT。本质上是一个left-to-right的语言模型。通常用于生成式任务,在长文本生成方面取得了巨大的成功,比如自然语言生成(NLG)领域的任务:摘要、翻译或抽象问答。当扩展到十亿级别参数时,表现出了少样本学习能力。缺点是单向注意力机制,在NLU任务中,无法完全捕捉上下文的依赖关系。
- autoencoding自编码模型(AE模型):代表作BERT。是通过某个降噪目标(比如MLM)训练的双向文本编码器。编码器会产出适用于NLU任务的上下文表示,但无法直接用于文本生成。
- encoder-decoder(Seq2seq模型):代表作T5。采用双向注意力机制,通常用于条件生成任务,比如文本摘要、机器翻译等。
三种预训练框架各有利弊,没有一种框架在以下三种领域的表现最佳:自然语言理解(NLU)、无条件生成以及条件生成。T5曾经尝试使用MTL的方式统一上述框架,然而自编码和自回归目标天然存在差异,简单的融合自然无法继承各个框架的优点。
在这个天下三分的僵持局面下,GLM诞生了。
GLM模型基于autoregressive blankinfilling方法,结合了上述三种预训练模型的思想。
2.2 GLM预训练框架
GLM特点
- 自编码思想:在输入文本中,随机删除连续的tokens。
- 自回归思想:顺序重建连续tokens。在使用自回归方式预测缺失tokens时,模型既可以访问corrupted文本,又可以访问之前已经被预测的spans。
- span shuffling + 二维位置编码技术。
- 通过改变缺失spans的数量和长度,自回归空格填充目标可以为条件生成以及无条件生成任务预训练语言模型。
2.2.1 自回归空格填充任务
给定一个输入文本\(x=\left[x_{1}, \ldotsx_{n}\right]\),可以采样得到多个文本spans \(\left\{s_{1}, \ldotss_{m}\right\}\)。为了充分捕捉各spans之间的相互依赖关系,可以对spans的顺序进行随机排列,得到所有可能的排列集合\(Z_m\),其中:\(S_{z<i}=\left[s_{z_{1}}, \ldots,s_{z_{i-1}}\right]\)。所以预训练目标很清晰:
\[\max _{\theta} \mathbb{E}_{\boldsymbol{z} \simZ_{m}}\left[\sum_{i=1}^{m} \log p_{\theta}\left(\boldsymbol{s}_{z_{i}}\mid \boldsymbol{x}_{\text {corrupt }},\boldsymbol{s}_{\boldsymbol{z}_{<i}}\right)\right]\]
GLM自回归空格填充任务的技术细节:
- 输入\(x\)可以被分成两部分:PartA是被mask的文本 \(x_{\text {corrupt}}\),Part B由masked spans组成。假设原始输入文本是
\([x1, x2, x3, x4, x5,x6]\),采样的两个文本片段是\([x3]\)以及\([x5,x6]\)。那么mask后的文本序列是:\(x1,x2, [M], x4, [M]\),即Part A;同时我们需要对PartB的片段进行shuffle。每个片段使用[S]
填充在开头作为输入,使用[E]
填充在末尾作为输出。 - 二维位置编码:Transformer使用位置编码来标记tokens中的绝对和相对位置。在GLM中,使用二维位置编码,第一个位置id用来标记PartA中的位置,第二个位置id用来表示跨度内部的相对位置。这两个位置id会通过embedding表被投影为两个向量,最终都会被加入到输入token的embedding表达中。
- 观察GLM中自定义attention mask的设计,非常巧妙:
- Part A中的tokens彼此可见,但是不可见B中的任意tokens。
- Part B tokens可见Part A。
- Part B tokens可见B中过去的tokens,不可见B中未来的tokens。
- 采样方式:文本片段的采样遵循泊松分布,重复采样,直到原始tokens中有15%被mask。
- 总结:模型可以自动学习双向encoder(Part A)以及单向decoder(PartB)。
2.2.2 多目标预训练
上述方法适合于NLU任务。作者希望可以训练一个既可以解决NLU任务,又具备文本生成能力的模型。因此除了空格填充目标之外,还需要增加一个生成长文本目标的任务。具体包含以下两个目标:
- 文档级别。从文档中采样一个文本片段进行mask,且片段长度为文档长度的50%~100%。这个目标用于长文本生成。
- 句子级别。限制被mask的片段必须是完整句子。多个片段需覆盖原始tokens的15%。这个目标是用于预测完整句子或者段落的seq2seq任务。
2.2.3 模型结构
GLM在原始single Transformer的基础上进行了一些修改:
- 重组了LN和残差连接的顺序;
- 使用单个线性层对输出token进行预测;
- 激活函数从ReLU换成了GeLUS。
但我觉得这部分的修改比较简单常见。核心和亮点还是空格填充任务的设计。
2.2.4 GLM微调
对于下游NLU任务来说,通常会将预训练模型产出的序列或tokens表达作为输入,使用线性分类器预测label。所以预训练与微调之间存在天然不一致。
作者按照PET的方式,将下游NLU任务重新表述为空白填充的生成任务。具体来说,比如给定一个已标注样本(x,y),将输入的文本x转换成一个包含masktoken的完形填空问题。比如,情感分类任务可以表述为:"{SENTENCE}. It’sreally [MASK]"。输出label y也同样会被映射到完形填空的答案中。“positive”和 “negative” 对应的标签就是“good” 和 “bad。
其实,预训练时,对较长的文本片段进行mask,以确保GLM的文本生成能力。但是在微调的时候,相当于将NLU任务也转换成了生成任务,这样其实是为了适应预训练的目标。但难免有一些牵强。
2.3 ChatGLM-2
2.3.1 主要创新
- 更长的上下文:基于
FlashAttention**技术,将基座模型的上下文长度(Context Length)由 ChatGLM-6B 的2K 扩展到了 32K**,并在对话阶段使用 8K的上下文长度训练。对于更长的上下文,发布了 ChatGLM2-6B-32K 模型。LongBench的测评结果表明,在等量级的开源模型中,ChatGLM2-6B-32K有着较为明显的竞争优势。 - 更强大的性能:基于 ChatGLM初代模型的开发经验,全面升级了 ChatGLM2-6B 的基座模型。ChatGLM2-6B使用了 GLM** 的混合目标函数**,经过了 1.4T中英标识符的预训练与人类偏好对齐训练,
评测结果显示,相比于初代模型,ChatGLM2-6B 在MMLU(+23%)、CEval(+33%)、GSM8K(+571%)、BBH(+60%)等数据集上的性能取得了大幅度的提升,在同尺寸开源模型中具有较强的竞争力。 - 更高效的推理:基于
Multi-Query Attention技术,ChatGLM2-6B有更高效的推理速度和更低的显存占用:在官方的模型实现下,推理速度相比初代提升了42%,INT4 量化下,6G 显存支持的对话长度由 1K 提升到了 8K。 - 更开放的协议:ChatGLM2-6B权重对学术研究完全开放,在填写
问卷进行登记后亦允许免费商业使用。
2.3.2 与ChatGLM的变化
- 使用了RoPE替换二维位置编码。这也是GLM中提出的亮点设计之一。但是目前大部分主流的LLMs都在使用RoPE,所以大势所趋。当前版本仍然采用了最初的RoPE设计,事实上现在的RoPE经过了xPOS→线性内插→NTK-AwareScaled RoPE→…若干次进化。
- Multi-QueryAttention:这是一种共享机制的Attention,相比Multi-HeadAttention,其Query部分没有区别,Key和Value可以只用一个Head。计算时,对Key和Value进行expand或者repeat操作,使它们填充到与Query一样的维度,后续计算就与Multi-HeadAttention没区别。
- Attention Mask: V1的attention mask分了2部分,PartA和Part B,Part A部分是双向Attention(代码中的
prefix_attention_mask),PartB部分是CausalAttention(原代码文件中的get_masks函数)。在V2版本,全部换成了CausalAttention,不再区分是Part A还是PartB,完全变成了decoder-only的架构。 - 多目标任务:Chat版本主要还是用的gMask生成式任务,但是在V1版本的代码还能看到mask、gMask等字样,V2已经摒弃了这些特殊token,原因与AttentionMask一致,均因为变成了decoder-only的架构,不再需要区分Part A和PartB。
2.3.3 ChatGLM-3
省流:ChatGLM2与ChatGLM3模型架构是完全一致的,ChatGLM与后继者结构不同。可见ChatGLM3相对于ChatGLM2没有模型架构上的改进。
相对于ChatGLM,ChatGLM2、ChatGLM3模型上的变化:
- 词表的大小从ChatGLM的150528缩小为65024(一个直观的体验是ChatGLM2、3加载比ChatGLM快不少)
- 位置编码从每个GLMBlock一份提升为全局一份
- SelfAttention之后的前馈网络有不同。ChatGLM用GELU(GaussianError LinearUnit)做激活;ChatGLM用Swish-1做激活。而且ChatGLM2、3应该是修正了之前的一个bug,因为GLU(GatedLinearUnit)本质上一半的入参是用来做门控制的,不需要输出到下层,所以ChatGLM2、3看起来前后维度不一致(27392->13696)反而是正确的。
3.BERT
3.1BERT用字粒度和词粒度的优缺点有哪些?
BERT可以使用字粒度(character-level)和词粒度(word-level)两种方式来进行文本表示,它们各自有优缺点:
字粒度(Character-level):
- 优点:处理未登录词(Out-of-Vocabulary,OOV):字粒度可以处理任意字符串,包括未登录词,不需要像词粒度那样遇到未登录词就忽略或使用特殊标记。对于少见词和低频词,字粒度可以学习更丰富的字符级别表示,使得模型能够更好地捕捉词汇的细粒度信息。
- 缺点:计算复杂度高:使用字粒度会导致输入序列的长度大大增加,进而增加模型的计算复杂度和内存消耗。需要更多的训练数据:字粒度模型对于少见词和低频词需要更多的训练数据来学习有效的字符级别表示,否则可能会导致过拟合。
词粒度(Word-level):
- 优点:计算效率高:使用词粒度可以大大减少输入序列的长度,从而降低模型的计算复杂度和内存消耗。学习到更加稳定的词级别表示:词粒度模型可以学习到更加稳定的词级别表示,特别是对于高频词和常见词,有更好的表示能力。
- 缺点:处理未登录词(OOV):词粒度模型无法处理未登录词,遇到未登录词时需要采用特殊处理(如使用未登录词的特殊标记或直接忽略)。对于多音字等形态复杂的词汇,可能无法准确捕捉其细粒度的信息。
3.2BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
3.3BERT用的是transformer里面的encoder还是decoder?
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
3.4为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?
BERT选择mask掉15%的词是一种经验性的选择,是原论文中的一种选择,并没有一个固定的理论依据,实际中当然可以尝试不同的比例,15%的比例是由BERT的作者在原始论文中提出,并在实验中发现对于BERT的训练效果是有效的
3.5为什么BERT在第一句前会加一个[CLS] 标志?
BERT在第一句前会加一个 [CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。为什么选它?因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。而[CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。
3.6 BERT非线性的来源在哪里?
主要来自两个地方:前馈层的gelu激活函数和self-attention。
前馈神经网络层:在BERT的Encoder中,每个自注意力层之后都跟着一个前馈神经网络层。前馈神经网络层是全连接的神经网络,通常包括一个线性变换和一个非线性的激活函数,如gelu。这样的非线性激活函数引入了非线性变换,使得模型能够学习更加复杂的特征表示。
self-attentionlayer:在自注意力层中,查询(Query)、键(Key)、值(Value)之间的点积得分会经过softmax操作,形成注意力权重,然后将这些权重与值向量相乘得到每个位置的自注意输出。这个过程中涉及了softmax操作,使得模型的计算是非线性的。
3.7BERT训练时使用的学习率 warm-up策略是怎样的?为什么要这么做?在BERT的训练中,使用了学习率warm-up策略,这是为了在训练的早期阶段增加学习率,以提高训练的稳定性和加快模型收敛。
学习率warm-up策略的具体做法是,在训练开始的若干个步骤(通常是一小部分训练数据的迭代次数)内,将学习率逐渐从一个较小的初始值增加到预定的最大学习率。在这个过程中,学习率的变化是线性的,即学习率在warm-up阶段的每个步骤按固定的步幅逐渐增加。学习率warm-up的目的是为了解决BERT在训练初期的两个问题:
- 不稳定性:在训练初期,由于模型参数的随机初始化以及模型的复杂性,模型可能处于一个较不稳定的状态。此时使用较大的学习率可能导致模型的参数变动太大,使得模型很难收敛,学习率warm-up可以在这个阶段将学习率保持较小,提高模型训练的稳定性。
- 避免过拟合:BERT模型往往需要较长的训练时间来获得高质量的表示。如果在训练的早期阶段就使用较大的学习率,可能会导致模型在训练初期就过度拟合训练数据,降低模型的泛化能力。通过学习率warm-up,在训练初期使用较小的学习率,可以避免过度拟合,等模型逐渐稳定后再使用较大的学习率进行更快的收敛。
3.8在BERT应用中,如何解决长文本问题?
在BERT应用中,处理长文本问题有以下几种常见的解决方案:
- 截断与填充:将长文本截断为固定长度或者进行填充。BERT模型的输入是一个固定长度的序列,因此当输入的文本长度超过模型的最大输入长度时,需要进行截断或者填充。通常,可以根据任务的要求,选择适当的最大长度,并对文本进行截断或者填充,使其满足模型输入的要求。
- SlidingWindow:将长文本分成多个短文本,然后分别输入BERT模型。这种方法被称为SlidingWindow技术。具体来说,将长文本按照固定的步长切分成多个片段,然后分别输入BERT模型进行处理。每个片段的输出可以进行进一步的汇总或者融合,得到最终的表示。
- HierarchicalModel:使用分层模型来处理长文本,其中底层模型用于处理短文本片段,然后将不同片段的表示进行汇总或者融合得到整个长文本的表示。这样的分层模型可以充分利用BERT模型的表示能力,同时处理长文本。
- Longformer、BigBird等模型:使用专门针对长文本的模型,如Longformer和BigBird。这些模型采用了不同的注意力机制,以处理超长序列,并且通常在处理长文本时具有更高的效率。
- Document-LevelModel:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
]]>
@@ -31,7 +58,7 @@
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
/2024/03/05/dl_llm_basic/
diff --git a/page/2/index.html b/page/2/index.html
index 9f0a906..1032d0f 100644
--- a/page/2/index.html
+++ b/page/2/index.html
@@ -202,6 +202,67 @@
+
+
+
+
+
+
+
+ 【深度学习】图神经网络
+
+
+
+
+
+
+ 图神经网络 GNN全称----图神经网络,它是一种直接作用于图结构上的神经网络。我们可以把图中的每一个节点 \(V\) 当作个体对象,而每一条边 \(E\) 当作个体与个体间的某种联系,所有节点组成的关系网就是最后的图 \(U\) GNN的输入一般是每个节点的起始特征向量和表示节点间关系的邻接矩阵,有了这两个输入信息,接下来就是聚合操作了。所谓的聚合,其实就是将周边与节点 V i ViVi 有关
+
+
+
+
+
+
+
@@ -765,74 +826,11 @@
-
-
-
-
-
-
-
- 【自动驾驶】RSS Model for Autonomous Driving
-
-
-
-
-
-
- RSS Model for Autonomous Driving 论文:《On a Formal Model of Safe and Scalable Self-driving Cars》 Contribution: Safety (RSS model) Reasonable care, Responsibility, agile driving policy Semantic (Semant
-
-
-
-
-
-
-
diff --git a/page/3/index.html b/page/3/index.html
new file mode 100644
index 0000000..abdef70
--- /dev/null
+++ b/page/3/index.html
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/search.xml b/search.xml
index a42b258..fb121df 100644
--- a/search.xml
+++ b/search.xml
@@ -7748,7 +7748,7 @@ href="https://so.csdn.net/so/search?q=conda&spm=1001.2101.3001.7020">conda
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
/2024/03/05/dl_llm_basic/
深度学习&LLM基础
@@ -9010,7 +9010,7 @@ alt="进制转换的示意图" />
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
/2024/03/08/dl_llm_model/
大语言模型简介
@@ -9498,8 +9498,8 @@ BERT用字粒度和词粒度的优缺点有哪些?
3.2
BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
-3.3BERT用的是transformer里面的encoder还是decoder?
+3.3
+BERT用的是transformer里面的encoder还是decoder?
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
@@ -9542,6 +9542,826 @@ Model:使用分层模型来处理长文本,其中底层模型用于
Document-Level
Model:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
+]]>
+
+ 深度学习
+
+
+ 深度学习
+ 大语言模型
+
+
+
+ 【大语言模型】有监督微调
+ /2024/03/24/dl-llm-ft/
+
+大语言模型微调
+1. 大模型微调简介
+1.1 微调方法定义
+微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
+下面是一般的微调步骤:
+
+- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。
+- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。
+- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specific
+head)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。
+- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。
+- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。
+- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。
+- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。
+- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。
+
+微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
+1.2 为什么需要 PEFT
+Parameter-Efficient
+Fine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trained
+language models
+)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
+PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
+参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
+参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
+高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Soft
+prompts)两个小类。
+
+
+Scaling Down to Scale Up: A Guide to Parameter-Efficient
+Fine-Tuning
+
+1.3
+微调和参数高效微调之间的区别
+微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
+微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
+另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
+1.4 PEFT 有什么优点
+在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
+
+- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本
+- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。
+- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。
+- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。
+- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。
+
+1.5 多种不同的高效微调方法对比
+参数有效策略可能涉及多种技术:
+
+- 选择性层调整(Selective Layer
+Tuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。
+- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。
+- 稀疏微调(Sparse
+Fine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。
+- 低秩近似(Low-Rank
+Approximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。
+- 正则化技术(Regularization
+Techniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。
+- 任务特定的头(Task-specific
+Heads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。
+
+1.6
+当前高效微调技术存在的一些问题
+当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
+
+- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。
+Ladder-side
+Tuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。
+- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。
+- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。
+- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用git
+fork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。
+
+1.7 PEFT技术实践
+针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
+
+- 明确指出参数数量类型。
+- 使用不同大小的模型进行评估。
+- 和类似方法进行比较。
+- 标准化PEFT测量基准。
+- 重视代码清晰度,以最小化进行实现。
+
+2. 微调Fine-Tune
+2.1 为什么SFT之后感觉LLM傻了?
+在进行Supervised
+Fine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
+
+- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。
+- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。
+- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。
+- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。
+
+为了解决这些问题,可以尝试以下方法:
+
+- 收集更多的训练数据,以增加数据的多样性和覆盖范围。
+- 仔细检查微调数据集的标注,确保标签的准确性和一致性。
+- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。
+- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。
+- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。
+
+通过这些方法,可以尽量减少Supervised
+Fine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
+2.2 SFT 指令微调数据 如何构建?
+构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
+
+- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。
+- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。
+- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。
+- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。
+- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。
+- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。
+- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。
+
+2.3 如何训练自己的大模型?
+
+- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。
+- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。
+- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。
+- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。
+- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。
+- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。
+- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。
+
+2.4 指令微调的好处?
+指令微调(Instruction
+Fine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
+
+- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。
+- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。
+- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。
+- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。
+- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。
+
+请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
+2.5 多轮对话任务微调调型
+在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
+
+- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。
+- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。
+- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。
+- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
+
+- 初始化模型参数:将预训练模型的参数加载到模型中。
+- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。
+- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。
+- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。
+
+- 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。
+- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。
+
+需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
+2.6 微调后的模型出现能力劣化
+灾难性遗忘(Catastrophic
+Forgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
+在微调大语言模型时,灾难性遗忘可能出现的原因包括:
+
+- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。
+- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。
+
+为了解决灾难性遗忘问题,可以尝试以下方法:
+
+- 经验回放(Replay
+Buffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。
+- 弹性权重共享(Elastic Weight
+Consolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。
+- 增量学习(Incremental
+Learning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。
+- 多任务学习(Multi-Task
+Learning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。
+
+综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
+2.7 预训练和SFT操作有什么不同
+大语言模型的预训练和有监督微调(Supervised
+Fine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
+目标:
+
+- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(Masked
+Language Model,MLM)或下一句预测(Next Sentence
+Prediction,NSP)等,来训练模型。
+- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。
+
+数据:
+
+- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。
+- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。
+
+训练方式:
+
+- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。
+- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。
+
+总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
+2.8 大模型LLM进行SFT
+如何对样本进行优化?
+对于大语言模型进行有监督微调(Supervised
+Fine-Tuning)时,可以采用以下几种方式对样本进行优化:
+
+- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。
+- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。
+- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。
+- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。
+- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。
+- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。
+- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。
+
+总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
+3. 预训练
+3.1 为什么要增量预训练?
+预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
+3.2
+进行增量预训练需要做哪些准备工作?
+
+- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。
+- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是
+TB 级别的。
+- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。
+
+3.3
+增量预训练训练流程是怎么样?
+
+- 数据预处理:参考 LLaMA
+的预训练长度,也把数据处理成2048长度(如果不够,做补全)。
+- 分词器:如果使用 LLaMA
+可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。
+- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选
+Chat 模型。
+- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。
+- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。
+- 模型测试:简单测试下续写能力,验证下模型是否正常。
+
+4. Prompting工程
+4.1 BitFit
+4.1.1 背景
+虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署,
+特别是随着任务数量的增加,很难维护。
+理想状况下,我们希望有一种满足以下条件的高效微调方法:
+
+- 到达能够匹配全量微调的效果。
+- 仅更改一小部分模型参数。
+- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。
+- 改变的参数在不同下游任务中是一致的。
+
+上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
+虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
+4.1.2 技术原理
+BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuning
+or Transformer-based Masked
+Language-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
+对于Transformer模型而言,冻结大部分 transformer-encoder
+参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
+在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了
+BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
+
+同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言,
+只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
+同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
+
+4.2 Prefix Tuning
+4.2.1 背景
+在Prefix
+Tuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
+除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
+基于上述两点,Prefix
+Tuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,
+这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的Virtual
+Token(Soft Prompt/Continuous
+Prompt),相比离散的Token,更好优化,效果更好。
+
+4.2.2 技术原理
+Prefix Tuning(论文:Prefix-Tuning: Optimizing Continuous
+Prompts for
+Generation),在输入token之前构造一段任务相关的virtual
+tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
+针对不同的模型结构,需要构造不同的Prefix。
+
+- 针对自回归架构模型:在句子前面添加前缀,得到
+
z = [PREFIX; x; y]
,合适的上文能够在固定 LM
+的情况下去引导生成下文(比如:GPT3的上下文学习)。
+- 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
+
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder
+端增加前缀是为了引导后续token的生成。
+
+
+该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
+
+除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
+
+另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为
+[PREFIX; x; y]
,Infix-tuning形式为
+[x; INFIX; y]
。
+4.3 Prompt Tuning
+4.3.1 背景
+大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
+基于此,作者提出了Prompt
+Tuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,
+训练完以后,用同一个模型可以做多任务推理。
+4.3.2 技术原理
+Prompt Tuning(论文:The Power of Scale for
+Parameter-Efficient Prompt Tuning),该方法可以看作是Prefix
+Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompt
+tokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
+
+通过实验发现,随着预训练模型参数量的增加,Prompt
+Tuning的方法会逼近全参数微调的结果。
+
+同时,Prompt Tuning 还提出了 Prompt
+Ensembling,也就是在一个批次(Batch)里同时训练同一个任务的不同
+prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
+
+4.4 P-Tuning
+4.4.1 背景
+该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(in
+context
+learning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
+同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtual
+token(同Prefix-Tuning类似)。
+
+4.4.2 技术原理
+P-Tuning(论文:GPT Understands,
+Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。
+
+相比Prefix Tuning,P-Tuning加入的可微的virtual
+token,但仅限于输入层,没有在每一层都加;另外,virtual
+token的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtual
+token。
+经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual
+token,容易优化到局部最优值,而这些virtual
+token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt
+encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual
+token以后,再输入到模型。
+从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
+并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
+4.5 P-Tuning v2
+4.5.1 背景
+之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
+第一,缺乏模型参数规模和任务通用性。
+
+- 缺乏规模通用性:Prompt
+Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
+- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些
+NLU
+基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。
+
+第二,缺少深度提示优化,在Prompt
+Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
+
+- 由于序列长度的限制,可调参数的数量是有限的。
+- 输入embedding对模型预测只有相对间接的影响。
+
+考虑到这些问题,作者提出了Ptuning
+v2,它利用深度提示优化(如:Prefix Tuning),对Prompt
+Tuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
+4.5.2 技术原理
+P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can Be
+Comparable to Fine-tuning Universally Across Scales and
+Tasks),该方法在每一层都加入了Prompts
+tokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
+
+- 更多可学习的参数(从P-tuning和Prompt
+Tuning的0.01%增加到0.1%-3%),同时也足够参数高效。
+- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。
+
+
+具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix
+Tuning技术适配到NLU任务中,然后做了一些改进:
+
+- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2
+中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
+- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。
+- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuning
+v2的有益补充。
+- 回归传统的分类标签范式,而不是映射器。标签词映射器(Label
+Word
+Verbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuning
+v2回归传统的CLS标签分类范式,采用随机初始化的分类头(Classification
+Head)应用于tokens之上,以增强通用性,可以适配到序列标注任务。
+
+论文中展示了P-tuning
+v2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),Prompt
+Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuning
+v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning
+v2在RTE中的表现明显优于微调,特别是在BERT中。
+5. Adapter-Tuning
+5.1 Adapter Tuning
+5.1.1 背景
+预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
+基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题
+Adapter
+在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
+5.1.2 技术原理
+Adapter Tuning(论文:Parameter-Efficient Transfer Learning
+for
+NLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的
+==Adapter 结构和 Layer Norm
+层==进行微调,从而保证了训练的高效性。
+每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
+
+5.1.3 具体细节
+每个 Adapter
+模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skip
+connection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便
+Adapter 一开始的参数初始化接近0,Adapter也由于skip
+connection的设置而接近于一个恒等映射,从而确保训练的有效性。
+\[
+h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p}
+\]
+通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
+总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
+5.2 AdapterFusion
+5.2.1 背景
+为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequential
+fine-tuning)或者多任务学习(multi-task
+learning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
+而之前的工作,Adapter
+Tuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter
+的参数某种程度上就表达了解决这个任务需要的知识。
+作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了
+AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
+5.2.2 技术原理
+Adapter Fusion(论文:AdapterFusion:Non-Destructive Task
+Composition for Transfer
+Learning),一种融合多任务信息的Adapter的变体,在
+Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+
+- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
+- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。
+
+
+对于第一阶段,有两种训练方式,分别如下:
+
+- Single-Task
+Adapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。
+- Multi-Task
+Adapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。
+
+对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
+5.2.3 AdapterFusion结构
+AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,
+value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
+
+通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
+总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
+5.3 AdapterDrop
+5.3.1 背景
+近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
+作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
+基于此,作者提出了AdapterDrop方法缓解该问题。
+5.3.2 技术原理
+AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters in
+Transformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+
+实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。
+例如,将前五个Transformer层中的Adapter丢弃,在对 8
+个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop
+也能保持良好的结果。
+除此之外,作者还研究了对
+AdapterFusion中的Adapter进行剪枝后的效果。
+
+通过实验表明可以移除 AdapterFusion
+中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整
+AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
+因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。
+这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
+总之,AdapterDrop
+通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+5.4 MAM Adapter
+5.4.1 背景
+近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
+下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,Prefix
+Tuning和LoRA都是性能比较好的方法。
+
+为什么看起来Adapter、Prefix
+Tuning、LoRA(在结构上和公式上)都不太一样,尤其是Prefix
+Tuning,但是这三种方法有近似的效果?
+基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、Prefix
+Tuning和LoRA)的设计,并提出了一种新方法MAM
+Adapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
+
+首先,作者通过对Prefix Tuning变换,发现Prefix
+Tuning和Adapters的公式高度相似。
+然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体)
+Parallel Adapter、 Scaled PA的结构。
+
+下表展示了高效微调方法Adapter、Prefix
+Tuning、LoRA以及新变体在新增可训练参数结构形式(functional
+form)、结构插入形式(Insertion
+form)、新增结构在PLM修改的具体位置(modified
+representation)、新增结构与PLM的组合函数(composition
+function)。其中,新增可训练参数结构形式为需要学习的部分(注:Prefix
+Tuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
+
+5.4.2 技术原理
+MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT
+TRANSFER LEARNING),一个在Adapter、Prefix
+Tuning和LoRA之间建立联系的统一方法。
+作者对Adapter的放置和软提示(soft
+prompt)进行了详细的调查。得出如下结论:
+
+- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN
+并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。
+- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。
+
+然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用
+FFN 层的并行Adapter和软提示的组合。
+通过最终的实验结果,可以看到 MAM Adapter
+在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于
+BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
+5.5 UniPELT
+5.5.1 背景
+近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
+基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+5.5.2 技术原理
+UniPELT(论文: UNIPELT: A Unified Framework for Parameter-Efficient
+Language Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
+更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,Prefix
+Tuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。
+对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括
+LoRA 矩阵
+WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
+
+UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter
+和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT
+的性能与这些方法相当或更好。
+实验还对不同 PELT 方法训练时间和推理时间进行了分析。
+
+- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围,
+- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。
+- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。
+
+6. lora
+6.1 LoRA
+6.1.1 背景
+神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsic
+rank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
+6.1.2 技术原理
+LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE
+MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsic
+rank)。
+
+可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
+
+在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
+\[
+h=W_{0} x+\Delta W x=W_{0} x+B A x
+\]
+在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
+此外,Transformer的权重矩阵包括Attention模块里用于计算query
,
+key
,
+value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整
+Wq 和 Wv 会产生最佳结果。
+实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
+6.2 AdaLoRA
+6.2.1 背景
+在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
+
+- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。
+- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。
+
+为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
+
+- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adapter
+tuning、Prefix tuning、Prompt
+Tuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adapter
+tuning引入了推理延时;Prefix tuning或Prompt
+tuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。
+- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diff
+pruning、LoRA等,
+此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diff
+pruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。
+LoRA则需要预先指定每个增量矩阵的本征秩 r
+相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。
+
+基于以上问题进行总结:
+
+- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。
+- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。
+
+为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
+6.2.2 技术原理
+AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FOR
+PARAMETEREFFICIENT
+FINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
+
+- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。
+
+\[
+W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q
+\]
+
+- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。
+
+通过实验证明,AdaLoRA
+实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。
+例如,当参数预算为 0.3M 时,AdaLoRA
+在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
+
+6.3 QLoRA
+6.3.1 背景
+微调大型语言模型 (LLM)
+是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以
+LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU
+内存。
+虽然最近的量化方法可以减少 LLM
+的内存占用,但此类技术仅适用于推理场景。
+基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为
+4 bit的模型。
+6.3.2 技术原理
+QLoRA(论文: QLORA: Efficient Finetuning of Quantized
+LLMs),使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA
+有一种低精度存储数据类型(4
+bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用
+QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16
+位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bit
+NormalFloat(NF4)
+量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
+
+- 4bit
+NormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比
+4 bit整数和 4bit 浮点数更好的实证结果。
+- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。
+- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的
+GPU 处理。该功能的工作方式类似于 CPU
+内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在
+GPU 内存不足时将其自动卸载到 CPU
+内存,并在优化器更新步骤需要时将其加载回 GPU 内存。
+
+
+实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
+7. 微调方法总结
+7.1
+当前高效微调技术的简述
+之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
+7.2 BitFit
+对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
+特点:
+
+- 训练参数量极小(约0.1%)。
+- 在大部分任务上效果会差于LoRA、Adapter等方法。
+
+7.3 Prefix Tuning
+在每一个Transformer层都带上一些virtual
+token作为前缀,以适应不同的任务。
+特点:
+
+- 前缀Token会占用序列长度,有一定的额外计算开销。
+- Prefix Tuning的线性插值是比较复杂的。
+
+7.4 Prompt Tuning
+该方法可以看着是Prefix
+Tuning的简化版本,针对不同的任务,仅在输入层引入virtual
+token形式的软提示(soft prompt)。
+特点:
+
+- 相对于Prefix
+Tuning,参与训练的参数量和改变的参数量更小,更节省显存。
+- 对一些简单的NLU
+任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。
+
+7.5 P-Tuning
+将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt
+Embedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtual
+token;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
+特点:
+
+- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtual
+token的相互依赖会收敛更快,效果更好。
+
+7.6 P-Tuning v2
+该方法在每一个Transformer层都加入了prompt
+token作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
+特点:
+
+- 解决了Prompt Tuning无法在小模型上有效提升的问题。
+- 移除了对模型效果改进较小的重参数化的编码器(如:Prefix
+Tuning中的MLP、P-Tuning中的LSTM)。
+- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。
+
+7.7 Adapter Tuning
+该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和Layer
+Norm 层进行微调。
+特点:
+
+- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。
+
+7.8 AdapterFusion
+一种融合多任务信息的Adapter的变体,在 Adapter
+的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+7.9 AdapterDrop
+该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+特点:
+
+- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。
+当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+
+7.10 LoRA
+该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+特点:
+
+- 将BA加到W上可以消除推理延迟。
+- 可以通过可插拔的形式切换到不同的任务。
+- 设计的比较好,简单且效果好。
+
+7.11 AdaLoRA
+对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+7.12 QLoRA
+使用一种新颖的高精度技术将预训练模型量化为 4
+bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
+特点:
+
+- 使用 QLoRA
+微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。
+
+7.13 MAM Adapter
+一种在 Adapter、Prefix Tuning 和 LoRA
+之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter
+和 软提示的组合。
+特点:
+
+- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。
+
+7.14 UniPELT
+一种将不同的PELT方法LoRA、Prefix
+Tuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+特点:
+
+- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。
+- 多种 PELT 方法的混合涉及PLM
+的不同部分对模型有效性和鲁棒性都有好处
+
+7.15 总结
+本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
+
+- 增加额外参数,如:Prefix Tuning、Prompt Tuning、Adapter
+Tuning及其变体。
+- 选取一部分参数更新,如:BitFit。
+- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。
+- 混合高效微调,如:MAM Adapter、UniPELT。
+
+并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
]]>
深度学习
diff --git a/tags/index.html b/tags/index.html
index 09b5b82..8d3b766 100644
--- a/tags/index.html
+++ b/tags/index.html
@@ -202,7 +202,7 @@
diff --git "a/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html" "b/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html"
index d1b80e6..144b637 100644
--- "a/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html"
+++ "b/tags/\345\244\247\350\257\255\350\250\200\346\250\241\345\236\213/index.html"
@@ -202,7 +202,7 @@
- 1 posts in total
+ 2 posts in total
@@ -210,9 +210,15 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
diff --git "a/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html" "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
index 04bf2b4..41f4f1e 100644
--- "a/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
+++ "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/index.html"
@@ -202,7 +202,7 @@
- 10 posts in total
+ 11 posts in total
@@ -210,15 +210,21 @@
2024
+
+
+ 【大语言模型】有监督微调
+
+
+
- 【深度学习】大语言模型简介
+ 【大语言模型】基础模型概念
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -266,15 +272,15 @@
【深度学习】PyTorch使用手册
-
-
-
- 【多智能体强化学习】Pymarl环境配置
-
-
+
+
diff --git "a/tags/\346\267\261\345\272\246\345\255\246\344\271\240/page/2/index.html" "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/page/2/index.html"
new file mode 100644
index 0000000..0ec8797
--- /dev/null
+++ "b/tags/\346\267\261\345\272\246\345\255\246\344\271\240/page/2/index.html"
@@ -0,0 +1,342 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Tags - 深度学习 - LIHAIBIN'S BLOG
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Search
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
【大语言模型】有监督微调
+ ++ + + Last updated on March 24, 2024 pm + + +
+ + +大语言模型微调
+1. 大模型微调简介
+1.1 微调方法定义
+微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
+下面是一般的微调步骤:
+-
+
- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。 +
- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。 +
- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specific +head)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。 +
- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。 +
- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。 +
- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。 +
- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。 +
- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。 +
微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
+1.2 为什么需要 PEFT
+Parameter-Efficient +Fine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trained +language models +)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
+PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
+参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
+参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
+高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Soft +prompts)两个小类。
+ +++Scaling Down to Scale Up: A Guide to Parameter-Efficient +Fine-Tuning
+
1.3 +微调和参数高效微调之间的区别
+微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
+微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
+另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
+1.4 PEFT 有什么优点
+在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
+-
+
- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本 +
- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。 +
- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。 +
- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。 +
- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。 +
1.5 多种不同的高效微调方法对比
+参数有效策略可能涉及多种技术:
+-
+
- 选择性层调整(Selective Layer +Tuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。 +
- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。 +
- 稀疏微调(Sparse +Fine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。 +
- 低秩近似(Low-Rank +Approximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。 +
- 正则化技术(Regularization +Techniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。 +
- 任务特定的头(Task-specific +Heads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。 +
1.6 +当前高效微调技术存在的一些问题
+当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
+-
+
- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。 +Ladder-side +Tuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。 +
- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。 +
- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。 +
- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用git +fork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。 +
1.7 PEFT技术实践
+针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
+-
+
- 明确指出参数数量类型。 +
- 使用不同大小的模型进行评估。 +
- 和类似方法进行比较。 +
- 标准化PEFT测量基准。 +
- 重视代码清晰度,以最小化进行实现。 +
2. 微调Fine-Tune
+2.1 为什么SFT之后感觉LLM傻了?
+在进行Supervised +Fine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
+-
+
- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。 +
- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。 +
- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。 +
- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。 +
为了解决这些问题,可以尝试以下方法:
+-
+
- 收集更多的训练数据,以增加数据的多样性和覆盖范围。 +
- 仔细检查微调数据集的标注,确保标签的准确性和一致性。 +
- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。 +
- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。 +
- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。 +
通过这些方法,可以尽量减少Supervised +Fine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
+2.2 SFT 指令微调数据 如何构建?
+构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
+-
+
- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。 +
- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。 +
- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。 +
- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。 +
- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。 +
- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。 +
- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。 +
2.3 如何训练自己的大模型?
+-
+
- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。 +
- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。 +
- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。 +
- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。 +
- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。 +
- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。 +
- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。 +
2.4 指令微调的好处?
+指令微调(Instruction +Fine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
+-
+
- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。 +
- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。 +
- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。 +
- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。 +
- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。 +
请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
+2.5 多轮对话任务微调调型
+在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
+-
+
- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。 +
- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。 +
- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。 +
- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
+
-
+
- 初始化模型参数:将预训练模型的参数加载到模型中。 +
- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。 +
- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。 +
- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。 +
+ - 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。 +
- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。 +
需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
+2.6 微调后的模型出现能力劣化
+灾难性遗忘(Catastrophic +Forgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
+在微调大语言模型时,灾难性遗忘可能出现的原因包括:
+-
+
- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。 +
- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。 +
为了解决灾难性遗忘问题,可以尝试以下方法:
+-
+
- 经验回放(Replay +Buffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。 +
- 弹性权重共享(Elastic Weight +Consolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。 +
- 增量学习(Incremental +Learning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。 +
- 多任务学习(Multi-Task +Learning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。 +
综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
+2.7 预训练和SFT操作有什么不同
+大语言模型的预训练和有监督微调(Supervised +Fine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
+目标:
+-
+
- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(Masked +Language Model,MLM)或下一句预测(Next Sentence +Prediction,NSP)等,来训练模型。 +
- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。 +
数据:
+-
+
- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。 +
- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。 +
训练方式:
+-
+
- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。 +
- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。 +
总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
+2.8 大模型LLM进行SFT +如何对样本进行优化?
+对于大语言模型进行有监督微调(Supervised +Fine-Tuning)时,可以采用以下几种方式对样本进行优化:
+-
+
- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。 +
- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。 +
- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。 +
- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。 +
- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。 +
- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。 +
- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。 +
总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
+3. 预训练
+3.1 为什么要增量预训练?
+预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
+3.2 +进行增量预训练需要做哪些准备工作?
+-
+
- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。 +
- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是 +TB 级别的。 +
- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。 +
3.3 +增量预训练训练流程是怎么样?
+-
+
- 数据预处理:参考 LLaMA +的预训练长度,也把数据处理成2048长度(如果不够,做补全)。 +
- 分词器:如果使用 LLaMA +可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。 +
- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选 +Chat 模型。 +
- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。 +
- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。 +
- 模型测试:简单测试下续写能力,验证下模型是否正常。 +
4. Prompting工程
+4.1 BitFit
+4.1.1 背景
+虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署, +特别是随着任务数量的增加,很难维护。
+理想状况下,我们希望有一种满足以下条件的高效微调方法:
+-
+
- 到达能够匹配全量微调的效果。 +
- 仅更改一小部分模型参数。 +
- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。 +
- 改变的参数在不同下游任务中是一致的。 +
上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
+虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
+4.1.2 技术原理
+BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuning +or Transformer-based Masked +Language-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
+对于Transformer模型而言,冻结大部分 transformer-encoder
+参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了 +BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
+ +同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言, +只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
+同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
+ +4.2 Prefix Tuning
+4.2.1 背景
+在Prefix +Tuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
+除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
+基于上述两点,Prefix +Tuning提出固定预训练LM,为LM添加可训练,任务特定的前缀, +这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的Virtual +Token(Soft Prompt/Continuous +Prompt),相比离散的Token,更好优化,效果更好。
+ +4.2.2 技术原理
+Prefix Tuning(论文:Prefix-Tuning: Optimizing Continuous +Prompts for +Generation),在输入token之前构造一段任务相关的virtual +tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
+针对不同的模型结构,需要构造不同的Prefix。
+-
+
- 针对自回归架构模型:在句子前面添加前缀,得到
+
z = [PREFIX; x; y]
,合适的上文能够在固定 LM +的情况下去引导生成下文(比如:GPT3的上下文学习)。
+ - 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
+
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder +端增加前缀是为了引导后续token的生成。
+
该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
+ +除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
+ +另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为
+[PREFIX; x; y]
,Infix-tuning形式为
+[x; INFIX; y]
。
4.3 Prompt Tuning
+4.3.1 背景
+大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
+基于此,作者提出了Prompt +Tuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数, +训练完以后,用同一个模型可以做多任务推理。
+4.3.2 技术原理
+Prompt Tuning(论文:The Power of Scale for +Parameter-Efficient Prompt Tuning),该方法可以看作是Prefix +Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompt +tokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
+ +通过实验发现,随着预训练模型参数量的增加,Prompt +Tuning的方法会逼近全参数微调的结果。
+ +同时,Prompt Tuning 还提出了 Prompt +Ensembling,也就是在一个批次(Batch)里同时训练同一个任务的不同 +prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
+ +4.4 P-Tuning
+4.4.1 背景
+该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(in +context +learning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
+同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtual +token(同Prefix-Tuning类似)。
+ +4.4.2 技术原理
+P-Tuning(论文:GPT Understands, +Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt +Embedding进行一层处理。
+ +相比Prefix Tuning,P-Tuning加入的可微的virtual +token,但仅限于输入层,没有在每一层都加;另外,virtual +token的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtual +token。
+经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual +token,容易优化到局部最优值,而这些virtual +token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt +encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual +token以后,再输入到模型。
+从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
+并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
+4.5 P-Tuning v2
+4.5.1 背景
+之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
+第一,缺乏模型参数规模和任务通用性。
+-
+
- 缺乏规模通用性:Prompt +Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。 +
- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些 +NLU +基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。 +
第二,缺少深度提示优化,在Prompt +Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
+-
+
- 由于序列长度的限制,可调参数的数量是有限的。 +
- 输入embedding对模型预测只有相对间接的影响。 +
考虑到这些问题,作者提出了Ptuning +v2,它利用深度提示优化(如:Prefix Tuning),对Prompt +Tuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
+4.5.2 技术原理
+P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can Be +Comparable to Fine-tuning Universally Across Scales and +Tasks),该方法在每一层都加入了Prompts +tokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
+-
+
- 更多可学习的参数(从P-tuning和Prompt +Tuning的0.01%增加到0.1%-3%),同时也足够参数高效。 +
- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。 +
具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix +Tuning技术适配到NLU任务中,然后做了一些改进:
+-
+
- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:Prefix +Tuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2 +中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。 +
- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。 +
- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuning +v2的有益补充。 +
- 回归传统的分类标签范式,而不是映射器。标签词映射器(Label +Word +Verbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuning +v2回归传统的CLS标签分类范式,采用随机初始化的分类头(Classification +Head)应用于tokens之上,以增强通用性,可以适配到序列标注任务。 +
论文中展示了P-tuning +v2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),Prompt +Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuning +v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning +v2在RTE中的表现明显优于微调,特别是在BERT中。
+5. Adapter-Tuning
+5.1 Adapter Tuning
+5.1.1 背景
+预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
+基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题 +Adapter +在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
+5.1.2 技术原理
+Adapter Tuning(论文:Parameter-Efficient Transfer Learning +for +NLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的 +==Adapter 结构和 Layer Norm +层==进行微调,从而保证了训练的高效性。
+每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
+ +5.1.3 具体细节
+每个 Adapter
+模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skip
+connection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便
+Adapter 一开始的参数初始化接近0,Adapter也由于skip
+connection的设置而接近于一个恒等映射,从而确保训练的有效性。
\[ +h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p} +\]
+通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
+总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
+5.2 AdapterFusion
+5.2.1 背景
+为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequential +fine-tuning)或者多任务学习(multi-task +learning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
+而之前的工作,Adapter +Tuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter +的参数某种程度上就表达了解决这个任务需要的知识。
+作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了 +AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
+5.2.2 技术原理
+Adapter Fusion(论文:AdapterFusion:Non-Destructive Task +Composition for Transfer +Learning),一种融合多任务信息的Adapter的变体,在 +Adapter +的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+-
+
- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。 +
- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。 +
对于第一阶段,有两种训练方式,分别如下:
+-
+
- Single-Task +Adapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。 +
- Multi-Task +Adapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。 +
对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
5.2.3 AdapterFusion结构
+AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,
+value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
+总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
+5.3 AdapterDrop
+5.3.1 背景
+近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
+作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
+基于此,作者提出了AdapterDrop方法缓解该问题。
+5.3.2 技术原理
+AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters in +Transformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+ +实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。 +例如,将前五个Transformer层中的Adapter丢弃,在对 8 +个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop +也能保持良好的结果。
+除此之外,作者还研究了对 +AdapterFusion中的Adapter进行剪枝后的效果。
+ +通过实验表明可以移除 AdapterFusion +中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整 +AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
+因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。 +这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
+总之,AdapterDrop +通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。 +当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+5.4 MAM Adapter
+5.4.1 背景
+近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
+下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,Prefix +Tuning和LoRA都是性能比较好的方法。
+ +为什么看起来Adapter、Prefix +Tuning、LoRA(在结构上和公式上)都不太一样,尤其是Prefix +Tuning,但是这三种方法有近似的效果?
+基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、Prefix +Tuning和LoRA)的设计,并提出了一种新方法MAM +Adapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
+ +首先,作者通过对Prefix Tuning变换,发现Prefix +Tuning和Adapters的公式高度相似。
+然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、Prefix +Tuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体) +Parallel Adapter、 Scaled PA的结构。
+ +下表展示了高效微调方法Adapter、Prefix +Tuning、LoRA以及新变体在新增可训练参数结构形式(functional +form)、结构插入形式(Insertion +form)、新增结构在PLM修改的具体位置(modified +representation)、新增结构与PLM的组合函数(composition +function)。其中,新增可训练参数结构形式为需要学习的部分(注:Prefix +Tuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
+ +5.4.2 技术原理
+MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT +TRANSFER LEARNING),一个在Adapter、Prefix +Tuning和LoRA之间建立联系的统一方法。
+作者对Adapter的放置和软提示(soft +prompt)进行了详细的调查。得出如下结论:
+-
+
- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN +并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。 +
- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。 +
然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用 +FFN 层的并行Adapter和软提示的组合。
+通过最终的实验结果,可以看到 MAM Adapter +在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于 +BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
+5.5 UniPELT
+5.5.1 背景
+近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
+基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+5.5.2 技术原理
+UniPELT(论文: UNIPELT: A Unified Framework for Parameter-Efficient +Language Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
+更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,Prefix +Tuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。 +对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括 +LoRA 矩阵 +WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
+ +UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter +和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT +的性能与这些方法相当或更好。
+实验还对不同 PELT 方法训练时间和推理时间进行了分析。
+-
+
- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围, +
- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。 +
- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。 +
6. lora
+6.1 LoRA
+6.1.1 背景
+神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsic +rank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
+6.1.2 技术原理
+LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE +MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsic +rank)。
+ +可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
\[ +h=W_{0} x+\Delta W x=W_{0} x+B A x +\]
+在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
此外,Transformer的权重矩阵包括Attention模块里用于计算query
,
+key
,
+value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整
+Wq 和 Wv 会产生最佳结果。
实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
+6.2 AdaLoRA
+6.2.1 背景
+在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
+-
+
- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。 +
- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。 +
为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
+-
+
- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adapter +tuning、Prefix tuning、Prompt +Tuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adapter +tuning引入了推理延时;Prefix tuning或Prompt +tuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。 +
- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diff +pruning、LoRA等, +此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diff +pruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。 +LoRA则需要预先指定每个增量矩阵的本征秩 r +相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。 +
基于以上问题进行总结:
+-
+
- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。 +
- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。 +
为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
+6.2.2 技术原理
+AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FOR +PARAMETEREFFICIENT +FINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
+-
+
- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。 +
- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。 +
\[ +W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q +\]
+-
+
- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。 +
通过实验证明,AdaLoRA +实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。 +例如,当参数预算为 0.3M 时,AdaLoRA +在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
+ +6.3 QLoRA
+6.3.1 背景
+微调大型语言模型 (LLM) +是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以 +LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU +内存。
+虽然最近的量化方法可以减少 LLM +的内存占用,但此类技术仅适用于推理场景。
+基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为 +4 bit的模型。
+6.3.2 技术原理
+QLoRA(论文: QLORA: Efficient Finetuning of Quantized +LLMs),使用一种新颖的高精度技术将预训练模型量化为 4 +bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA +有一种低精度存储数据类型(4 +bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用 +QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16 +位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bit +NormalFloat(NF4) +量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
+-
+
- 4bit +NormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比 +4 bit整数和 4bit 浮点数更好的实证结果。 +
- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。 +
- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的 +GPU 处理。该功能的工作方式类似于 CPU +内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在 +GPU 内存不足时将其自动卸载到 CPU +内存,并在优化器更新步骤需要时将其加载回 GPU 内存。 +
实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
+7. 微调方法总结
+7.1 +当前高效微调技术的简述
+之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
+7.2 BitFit
+对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
+特点:
+-
+
- 训练参数量极小(约0.1%)。 +
- 在大部分任务上效果会差于LoRA、Adapter等方法。 +
7.3 Prefix Tuning
+在每一个Transformer层都带上一些virtual +token作为前缀,以适应不同的任务。
+特点:
+-
+
- 前缀Token会占用序列长度,有一定的额外计算开销。 +
- Prefix Tuning的线性插值是比较复杂的。 +
7.4 Prompt Tuning
+该方法可以看着是Prefix +Tuning的简化版本,针对不同的任务,仅在输入层引入virtual +token形式的软提示(soft prompt)。
+特点:
+-
+
- 相对于Prefix +Tuning,参与训练的参数量和改变的参数量更小,更节省显存。 +
- 对一些简单的NLU +任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。 +
7.5 P-Tuning
+将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt +Embedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtual +token;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
+特点:
+-
+
- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtual +token的相互依赖会收敛更快,效果更好。 +
7.6 P-Tuning v2
+该方法在每一个Transformer层都加入了prompt +token作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
+特点:
+-
+
- 解决了Prompt Tuning无法在小模型上有效提升的问题。 +
- 移除了对模型效果改进较小的重参数化的编码器(如:Prefix +Tuning中的MLP、P-Tuning中的LSTM)。 +
- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。 +
7.7 Adapter Tuning
+该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和Layer +Norm 层进行微调。
+特点:
+-
+
- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。 +
7.8 AdapterFusion
+一种融合多任务信息的Adapter的变体,在 Adapter +的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+7.9 AdapterDrop
+该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+特点:
+-
+
- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。 +当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。 +
7.10 LoRA
+该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+特点:
+-
+
- 将BA加到W上可以消除推理延迟。 +
- 可以通过可插拔的形式切换到不同的任务。 +
- 设计的比较好,简单且效果好。 +
7.11 AdaLoRA
+对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+7.12 QLoRA
+使用一种新颖的高精度技术将预训练模型量化为 4 +bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
+特点:
+-
+
- 使用 QLoRA +微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。 +
7.13 MAM Adapter
+一种在 Adapter、Prefix Tuning 和 LoRA +之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter +和 软提示的组合。
+特点:
+-
+
- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。 +
7.14 UniPELT
+一种将不同的PELT方法LoRA、Prefix +Tuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+特点:
+-
+
- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。 +
- 多种 PELT 方法的混合涉及PLM +的不同部分对模型有效性和鲁棒性都有好处 +
7.15 总结
+本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
+-
+
- 增加额外参数,如:Prefix Tuning、Prompt Tuning、Adapter +Tuning及其变体。 +
- 选取一部分参数更新,如:BitFit。 +
- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。 +
- 混合高效微调,如:MAM Adapter、UniPELT。 +
并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
+ + ++
Search
+ +20 posts in total
+21 posts in total
diff --git a/archives/2023/11/index.html b/archives/2023/11/index.html index 7842f5a..be3c6c6 100644 --- a/archives/2023/11/index.html +++ b/archives/2023/11/index.html @@ -202,7 +202,7 @@
20 posts in total
+21 posts in total
diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html index 092c79f..bcb7a34 100644 --- a/archives/2023/12/index.html +++ b/archives/2023/12/index.html @@ -202,7 +202,7 @@
20 posts in total
+21 posts in total
diff --git a/archives/2023/index.html b/archives/2023/index.html index 2dd443e..00a9f5f 100644 --- a/archives/2023/index.html +++ b/archives/2023/index.html @@ -202,7 +202,7 @@
20 posts in total
+21 posts in total
diff --git a/archives/2024/01/index.html b/archives/2024/01/index.html index 84e676d..9a09053 100644 --- a/archives/2024/01/index.html +++ b/archives/2024/01/index.html @@ -202,7 +202,7 @@
20 posts in total
+21 posts in total
diff --git a/archives/2024/02/index.html b/archives/2024/02/index.html index b9e819b..a800db7 100644 --- a/archives/2024/02/index.html +++ b/archives/2024/02/index.html @@ -202,7 +202,7 @@
20 posts in total
+21 posts in total
diff --git a/archives/2024/03/index.html b/archives/2024/03/index.html index 45df041..e6980a4 100644 --- a/archives/2024/03/index.html +++ b/archives/2024/03/index.html @@ -202,7 +202,7 @@
20 posts in total
+21 posts in total
@@ -210,15 +210,21 @@
2024
+ + +20 posts in total
+21 posts in total
@@ -210,15 +210,21 @@
2024
+ + +20 posts in total
+21 posts in total
@@ -210,6 +210,12 @@
2024
+ + +20 posts in total
+21 posts in total
@@ -210,15 +210,21 @@
2024
+ + +20 posts in total
+21 posts in total
@@ -210,6 +210,12 @@
2024
+ + +Search
+ +8 posts in total
+9 posts in total
@@ -210,15 +210,21 @@
2024
+ + ++ + + 【大语言模型】有监督微调 + +
+ + + +- 【深度学习】大语言模型简介 + 【大语言模型】基础模型概念
@@ -272,7 +335,7 @@
- 【深度学习】DeepL基础知识
+ 【深度学习】DeepL|LLM基础知识
@@ -769,72 +832,11 @@
- - - 【深度学习】图神经网络 - -
- - - -大语言模型微调
1. 大模型微调简介
1.1 微调方法定义
微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
下面是一般的微调步骤:
- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。
- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。
- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specifichead)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。
- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。
- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。
- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。
- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。
- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。
微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
1.2 为什么需要 PEFT
Parameter-EfficientFine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trainedlanguage models)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Softprompts)两个小类。
Scaling Down to Scale Up: A Guide to Parameter-EfficientFine-Tuning
1.3微调和参数高效微调之间的区别
微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
1.4 PEFT 有什么优点
在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本
- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。
- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。
- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。
- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。
1.5 多种不同的高效微调方法对比
参数有效策略可能涉及多种技术:
- 选择性层调整(Selective LayerTuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。
- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。
- 稀疏微调(SparseFine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。
- 低秩近似(Low-RankApproximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。
- 正则化技术(RegularizationTechniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。
- 任务特定的头(Task-specificHeads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。
1.6当前高效微调技术存在的一些问题
当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。Ladder-sideTuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。
- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。
- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。
- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用gitfork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。
1.7 PEFT技术实践
针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
- 明确指出参数数量类型。
- 使用不同大小的模型进行评估。
- 和类似方法进行比较。
- 标准化PEFT测量基准。
- 重视代码清晰度,以最小化进行实现。
2. 微调Fine-Tune
2.1 为什么SFT之后感觉LLM傻了?
在进行SupervisedFine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。
- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。
- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。
- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。
为了解决这些问题,可以尝试以下方法:
- 收集更多的训练数据,以增加数据的多样性和覆盖范围。
- 仔细检查微调数据集的标注,确保标签的准确性和一致性。
- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。
- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。
- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。
通过这些方法,可以尽量减少SupervisedFine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
2.2 SFT 指令微调数据 如何构建?
构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。
- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。
- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。
- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。
- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。
- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。
- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。
2.3 如何训练自己的大模型?
- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。
- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。
- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。
- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。
- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。
- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。
- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。
2.4 指令微调的好处?
指令微调(InstructionFine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。
- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。
- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。
- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。
- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。
请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
2.5 多轮对话任务微调调型
在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。
- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。
- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。
- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
- 初始化模型参数:将预训练模型的参数加载到模型中。
- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。
- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。
- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。
- 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。
- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。
需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
2.6 微调后的模型出现能力劣化
灾难性遗忘(CatastrophicForgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
在微调大语言模型时,灾难性遗忘可能出现的原因包括:
- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。
- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。
为了解决灾难性遗忘问题,可以尝试以下方法:
- 经验回放(ReplayBuffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。
- 弹性权重共享(Elastic WeightConsolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。
- 增量学习(IncrementalLearning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。
- 多任务学习(Multi-TaskLearning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。
综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
2.7 预训练和SFT操作有什么不同
大语言模型的预训练和有监督微调(SupervisedFine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
目标:
- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(MaskedLanguage Model,MLM)或下一句预测(Next SentencePrediction,NSP)等,来训练模型。
- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。
数据:
- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。
- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。
训练方式:
- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。
- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。
总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
2.8 大模型LLM进行SFT如何对样本进行优化?
对于大语言模型进行有监督微调(SupervisedFine-Tuning)时,可以采用以下几种方式对样本进行优化:
- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。
- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。
- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。
- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。
- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。
- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。
- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。
总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
3. 预训练
3.1 为什么要增量预训练?
预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
3.2进行增量预训练需要做哪些准备工作?
- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。
- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是TB 级别的。
- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。
3.3增量预训练训练流程是怎么样?
- 数据预处理:参考 LLaMA的预训练长度,也把数据处理成2048长度(如果不够,做补全)。
- 分词器:如果使用 LLaMA可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。
- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选Chat 模型。
- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。
- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。
- 模型测试:简单测试下续写能力,验证下模型是否正常。
4. Prompting工程
4.1 BitFit
4.1.1 背景
虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署,特别是随着任务数量的增加,很难维护。
理想状况下,我们希望有一种满足以下条件的高效微调方法:
- 到达能够匹配全量微调的效果。
- 仅更改一小部分模型参数。
- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。
- 改变的参数在不同下游任务中是一致的。
上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
4.1.2 技术原理
BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuningor Transformer-based MaskedLanguage-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
对于Transformer模型而言,冻结大部分 transformer-encoder参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言,只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
4.2 Prefix Tuning
4.2.1 背景
在PrefixTuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
基于上述两点,PrefixTuning提出固定预训练LM,为LM添加可训练,任务特定的前缀,这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的VirtualToken(Soft Prompt/ContinuousPrompt),相比离散的Token,更好优化,效果更好。
4.2.2 技术原理
Prefix Tuning(论文:Prefix-Tuning: Optimizing ContinuousPrompts forGeneration),在输入token之前构造一段任务相关的virtualtokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
针对不同的模型结构,需要构造不同的Prefix。
- 针对自回归架构模型:在句子前面添加前缀,得到
z = [PREFIX; x; y]
,合适的上文能够在固定 LM的情况下去引导生成下文(比如:GPT3的上下文学习)。 - 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder端增加前缀是为了引导后续token的生成。
该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为[PREFIX; x; y]
,Infix-tuning形式为[x; INFIX; y]
。
4.3 Prompt Tuning
4.3.1 背景
大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
基于此,作者提出了PromptTuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数,训练完以后,用同一个模型可以做多任务推理。
4.3.2 技术原理
Prompt Tuning(论文:The Power of Scale forParameter-Efficient Prompt Tuning),该方法可以看作是PrefixTuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompttokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
通过实验发现,随着预训练模型参数量的增加,PromptTuning的方法会逼近全参数微调的结果。
同时,Prompt Tuning 还提出了 PromptEnsembling,也就是在一个批次(Batch)里同时训练同一个任务的不同prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
4.4 P-Tuning
4.4.1 背景
该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(incontextlearning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtualtoken(同Prefix-Tuning类似)。
4.4.2 技术原理
P-Tuning(论文:GPT Understands,Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对PromptEmbedding进行一层处理。
相比Prefix Tuning,P-Tuning加入的可微的virtualtoken,但仅限于输入层,没有在每一层都加;另外,virtualtoken的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtualtoken。
经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtualtoken,容易优化到局部最优值,而这些virtualtoken理论是应该有相关关联的。因此,作者通过实验发现用一个promptencoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtualtoken以后,再输入到模型。
从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
4.5 P-Tuning v2
4.5.1 背景
之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
第一,缺乏模型参数规模和任务通用性。
- 缺乏规模通用性:PromptTuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。
- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些NLU基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。
第二,缺少深度提示优化,在PromptTuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
- 由于序列长度的限制,可调参数的数量是有限的。
- 输入embedding对模型预测只有相对间接的影响。
考虑到这些问题,作者提出了Ptuningv2,它利用深度提示优化(如:Prefix Tuning),对PromptTuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
4.5.2 技术原理
P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can BeComparable to Fine-tuning Universally Across Scales andTasks),该方法在每一层都加入了Promptstokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
- 更多可学习的参数(从P-tuning和PromptTuning的0.01%增加到0.1%-3%),同时也足够参数高效。
- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。
具体做法基本同Prefix Tuning,可以看作是将文本生成的PrefixTuning技术适配到NLU任务中,然后做了一些改进:
- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:PrefixTuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。
- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。
- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuningv2的有益补充。
- 回归传统的分类标签范式,而不是映射器。标签词映射器(LabelWordVerbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuningv2回归传统的CLS标签分类范式,采用随机初始化的分类头(ClassificationHead)应用于tokens之上,以增强通用性,可以适配到序列标注任务。
论文中展示了P-tuningv2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),PromptTuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuningv2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuningv2在RTE中的表现明显优于微调,特别是在BERT中。
5. Adapter-Tuning
5.1 Adapter Tuning
5.1.1 背景
预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题Adapter在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
5.1.2 技术原理
Adapter Tuning(论文:Parameter-Efficient Transfer LearningforNLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的==Adapter 结构和 Layer Norm层==进行微调,从而保证了训练的高效性。
每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
5.1.3 具体细节
每个 Adapter模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skipconnection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便Adapter 一开始的参数初始化接近0,Adapter也由于skipconnection的设置而接近于一个恒等映射,从而确保训练的有效性。
\[h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p}\]
通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
5.2 AdapterFusion
5.2.1 背景
为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequentialfine-tuning)或者多任务学习(multi-tasklearning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
而之前的工作,AdapterTuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter的参数某种程度上就表达了解决这个任务需要的知识。
作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
5.2.2 技术原理
Adapter Fusion(论文:AdapterFusion:Non-Destructive TaskComposition for TransferLearning),一种融合多任务信息的Adapter的变体,在Adapter的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。
- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。
对于第一阶段,有两种训练方式,分别如下:
- Single-TaskAdapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。
- Multi-TaskAdapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。
对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
5.2.3 AdapterFusion结构
AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
5.3 AdapterDrop
5.3.1 背景
近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
基于此,作者提出了AdapterDrop方法缓解该问题。
5.3.2 技术原理
AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters inTransformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。例如,将前五个Transformer层中的Adapter丢弃,在对 8个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop也能保持良好的结果。
除此之外,作者还研究了对AdapterFusion中的Adapter进行剪枝后的效果。
通过实验表明可以移除 AdapterFusion中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
总之,AdapterDrop通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
5.4 MAM Adapter
5.4.1 背景
近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,PrefixTuning和LoRA都是性能比较好的方法。
为什么看起来Adapter、PrefixTuning、LoRA(在结构上和公式上)都不太一样,尤其是PrefixTuning,但是这三种方法有近似的效果?
基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、PrefixTuning和LoRA)的设计,并提出了一种新方法MAMAdapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
首先,作者通过对Prefix Tuning变换,发现PrefixTuning和Adapters的公式高度相似。
然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、PrefixTuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体)Parallel Adapter、 Scaled PA的结构。
下表展示了高效微调方法Adapter、PrefixTuning、LoRA以及新变体在新增可训练参数结构形式(functionalform)、结构插入形式(Insertionform)、新增结构在PLM修改的具体位置(modifiedrepresentation)、新增结构与PLM的组合函数(compositionfunction)。其中,新增可训练参数结构形式为需要学习的部分(注:PrefixTuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
5.4.2 技术原理
MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENTTRANSFER LEARNING),一个在Adapter、PrefixTuning和LoRA之间建立联系的统一方法。
作者对Adapter的放置和软提示(softprompt)进行了详细的调查。得出如下结论:
- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。
- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。
然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用FFN 层的并行Adapter和软提示的组合。
通过最终的实验结果,可以看到 MAM Adapter在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
5.5 UniPELT
5.5.1 背景
近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
5.5.2 技术原理
UniPELT(论文: UNIPELT: A Unified Framework for Parameter-EfficientLanguage Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,PrefixTuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括LoRA 矩阵WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT的性能与这些方法相当或更好。
实验还对不同 PELT 方法训练时间和推理时间进行了分析。
- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围,
- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。
- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。
6. lora
6.1 LoRA
6.1.1 背景
神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsicrank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
6.1.2 技术原理
LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGEMODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsicrank)。
可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
\[h=W_{0} x+\Delta W x=W_{0} x+B A x\]
在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
此外,Transformer的权重矩阵包括Attention模块里用于计算query
,key
,value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整Wq 和 Wv 会产生最佳结果。
实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
6.2 AdaLoRA
6.2.1 背景
在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。
- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。
为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adaptertuning、Prefix tuning、PromptTuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adaptertuning引入了推理延时;Prefix tuning或Prompttuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。
- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diffpruning、LoRA等,此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diffpruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。LoRA则需要预先指定每个增量矩阵的本征秩 r相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。
基于以上问题进行总结:
- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。
- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。
为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
6.2.2 技术原理
AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FORPARAMETEREFFICIENTFINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。
\[W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q\]
- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。
通过实验证明,AdaLoRA实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。例如,当参数预算为 0.3M 时,AdaLoRA在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
6.3 QLoRA
6.3.1 背景
微调大型语言模型 (LLM)是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU内存。
虽然最近的量化方法可以减少 LLM的内存占用,但此类技术仅适用于推理场景。
基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为4 bit的模型。
6.3.2 技术原理
QLoRA(论文: QLORA: Efficient Finetuning of QuantizedLLMs),使用一种新颖的高精度技术将预训练模型量化为 4bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA有一种低精度存储数据类型(4bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bitNormalFloat(NF4)量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
- 4bitNormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比4 bit整数和 4bit 浮点数更好的实证结果。
- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。
- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的GPU 处理。该功能的工作方式类似于 CPU内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在GPU 内存不足时将其自动卸载到 CPU内存,并在优化器更新步骤需要时将其加载回 GPU 内存。
实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
7. 微调方法总结
7.1当前高效微调技术的简述
之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
7.2 BitFit
对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
特点:
- 训练参数量极小(约0.1%)。
- 在大部分任务上效果会差于LoRA、Adapter等方法。
7.3 Prefix Tuning
在每一个Transformer层都带上一些virtualtoken作为前缀,以适应不同的任务。
特点:
- 前缀Token会占用序列长度,有一定的额外计算开销。
- Prefix Tuning的线性插值是比较复杂的。
7.4 Prompt Tuning
该方法可以看着是PrefixTuning的简化版本,针对不同的任务,仅在输入层引入virtualtoken形式的软提示(soft prompt)。
特点:
- 相对于PrefixTuning,参与训练的参数量和改变的参数量更小,更节省显存。
- 对一些简单的NLU任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。
7.5 P-Tuning
将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对PromptEmbedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtualtoken;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
特点:
- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtualtoken的相互依赖会收敛更快,效果更好。
7.6 P-Tuning v2
该方法在每一个Transformer层都加入了prompttoken作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
特点:
- 解决了Prompt Tuning无法在小模型上有效提升的问题。
- 移除了对模型效果改进较小的重参数化的编码器(如:PrefixTuning中的MLP、P-Tuning中的LSTM)。
- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。
7.7 Adapter Tuning
该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和LayerNorm 层进行微调。
特点:
- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。
7.8 AdapterFusion
一种融合多任务信息的Adapter的变体,在 Adapter的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
7.9 AdapterDrop
该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
特点:
- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
7.10 LoRA
该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
特点:
- 将BA加到W上可以消除推理延迟。
- 可以通过可插拔的形式切换到不同的任务。
- 设计的比较好,简单且效果好。
7.11 AdaLoRA
对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
7.12 QLoRA
使用一种新颖的高精度技术将预训练模型量化为 4bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
特点:
- 使用 QLoRA微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。
7.13 MAM Adapter
一种在 Adapter、Prefix Tuning 和 LoRA之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter和 软提示的组合。
特点:
- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。
7.14 UniPELT
一种将不同的PELT方法LoRA、PrefixTuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
特点:
- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。
- 多种 PELT 方法的混合涉及PLM的不同部分对模型有效性和鲁棒性都有好处
7.15 总结
本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
- 增加额外参数,如:Prefix Tuning、Prompt Tuning、AdapterTuning及其变体。
- 选取一部分参数更新,如:BitFit。
- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。
- 混合高效微调,如:MAM Adapter、UniPELT。
并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
]]>大语言模型简介
1.llm概念
1.1 主流的开源模型体系
目前主流的开源LLM(语言模型)模型体系包括以下几个:
- GPT(Generative Pre-trainedTransformer)系列:由OpenAI发布的一系列基于Transformer架构的语言模型,包括GPT、GPT-2、GPT-3等。GPT模型通过在大规模无标签文本上进行预训练,然后在特定任务上进行微调,具有很强的生成能力和语言理解能力。
- BERT(Bidirectional Encoder Representations fromTransformers):由Google发布的一种基于Transformer架构的双向预训练语言模型。BERT模型通过在大规模无标签文本上进行预训练,然后在下游任务上进行微调,具有强大的语言理解能力和表征能力。
- XLNet:由CMU和GoogleBrain发布的一种基于Transformer架构的自回归预训练语言模型。XLNet模型通过自回归方式预训练,可以建模全局依赖关系,具有更好的语言建模能力和生成能力。
- RoBERTa:由Facebook发布的一种基于Transformer架构的预训练语言模型。RoBERTa模型在BERT的基础上进行了改进,通过更大规模的数据和更长的训练时间,取得了更好的性能。
- T5(Text-to-Text TransferTransformer):由Google发布的一种基于Transformer架构的多任务预训练语言模型。T5模型通过在大规模数据集上进行预训练,可以用于多种自然语言处理任务,如文本分类、机器翻译、问答等。
这些模型在自然语言处理领域取得了显著的成果,并被广泛应用于各种任务和应用中。
1.2 prefix LM 和 causal LM区别是什么?
Prefix LM(前缀语言模型)和CausalLM(因果语言模型)是两种不同类型的语言模型,它们的区别在于生成文本的方式和训练目标。
- PrefixLM:前缀语言模型是一种生成模型,它在生成每个词时都可以考虑之前的上下文信息。在生成时,前缀语言模型会根据给定的前缀(即部分文本序列)预测下一个可能的词。这种模型可以用于文本生成、机器翻译等任务。
- CausalLM:因果语言模型是一种自回归模型,它只能根据之前的文本生成后续的文本,而不能根据后续的文本生成之前的文本。在训练时,因果语言模型的目标是预测下一个词的概率,给定之前的所有词作为上下文。这种模型可以用于文本生成、语言建模等任务。
总结来说,前缀语言模型可以根据给定的前缀生成后续的文本,而因果语言模型只能根据之前的文本生成后续的文本。它们的训练目标和生成方式略有不同,适用于不同的任务和应用场景。
1.3 大模型LLM的训练目标
大型语言模型(Large LanguageModels,LLM)的训练目标通常是最大似然估计(Maximum LikelihoodEstimation,MLE)。最大似然估计是一种统计方法,用于从给定数据中估计概率模型的参数。
在LLM的训练过程中,使用的数据通常是大量的文本语料库。训练目标是最大化模型生成训练数据中观察到的文本序列的概率。具体来说,对于每个文本序列,模型根据前面的上下文生成下一个词的条件概率分布,并通过最大化生成的词序列的概率来优化模型参数。
为了最大化似然函数,可以使用梯度下降等优化算法来更新模型参数,使得模型生成的文本序列的概率逐步提高。在训练过程中,通常会使用批量训练(batchtraining)的方法,通过每次处理一小批数据样本来进行参数更新。
1.4 涌现能力是啥原因?
大语言模型的涌现能力:现象与解释- 知乎 (zhihu.com)
涌现能力(EmergentAbility)是指模型在训练过程中能够生成出令人惊喜、创造性和新颖的内容或行为。这种能力使得模型能够超出其训练数据所提供的内容,并产生出具有创造性和独特性的输出。
涌现能力的产生可以归因于以下几个原因:
- 任务的评价指标不够平滑:因为很多任务的评价指标不够平滑,导致我们现在看到的涌现现象。如果评价指标要求很严格,要求一字不错才算对,那么Emoji_movie任务我们就会看到涌现现象的出现。但是,如果我们把问题形式换成多选题,就是给出几个候选答案,让LLM选,那么随着模型不断增大,任务效果在持续稳定变好,但涌现现象消失,如上图图右所示。这说明评价指标不够平滑,起码是一部分任务看到涌现现象的原因。
- 复杂任务 vs子任务:展现出涌现现象的任务有一个共性,就是任务往往是由多个子任务构成的复杂任务。也就是说,最终任务过于复杂,如果仔细分析,可以看出它由多个子任务构成,这时候,子任务效果往往随着模型增大,符合Scaling Law,而最终任务则体现为涌现现象。
- 用 Grokking(顿悟)来解释涌现:对于某个任务T,尽管我们看到的预训练数据总量是巨大的,但是与T相关的训练数据其实数量很少。当我们推大模型规模的时候,往往会伴随着增加预训练数据的数据量操作,这样,当模型规模达到某个点的时候,与任务T相关的数据量,突然就达到了最小要求临界点,于是我们就看到了这个任务产生了Grokking现象。
尽管涌现能力为模型带来了创造性和独特性,但也需要注意其生成的内容可能存在偏差、错误或不完整性。因此,在应用和使用涌现能力强的模型时,需要谨慎评估和验证生成的输出,以确保其质量和准确性。
1.5为何现在的大模型大部分是Decoder only结构
- 自回归生成:Decoder-only结构适用于自回归生成任务,其中模型根据先前的输入生成下一个输出。这种结构在自然语言处理任务中非常有用,如文本生成、机器翻译和对话生成等。Decoder-only结构能够利用上下文信息来生成连续的输出序列,使得生成的结果更加准确和连贯。
- 生成多样性:Decoder-only结构可以通过在训练期间使用不同的解码策略来生成多样化的结果。例如,在生成文本时,可以使用不同的采样策略(如贪婪采样或随机采样)或温度参数来调整生成的多样性。这种能力对于一些任务(如对话生成)非常重要,因为它可以产生更加有趣和多样化的回复。
- 模型训练和推理的一致性:Decoder-only结构使得模型的训练和推理过程更加一致。在训练期间,模型可以使用教师强制(teacherforcing)策略,即将真实的目标输出作为输入传递给解码器。而在推理期间,模型可以逐步生成输出,将前一个时间步的输出作为输入传递给下一个时间步。这种一致性有助于更好地控制模型的生成过程,并提高模型的稳定性和可靠性。
1.6 大模型架构介绍
LLM(Large LanguageModel,大型语言模型)是指基于大规模数据和参数量的语言模型。具体的架构可以有多种选择,以下是一种常见的大模型LLM的架构介绍:
- Transformer架构:大模型LLM常使用Transformer架构,它是一种基于自注意力机制的序列模型。Transformer架构由多个编码器层和解码器层组成,每个层都包含多头自注意力机制和前馈神经网络。这种架构可以捕捉长距离的依赖关系和语言结构,适用于处理大规模语言数据。
- 自注意力机制(Self-Attention):自注意力机制是Transformer架构的核心组件之一。它允许模型在生成每个词时,根据输入序列中的其他词来计算该词的表示。自注意力机制能够动态地为每个词分配不同的权重,从而更好地捕捉上下文信息。
- 多头注意力(Multi-HeadAttention):多头注意力是自注意力机制的一种扩展形式。它将自注意力机制应用多次,每次使用不同的权重矩阵进行计算,得到多个注意力头。多头注意力可以提供更丰富的上下文表示,增强模型的表达能力。
- 前馈神经网络(Feed-ForwardNetwork):在Transformer架构中,每个注意力层后面都有一个前馈神经网络。前馈神经网络由两个全连接层组成,通过非线性激活函数(如ReLU)进行变换。它可以对注意力层输出的表示进行进一步的映射和调整。
- 预训练和微调:大模型LLM通常采用预训练和微调的方法进行训练。预训练阶段使用大规模无标签数据,通过自监督学习等方法进行训练,使模型学习到丰富的语言知识。微调阶段使用有标签的特定任务数据,如文本生成、机器翻译等,通过有监督学习进行模型的微调和优化。
需要注意的是,大模型LLM的具体架构可能会因不同的研究和应用而有所不同。上述介绍的是一种常见的架构,但实际应用中可能会有一些变体或改进。
1.7 LLMs复读机问题
1.7.1 什么是 LLMs 复读机问题?
LLMs复读机问题(LLMs ParrotingProblem)是指大型语言模型在生成文本时过度依赖输入文本的复制,而缺乏创造性和独特性。当面对一个问题或指令时,模型可能会简单地复制输入文本的一部分或全部内容,并将其作为生成的输出,而不是提供有意义或新颖的回应。
1.7.2 为什么会出现 LLMs复读机问题?
- 数据偏差:大型语言模型通常是通过预训练阶段使用大规模无标签数据进行训练的。如果训练数据中存在大量的重复文本或者某些特定的句子或短语出现频率较高,模型在生成文本时可能会倾向于复制这些常见的模式。
- 训练目标的限制:大型语言模型的训练通常是基于自监督学习的方法,通过预测下一个词或掩盖词来学习语言模型。这样的训练目标可能使得模型更倾向于生成与输入相似的文本,导致复读机问题的出现。
- 缺乏多样性的训练数据:虽然大型语言模型可以处理大规模的数据,但如果训练数据中缺乏多样性的语言表达和语境,模型可能无法学习到足够的多样性和创造性,导致复读机问题的出现。
- 模型结构和参数设置:大型语言模型的结构和参数设置也可能对复读机问题产生影响。例如,模型的注意力机制和生成策略可能导致模型更倾向于复制输入的文本。
1.7.3 如何缓解 LLMs 复读机问题?
为了缓解LLMs复读机问题,可以尝试以下方法:
- 多样性训练数据:在训练阶段,使用多样性的语料库来训练模型,避免数据偏差和重复文本的问题。这可以包括从不同领域、不同来源和不同风格的文本中获取数据。
- 引入噪声:在生成文本时,引入一些随机性或噪声,例如通过采样不同的词或短语,或者引入随机的变换操作,以增加生成文本的多样性。这可以通过在生成过程中对模型的输出进行采样或添加随机性来实现。
- 温度参数调整:温度参数是用来控制生成文本的多样性的一个参数。通过调整温度参数的值,可以控制生成文本的独创性和多样性。较高的温度值会增加随机性,从而减少复读机问题的出现。
- Beam搜索调整:在生成文本时,可以调整Beam搜索算法的参数。Beam搜索是一种常用的生成策略,它在生成过程中维护了一个候选序列的集合。通过调整Beam大小和搜索宽度,可以控制生成文本的多样性和创造性。
- 后处理和过滤:对生成的文本进行后处理和过滤,去除重复的句子或短语,以提高生成文本的质量和多样性。可以使用文本相似度计算方法或规则来检测和去除重复的文本。
- 人工干预和控制:对于关键任务或敏感场景,可以引入人工干预和控制机制,对生成的文本进行审查和筛选,确保生成结果的准确性和多样性。
需要注意的是,缓解LLMs复读机问题是一个复杂的任务,没有一种通用的解决方案。不同的方法可能适用于不同的场景和任务,需要根据具体情况进行选择和调整。此外,解决复读机问题还需要综合考虑数据、训练目标、模型架构和生成策略等多个因素,需要进一步的研究和实践来提高大型语言模型的生成文本多样性和创造性。
1.8LLMs输入句子长度理论上可以无限长吗?
理论上来说,LLMs(大型语言模型)可以处理任意长度的输入句子,但实际上存在一些限制和挑战。下面是一些相关的考虑因素:
- 计算资源:生成长句子需要更多的计算资源,包括内存和计算时间。由于LLMs通常是基于神经网络的模型,计算长句子可能会导致内存不足或计算时间过长的问题。
- 模型训练和推理:训练和推理长句子可能会面临一些挑战。在训练阶段,处理长句子可能会导致梯度消失或梯度爆炸的问题,影响模型的收敛性和训练效果。在推理阶段,生成长句子可能会增加模型的错误率和生成时间。
- 上下文建模:LLMs是基于上下文建模的模型,长句子的上下文可能会更加复杂和深层。模型需要能够捕捉长句子中的语义和语法结构,以生成准确和连贯的文本。
1.9如何让大模型处理更长的文本?
要让大模型处理更长的文本,可以考虑以下几个方法:
- 分块处理:将长文本分割成较短的片段,然后逐个片段输入模型进行处理。这样可以避免长文本对模型内存和计算资源的压力。在处理分块文本时,可以使用重叠的方式,即将相邻片段的一部分重叠,以保持上下文的连贯性。
- 层次建模:通过引入层次结构,将长文本划分为更小的单元。例如,可以将文本分为段落、句子或子句等层次,然后逐层输入模型进行处理。这样可以减少每个单元的长度,提高模型处理长文本的能力。
- 部分生成:如果只需要模型生成文本的一部分,而不是整个文本,可以只输入部分文本作为上下文,然后让模型生成所需的部分。例如,输入前一部分文本,让模型生成后续的内容。
- 注意力机制:注意力机制可以帮助模型关注输入中的重要部分,可以用于处理长文本时的上下文建模。通过引入注意力机制,模型可以更好地捕捉长文本中的关键信息。
- 模型结构优化:通过优化模型结构和参数设置,可以提高模型处理长文本的能力。例如,可以增加模型的层数或参数量,以增加模型的表达能力。还可以使用更高效的模型架构,如Transformer等,以提高长文本的处理效率。
需要注意的是,处理长文本时还需考虑计算资源和时间的限制。较长的文本可能需要更多的内存和计算时间,因此在实际应用中需要根据具体情况进行权衡和调整。
2.LLama系列模型
2.1LLama
2.1.1 简介
LLaMA 所采用的 Transformer 结构和细节,与标准的 Transformer架构不同的地方包括采用了前置层归一化(Pre-normalization)并使用RMSNorm 归一化函数 (NormalizingFunction)、激活函数更换为SwiGLU,并使用了旋转位置嵌入(RoP),整体Transformer 架构与 GPT-2 类似。
2.1.2 RMSNorm归一化函数
为了使得模型训练过程更加稳定,GPT-2 相较于 GPT就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了RMSNorm 归一化函数。 针对输入向量a,RMSNorm 函数计算公式如下
\[\bar{a}_{i}=\frac{a_{i}}{R M S(\boldsymbol{a})}\]
此外,RMSNorm 还可以引入可学习的缩放因子 $ g_ i $和偏移参数
1 |
|
为什么要用RMSNorm优势在哪里?
不用计算均值,直接算一次就能得到结果
2.1.3 SwiGLU激活函数
SwiGLU激活函数是相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA中全连接层使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-ForwardNetwork)的计算公式如下:
\[\operatorname{FFN}_{\text {SwiGLU }}\left(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V},\boldsymbol{W}_{2}\right)=\operatorname{SwiGLU}(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V}) \boldsymbol{W}_{2}\]
\[\operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W},\boldsymbol{V})=\operatorname{Swish}_{\beta}(x \boldsymbol{W}) \otimes\boldsymbol{x} \boldsymbol{V}\]
\[\operatorname{Swish}_{\beta}(\boldsymbol{x})=\boldsymbol{x}\sigma(\boldsymbol{\beta} \boldsymbol{x})\]
其中,\(σ(x)\) 是 Sigmoid函数。下图给出了 Swish 激活函数在参数
LLaMA中直接将FFN中的ReLU替换为SwiGLU,并将维度放缩为
2.1.4 旋转位置嵌入(RoPE)
在位置编码上,使用旋转位置嵌入(Rotary PositionalEmbeddings,RoPE)代替原有的绝对位置编码。RoPE借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给q
,k
添加绝对位置信息:
\[\tilde{\boldsymbol{q}}_{m}=f(\boldsymbol{q}, m),\tilde{\boldsymbol{k}}_{n}=f(\boldsymbol{k}, n)\]
经过上述操作后,
最终可以得到二维情况下用复数表示的 RoPE:
\[f(\boldsymbol{q}, m)=R_{f}(\boldsymbol{q}, m) e^{i\Theta_{f}(\boldsymbol{q}, m)}=\|\boldsymbol{q}\|e^{i(\Theta(\boldsymbol{q})+m \theta)}=\boldsymbol{q} e^{i m \theta}\]
根据复数乘法的几何意义,上述变换实际上是对应向量旋转,所以位置向量称为“旋转式位置编码”。还可以使用矩阵形式表示
\[f(\boldsymbol{q}, m)=\left(\begin{array}{cc}\cos m \theta & -\sin\cos m \theta \\ \sin m \theta & \cos m\theta\end{array}\right)\left(\begin{array}{l}\boldsymbol{q}_{0} \\\boldsymbol{q}_{1}\end{array}\right)\]
根据内积满足线性叠加的性质,任意偶数维的RoPE,都可以表示为二维情形的拼接,即:
\[f(\boldsymbol{q}, m)=\underbrace{\left(\begin{array}{ccccccc}\cos m\theta_{0} & -\sin m \theta_{0} & 0 & 0 & \cdots & 0& 0 \\ \sin m \theta_{0} & \cos m \theta_{0} & 0 & 0& \cdots & 0 & 0 \\ 0 & 0 & \cos m \theta_{1} &-\sin m \theta_{1} & \cdots & 0 & 0 \\ 0 & 0 & \sinm \theta_{1} & \cos m \theta_{1} & \cdots & 0 & 0 \\\cdots & \cdots & \cdots & \cdots & \ddots & \cdots& \cdots \\ 0 & 0 & 0 & 0 & \cdots & \cos m\theta_{d / 2-1} & -\sin m \theta_{d / 2-1} \\ 0 & 0 & 0& 0 & \cdots & \sin m \theta_{d / 2-1} & \cos m\theta_{d /2-1}\end{array}\right)}_{\boldsymbol{R}_{d}}\left(\begin{array}{c}\boldsymbol{q}_{0}\\ \boldsymbol{q}_{1} \\ \boldsymbol{q}_{2} \\ \boldsymbol{q}_{3} \\\cdots \\ \boldsymbol{q}_{d-2} \\ \boldsymbol{q}_{d-1}\end{array}\right)\]
RoPE 在 HuggingFace Transformer 库中代码实现如下所示:
1 |
|
1.2 Alpaca
1.2.1 简介
Stanford Alpaca: An Instruction-following LLaMA Model
Alpaca是在LLaMA基础上使用52K指令数据精调的预训练模型,作者只用了不到600美元的成本训练出了该模型(数据$500+ 机器$100)。初步实验结果表明Alpaca可以达到与OpenAItext-davinci-003相匹敌的效果
1.2.2 微调方法
- 第一步:构造175条self-instruct 种子示例任务
- 第二步:基于上述种子任务,利 用text-davinci-003爬取指令数据
- 第三步:使用爬取下来的52K指令 数据在LLaMA上进行精调,最终得到Alpaca
1.2.3 Self-instruct数据构造
首先由人工构造175条种子数据
1 |
|
将“爬取要求”和种子数据进行适当组合,送入textdavinci-003,要求生成类似的指令数据。要求包括:提升指令多样性、包含真实数据、字数要求、语言要求、拒绝不合适指令等
1.2.4 指令数据格式
instruction
: 描述模型需要执行的指令内容input
(可选):任务上下文或输入信息,例如当指令是“对文章进行总结”,则input是文章内容output
: 由text-davinci-003生成的针对指令的回复
1.3.Llama-2
1.3.1 简介
Llama 2: Open Foundation and Fine-Tuned Chat Models
2023年7月,Meta推出了Llama-2开源大模型,并且推出了Llama-2-Chat对话模型
与一代LLaMA主要区别体现在更多的训练数据、更⻓的上下文窗口、GQA技术等
二次分发是什么?
模型结构的变动主要是体现在GQA和FFN缩放上
- MHA改成GQA:整体参数量会有减少
- FFN模块矩阵维度有扩充:增强泛化能力,整体参数量增加
- 上下文长度是llama两倍(长度从2048->4096)训练语料增加约 40%,体现在1.4T->2.0T的Tokensllama2-34B和llama2-70B使用了GQA,加速模型训练和推理速度
1.3.2 GQA
GQA和MQA都是注意力的变体,其中多个查询头关注相同的键和值头,以减少推理过程中KV 缓存的大小,并可以显著提高推理吞吐量。
MHA、GQA、MQA的区别和联系,具体的优点如下:
Mutil-Head Attention
因为自回归模型生成回答时,需要前面生成的KV缓存起来,来加速计算。Multi-Query Attention
多个头之间可以共享KV对,因此速度上非常有优势,实验验证大约减少30-40%吞吐。Group Query Attention
没有像MQA那么极端,将query分组,组内共享KV,效果接近MQA,速度上与MQA可比较。
Llama-2中使用了8个KV映射,即GQA-8,GQA在多数任务上与MHA效果相当,且平均效果优于MQA;GQA和MQA均比MHA有更好的吞吐量
1.3.3 源码
2.ChatGLM
2.1 背景
主流的预训练框架主要有三种:
- autoregressive自回归模型(AR模型):代表作GPT。本质上是一个left-to-right的语言模型。通常用于生成式任务,在长文本生成方面取得了巨大的成功,比如自然语言生成(NLG)领域的任务:摘要、翻译或抽象问答。当扩展到十亿级别参数时,表现出了少样本学习能力。缺点是单向注意力机制,在NLU任务中,无法完全捕捉上下文的依赖关系。
- autoencoding自编码模型(AE模型):代表作BERT。是通过某个降噪目标(比如MLM)训练的双向文本编码器。编码器会产出适用于NLU任务的上下文表示,但无法直接用于文本生成。
- encoder-decoder(Seq2seq模型):代表作T5。采用双向注意力机制,通常用于条件生成任务,比如文本摘要、机器翻译等。
三种预训练框架各有利弊,没有一种框架在以下三种领域的表现最佳:自然语言理解(NLU)、无条件生成以及条件生成。T5曾经尝试使用MTL的方式统一上述框架,然而自编码和自回归目标天然存在差异,简单的融合自然无法继承各个框架的优点。
在这个天下三分的僵持局面下,GLM诞生了。
GLM模型基于autoregressive blankinfilling方法,结合了上述三种预训练模型的思想。
2.2 GLM预训练框架
GLM特点
- 自编码思想:在输入文本中,随机删除连续的tokens。
- 自回归思想:顺序重建连续tokens。在使用自回归方式预测缺失tokens时,模型既可以访问corrupted文本,又可以访问之前已经被预测的spans。
- span shuffling + 二维位置编码技术。
- 通过改变缺失spans的数量和长度,自回归空格填充目标可以为条件生成以及无条件生成任务预训练语言模型。
2.2.1 自回归空格填充任务
给定一个输入文本\(x=\left[x_{1}, \ldotsx_{n}\right]\),可以采样得到多个文本spans
\[\max _{\theta} \mathbb{E}_{\boldsymbol{z} \simZ_{m}}\left[\sum_{i=1}^{m} \log p_{\theta}\left(\boldsymbol{s}_{z_{i}}\mid \boldsymbol{x}_{\text {corrupt }},\boldsymbol{s}_{\boldsymbol{z}_{<i}}\right)\right]\]
GLM自回归空格填充任务的技术细节:
- 输入\(x\)可以被分成两部分:PartA是被mask的文本 \(x_{\text {corrupt}}\),Part B由masked spans组成。假设原始输入文本是
\([x1, x2, x3, x4, x5,x6]\),采样的两个文本片段是 \([x3]\)以及\([x5,x6]\)。那么mask后的文本序列是:\(x1,x2, [M], x4, [M]\),即Part A;同时我们需要对PartB的片段进行shuffle。每个片段使用 [S]
填充在开头作为输入,使用[E]
填充在末尾作为输出。 - 二维位置编码:Transformer使用位置编码来标记tokens中的绝对和相对位置。在GLM中,使用二维位置编码,第一个位置id用来标记PartA中的位置,第二个位置id用来表示跨度内部的相对位置。这两个位置id会通过embedding表被投影为两个向量,最终都会被加入到输入token的embedding表达中。
- 观察GLM中自定义attention mask的设计,非常巧妙:
- Part A中的tokens彼此可见,但是不可见B中的任意tokens。
- Part B tokens可见Part A。
- Part B tokens可见B中过去的tokens,不可见B中未来的tokens。
- 采样方式:文本片段的采样遵循泊松分布,重复采样,直到原始tokens中有15%被mask。
- 总结:模型可以自动学习双向encoder(Part A)以及单向decoder(PartB)。
2.2.2 多目标预训练
上述方法适合于NLU任务。作者希望可以训练一个既可以解决NLU任务,又具备文本生成能力的模型。因此除了空格填充目标之外,还需要增加一个生成长文本目标的任务。具体包含以下两个目标:
- 文档级别。从文档中采样一个文本片段进行mask,且片段长度为文档长度的50%~100%。这个目标用于长文本生成。
- 句子级别。限制被mask的片段必须是完整句子。多个片段需覆盖原始tokens的15%。这个目标是用于预测完整句子或者段落的seq2seq任务。
2.2.3 模型结构
GLM在原始single Transformer的基础上进行了一些修改:
- 重组了LN和残差连接的顺序;
- 使用单个线性层对输出token进行预测;
- 激活函数从ReLU换成了GeLUS。
但我觉得这部分的修改比较简单常见。核心和亮点还是空格填充任务的设计。
2.2.4 GLM微调
对于下游NLU任务来说,通常会将预训练模型产出的序列或tokens表达作为输入,使用线性分类器预测label。所以预训练与微调之间存在天然不一致。
作者按照PET的方式,将下游NLU任务重新表述为空白填充的生成任务。具体来说,比如给定一个已标注样本(x,y),将输入的文本x转换成一个包含masktoken的完形填空问题。比如,情感分类任务可以表述为:"{SENTENCE}. It’sreally [MASK]"。输出label y也同样会被映射到完形填空的答案中。“positive”和 “negative” 对应的标签就是“good” 和 “bad。
其实,预训练时,对较长的文本片段进行mask,以确保GLM的文本生成能力。但是在微调的时候,相当于将NLU任务也转换成了生成任务,这样其实是为了适应预训练的目标。但难免有一些牵强。
2.3 ChatGLM-2
2.3.1 主要创新
- 更长的上下文:基于
FlashAttention**技术,将基座模型的上下文长度(Context Length)由 ChatGLM-6B 的2K 扩展到了 32K**,并在对话阶段使用 8K的上下文长度训练。对于更长的上下文,发布了 ChatGLM2-6B-32K 模型。 LongBench的测评结果表明,在等量级的开源模型中,ChatGLM2-6B-32K有着较为明显的竞争优势。 - 更强大的性能:基于 ChatGLM初代模型的开发经验,全面升级了 ChatGLM2-6B 的基座模型。ChatGLM2-6B使用了 GLM** 的混合目标函数**,经过了 1.4T中英标识符的预训练与人类偏好对齐训练,
评测结果显示,相比于初代模型,ChatGLM2-6B 在MMLU(+23%)、CEval(+33%)、GSM8K(+571%)、BBH(+60%)等数据集上的性能取得了大幅度的提升,在同尺寸开源模型中具有较强的竞争力。 - 更高效的推理:基于
Multi-Query Attention技术,ChatGLM2-6B有更高效的推理速度和更低的显存占用:在官方的模型实现下,推理速度相比初代提升了42%,INT4 量化下,6G 显存支持的对话长度由 1K 提升到了 8K。 - 更开放的协议:ChatGLM2-6B权重对学术研究完全开放,在填写
问卷进行登记后亦允许免费商业使用。
2.3.2 与ChatGLM的变化
- 使用了RoPE替换二维位置编码。这也是GLM中提出的亮点设计之一。但是目前大部分主流的LLMs都在使用RoPE,所以大势所趋。当前版本仍然采用了最初的RoPE设计,事实上现在的RoPE经过了xPOS→线性内插→NTK-AwareScaled RoPE→…若干次进化。
- Multi-QueryAttention:这是一种共享机制的Attention,相比Multi-HeadAttention,其Query部分没有区别,Key和Value可以只用一个Head。计算时,对Key和Value进行expand或者repeat操作,使它们填充到与Query一样的维度,后续计算就与Multi-HeadAttention没区别。
- Attention Mask: V1的attention mask分了2部分,PartA和Part B,Part A部分是双向Attention(代码中的
prefix_attention_mask),PartB部分是CausalAttention(原代码文件中的get_masks函数)。在V2版本,全部换成了CausalAttention,不再区分是Part A还是PartB,完全变成了decoder-only的架构。 - 多目标任务:Chat版本主要还是用的gMask生成式任务,但是在V1版本的代码还能看到mask、gMask等字样,V2已经摒弃了这些特殊token,原因与AttentionMask一致,均因为变成了decoder-only的架构,不再需要区分Part A和PartB。
2.3.3 ChatGLM-3
省流:ChatGLM2与ChatGLM3模型架构是完全一致的,ChatGLM与后继者结构不同。可见ChatGLM3相对于ChatGLM2没有模型架构上的改进。
相对于ChatGLM,ChatGLM2、ChatGLM3模型上的变化:
- 词表的大小从ChatGLM的150528缩小为65024(一个直观的体验是ChatGLM2、3加载比ChatGLM快不少)
- 位置编码从每个GLMBlock一份提升为全局一份
- SelfAttention之后的前馈网络有不同。ChatGLM用GELU(GaussianError LinearUnit)做激活;ChatGLM用Swish-1做激活。而且ChatGLM2、3应该是修正了之前的一个bug,因为GLU(GatedLinearUnit)本质上一半的入参是用来做门控制的,不需要输出到下层,所以ChatGLM2、3看起来前后维度不一致(27392->13696)反而是正确的。
3.BERT
3.1BERT用字粒度和词粒度的优缺点有哪些?
BERT可以使用字粒度(character-level)和词粒度(word-level)两种方式来进行文本表示,它们各自有优缺点:
字粒度(Character-level):
- 优点:处理未登录词(Out-of-Vocabulary,OOV):字粒度可以处理任意字符串,包括未登录词,不需要像词粒度那样遇到未登录词就忽略或使用特殊标记。对于少见词和低频词,字粒度可以学习更丰富的字符级别表示,使得模型能够更好地捕捉词汇的细粒度信息。
- 缺点:计算复杂度高:使用字粒度会导致输入序列的长度大大增加,进而增加模型的计算复杂度和内存消耗。需要更多的训练数据:字粒度模型对于少见词和低频词需要更多的训练数据来学习有效的字符级别表示,否则可能会导致过拟合。
词粒度(Word-level):
- 优点:计算效率高:使用词粒度可以大大减少输入序列的长度,从而降低模型的计算复杂度和内存消耗。学习到更加稳定的词级别表示:词粒度模型可以学习到更加稳定的词级别表示,特别是对于高频词和常见词,有更好的表示能力。
- 缺点:处理未登录词(OOV):词粒度模型无法处理未登录词,遇到未登录词时需要采用特殊处理(如使用未登录词的特殊标记或直接忽略)。对于多音字等形态复杂的词汇,可能无法准确捕捉其细粒度的信息。
3.2BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
3.4为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?
BERT选择mask掉15%的词是一种经验性的选择,是原论文中的一种选择,并没有一个固定的理论依据,实际中当然可以尝试不同的比例,15%的比例是由BERT的作者在原始论文中提出,并在实验中发现对于BERT的训练效果是有效的
3.5为什么BERT在第一句前会加一个[CLS] 标志?
BERT在第一句前会加一个 [CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。为什么选它?因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。而[CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。
3.6 BERT非线性的来源在哪里?
主要来自两个地方:前馈层的gelu激活函数和self-attention。
前馈神经网络层:在BERT的Encoder中,每个自注意力层之后都跟着一个前馈神经网络层。前馈神经网络层是全连接的神经网络,通常包括一个线性变换和一个非线性的激活函数,如gelu。这样的非线性激活函数引入了非线性变换,使得模型能够学习更加复杂的特征表示。
self-attentionlayer:在自注意力层中,查询(Query)、键(Key)、值(Value)之间的点积得分会经过softmax操作,形成注意力权重,然后将这些权重与值向量相乘得到每个位置的自注意输出。这个过程中涉及了softmax操作,使得模型的计算是非线性的。
在BERT的训练中,使用了学习率warm-up策略,这是为了在训练的早期阶段增加学习率,以提高训练的稳定性和加快模型收敛。
学习率warm-up策略的具体做法是,在训练开始的若干个步骤(通常是一小部分训练数据的迭代次数)内,将学习率逐渐从一个较小的初始值增加到预定的最大学习率。在这个过程中,学习率的变化是线性的,即学习率在warm-up阶段的每个步骤按固定的步幅逐渐增加。学习率warm-up的目的是为了解决BERT在训练初期的两个问题:
- 不稳定性:在训练初期,由于模型参数的随机初始化以及模型的复杂性,模型可能处于一个较不稳定的状态。此时使用较大的学习率可能导致模型的参数变动太大,使得模型很难收敛,学习率warm-up可以在这个阶段将学习率保持较小,提高模型训练的稳定性。
- 避免过拟合:BERT模型往往需要较长的训练时间来获得高质量的表示。如果在训练的早期阶段就使用较大的学习率,可能会导致模型在训练初期就过度拟合训练数据,降低模型的泛化能力。通过学习率warm-up,在训练初期使用较小的学习率,可以避免过度拟合,等模型逐渐稳定后再使用较大的学习率进行更快的收敛。
3.8在BERT应用中,如何解决长文本问题?
在BERT应用中,处理长文本问题有以下几种常见的解决方案:
- 截断与填充:将长文本截断为固定长度或者进行填充。BERT模型的输入是一个固定长度的序列,因此当输入的文本长度超过模型的最大输入长度时,需要进行截断或者填充。通常,可以根据任务的要求,选择适当的最大长度,并对文本进行截断或者填充,使其满足模型输入的要求。
- SlidingWindow:将长文本分成多个短文本,然后分别输入BERT模型。这种方法被称为SlidingWindow技术。具体来说,将长文本按照固定的步长切分成多个片段,然后分别输入BERT模型进行处理。每个片段的输出可以进行进一步的汇总或者融合,得到最终的表示。
- HierarchicalModel:使用分层模型来处理长文本,其中底层模型用于处理短文本片段,然后将不同片段的表示进行汇总或者融合得到整个长文本的表示。这样的分层模型可以充分利用BERT模型的表示能力,同时处理长文本。
- Longformer、BigBird等模型:使用专门针对长文本的模型,如Longformer和BigBird。这些模型采用了不同的注意力机制,以处理超长序列,并且通常在处理长文本时具有更高的效率。
- Document-LevelModel:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
大语言模型简介
1.llm概念
1.1 主流的开源模型体系
目前主流的开源LLM(语言模型)模型体系包括以下几个:
- GPT(Generative Pre-trainedTransformer)系列:由OpenAI发布的一系列基于Transformer架构的语言模型,包括GPT、GPT-2、GPT-3等。GPT模型通过在大规模无标签文本上进行预训练,然后在特定任务上进行微调,具有很强的生成能力和语言理解能力。
- BERT(Bidirectional Encoder Representations fromTransformers):由Google发布的一种基于Transformer架构的双向预训练语言模型。BERT模型通过在大规模无标签文本上进行预训练,然后在下游任务上进行微调,具有强大的语言理解能力和表征能力。
- XLNet:由CMU和GoogleBrain发布的一种基于Transformer架构的自回归预训练语言模型。XLNet模型通过自回归方式预训练,可以建模全局依赖关系,具有更好的语言建模能力和生成能力。
- RoBERTa:由Facebook发布的一种基于Transformer架构的预训练语言模型。RoBERTa模型在BERT的基础上进行了改进,通过更大规模的数据和更长的训练时间,取得了更好的性能。
- T5(Text-to-Text TransferTransformer):由Google发布的一种基于Transformer架构的多任务预训练语言模型。T5模型通过在大规模数据集上进行预训练,可以用于多种自然语言处理任务,如文本分类、机器翻译、问答等。
这些模型在自然语言处理领域取得了显著的成果,并被广泛应用于各种任务和应用中。
1.2 prefix LM 和 causal LM区别是什么?
Prefix LM(前缀语言模型)和CausalLM(因果语言模型)是两种不同类型的语言模型,它们的区别在于生成文本的方式和训练目标。
- PrefixLM:前缀语言模型是一种生成模型,它在生成每个词时都可以考虑之前的上下文信息。在生成时,前缀语言模型会根据给定的前缀(即部分文本序列)预测下一个可能的词。这种模型可以用于文本生成、机器翻译等任务。
- CausalLM:因果语言模型是一种自回归模型,它只能根据之前的文本生成后续的文本,而不能根据后续的文本生成之前的文本。在训练时,因果语言模型的目标是预测下一个词的概率,给定之前的所有词作为上下文。这种模型可以用于文本生成、语言建模等任务。
总结来说,前缀语言模型可以根据给定的前缀生成后续的文本,而因果语言模型只能根据之前的文本生成后续的文本。它们的训练目标和生成方式略有不同,适用于不同的任务和应用场景。
1.3 大模型LLM的训练目标
大型语言模型(Large LanguageModels,LLM)的训练目标通常是最大似然估计(Maximum LikelihoodEstimation,MLE)。最大似然估计是一种统计方法,用于从给定数据中估计概率模型的参数。
在LLM的训练过程中,使用的数据通常是大量的文本语料库。训练目标是最大化模型生成训练数据中观察到的文本序列的概率。具体来说,对于每个文本序列,模型根据前面的上下文生成下一个词的条件概率分布,并通过最大化生成的词序列的概率来优化模型参数。
为了最大化似然函数,可以使用梯度下降等优化算法来更新模型参数,使得模型生成的文本序列的概率逐步提高。在训练过程中,通常会使用批量训练(batchtraining)的方法,通过每次处理一小批数据样本来进行参数更新。
1.4 涌现能力是啥原因?
大语言模型的涌现能力:现象与解释- 知乎 (zhihu.com)
涌现能力(EmergentAbility)是指模型在训练过程中能够生成出令人惊喜、创造性和新颖的内容或行为。这种能力使得模型能够超出其训练数据所提供的内容,并产生出具有创造性和独特性的输出。
涌现能力的产生可以归因于以下几个原因:
- 任务的评价指标不够平滑:因为很多任务的评价指标不够平滑,导致我们现在看到的涌现现象。如果评价指标要求很严格,要求一字不错才算对,那么Emoji_movie任务我们就会看到涌现现象的出现。但是,如果我们把问题形式换成多选题,就是给出几个候选答案,让LLM选,那么随着模型不断增大,任务效果在持续稳定变好,但涌现现象消失,如上图图右所示。这说明评价指标不够平滑,起码是一部分任务看到涌现现象的原因。
- 复杂任务 vs子任务:展现出涌现现象的任务有一个共性,就是任务往往是由多个子任务构成的复杂任务。也就是说,最终任务过于复杂,如果仔细分析,可以看出它由多个子任务构成,这时候,子任务效果往往随着模型增大,符合Scaling Law,而最终任务则体现为涌现现象。
- 用 Grokking(顿悟)来解释涌现:对于某个任务T,尽管我们看到的预训练数据总量是巨大的,但是与T相关的训练数据其实数量很少。当我们推大模型规模的时候,往往会伴随着增加预训练数据的数据量操作,这样,当模型规模达到某个点的时候,与任务T相关的数据量,突然就达到了最小要求临界点,于是我们就看到了这个任务产生了Grokking现象。
尽管涌现能力为模型带来了创造性和独特性,但也需要注意其生成的内容可能存在偏差、错误或不完整性。因此,在应用和使用涌现能力强的模型时,需要谨慎评估和验证生成的输出,以确保其质量和准确性。
1.5为何现在的大模型大部分是Decoder only结构
- 自回归生成:Decoder-only结构适用于自回归生成任务,其中模型根据先前的输入生成下一个输出。这种结构在自然语言处理任务中非常有用,如文本生成、机器翻译和对话生成等。Decoder-only结构能够利用上下文信息来生成连续的输出序列,使得生成的结果更加准确和连贯。
- 生成多样性:Decoder-only结构可以通过在训练期间使用不同的解码策略来生成多样化的结果。例如,在生成文本时,可以使用不同的采样策略(如贪婪采样或随机采样)或温度参数来调整生成的多样性。这种能力对于一些任务(如对话生成)非常重要,因为它可以产生更加有趣和多样化的回复。
- 模型训练和推理的一致性:Decoder-only结构使得模型的训练和推理过程更加一致。在训练期间,模型可以使用教师强制(teacherforcing)策略,即将真实的目标输出作为输入传递给解码器。而在推理期间,模型可以逐步生成输出,将前一个时间步的输出作为输入传递给下一个时间步。这种一致性有助于更好地控制模型的生成过程,并提高模型的稳定性和可靠性。
1.6 大模型架构介绍
LLM(Large LanguageModel,大型语言模型)是指基于大规模数据和参数量的语言模型。具体的架构可以有多种选择,以下是一种常见的大模型LLM的架构介绍:
- Transformer架构:大模型LLM常使用Transformer架构,它是一种基于自注意力机制的序列模型。Transformer架构由多个编码器层和解码器层组成,每个层都包含多头自注意力机制和前馈神经网络。这种架构可以捕捉长距离的依赖关系和语言结构,适用于处理大规模语言数据。
- 自注意力机制(Self-Attention):自注意力机制是Transformer架构的核心组件之一。它允许模型在生成每个词时,根据输入序列中的其他词来计算该词的表示。自注意力机制能够动态地为每个词分配不同的权重,从而更好地捕捉上下文信息。
- 多头注意力(Multi-HeadAttention):多头注意力是自注意力机制的一种扩展形式。它将自注意力机制应用多次,每次使用不同的权重矩阵进行计算,得到多个注意力头。多头注意力可以提供更丰富的上下文表示,增强模型的表达能力。
- 前馈神经网络(Feed-ForwardNetwork):在Transformer架构中,每个注意力层后面都有一个前馈神经网络。前馈神经网络由两个全连接层组成,通过非线性激活函数(如ReLU)进行变换。它可以对注意力层输出的表示进行进一步的映射和调整。
- 预训练和微调:大模型LLM通常采用预训练和微调的方法进行训练。预训练阶段使用大规模无标签数据,通过自监督学习等方法进行训练,使模型学习到丰富的语言知识。微调阶段使用有标签的特定任务数据,如文本生成、机器翻译等,通过有监督学习进行模型的微调和优化。
需要注意的是,大模型LLM的具体架构可能会因不同的研究和应用而有所不同。上述介绍的是一种常见的架构,但实际应用中可能会有一些变体或改进。
1.7 LLMs复读机问题
1.7.1 什么是 LLMs 复读机问题?
LLMs复读机问题(LLMs ParrotingProblem)是指大型语言模型在生成文本时过度依赖输入文本的复制,而缺乏创造性和独特性。当面对一个问题或指令时,模型可能会简单地复制输入文本的一部分或全部内容,并将其作为生成的输出,而不是提供有意义或新颖的回应。
1.7.2 为什么会出现 LLMs复读机问题?
- 数据偏差:大型语言模型通常是通过预训练阶段使用大规模无标签数据进行训练的。如果训练数据中存在大量的重复文本或者某些特定的句子或短语出现频率较高,模型在生成文本时可能会倾向于复制这些常见的模式。
- 训练目标的限制:大型语言模型的训练通常是基于自监督学习的方法,通过预测下一个词或掩盖词来学习语言模型。这样的训练目标可能使得模型更倾向于生成与输入相似的文本,导致复读机问题的出现。
- 缺乏多样性的训练数据:虽然大型语言模型可以处理大规模的数据,但如果训练数据中缺乏多样性的语言表达和语境,模型可能无法学习到足够的多样性和创造性,导致复读机问题的出现。
- 模型结构和参数设置:大型语言模型的结构和参数设置也可能对复读机问题产生影响。例如,模型的注意力机制和生成策略可能导致模型更倾向于复制输入的文本。
1.7.3 如何缓解 LLMs 复读机问题?
为了缓解LLMs复读机问题,可以尝试以下方法:
- 多样性训练数据:在训练阶段,使用多样性的语料库来训练模型,避免数据偏差和重复文本的问题。这可以包括从不同领域、不同来源和不同风格的文本中获取数据。
- 引入噪声:在生成文本时,引入一些随机性或噪声,例如通过采样不同的词或短语,或者引入随机的变换操作,以增加生成文本的多样性。这可以通过在生成过程中对模型的输出进行采样或添加随机性来实现。
- 温度参数调整:温度参数是用来控制生成文本的多样性的一个参数。通过调整温度参数的值,可以控制生成文本的独创性和多样性。较高的温度值会增加随机性,从而减少复读机问题的出现。
- Beam搜索调整:在生成文本时,可以调整Beam搜索算法的参数。Beam搜索是一种常用的生成策略,它在生成过程中维护了一个候选序列的集合。通过调整Beam大小和搜索宽度,可以控制生成文本的多样性和创造性。
- 后处理和过滤:对生成的文本进行后处理和过滤,去除重复的句子或短语,以提高生成文本的质量和多样性。可以使用文本相似度计算方法或规则来检测和去除重复的文本。
- 人工干预和控制:对于关键任务或敏感场景,可以引入人工干预和控制机制,对生成的文本进行审查和筛选,确保生成结果的准确性和多样性。
需要注意的是,缓解LLMs复读机问题是一个复杂的任务,没有一种通用的解决方案。不同的方法可能适用于不同的场景和任务,需要根据具体情况进行选择和调整。此外,解决复读机问题还需要综合考虑数据、训练目标、模型架构和生成策略等多个因素,需要进一步的研究和实践来提高大型语言模型的生成文本多样性和创造性。
1.8LLMs输入句子长度理论上可以无限长吗?
理论上来说,LLMs(大型语言模型)可以处理任意长度的输入句子,但实际上存在一些限制和挑战。下面是一些相关的考虑因素:
- 计算资源:生成长句子需要更多的计算资源,包括内存和计算时间。由于LLMs通常是基于神经网络的模型,计算长句子可能会导致内存不足或计算时间过长的问题。
- 模型训练和推理:训练和推理长句子可能会面临一些挑战。在训练阶段,处理长句子可能会导致梯度消失或梯度爆炸的问题,影响模型的收敛性和训练效果。在推理阶段,生成长句子可能会增加模型的错误率和生成时间。
- 上下文建模:LLMs是基于上下文建模的模型,长句子的上下文可能会更加复杂和深层。模型需要能够捕捉长句子中的语义和语法结构,以生成准确和连贯的文本。
1.9如何让大模型处理更长的文本?
要让大模型处理更长的文本,可以考虑以下几个方法:
- 分块处理:将长文本分割成较短的片段,然后逐个片段输入模型进行处理。这样可以避免长文本对模型内存和计算资源的压力。在处理分块文本时,可以使用重叠的方式,即将相邻片段的一部分重叠,以保持上下文的连贯性。
- 层次建模:通过引入层次结构,将长文本划分为更小的单元。例如,可以将文本分为段落、句子或子句等层次,然后逐层输入模型进行处理。这样可以减少每个单元的长度,提高模型处理长文本的能力。
- 部分生成:如果只需要模型生成文本的一部分,而不是整个文本,可以只输入部分文本作为上下文,然后让模型生成所需的部分。例如,输入前一部分文本,让模型生成后续的内容。
- 注意力机制:注意力机制可以帮助模型关注输入中的重要部分,可以用于处理长文本时的上下文建模。通过引入注意力机制,模型可以更好地捕捉长文本中的关键信息。
- 模型结构优化:通过优化模型结构和参数设置,可以提高模型处理长文本的能力。例如,可以增加模型的层数或参数量,以增加模型的表达能力。还可以使用更高效的模型架构,如Transformer等,以提高长文本的处理效率。
需要注意的是,处理长文本时还需考虑计算资源和时间的限制。较长的文本可能需要更多的内存和计算时间,因此在实际应用中需要根据具体情况进行权衡和调整。
2.LLama系列模型
2.1LLama
2.1.1 简介
LLaMA 所采用的 Transformer 结构和细节,与标准的 Transformer架构不同的地方包括采用了前置层归一化(Pre-normalization)并使用RMSNorm 归一化函数 (NormalizingFunction)、激活函数更换为SwiGLU,并使用了旋转位置嵌入(RoP),整体Transformer 架构与 GPT-2 类似。
2.1.2 RMSNorm归一化函数
为了使得模型训练过程更加稳定,GPT-2 相较于 GPT就引入了前置层归一化方法,将第一个层归一化移动到多头自注意力层之前,第二个层归一化也移动到了全连接层之前,同时残差连接的位置也调整到了多头自注意力层与全连接层之后。层归一化中也采用了RMSNorm 归一化函数。 针对输入向量a,RMSNorm 函数计算公式如下
\[\bar{a}_{i}=\frac{a_{i}}{R M S(\boldsymbol{a})}\]
此外,RMSNorm 还可以引入可学习的缩放因子 $ g_ i $和偏移参数
1 |
|
为什么要用RMSNorm优势在哪里?
不用计算均值,直接算一次就能得到结果
2.1.3 SwiGLU激活函数
SwiGLU激活函数是相较于 ReLU 函数在大部分评测中都有不少提升。在 LLaMA中全连接层使用带有 SwiGLU 激活函数的 FFN(Position-wise Feed-ForwardNetwork)的计算公式如下:
\[\operatorname{FFN}_{\text {SwiGLU }}\left(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V},\boldsymbol{W}_{2}\right)=\operatorname{SwiGLU}(\boldsymbol{x},\boldsymbol{W}, \boldsymbol{V}) \boldsymbol{W}_{2}\]
\[\operatorname{SwiGLU}(\boldsymbol{x}, \boldsymbol{W},\boldsymbol{V})=\operatorname{Swish}_{\beta}(x \boldsymbol{W}) \otimes\boldsymbol{x} \boldsymbol{V}\]
\[\operatorname{Swish}_{\beta}(\boldsymbol{x})=\boldsymbol{x}\sigma(\boldsymbol{\beta} \boldsymbol{x})\]
其中,\(σ(x)\) 是 Sigmoid函数。下图给出了 Swish 激活函数在参数
LLaMA中直接将FFN中的ReLU替换为SwiGLU,并将维度放缩为
2.1.4 旋转位置嵌入(RoPE)
在位置编码上,使用旋转位置嵌入(Rotary PositionalEmbeddings,RoPE)代替原有的绝对位置编码。RoPE借助了复数的思想,出发点是通过绝对位置编码的方式实现相对位置编码。其目标是通过下述运算来给q
,k
添加绝对位置信息:
\[\tilde{\boldsymbol{q}}_{m}=f(\boldsymbol{q}, m),\tilde{\boldsymbol{k}}_{n}=f(\boldsymbol{k}, n)\]
经过上述操作后,
最终可以得到二维情况下用复数表示的 RoPE:
\[f(\boldsymbol{q}, m)=R_{f}(\boldsymbol{q}, m) e^{i\Theta_{f}(\boldsymbol{q}, m)}=\|\boldsymbol{q}\|e^{i(\Theta(\boldsymbol{q})+m \theta)}=\boldsymbol{q} e^{i m \theta}\]
根据复数乘法的几何意义,上述变换实际上是对应向量旋转,所以位置向量称为“旋转式位置编码”。还可以使用矩阵形式表示
\[f(\boldsymbol{q}, m)=\left(\begin{array}{cc}\cos m \theta & -\sin\cos m \theta \\ \sin m \theta & \cos m\theta\end{array}\right)\left(\begin{array}{l}\boldsymbol{q}_{0} \\\boldsymbol{q}_{1}\end{array}\right)\]
根据内积满足线性叠加的性质,任意偶数维的RoPE,都可以表示为二维情形的拼接,即:
\[f(\boldsymbol{q}, m)=\underbrace{\left(\begin{array}{ccccccc}\cos m\theta_{0} & -\sin m \theta_{0} & 0 & 0 & \cdots & 0& 0 \\ \sin m \theta_{0} & \cos m \theta_{0} & 0 & 0& \cdots & 0 & 0 \\ 0 & 0 & \cos m \theta_{1} &-\sin m \theta_{1} & \cdots & 0 & 0 \\ 0 & 0 & \sinm \theta_{1} & \cos m \theta_{1} & \cdots & 0 & 0 \\\cdots & \cdots & \cdots & \cdots & \ddots & \cdots& \cdots \\ 0 & 0 & 0 & 0 & \cdots & \cos m\theta_{d / 2-1} & -\sin m \theta_{d / 2-1} \\ 0 & 0 & 0& 0 & \cdots & \sin m \theta_{d / 2-1} & \cos m\theta_{d /2-1}\end{array}\right)}_{\boldsymbol{R}_{d}}\left(\begin{array}{c}\boldsymbol{q}_{0}\\ \boldsymbol{q}_{1} \\ \boldsymbol{q}_{2} \\ \boldsymbol{q}_{3} \\\cdots \\ \boldsymbol{q}_{d-2} \\ \boldsymbol{q}_{d-1}\end{array}\right)\]
RoPE 在 HuggingFace Transformer 库中代码实现如下所示:
1 |
|
1.2 Alpaca
1.2.1 简介
Stanford Alpaca: An Instruction-following LLaMA Model
Alpaca是在LLaMA基础上使用52K指令数据精调的预训练模型,作者只用了不到600美元的成本训练出了该模型(数据$500+ 机器$100)。初步实验结果表明Alpaca可以达到与OpenAItext-davinci-003相匹敌的效果
1.2.2 微调方法
- 第一步:构造175条self-instruct 种子示例任务
- 第二步:基于上述种子任务,利 用text-davinci-003爬取指令数据
- 第三步:使用爬取下来的52K指令 数据在LLaMA上进行精调,最终得到Alpaca
1.2.3 Self-instruct数据构造
首先由人工构造175条种子数据
1 |
|
将“爬取要求”和种子数据进行适当组合,送入textdavinci-003,要求生成类似的指令数据。要求包括:提升指令多样性、包含真实数据、字数要求、语言要求、拒绝不合适指令等
1.2.4 指令数据格式
instruction
: 描述模型需要执行的指令内容input
(可选):任务上下文或输入信息,例如当指令是“对文章进行总结”,则input是文章内容output
: 由text-davinci-003生成的针对指令的回复
1.3.Llama-2
1.3.1 简介
Llama 2: Open Foundation and Fine-Tuned Chat Models
2023年7月,Meta推出了Llama-2开源大模型,并且推出了Llama-2-Chat对话模型
与一代LLaMA主要区别体现在更多的训练数据、更⻓的上下文窗口、GQA技术等
二次分发是什么?
模型结构的变动主要是体现在GQA和FFN缩放上
- MHA改成GQA:整体参数量会有减少
- FFN模块矩阵维度有扩充:增强泛化能力,整体参数量增加
- 上下文长度是llama两倍(长度从2048->4096)训练语料增加约 40%,体现在1.4T->2.0T的Tokensllama2-34B和llama2-70B使用了GQA,加速模型训练和推理速度
1.3.2 GQA
GQA和MQA都是注意力的变体,其中多个查询头关注相同的键和值头,以减少推理过程中KV 缓存的大小,并可以显著提高推理吞吐量。
MHA、GQA、MQA的区别和联系,具体的优点如下:
Mutil-Head Attention
因为自回归模型生成回答时,需要前面生成的KV缓存起来,来加速计算。Multi-Query Attention
多个头之间可以共享KV对,因此速度上非常有优势,实验验证大约减少30-40%吞吐。Group Query Attention
没有像MQA那么极端,将query分组,组内共享KV,效果接近MQA,速度上与MQA可比较。
Llama-2中使用了8个KV映射,即GQA-8,GQA在多数任务上与MHA效果相当,且平均效果优于MQA;GQA和MQA均比MHA有更好的吞吐量
1.3.3 源码
2.ChatGLM
2.1 背景
主流的预训练框架主要有三种:
- autoregressive自回归模型(AR模型):代表作GPT。本质上是一个left-to-right的语言模型。通常用于生成式任务,在长文本生成方面取得了巨大的成功,比如自然语言生成(NLG)领域的任务:摘要、翻译或抽象问答。当扩展到十亿级别参数时,表现出了少样本学习能力。缺点是单向注意力机制,在NLU任务中,无法完全捕捉上下文的依赖关系。
- autoencoding自编码模型(AE模型):代表作BERT。是通过某个降噪目标(比如MLM)训练的双向文本编码器。编码器会产出适用于NLU任务的上下文表示,但无法直接用于文本生成。
- encoder-decoder(Seq2seq模型):代表作T5。采用双向注意力机制,通常用于条件生成任务,比如文本摘要、机器翻译等。
三种预训练框架各有利弊,没有一种框架在以下三种领域的表现最佳:自然语言理解(NLU)、无条件生成以及条件生成。T5曾经尝试使用MTL的方式统一上述框架,然而自编码和自回归目标天然存在差异,简单的融合自然无法继承各个框架的优点。
在这个天下三分的僵持局面下,GLM诞生了。
GLM模型基于autoregressive blankinfilling方法,结合了上述三种预训练模型的思想。
2.2 GLM预训练框架
GLM特点
- 自编码思想:在输入文本中,随机删除连续的tokens。
- 自回归思想:顺序重建连续tokens。在使用自回归方式预测缺失tokens时,模型既可以访问corrupted文本,又可以访问之前已经被预测的spans。
- span shuffling + 二维位置编码技术。
- 通过改变缺失spans的数量和长度,自回归空格填充目标可以为条件生成以及无条件生成任务预训练语言模型。
2.2.1 自回归空格填充任务
给定一个输入文本\(x=\left[x_{1}, \ldotsx_{n}\right]\),可以采样得到多个文本spans
\[\max _{\theta} \mathbb{E}_{\boldsymbol{z} \simZ_{m}}\left[\sum_{i=1}^{m} \log p_{\theta}\left(\boldsymbol{s}_{z_{i}}\mid \boldsymbol{x}_{\text {corrupt }},\boldsymbol{s}_{\boldsymbol{z}_{<i}}\right)\right]\]
GLM自回归空格填充任务的技术细节:
- 输入\(x\)可以被分成两部分:PartA是被mask的文本 \(x_{\text {corrupt}}\),Part B由masked spans组成。假设原始输入文本是
\([x1, x2, x3, x4, x5,x6]\),采样的两个文本片段是 \([x3]\)以及\([x5,x6]\)。那么mask后的文本序列是:\(x1,x2, [M], x4, [M]\),即Part A;同时我们需要对PartB的片段进行shuffle。每个片段使用 [S]
填充在开头作为输入,使用[E]
填充在末尾作为输出。 - 二维位置编码:Transformer使用位置编码来标记tokens中的绝对和相对位置。在GLM中,使用二维位置编码,第一个位置id用来标记PartA中的位置,第二个位置id用来表示跨度内部的相对位置。这两个位置id会通过embedding表被投影为两个向量,最终都会被加入到输入token的embedding表达中。
- 观察GLM中自定义attention mask的设计,非常巧妙:
- Part A中的tokens彼此可见,但是不可见B中的任意tokens。
- Part B tokens可见Part A。
- Part B tokens可见B中过去的tokens,不可见B中未来的tokens。
- 采样方式:文本片段的采样遵循泊松分布,重复采样,直到原始tokens中有15%被mask。
- 总结:模型可以自动学习双向encoder(Part A)以及单向decoder(PartB)。
2.2.2 多目标预训练
上述方法适合于NLU任务。作者希望可以训练一个既可以解决NLU任务,又具备文本生成能力的模型。因此除了空格填充目标之外,还需要增加一个生成长文本目标的任务。具体包含以下两个目标:
- 文档级别。从文档中采样一个文本片段进行mask,且片段长度为文档长度的50%~100%。这个目标用于长文本生成。
- 句子级别。限制被mask的片段必须是完整句子。多个片段需覆盖原始tokens的15%。这个目标是用于预测完整句子或者段落的seq2seq任务。
2.2.3 模型结构
GLM在原始single Transformer的基础上进行了一些修改:
- 重组了LN和残差连接的顺序;
- 使用单个线性层对输出token进行预测;
- 激活函数从ReLU换成了GeLUS。
但我觉得这部分的修改比较简单常见。核心和亮点还是空格填充任务的设计。
2.2.4 GLM微调
对于下游NLU任务来说,通常会将预训练模型产出的序列或tokens表达作为输入,使用线性分类器预测label。所以预训练与微调之间存在天然不一致。
作者按照PET的方式,将下游NLU任务重新表述为空白填充的生成任务。具体来说,比如给定一个已标注样本(x,y),将输入的文本x转换成一个包含masktoken的完形填空问题。比如,情感分类任务可以表述为:"{SENTENCE}. It’sreally [MASK]"。输出label y也同样会被映射到完形填空的答案中。“positive”和 “negative” 对应的标签就是“good” 和 “bad。
其实,预训练时,对较长的文本片段进行mask,以确保GLM的文本生成能力。但是在微调的时候,相当于将NLU任务也转换成了生成任务,这样其实是为了适应预训练的目标。但难免有一些牵强。
2.3 ChatGLM-2
2.3.1 主要创新
- 更长的上下文:基于
FlashAttention**技术,将基座模型的上下文长度(Context Length)由 ChatGLM-6B 的2K 扩展到了 32K**,并在对话阶段使用 8K的上下文长度训练。对于更长的上下文,发布了 ChatGLM2-6B-32K 模型。 LongBench的测评结果表明,在等量级的开源模型中,ChatGLM2-6B-32K有着较为明显的竞争优势。 - 更强大的性能:基于 ChatGLM初代模型的开发经验,全面升级了 ChatGLM2-6B 的基座模型。ChatGLM2-6B使用了 GLM** 的混合目标函数**,经过了 1.4T中英标识符的预训练与人类偏好对齐训练,
评测结果显示,相比于初代模型,ChatGLM2-6B 在MMLU(+23%)、CEval(+33%)、GSM8K(+571%)、BBH(+60%)等数据集上的性能取得了大幅度的提升,在同尺寸开源模型中具有较强的竞争力。 - 更高效的推理:基于
Multi-Query Attention技术,ChatGLM2-6B有更高效的推理速度和更低的显存占用:在官方的模型实现下,推理速度相比初代提升了42%,INT4 量化下,6G 显存支持的对话长度由 1K 提升到了 8K。 - 更开放的协议:ChatGLM2-6B权重对学术研究完全开放,在填写
问卷进行登记后亦允许免费商业使用。
2.3.2 与ChatGLM的变化
- 使用了RoPE替换二维位置编码。这也是GLM中提出的亮点设计之一。但是目前大部分主流的LLMs都在使用RoPE,所以大势所趋。当前版本仍然采用了最初的RoPE设计,事实上现在的RoPE经过了xPOS→线性内插→NTK-AwareScaled RoPE→…若干次进化。
- Multi-QueryAttention:这是一种共享机制的Attention,相比Multi-HeadAttention,其Query部分没有区别,Key和Value可以只用一个Head。计算时,对Key和Value进行expand或者repeat操作,使它们填充到与Query一样的维度,后续计算就与Multi-HeadAttention没区别。
- Attention Mask: V1的attention mask分了2部分,PartA和Part B,Part A部分是双向Attention(代码中的
prefix_attention_mask),PartB部分是CausalAttention(原代码文件中的get_masks函数)。在V2版本,全部换成了CausalAttention,不再区分是Part A还是PartB,完全变成了decoder-only的架构。 - 多目标任务:Chat版本主要还是用的gMask生成式任务,但是在V1版本的代码还能看到mask、gMask等字样,V2已经摒弃了这些特殊token,原因与AttentionMask一致,均因为变成了decoder-only的架构,不再需要区分Part A和PartB。
2.3.3 ChatGLM-3
省流:ChatGLM2与ChatGLM3模型架构是完全一致的,ChatGLM与后继者结构不同。可见ChatGLM3相对于ChatGLM2没有模型架构上的改进。
相对于ChatGLM,ChatGLM2、ChatGLM3模型上的变化:
- 词表的大小从ChatGLM的150528缩小为65024(一个直观的体验是ChatGLM2、3加载比ChatGLM快不少)
- 位置编码从每个GLMBlock一份提升为全局一份
- SelfAttention之后的前馈网络有不同。ChatGLM用GELU(GaussianError LinearUnit)做激活;ChatGLM用Swish-1做激活。而且ChatGLM2、3应该是修正了之前的一个bug,因为GLU(GatedLinearUnit)本质上一半的入参是用来做门控制的,不需要输出到下层,所以ChatGLM2、3看起来前后维度不一致(27392->13696)反而是正确的。
3.BERT
3.1BERT用字粒度和词粒度的优缺点有哪些?
BERT可以使用字粒度(character-level)和词粒度(word-level)两种方式来进行文本表示,它们各自有优缺点:
字粒度(Character-level):
- 优点:处理未登录词(Out-of-Vocabulary,OOV):字粒度可以处理任意字符串,包括未登录词,不需要像词粒度那样遇到未登录词就忽略或使用特殊标记。对于少见词和低频词,字粒度可以学习更丰富的字符级别表示,使得模型能够更好地捕捉词汇的细粒度信息。
- 缺点:计算复杂度高:使用字粒度会导致输入序列的长度大大增加,进而增加模型的计算复杂度和内存消耗。需要更多的训练数据:字粒度模型对于少见词和低频词需要更多的训练数据来学习有效的字符级别表示,否则可能会导致过拟合。
词粒度(Word-level):
- 优点:计算效率高:使用词粒度可以大大减少输入序列的长度,从而降低模型的计算复杂度和内存消耗。学习到更加稳定的词级别表示:词粒度模型可以学习到更加稳定的词级别表示,特别是对于高频词和常见词,有更好的表示能力。
- 缺点:处理未登录词(OOV):词粒度模型无法处理未登录词,遇到未登录词时需要采用特殊处理(如使用未登录词的特殊标记或直接忽略)。对于多音字等形态复杂的词汇,可能无法准确捕捉其细粒度的信息。
3.2BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
3.3BERT用的是transformer里面的encoder还是decoder?
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
3.4为什么BERT选择mask掉15%这个比例的词,可以是其他的比例吗?
BERT选择mask掉15%的词是一种经验性的选择,是原论文中的一种选择,并没有一个固定的理论依据,实际中当然可以尝试不同的比例,15%的比例是由BERT的作者在原始论文中提出,并在实验中发现对于BERT的训练效果是有效的
3.5为什么BERT在第一句前会加一个[CLS] 标志?
BERT在第一句前会加一个 [CLS]标志,最后一层该位对应向量可以作为整句话的语义表示,从而用于下游的分类任务等。为什么选它?因为与文本中已有的其它词相比,这个无明显语义信息的符号会更“公平”地融合文本中各个词的语义信息,从而更好的表示整句话的语义。
具体来说,self-attention是用文本中的其它词来增强目标词的语义表示,但是目标词本身的语义还是会占主要部分的,因此,经过BERT的12层,每次词的embedding融合了所有词的信息,可以去更好的表示自己的语义。而[CLS]位本身没有语义,经过12层,得到的是attention后所有词的加权平均,相比其他正常词,可以更好的表征句子语义。
3.6 BERT非线性的来源在哪里?
主要来自两个地方:前馈层的gelu激活函数和self-attention。
前馈神经网络层:在BERT的Encoder中,每个自注意力层之后都跟着一个前馈神经网络层。前馈神经网络层是全连接的神经网络,通常包括一个线性变换和一个非线性的激活函数,如gelu。这样的非线性激活函数引入了非线性变换,使得模型能够学习更加复杂的特征表示。
self-attentionlayer:在自注意力层中,查询(Query)、键(Key)、值(Value)之间的点积得分会经过softmax操作,形成注意力权重,然后将这些权重与值向量相乘得到每个位置的自注意输出。这个过程中涉及了softmax操作,使得模型的计算是非线性的。
在BERT的训练中,使用了学习率warm-up策略,这是为了在训练的早期阶段增加学习率,以提高训练的稳定性和加快模型收敛。
学习率warm-up策略的具体做法是,在训练开始的若干个步骤(通常是一小部分训练数据的迭代次数)内,将学习率逐渐从一个较小的初始值增加到预定的最大学习率。在这个过程中,学习率的变化是线性的,即学习率在warm-up阶段的每个步骤按固定的步幅逐渐增加。学习率warm-up的目的是为了解决BERT在训练初期的两个问题:
- 不稳定性:在训练初期,由于模型参数的随机初始化以及模型的复杂性,模型可能处于一个较不稳定的状态。此时使用较大的学习率可能导致模型的参数变动太大,使得模型很难收敛,学习率warm-up可以在这个阶段将学习率保持较小,提高模型训练的稳定性。
- 避免过拟合:BERT模型往往需要较长的训练时间来获得高质量的表示。如果在训练的早期阶段就使用较大的学习率,可能会导致模型在训练初期就过度拟合训练数据,降低模型的泛化能力。通过学习率warm-up,在训练初期使用较小的学习率,可以避免过度拟合,等模型逐渐稳定后再使用较大的学习率进行更快的收敛。
3.8在BERT应用中,如何解决长文本问题?
在BERT应用中,处理长文本问题有以下几种常见的解决方案:
- 截断与填充:将长文本截断为固定长度或者进行填充。BERT模型的输入是一个固定长度的序列,因此当输入的文本长度超过模型的最大输入长度时,需要进行截断或者填充。通常,可以根据任务的要求,选择适当的最大长度,并对文本进行截断或者填充,使其满足模型输入的要求。
- SlidingWindow:将长文本分成多个短文本,然后分别输入BERT模型。这种方法被称为SlidingWindow技术。具体来说,将长文本按照固定的步长切分成多个片段,然后分别输入BERT模型进行处理。每个片段的输出可以进行进一步的汇总或者融合,得到最终的表示。
- HierarchicalModel:使用分层模型来处理长文本,其中底层模型用于处理短文本片段,然后将不同片段的表示进行汇总或者融合得到整个长文本的表示。这样的分层模型可以充分利用BERT模型的表示能力,同时处理长文本。
- Longformer、BigBird等模型:使用专门针对长文本的模型,如Longformer和BigBird。这些模型采用了不同的注意力机制,以处理超长序列,并且通常在处理长文本时具有更高的效率。
- Document-LevelModel:将文本看作是一个整体,而不是将其拆分成句子或段落,然后输入BERT模型进行处理。这样的文档级模型可以更好地捕捉整个文档的上下文信息,但需要更多的计算资源。
+ + + 【深度学习】图神经网络 + +
+ + + +- - - 【自动驾驶】RSS Model for Autonomous Driving - -
- - - -Search
+ +深度学习&LLM基础
@@ -9010,7 +9010,7 @@ alt="进制转换的示意图" />大语言模型简介
@@ -9498,8 +9498,8 @@ BERT用字粒度和词粒度的优缺点有哪些?3.2 BERT的Encoder与Decoder掩码有什么区别?
Encoder主要使用自注意力掩码和填充掩码,而Decoder除了自注意力掩码外,还需要使用编码器-解码器注意力掩码来避免未来位置信息的泄露。这些掩码操作保证了Transformer在处理自然语言序列时能够准确、有效地进行计算,从而获得更好的表现。
-3.3BERT用的是transformer里面的encoder还是decoder?
+3.3 +BERT用的是transformer里面的encoder还是decoder?
BERT使用的是Transformer中的Encoder部分,而不是Decoder部分。
Transformer模型由Encoder和Decoder两个部分组成。Encoder用于将输入序列编码为一系列高级表示,而Decoder用于基于这些表示生成输出序列。
在BERT模型中,只使用了Transformer的Encoder部分,并且对其进行了一些修改和自定义的预训练任务,而没有使用Transformer的Decoder部分。
@@ -9542,6 +9542,826 @@ Model:使用分层模型来处理长文本,其中底层模型用于大语言模型微调
+1. 大模型微调简介
+1.1 微调方法定义
+微调(Fine-tuning)是一种迁移学习的方法,用于在一个预训练模型的基础上,通过在特定任务的数据上进行有监督训练,来适应该任务的要求并提高模型性能。微调利用了预训练模型在大规模通用数据上学习到的语言知识和表示能力,将其迁移到特定任务上。
+下面是一般的微调步骤:
+-
+
- 预训练模型选择:选择一个在大规模数据上进行预训练的模型作为基础模型。例如,可以选择一种预训练的语言模型,如BERT、GPT等。 +
- 数据准备:准备用于微调的特定任务数据集。这些数据集应包含任务相关的样本和相应的标签或目标。确保数据集与任务的特定领域或问题相关。 +
- 构建任务特定的模型头:根据任务的要求,构建一个特定的模型头(task-specific +head)。模型头是添加到预训练模型之上的额外层或结构,用于根据任务要求进行输出预测或分类。例如,对于文本分类任务,可以添加一个全连接层和softmax激活函数。 +
- 参数初始化:将预训练模型的参数作为初始参数加载到微调模型中。这些参数可以被视为模型已经学习到的通用语言表示。 +
- 微调训练:使用特定任务的数据集对模型进行有监督训练。这包括将任务数据输入到模型中,计算损失函数,并通过反向传播和优化算法(如梯度下降)更新模型参数。在微调过程中,只有模型头的参数会被更新,而预训练模型的参数会保持不变。 +
- 调整超参数:微调过程中,可以根据需要调整学习率、批量大小、训练迭代次数等超参数,以达到更好的性能。 +
- 评估和验证:在微调完成后,使用验证集或测试集对微调模型进行评估,以评估其在特定任务上的性能。可以使用各种指标,如准确率、精确率、召回率等。 +
- 可选的后续微调:根据实际情况,可以选择在特定任务的数据上进行进一步的微调迭代,以进一步提高模型性能。 +
微调的关键是在预训练模型的基础上进行训练,从而将模型的知识迁移到特定任务上。通过这种方式,可以在较少的数据和计算资源下,快速构建和训练高性能的模型。
+1.2 为什么需要 PEFT
+Parameter-Efficient +Fine-Tuning(PEFT)是一种微调策略,旨在仅训练少量参数使模型适应到下游任务。对大规模PLM(pre-trained +language models +)进行微调的成本往往高得令人望而却步。在这方面,PEFT方法只微调了少量(额外的)模型参数,从而大大降低了计算和存储成本。最近最先进的PEFT技术实现了与完全微调相当的性能。
+PEFT通过冻结预训练模型的某些层,并仅微调特定于下游任务的最后几层来实现这种效率。这样,模型就可以适应新的任务,计算开销更少,标记的例子也更少。尽管PEFT是一个相对较新的概念,但自从引入迁移学习以来,更新最后一层模型已经在计算机视觉领域得到了实践。即使在NLP中,静态和非静态词嵌入的实验也很早就进行了。
+参数高效微调旨在提高预训练模型(如BERT和RoBERTa)在各种下游任务上的性能,包括情感分析、命名实体识别和问答。它在数据和计算资源有限的低资源设置中实现了这一点。它只修改模型参数的一小部分,并且不容易过度拟合。
+参数高效的微调在计算资源有限或涉及大型预训练模型的情况下特别有用。在这种情况下,PEFT可以在不牺牲性能的情况下提供一种更有效的方法来微调模型。然而,需要注意的是,PEFT有时可能会达到与完全微调不同的性能水平,特别是在预训练模型需要进行重大修改才能在新任务上表现良好的情况下。
+高效微调技术可以粗略分为以下三大类:增加额外参数(A)、选取一部分参数更新(S)、引入重参数化(R)。而在增加额外参数这类方法中,又主要分为类适配器(Adapter-like)方法和软提示(Soft +prompts)两个小类。
+ +++Scaling Down to Scale Up: A Guide to Parameter-Efficient +Fine-Tuning
+
1.3 +微调和参数高效微调之间的区别
+微调和参数高效微调是机器学习中用于提高预训练模型在特定任务上的性能的两种方法。
+微调就是把一个预先训练好的模型用新的数据在一个新的任务上进一步训练它。整个预训练模型通常在微调中进行训练,包括它的所有层和参数。这个过程在计算上非常昂贵且耗时,特别是对于大型模型。
+另一方面,参数高效微调是一种专注于只训练预训练模型参数的子集的微调方法。这种方法包括为新任务识别最重要的参数,并且只在训练期间更新这些参数。这样,PEFT可以显著减少微调所需的计算量。
+1.4 PEFT 有什么优点
+在这里,只讨论PEFT相对于传统微调的好处。因此,理解为什么参数有效的微调比微调更有益。
+-
+
- 减少计算和存储成本:PEFT只涉及微调少量额外的模型参数,而冻结预训练llm的大部分参数,从而显着降低计算和存储成本 +
- 克服灾难性遗忘:在LLM的全面微调期间,灾难性遗忘可能发生在模型忘记它在预训练期间学到的知识的地方。PEFT通过只更新几个参数来克服这个问题。 +
- 低数据环境下更好的性能:PEFT方法在低数据环境下的表现优于完全微调,并且可以更好地推广到域外场景。 +
- 可移植性:与全面微调的大检查点相比,PEFT方法使用户能够获得价值几mb的小检查点。这使得来自PEFT方法的训练权重易于部署和用于多个任务,而无需替换整个模型。 +
- 与完全微调相当的性能:PEFT仅使用少量可训练参数即可实现与完全微调相当的性能。 +
1.5 多种不同的高效微调方法对比
+参数有效策略可能涉及多种技术:
+-
+
- 选择性层调整(Selective Layer +Tuning):可以只微调层的一个子集,而不是微调模型的所有层。这减少了需要更新的参数数量。 +
- 适配器(Adapters):适配器层是插入预训练模型层之间的小型神经网络。在微调过程中,只训练这些适配器层,保持预先训练的参数冻结。通过这种方式,适配器学习将预先训练的模型提取的特征适应新任务。 +
- 稀疏微调(Sparse +Fine-Tuning):传统的微调会略微调整所有参数,但稀疏微调只涉及更改模型参数的一个子集。这通常是基于一些标准来完成的,这些标准标识了与新任务最相关的参数。 +
- 低秩近似(Low-Rank +Approximations):另一种策略是用一个参数较少但在任务中表现相似的模型来近似微调后的模型。 +
- 正则化技术(Regularization +Techniques):可以将正则化项添加到损失函数中,以阻止参数发生较大变化,从而以更“参数高效”的方式有效地微调模型。 +
- 任务特定的头(Task-specific +Heads):有时,在预先训练的模型架构中添加一个任务特定的层或“头”,只对这个头进行微调,从而减少需要学习的参数数量。 +
1.6 +当前高效微调技术存在的一些问题
+当前的高效微调技术很难在类似方法之间进行直接比较并评估它们的真实性能,主要的原因如下所示:
+-
+
- 参数计算口径不一致:参数计算可以分为三类:可训练参数的数量、微调模型与原始模型相比改变的参数的数量、微调模型和原始模型之间差异的等级。例如,DiffPruning更新0.5%的参数,但是实际参与训练的参数量是200%。这为比较带来了困难。尽管可训练的参数量是最可靠的存储高效指标,但是也不完美。 +Ladder-side +Tuning使用一个单独的小网络,参数量高于LoRA或BitFit,但是因为反向传播不经过主网络,其消耗的内存反而更小。 +
- 缺乏模型大小的考虑:已有工作表明,大模型在微调中需要更新的参数量更小(无论是以百分比相对而论还是以绝对数量而论),因此(基)模型大小在比较不同PEFT方法时也要考虑到。 +
- 缺乏测量基准和评价标准:不同方法所使用的的模型/数据集组合都不一样,评价指标也不一样,难以得到有意义的结论。 +
- 代码实现可读性差:很多开源代码都是简单拷贝Transformer代码库,然后进行小修小补。这些拷贝也不使用git +fork,难以找出改了哪里。即便是能找到,可复用性也比较差(通常指定某个Transformer版本,没有说明如何脱离已有代码库复用这些方法)。 +
1.7 PEFT技术实践
+针对以上存在的问题,研究高效微调技术时,建议按照最佳实践进行实施:
+-
+
- 明确指出参数数量类型。 +
- 使用不同大小的模型进行评估。 +
- 和类似方法进行比较。 +
- 标准化PEFT测量基准。 +
- 重视代码清晰度,以最小化进行实现。 +
2. 微调Fine-Tune
+2.1 为什么SFT之后感觉LLM傻了?
+在进行Supervised +Fine-Tuning(SFT)之后,有时可能会观察到基座模型(如语言模型)的性能下降或产生一些“傻”的行为。这可能是由于以下原因:
+-
+
- 数据偏移:SFT过程中使用的微调数据集可能与基座模型在预训练阶段接触到的数据分布有所不同。如果微调数据集与预训练数据集之间存在显著的差异,模型可能会在新任务上表现较差。这种数据偏移可能导致模型在新任务上出现错误的预测或不准确的输出。 +
- 非典型标注:微调数据集的标注可能存在错误或不准确的标签。这些错误的标签可能会对模型的性能产生负面影响,导致模型产生“傻”的行为。 +
- 过拟合:如果微调数据集相对较小,或者模型的容量(参数数量)较大,模型可能会过拟合微调数据,导致在新的输入上表现不佳。过拟合可能导致模型过于依赖微调数据的特定样本,而无法泛化到更广泛的输入。 +
- 缺乏多样性:微调数据集可能缺乏多样性,未能涵盖模型在新任务上可能遇到的各种输入情况。这可能导致模型在面对新的、与微调数据集不同的输入时出现困惑或错误的预测。 +
为了解决这些问题,可以尝试以下方法:
+-
+
- 收集更多的训练数据,以增加数据的多样性和覆盖范围。 +
- 仔细检查微调数据集的标注,确保标签的准确性和一致性。 +
- 使用正则化技术(如权重衰减、dropout)来减少过拟合的风险。 +
- 进行数据增强,通过对微调数据进行一些变换或扩充来增加多样性。 +
- 使用更复杂的模型架构或调整模型的超参数,以提高模型的性能和泛化能力。 +
通过这些方法,可以尽量减少Supervised +Fine-Tuning之后模型出现“傻”的情况,并提高模型在新任务上的表现。
+2.2 SFT 指令微调数据 如何构建?
+构建Supervised Fine-Tuning(SFT)的微调数据需要以下步骤:
+-
+
- 收集原始数据:首先,您需要收集与目标任务相关的原始数据。这可以是对话数据、分类数据、生成任务数据等,具体取决于您的任务类型。确保数据集具有代表性和多样性,以提高模型的泛化能力。 +
- 标注数据:对原始数据进行标注,为每个样本提供正确的标签或目标输出。标签的类型取决于您的任务,可以是分类标签、生成文本、对话回复等。确保标注的准确性和一致性。 +
- 划分数据集:将标注数据划分为训练集、验证集和测试集。通常,大部分数据用于训练,一小部分用于验证模型的性能和调整超参数,最后一部分用于最终评估模型的泛化能力。 +
- 数据预处理:根据任务的要求,对数据进行预处理。这可能包括文本清洗、分词、去除停用词、词干化等处理步骤。确保数据格式和特征表示适合模型的输入要求。 +
- 格式转换:将数据转换为适合模型训练的格式。这可能涉及将数据转换为文本文件、JSON格式或其他适合模型输入的格式。 +
- 模型微调:使用转换后的数据对基座模型进行微调。根据任务的要求,选择适当的微调方法和超参数进行训练。这可以使用常见的深度学习框架(如PyTorch、TensorFlow)来实现。 +
- 模型评估:使用测试集对微调后的模型进行评估,计算模型在任务上的性能指标,如准确率、召回率、生成质量等。根据评估结果对模型进行进一步的优化和调整。 +
2.3 如何训练自己的大模型?
+-
+
- 数据收集和准备:首先,需要收集与目标任务和领域相关的大规模数据集。这可以包括从互联网上爬取数据、使用公开数据集或者与合作伙伴合作获取数据。然后,对数据进行预处理和清洗,包括去除噪声、处理缺失值、标准化数据等。 +
- 模型设计和架构选择:根据任务的特点和目标,选择适合的模型架构。可以基于已有的模型进行修改和调整,或者设计全新的模型。常见的大模型架构包括深度神经网络(如卷积神经网络、循环神经网络、Transformer等)和预训练语言模型(如BERT、GPT等)。 +
- 数据划分和预处理:将数据集划分为训练集、验证集和测试集。训练集用于模型的训练,验证集用于调整超参数和模型选择,测试集用于最终评估模型的性能。进行数据预处理,如分词、编码、标记化、特征提取等,以便输入到模型中。 +
- 模型训练:使用训练集对模型进行训练。训练过程中,需要选择合适的优化算法、损失函数和学习率等超参数,并进行适当的调整和优化。可以使用GPU或者分布式训练来加速训练过程。 +
- 模型调优和验证:使用验证集对训练过程中的模型进行调优和验证。根据验证集的性能指标,调整模型的超参数、网络结构或者其他相关参数,以提升模型的性能。 +
- 模型评估和测试:使用测试集对最终训练好的模型进行评估和测试。计算模型的性能指标,如准确率、召回率、F1值等,评估模型的性能和泛化能力。 +
- 模型部署和优化:将训练好的模型部署到实际应用中。根据实际需求,对模型进行进一步的优化和调整,以提高模型的效率和性能。 +
2.4 指令微调的好处?
+指令微调(Instruction +Fine-Tuning)是一种在预训练模型上进行微调的方法,其中模型接收指令或约束来生成特定的输出。指令微调具有以下几个好处:
+-
+
- 控制生成输出:指令微调使得模型能够根据指定的指令或约束生成特定的输出。这对于需要精确控制模型生成结果的任务非常有用,例如自然语言生成任务中的文本摘要、翻译或对话系统。 +
- 可解释性和可控性:通过指令微调,可以将任务的要求以指令的形式传达给模型。这增加了模型的可解释性和可控性,使得用户能够更好地理解和干预模型的生成过程。 +
- 避免不符合要求的输出:通过指令微调,可以避免模型生成不符合任务要求或偏离期望的输出。通过明确的指令或约束,模型能够更好地遵循任务的要求,并生成符合期望的结果。 +
- 提高任务性能:指令微调可以针对具体任务进行优化,使得模型在该任务上的性能得到提升。通过引入任务特定的指令或约束,模型可以更好地适应特定任务的需求,并生成更准确、更合理的输出。 +
- 灵活性和可扩展性:指令微调是一种灵活且可扩展的方法,允许在不同任务和场景中进行微调。通过调整和修改指令或约束,可以适应不同的任务需求,并在多个任务上进行微调。 +
请注意,指令微调需要提供明确的指令或约束,并对模型进行适当的调整和微调。在实践中,需要根据具体任务和应用场景来决定是否采用指令微调以及如何设计和实施指令。
+2.5 多轮对话任务微调调型
+在多轮对话任务中,微调模型的目标是使其能够更好地理解和生成连续的对话内容,并具备上下文理解和一致性回复的能力。下面是一种常见的微调模型的方法:
+-
+
- 数据准备:收集或创建适用于多轮对话任务的数据集,包括对话文本和相应的标签或回复。确保数据集中包含上下文信息和对话的连续性。 +
- 构建输入输出格式:将对话数据转换为适合模型输入的格式。通常情况下,输入可以是包含多个对话轮次的上下文文本,输出可以是下一轮对话的回复或标签。 +
- 模型选择:选择适合多轮对话任务的预训练模型,如DialoGPT、BERT等。这些模型已经在大规模对话数据上进行了预训练,并具备一定的对话理解和生成能力。 +
- 微调模型:使用多轮对话数据集对预训练模型进行微调。微调的过程通常包括以下步骤:
+
-
+
- 初始化模型参数:将预训练模型的参数加载到模型中。 +
- 定义损失函数:根据任务要求,定义适当的损失函数,如交叉熵损失函数或生成模型中的对抗损失函数。 +
- 进行反向传播和参数更新:根据损失函数,通过反向传播算法计算梯度,并更新模型参数。 +
- 重复训练步骤:重复进行微调步骤,直到模型在验证集上达到满意的性能。 +
+ - 超参数调优:根据任务需求和数据情况,调整微调过程中的超参数,如学习率、批大小、微调步数等。可以使用验证集来评估模型性能并选择最佳的超参数配置。 +
- 评估和测试:使用测试集对微调后的模型进行评估和测试,评估模型在多轮对话任务上的性能和表现。 +
需要注意的是,微调多轮对话模型时,除了常规的微调方法,还可以采用一些特定的技巧,如引入对话历史的注意力机制、使用特定的对话策略进行训练等,以进一步提升模型在多轮对话任务中的性能。
+2.6 微调后的模型出现能力劣化
+灾难性遗忘(Catastrophic +Forgetting)是指在模型微调过程中,当模型在新任务上进行训练时,可能会忘记之前学习到的知识,导致在旧任务上的性能下降。这种现象常见于神经网络模型的迁移学习或连续学习场景中。
+在微调大语言模型时,灾难性遗忘可能出现的原因包括:
+-
+
- 数据分布差异:微调过程中使用的新任务数据与预训练数据或旧任务数据的分布存在差异。如果新任务的数据分布与预训练数据差异较大,模型可能会过度调整以适应新任务,导致旧任务上的性能下降。 +
- 参数更新冲突:微调过程中,对新任务进行训练时,模型参数可能会被更新,导致之前学习到的知识被覆盖或丢失。新任务的梯度更新可能会与旧任务的梯度更新发生冲突,导致旧任务的知识被遗忘。 +
为了解决灾难性遗忘问题,可以尝试以下方法:
+-
+
- 经验回放(Replay +Buffer):在微调过程中,使用一个缓冲区来存储旧任务的样本,然后将旧任务的样本与新任务的样本一起用于训练。这样可以保留旧任务的知识,减少灾难性遗忘的发生。 +
- 弹性权重共享(Elastic Weight +Consolidation):通过引入正则化项,限制模型参数的变动范围,以保护之前学习到的知识。这种方法可以在微调过程中平衡新任务和旧任务之间的重要性。 +
- 增量学习(Incremental +Learning):将微调过程分为多个阶段,每个阶段只微调一小部分参数。这样可以逐步引入新任务,减少参数更新的冲突,降低灾难性遗忘的风险。 +
- 多任务学习(Multi-Task +Learning):在微调过程中,同时训练多个相关任务,以提高模型的泛化能力和抗遗忘能力。通过共享模型参数,可以在不同任务之间传递知识,减少灾难性遗忘的影响。 +
综上所述,灾难性遗忘是在模型微调过程中可能出现的问题。通过合适的方法和技术,可以减少灾难性遗忘的发生,保留之前学习到的知识,提高模型的整体性能。
+2.7 预训练和SFT操作有什么不同
+大语言模型的预训练和有监督微调(Supervised +Fine-Tuning)是两个不同的操作,它们在目标、数据和训练方式等方面存在一些区别。
+目标:
+-
+
- 预训练的目标是通过无监督学习从大规模的文本语料库中学习语言模型的表示能力和语言知识。预训练的目标通常是通过自我预测任务,例如掩码语言模型(Masked +Language Model,MLM)或下一句预测(Next Sentence +Prediction,NSP)等,来训练模型。 +
- 有监督微调的目标是在特定的任务上进行训练,例如文本分类、命名实体识别等。在有监督微调中,模型会利用预训练阶段学到的语言表示和知识,通过有监督的方式调整模型参数,以适应特定任务的要求。 +
数据:
+-
+
- 在预训练阶段,大语言模型通常使用大规模的无标签文本数据进行训练,例如维基百科、网页文本等。这些数据没有特定的标签或任务信息,模型通过自我预测任务来学习语言模型。 +
- 在有监督微调中,模型需要使用带有标签的任务相关数据进行训练。这些数据通常是人工标注的,包含了输入文本和对应的标签或目标。模型通过这些标签来进行有监督学习,调整参数以适应特定任务。 +
训练方式:
+-
+
- 预训练阶段通常使用无监督的方式进行训练,模型通过最大化预训练任务的目标函数来学习语言模型的表示能力。 +
- 有监督微调阶段则使用有监督的方式进行训练,模型通过最小化损失函数来学习任务相关的特征和模式。在微调阶段,通常会使用预训练模型的参数作为初始参数,并在任务相关的数据上进行训练。 +
总的来说,预训练和有监督微调是大语言模型训练的两个阶段,目标、数据和训练方式等方面存在差异。预训练阶段通过无监督学习从大规模文本数据中学习语言模型,而有监督微调阶段则在特定任务上使用带有标签的数据进行有监督学习,以适应任务要求。
+2.8 大模型LLM进行SFT +如何对样本进行优化?
+对于大语言模型进行有监督微调(Supervised +Fine-Tuning)时,可以采用以下几种方式对样本进行优化:
+-
+
- 数据清洗和预处理:对于有监督微调的任务,首先需要对样本数据进行清洗和预处理。这包括去除噪声、处理缺失值、进行标准化或归一化等操作,以确保数据的质量和一致性。 +
- 数据增强:通过数据增强技术可以扩充训练数据,增加样本的多样性和数量。例如,可以使用数据扩充方法如随机裁剪、旋转、翻转、加噪声等来生成新的训练样本,从而提高模型的泛化能力。 +
- 标签平衡:如果样本标签不平衡,即某些类别的样本数量远远多于其他类别,可以采取一些方法来平衡样本标签。例如,可以通过欠采样、过采样或生成合成样本等技术来平衡不同类别的样本数量。 +
- 样本选择:在有限的资源和时间下,可以选择一部分具有代表性的样本进行微调训练。可以根据任务的需求和数据分布的特点,选择一些关键样本或难样本进行训练,以提高模型在关键样本上的性能。 +
- 样本权重:对于一些重要的样本或困难样本,可以给予更高的权重,以便模型更加关注这些样本的学习。可以通过调整损失函数中样本的权重或采用加权采样的方式来实现。 +
- 样本组合和分割:根据任务的特点和数据的结构,可以将多个样本组合成一个样本,或将一个样本分割成多个子样本。这样可以扩展训练数据,提供更多的信息和多样性。 +
- 样本筛选和策略:根据任务需求,可以制定一些样本筛选和选择策略。例如,可以根据样本的置信度、难度、多样性等指标进行筛选和选择,以提高模型的性能和泛化能力。 +
总的来说,对大语言模型进行有监督微调时,可以通过数据清洗和预处理、数据增强、标签平衡、样本选择、样本权重、样本组合和分割、样本筛选和策略等方式对样本进行优化。这些优化方法可以提高训练样本的质量、多样性和数量,从而提升模型的性能和泛化能力。具体的优化策略需要根据任务需求和数据特点进行选择和调整。
+3. 预训练
+3.1 为什么要增量预训练?
+预训练学知识,指令微调学格式,强化学习对齐人类偏好,所以要想大模型有领域知识,得增量预训练(靠指令微调记知识不靠谱,不是几十w条数据能做到的)。
+3.2 +进行增量预训练需要做哪些准备工作?
+-
+
- 选取底座模型:可以根据自己的项目需求和硬件基础来选择合适的底座模型及模型参数量的大小。 +
- 收集数据:一般来说需要收集大量的文本数据,包含各个领域,主要从互联网上获取,一般预训练数据的大小都是 +TB 级别的。 +
- 数据清洗:所有的信息都能够在互联网信息中被找到,只是信息密度相比「人工精选数据集」要更低。例如「明星信息」、「如何写代码」这些信息都能在新闻网站、或是问答网站中找到,只不过「维基百科」或是「Github」则是将这些信息给「高密度」且「结构化」地进行了存储。这使得我们在使用维基百科作为训练语料的时候,模型能够更快的学习到这些高密度信息(人物的经历、年龄、性别、职业等等),而这些内容在互联网信息(如新闻)中的信息密度则较低,即很少会有一条新闻完整的介绍一个艺人的过往经历。只要我们对互联网信息进行严格的处理(去除冗余信息,提高有用信息的密度),就能够加快模型的学习速度。 +
3.3 +增量预训练训练流程是怎么样?
+-
+
- 数据预处理:参考 LLaMA +的预训练长度,也把数据处理成2048长度(如果不够,做补全)。 +
- 分词器:如果使用 LLaMA +可能需要添加中文词表,目前有不少人做了相关工作,当然也可以自己添加自己需要的词表。 +
- 原始模型:各家框架的模型层名不太一样,训练时可能需要做一些调整,在预训练时尽量选择基座模型,不选 +Chat 模型。 +
- 训练模型:跑通只是第一步,根据训练情况反复调整比较重要。 +
- 模型转换:不同框架的checkpoint格式不同,还会根据并行度分成很多个文件。 +
- 模型测试:简单测试下续写能力,验证下模型是否正常。 +
4. Prompting工程
+4.1 BitFit
+4.1.1 背景
+虽然对每个任务进行全量微调非常有效,但它也会为每个预训练任务生成一个独特的大型模型,这使得很难推断微调过程中发生了什么变化,也很难部署, +特别是随着任务数量的增加,很难维护。
+理想状况下,我们希望有一种满足以下条件的高效微调方法:
+-
+
- 到达能够匹配全量微调的效果。 +
- 仅更改一小部分模型参数。 +
- 使数据可以通过流的方式到达,而不是同时到达,便于高效的硬件部署。 +
- 改变的参数在不同下游任务中是一致的。 +
上述的问题取决于微调过程能多大程度引导新能力的学习以及暴露在预训练LM中学到的能力。
+虽然,之前的高效微调方法Adapter-Tuning、Diff-Pruning也能够部分满足上述的需求。但是,作者提出了一种参数量更小的稀疏的微调方法BitFit,来满足上述的需求。
+4.1.2 技术原理
+BitFit(论文:BitFit: Simple Parameter-efficient Fine-tuning +or Transformer-based Masked +Language-models)是一种稀疏的微调方法,它训练时只更新bias的参数或者部分bias参数。
+对于Transformer模型而言,冻结大部分 transformer-encoder
+参数,只更新bias参数跟特定任务的分类层参数。涉及到的bias参数有attention模块中计算query
,key
,value
跟合并多个attention结果时涉及到的bias,MLP层中的bias,Layernormalization层的bias参数。
在Bert-Base/Bert-Large这种模型里,bias参数仅占模型全部参数量的0.08%~0.09%。但是通过在Bert-Large模型上基于GLUE数据集进行了 +BitFit、Adapter和Diff-Pruning的效果对比发现,BitFit在参数量远小于Adapter、Diff-Pruning的情况下,效果与Adapter、Diff-Pruning想当,甚至在某些任务上略优于Adapter、Diff-Pruning。
+ +同时,通过实验结果还可以看出,BitFit微调结果相对全量参数微调而言, +只更新极少量参数的情况下,在多个数据集上都达到了不错的效果,虽不及全量参数微调,但是远超固定全部模型参数的Frozen方式。
+同时,通过对比BitFit训练前后的参数,发现很多bias参数并没有太多变化(例如:跟计算key所涉及到的bias参数)。发现计算query和将特征维度从N放大到4N的FFN层(intermediate)的bias参数变化最为明显,只更新这两类bias参数也能达到不错的效果,反之,固定其中任何一者,模型的效果都有较大损失。
+ +4.2 Prefix Tuning
+4.2.1 背景
+在Prefix +Tuning之前的工作主要是人工设计离散的模版或者自动化搜索离散的模版。对于人工设计的模版,模版的变化对模型最终的性能特别敏感,加一个词、少一个词或者变动位置都会造成比较大的变化。而对于自动化搜索模版,成本也比较高;同时,以前这种离散化的token搜索出来的结果可能并不是最优的。
+除此之外,传统的微调范式利用预训练模型去对不同的下游任务进行微调,对每个任务都要保存一份微调后的模型权重,一方面微调整个模型耗时长;另一方面也会占很多存储空间。
+基于上述两点,Prefix +Tuning提出固定预训练LM,为LM添加可训练,任务特定的前缀, +这样就可以为不同任务保存不同的前缀,微调成本也小;同时,这种Prefix实际就是连续可微的Virtual +Token(Soft Prompt/Continuous +Prompt),相比离散的Token,更好优化,效果更好。
+ +4.2.2 技术原理
+Prefix Tuning(论文:Prefix-Tuning: Optimizing Continuous +Prompts for +Generation),在输入token之前构造一段任务相关的virtual +tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而PLM中的其他部分参数固定。
+针对不同的模型结构,需要构造不同的Prefix。
+-
+
- 针对自回归架构模型:在句子前面添加前缀,得到
+
z = [PREFIX; x; y]
,合适的上文能够在固定 LM +的情况下去引导生成下文(比如:GPT3的上下文学习)。
+ - 针对编码器-解码器架构模型:Encoder和Decoder都增加了前缀,得到
+
z = [PREFIX; x; PREFIX0; y]
。Encoder端增加前缀是为了引导输入部分的编码,Decoder +端增加前缀是为了引导后续token的生成。
+
该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定和性能下降的情况,在Prefix层前面加了MLP结构,训练完成后,只保留Prefix的参数。
+ +除此之外,通过消融实验证实,只调整embedding层的表现力不够,将导致性能显著下降,因此,在每层都加了prompt的参数,改动较大。
+ +另外,实验还对比了位置对于生成效果的影响,Prefix-tuning也是要略优于Infix-tuning的。其中,Prefix-tuning形式为
+[PREFIX; x; y]
,Infix-tuning形式为
+[x; INFIX; y]
。
4.3 Prompt Tuning
+4.3.1 背景
+大模型全量微调对每个任务训练一个模型,开销和部署成本都比较高。同时,离散的prompts(指人工设计prompts提示语加入到模型)方法,成本比较高,并且效果不太好。
+基于此,作者提出了Prompt +Tuning,通过反向传播更新参数来学习prompts,而不是人工设计prompts;同时冻结模型原始权重,只训练prompts参数, +训练完以后,用同一个模型可以做多任务推理。
+4.3.2 技术原理
+Prompt Tuning(论文:The Power of Scale for +Parameter-Efficient Prompt Tuning),该方法可以看作是Prefix +Tuning的简化版本,它给每个任务定义了自己的Prompt,然后拼接到数据上作为输入,但只在输入层加入prompt +tokens,并且不需要加入 MLP 进行调整来解决难训练的问题。
+ +通过实验发现,随着预训练模型参数量的增加,Prompt +Tuning的方法会逼近全参数微调的结果。
+ +同时,Prompt Tuning 还提出了 Prompt +Ensembling,也就是在一个批次(Batch)里同时训练同一个任务的不同 +prompt(即采用多种不同方式询问同一个问题),这样相当于训练了不同模型,比模型集成的成本小多了。
+ +4.4 P-Tuning
+4.4.1 背景
+该方法的提出主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。比如:GPT-3采用人工构造的模版来做上下文学习(in +context +learning),但人工设计的模版的变化特别敏感,加一个词或者少一个词,或者变动位置都会造成比较大的变化。
+同时,近来的自动化搜索模版工作成本也比较高,以前这种离散化的token的搜索出来的结果可能并不是最优的,导致性能不稳定。基于此,作者提出了P-Tuning,设计了一种连续可微的virtual +token(同Prefix-Tuning类似)。
+ +4.4.2 技术原理
+P-Tuning(论文:GPT Understands, +Too),该方法将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt +Embedding进行一层处理。
+ +相比Prefix Tuning,P-Tuning加入的可微的virtual +token,但仅限于输入层,没有在每一层都加;另外,virtual +token的位置也不一定是前缀,插入的位置是可选的。这里的出发点实际是把传统人工设计模版中的真实token替换成可微的virtual +token。
+经过预训练的LM的词嵌入已经变得高度离散,如果随机初始化virtual +token,容易优化到局部最优值,而这些virtual +token理论是应该有相关关联的。因此,作者通过实验发现用一个prompt +encoder来编码会收敛更快,效果更好。即用一个LSTM+MLP去编码这些virtual +token以后,再输入到模型。
+从对比实验证实看出,P-Tuning获得了与全参数一致的效果。甚至在某些任务上优于全参数微调。
+并且在实验中还发现,相同参数规模,如果进行全参数微调,Bert的在NLU任务上的效果,超过GPT很多;但是在P-Tuning下,GPT可以取得超越Bert的效果。
+4.5 P-Tuning v2
+4.5.1 背景
+之前的Prompt Tuning和P-Tuning等方法存在两个主要的问题:
+第一,缺乏模型参数规模和任务通用性。
+-
+
- 缺乏规模通用性:Prompt +Tuning论文中表明当模型规模超过100亿个参数时,提示优化可以与全量微调相媲美。但是对于那些较小的模型(从100M到1B),提示优化和全量微调的表现有很大差异,这大大限制了提示优化的适用性。 +
- 缺乏任务普遍性:尽管Prompt Tuning和P-tuning在一些 +NLU +基准测试中表现出优势,但提示调优对硬序列标记任务(即序列标注)的有效性尚未得到验证。 +
第二,缺少深度提示优化,在Prompt +Tuning和P-tuning中,连续提示只被插入transformer第一层的输入embedding序列中,在接下来的transformer层中,插入连续提示的位置的embedding是由之前的transformer层计算出来的,这可能导致两个可能的优化挑战。
+-
+
- 由于序列长度的限制,可调参数的数量是有限的。 +
- 输入embedding对模型预测只有相对间接的影响。 +
考虑到这些问题,作者提出了Ptuning +v2,它利用深度提示优化(如:Prefix Tuning),对Prompt +Tuning和P-Tuning进行改进,作为一个跨规模和NLU任务的通用解决方案。
+4.5.2 技术原理
+P-Tuning v2(论文: P-Tuning v2: Prompt Tuning Can Be +Comparable to Fine-tuning Universally Across Scales and +Tasks),该方法在每一层都加入了Prompts +tokens作为输入,而不是仅仅加在输入层,这带来两个方面的好处:
+-
+
- 更多可学习的参数(从P-tuning和Prompt +Tuning的0.01%增加到0.1%-3%),同时也足够参数高效。 +
- 加入到更深层结构中的Prompt能给模型预测带来更直接的影响。 +
具体做法基本同Prefix Tuning,可以看作是将文本生成的Prefix +Tuning技术适配到NLU任务中,然后做了一些改进:
+-
+
- 移除重参数化的编码器。以前的方法利用重参数化功能来提高训练速度和鲁棒性(如:Prefix +Tuning中的MLP、P-Tuning中的LSTM))。在 P-tuning v2 +中,作者发现重参数化的改进很小,尤其是对于较小的模型,同时还会影响模型的表现。 +
- 针对不同任务采用不同的提示长度。提示长度在提示优化方法的超参数搜索中起着核心作用。在实验中,我们发现不同的理解任务通常用不同的提示长度来实现其最佳性能,这与Prefix-Tuning中的发现一致,不同的文本生成任务可能有不同的最佳提示长度。 +
- 引入多任务学习。先在多任务的Prompt上进行预训练,然后再适配下游任务。多任务学习对我们的方法来说是可选的,但可能是相当有帮助的。一方面,连续提示的随机惯性给优化带来了困难,这可以通过更多的训练数据或与任务相关的无监督预训练来缓解;另一方面,连续提示是跨任务和数据集的特定任务知识的完美载体。我们的实验表明,在一些困难的序列任务中,多任务学习可以作为P-tuning +v2的有益补充。 +
- 回归传统的分类标签范式,而不是映射器。标签词映射器(Label +Word +Verbalizer)一直是提示优化的核心组成部分,它将one-hot类标签变成有意义的词,以利用预训练语言模型头。尽管它在few-shot设置中具有潜在的必要性,但在全数据监督设置中,Verbalizer并不是必须的。它阻碍了提示调优在我们需要无实际意义的标签和句子嵌入的场景中的应用。因此,P-Tuning +v2回归传统的CLS标签分类范式,采用随机初始化的分类头(Classification +Head)应用于tokens之上,以增强通用性,可以适配到序列标注任务。 +
论文中展示了P-tuning +v2在不同模型规模下的表现。对于简单的NLU任务,如SST-2(单句分类),Prompt +Tuning和P-Tuning在较小的规模下没有显示出明显的劣势。但是当涉及到复杂的挑战时,如:自然语言推理(RTE)和多选题回答(BoolQ),它们的性能会非常差。相反,P-Tuning +v2在较小规模的所有任务中都与微调的性能相匹配。并且,P-tuning +v2在RTE中的表现明显优于微调,特别是在BERT中。
+5. Adapter-Tuning
+5.1 Adapter Tuning
+5.1.1 背景
+预训练模型参数量越来越多,在训练下游任务时进行全量微调变得昂贵且耗时。
+基于此,作者提出了Adapter Tuning,Adapter 的出现缓解了上述问题 +Adapter +在预训练模型每层中插入用于下游任务的参数(针对每个下游任务,仅增加3.6%的参数),在微调时将模型主体冻结,仅训练特定于任务的参数,从而减少了训练时的算力开销。
+5.1.2 技术原理
+Adapter Tuning(论文:Parameter-Efficient Transfer Learning +for +NLP),该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构(分别是多头注意力的投影之后和第二个feed-forward层之后),在训练时,固定住原来预训练模型的参数不变,只对新增的 +==Adapter 结构和 Layer Norm +层==进行微调,从而保证了训练的高效性。
+每当出现新的下游任务,通过添加Adapter模块来产生一个易于扩展的下游模型,从而避免全量微调与灾难性遗忘的问题。
+ +5.1.3 具体细节
+每个 Adapter
+模块主要由两个前馈(Feedforward)子层组成,第一个前馈子层(down-project)将Transformer块的输出作为输入,将原始输入维度d
(高维特征)投影到m
(低维特征),通过控制m的大小来限制Adapter模块的参数量,通常情况下,m<<d
。然后,中间通过一个非线形层。在输出阶段,通过第二个前馈子层(up-project)还原输入维度,将m(低维特征)重新映射回d(原来的高维特征),作为Adapter模块的输出。同时,通过一个skip
+connection来将Adapter的输入重新加到最终的输出中去,这样可以保证,即便
+Adapter 一开始的参数初始化接近0,Adapter也由于skip
+connection的设置而接近于一个恒等映射,从而确保训练的有效性。
\[ +h \leftarrow h+f\left(h W_{\text {down }}\right) W_{u p} +\]
+通过实验发现,只训练少量参数的Adapter方法的效果可以媲美全量微调,这也验证了Adapter是一种高效的参数训练方法,可以快速将语言模型的能力迁移到下游任务中去。
+总之,Adapter通过引入0.5%~5%的模型参数可以达到不落后全量微调模型1%的性能。
+5.2 AdapterFusion
+5.2.1 背景
+为了整合来自多个任务的知识,传统的两个方法是按一定顺序微调(Sequential +fine-tuning)或者多任务学习(multi-task +learning)。前者的一大问题是需要先验知识来确定顺序,且模型容易遗忘之前任务学到的知识,后者的问题是不同的任务会互相影响,也难以平衡数据集大小差距很大的任务。
+而之前的工作,Adapter +Tuning的一个优势就是不用更新预训练模型的参数,而是插入比较少的新的参数就可以很好地学会一个任务。此时,Adapter +的参数某种程度上就表达了解决这个任务需要的知识。
+作者受此启发,如果想要把来自多个任务的知识结合起来,是否可以考虑把多个任务的Adapter的参数结合起来?基于此,作者提出了 +AdapterFusion,这是一种新的两阶段学习算法,可以利用来自多个任务的知识。
+5.2.2 技术原理
+Adapter Fusion(论文:AdapterFusion:Non-Destructive Task +Composition for Transfer +Learning),一种融合多任务信息的Adapter的变体,在 +Adapter +的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+-
+
- 知识提取阶段:在不同任务下引入各自的Adapter模块,用于学习特定任务的信息。 +
- 知识组合阶段:将预训练模型参数与特定于任务的Adapter参数固定,引入新参数(AdapterFusion)来学习组合多个Adapter中的知识,以提高模型在目标任务中的表现。 +
对于第一阶段,有两种训练方式,分别如下:
+-
+
- Single-Task +Adapters(ST-A):对于N个任务,模型都分别独立进行优化,各个任务之间互不干扰,互不影响。 +
- Multi-Task +Adapters(MT-A):N个任务通过多任务学习的方式,进行联合优化。 +
对于第二阶段,为了避免通过引入特定任务参数而带来的灾难性遗忘问题,AdapterFusion提出了一个共享多任务信息的结构。针对特定任务m
,AdapterFusion联合了第一阶段训练得到的N
个Adapter信息。固定语言模型的参数跟N
个Adapter的参数,新引入AdapterFusion的参数,目标函数也是学习针对特定任务m
的AdapterFusion的参数。
5.2.3 AdapterFusion结构
+AdapterFusion具体结构就是一个Attention,它的参数包括query
,key
,
+value
的矩阵参数,在transformer的每一层都存在,它的query是transformer每个子模块的输出结果,它的key跟value则是N个任务的adapter的输出。通过AdapterFusion,模型可以为不同的任务对应的adapter分配不同的权重,聚合N个任务的信息,从而为特定任务输出更合适的结果。
通过对全量微调、Adapter Tuning、AdapterFusion这三种方法在各个数据集上进行对比实验可以看出,AdapterFusion在大多数情况下性能优于全模型微调和Adapter Tuning,特别在MRPC与RTE数据集中,性能显著优于另外两种方法。
+总之,通过将适配器的训练分为知识提取和知识组合两部分,解决了灾难性遗忘、任务间干扰和训练不稳定的问题。但是,Adapter模块的添加也导致模型整体参数量的增加,降低了模型推理时的性能。
+5.3 AdapterDrop
+5.3.1 背景
+近年来Adapter已被证明可以很好地用于机器翻译、跨语言迁移、社区问答和迁移学习的任务组合。尽管它们最近很受欢迎,但Adapter的计算效率尚未在参数效率之外得到探索。
+作者通过对Adapter的计算效率进行分析,发现与全量微调相比,Adapter在训练时快60%,但是在推理时慢4%-6%。
+基于此,作者提出了AdapterDrop方法缓解该问题。
+5.3.2 技术原理
+AdapterDrop(论文:AdapterDrop: On the Efficiency of Adapters in +Transformers),在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+ +实验表明,从较低的 Transformer 层中删除Adapter可以显着提高多任务设置中的推理速度。 +例如,将前五个Transformer层中的Adapter丢弃,在对 8 +个任务进行推理时,速度提高了 39%。并且即使有多个丢弃层,AdapterDrop +也能保持良好的结果。
+除此之外,作者还研究了对 +AdapterFusion中的Adapter进行剪枝后的效果。
+ +通过实验表明可以移除 AdapterFusion +中的大多数Adapter而不影响任务性能。使用剩余的两个Adapter,实现了与具有八个Adapter的完整 +AdapterFusion 模型相当的结果,并将推理速度提高了 68%。
+因此,作者建议在实际部署这些模型之前执行 AdaperFusion 剪枝。 +这是一种简单而有效的技术,即使在完全保持性能的情况下也能实现效率提升。
+总之,AdapterDrop +通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。 +当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。
+5.4 MAM Adapter
+5.4.1 背景
+近年来提出了多种参数高效的迁移学习方法,这些方法仅微调少量(额外)参数即可获得强大的性能。虽然有效,但人们对为什么有效的关键要素以及各种高效微调方法之间的联系知之甚少。
+下图展示了不同的微调方法,在Xsum数据集上做英文文本摘要任务的效果(ROUGE-2是该任务的评价指标(越大越好))以及其他高效微调方法参数量相对于全参数微调参数量的百分比。图中的左上角的位置是理想化的方法。从图中发现,Adapter,Prefix +Tuning和LoRA都是性能比较好的方法。
+ +为什么看起来Adapter、Prefix +Tuning、LoRA(在结构上和公式上)都不太一样,尤其是Prefix +Tuning,但是这三种方法有近似的效果?
+基于此,作者分解了当下最先进的参数高效迁移学习方法(Adapter、Prefix +Tuning和LoRA)的设计,并提出了一种新方法MAM +Adapter,一个在它们之间建立联系的统一框架。具体来说,将它们重新构建为对预训练模型中特定隐藏状态的修改,并定义一组设计维度,不同的方法沿着这些维度变化。
+ +首先,作者通过对Prefix Tuning变换,发现Prefix +Tuning和Adapters的公式高度相似。
+然后,分析不同微调方法的内部结构和结构插入形式的相似之处。下图展示了高效微调方法Adapter、Prefix +Tuning、LoRA以及新变体(通过更换一些元素,设计了前人的工作里没有的变体) +Parallel Adapter、 Scaled PA的结构。
+ +下表展示了高效微调方法Adapter、Prefix +Tuning、LoRA以及新变体在新增可训练参数结构形式(functional +form)、结构插入形式(Insertion +form)、新增结构在PLM修改的具体位置(modified +representation)、新增结构与PLM的组合函数(composition +function)。其中,新增可训练参数结构形式为需要学习的部分(注:Prefix +Tuning为经过转换后的格式);插入形式有串联或并联;模型修改的具体位置有Attention、FFN层。
+ +5.4.2 技术原理
+MAM Adapter(论文:TOWARDS A UNIFIED VIEW OF PARAMETER-EFFICIENT +TRANSFER LEARNING),一个在Adapter、Prefix +Tuning和LoRA之间建立联系的统一方法。
+作者对Adapter的放置和软提示(soft +prompt)进行了详细的调查。得出如下结论:
+-
+
- 并行放置的Adapter优于顺序放置的Adapter,并且与 FFN +并行放置的Adapter优于多头注意力(MHA)并行放置的Adapter(模型修改的位置如下图中所示,蓝色表示修改Attention、红色表示修改FFN)。 +
- 软提示可以通过仅更改 0.1% 的参数来有效地修改注意力。 +
然后,提出了“mix-and-match”(MAM)。 因此,最终模型 MAM Adapter 是用 +FFN 层的并行Adapter和软提示的组合。
+通过最终的实验结果,可以看到 MAM Adapter +在仅用了6.7%参数量(相比全量微调)的情况下,在Xsum和MT这两个任务上达到了和全量微调相近的效果,并且该方法大大优于 +BitFit 和 Prompt Tuning,并始终优于 LoRA、Adapter 和 Prefix Tuning。
+5.5 UniPELT
+5.5.1 背景
+近年来,涌现出了许多针对语言模型的参数高效微调(PELT)方法,在模型训练参数极大的减少的情况下,模型效果与全量微调相当。但是不同的PELT方法在同一个任务上表现差异可能都非常大,这让针对特定任务选择合适的方法非常繁琐。
+基于此,作者提出了UniPELT方法,将不同的PELT方法作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+5.5.2 技术原理
+UniPELT(论文: UNIPELT: A Unified Framework for Parameter-Efficient +Language Model Tuning)是 LoRA、Prefix Tuning和Adapter的门控组合。
+更具体地说,LoRA 重新参数化用于 WQ 和 WV 注意力矩阵,Prefix +Tuning应用于每一Transformer层的key和value,并在Transformer块的feed-forward子层之后添加Adapter。 +对于每个模块,门控被实现为线性层,通过GP参数控制Prefix-tuning方法的开关,GL控制LoRA方法的开关,GA控制Adapter方法的开关。可训练参数包括 +LoRA 矩阵 +WA(Down)和WB(Up),提示调优参数Pk和Pv、Adapter参数和门函数权重。即图中蓝颜色的参数为可学习的参数。
+ +UniPELT 仅用 100 个示例就在低数据场景中展示了相对于单个 LoRA、Adapter +和 Prefix Tuning 方法的显著改进。在更高数据的场景中,UniPELT +的性能与这些方法相当或更好。
+实验还对不同 PELT 方法训练时间和推理时间进行了分析。
+-
+
- 从训练速度来看,UniPELT比之前微调的方法多一些,但是还在能接受的范围, +
- 从推理时间来看,BitFit方法增加的最少,UniPELT方法时间增加了27%。 +
- 从训练参数量来看,LoRA,BitFit,Prefix-tuning都比较小,UniPELT参数量相对会多一些。 +
6. lora
+6.1 LoRA
+6.1.1 背景
+神经网络包含很多全连接层,其借助于矩阵乘法得以实现,然而,很多全连接层的权重矩阵都是满秩的。当针对特定任务进行微调后,模型中权重矩阵其实具有很低的本征秩(intrinsic +rank),因此,论文的作者认为权重更新的那部分参数矩阵尽管随机投影到较小的子空间,仍然可以有效的学习,可以理解为针对特定的下游任务这些权重矩阵就不要求满秩。
+6.1.2 技术原理
+LoRA(论文:LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE +MODELS),该方法的核心思想就是通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+在涉及到矩阵相乘的模块,在原始的PLM旁边增加一个新的通路,通过前后两个矩阵A,B相乘,第一个矩阵A负责降维,第二个矩阵B负责升维,中间层维度为r,从而来模拟所谓的本征秩(intrinsic +rank)。
+ +可训练层维度和预训练模型层维度一致为d
,先将维度d
通过全连接层降维至r
,再从r
通过全连接层映射回d
维度,其中,r<<d
,r是矩阵的秩,这样矩阵计算就从d x d
变为d x r + r x d
,参数量减少很多。
在下游任务训练时,固定模型的其他参数,只优化新增的两个矩阵的权重参数,将PLM跟新增的通路两部分的结果加起来作为最终的结果(两边通路的输入跟输出维度是一致的),即h=Wx+BAx
。第一个矩阵的A的权重参数会通过高斯函数初始化,而第二个矩阵的B的权重参数则会初始化为零矩阵,这样能保证训练开始时新增的通路BA=0从而对模型结果没有影响。
\[ +h=W_{0} x+\Delta W x=W_{0} x+B A x +\]
+在推理时,将左右两部分的结果加到一起即可,h=Wx+BAx=(W+BA)x
,所以只要将训练完成的矩阵乘积BA
跟原本的权重矩阵W
加到一起作为新权重参数替换原本PLM的W即可,对于推理来说,不会增加额外的计算资源。
此外,Transformer的权重矩阵包括Attention模块里用于计算query
,
+key
,
+value
的Wq
,Wk
,Wv
以及多头attention的Wo
,以及MLP层的权重矩阵,LoRA只应用于Attention模块中的4种权重矩阵,而且通过消融实验发现同时调整
+Wq 和 Wv 会产生最佳结果。
实验还发现,保证权重矩阵的种类的数量比起增加隐藏层维度r更为重要,增加r并不一定能覆盖更加有意义的子空间。
+6.2 AdaLoRA
+6.2.1 背景
+在NLP领域,对于下游任务进行大型预训练语言模型的微调已经成为一种重要的做法。一般而言,我们会采用对原有的预训练模型进行全量微调的方法来适配下游任务,但这种方法存在两个问题。
+-
+
- 训练阶段。对于预训练模型进行微调的时候,为了更新权重参数,需要大量的显存来存储参数的梯度和优化器信息,在当今预训练模型的参数变得越来越大的情况下,针对下游任务微调门槛变得越来越高。 +
- 推理阶段。由于我们训练的时候是对于模型参数进行全量的更新,所以多个下游任务需要为每个任务维护一个大型模型的独立副本,这样就导致我们在实际应用的时候浪费了不必要的存储。 +
为了解决这些问题,研究者提出了两个主要研究方向,以减少微调参数的数量,同时保持甚至提高预训练语言模型的性能。
+-
+
- 方向一:添加小型网络模块:将小型网络模块添加到PLMs中,保持基础模型保持不变的情况下仅针对每个任务微调这些模块,可以用于所有任务。这样,只需引入和更新少量任务特定的参数,就可以适配下游的任务,大大提高了预训练模型的实用性。如:Adapter +tuning、Prefix tuning、Prompt +Tuning等,这类方法虽然大大减少了内存消耗。但是这些方法存在一些问题,比如:Adapter +tuning引入了推理延时;Prefix tuning或Prompt +tuning直接优化Prefix和Prompt是非单调的,比较难收敛,并且消耗了输入的token。 +
- 方向二:下游任务增量更新:对预训练权重的增量更新进行建模,而无需修改模型架构,即W=W0+△W。比如:Diff +pruning、LoRA等, +此类方法可以达到与完全微调几乎相当的性能,但是也存在一些问题,比如:Diff +pruning需要底层实现来加速非结构化稀疏矩阵的计算,不能直接使用现有的框架,训练过程中需要存储完整的∆W矩阵,相比于全量微调并没有降低计算成本。 +LoRA则需要预先指定每个增量矩阵的本征秩 r +相同,忽略了在微调预训练模型时,权重矩阵的重要性在不同模块和层之间存在显著差异,并且只训练了Attention,没有训练FFN,事实上FFN更重要。 +
基于以上问题进行总结:
+-
+
- 第一,我们不能预先指定矩阵的秩,需要动态更新增量矩阵的R,因为权重矩阵的重要性在不同模块和层之间存在显著差异。 +
- 第二,需要找到更加重要的矩阵,分配更多的参数,裁剪不重要的矩阵。找到重要的矩阵,可以提升模型效果;而裁剪不重要的矩阵,可以降低参数计算量,降低模型效果差的风险。 +
为了弥补这一差距,作者提出了AdaLoRA,它根据权重矩阵的重要性得分,在权重矩阵之间自适应地分配参数预算。
+6.2.2 技术原理
+AdaLoRA(论文:ADAPTIVE BUDGET ALLOCATION FOR +PARAMETEREFFICIENT +FINE-TUNING),是对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵。具体做法如下:
+-
+
- 调整增量矩分配。AdaLoRA将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。 +
- 以奇异值分解的形式对增量更新进行参数化,并根据重要性指标裁剪掉不重要的奇异值,同时保留奇异向量。由于对一个大矩阵进行精确SVD分解的计算消耗非常大,这种方法通过减少它们的参数预算来加速计算,同时,保留未来恢复的可能性并稳定训练。 +
\[ +W=W^{(0)}+\Delta=W^{(0)}+P \Lambda Q +\]
+-
+
- 在训练损失中添加了额外的惩罚项,以规范奇异矩阵P和Q的正交性,从而避免SVD的大量计算并稳定训练。 +
通过实验证明,AdaLoRA +实现了在所有预算、所有数据集上与现有方法相比,性能更好或相当的水平。 +例如,当参数预算为 0.3M 时,AdaLoRA +在RTE数据集上,比表现最佳的基线(Baseline)高 1.8%。
+ +6.3 QLoRA
+6.3.1 背景
+微调大型语言模型 (LLM) +是提高其性能以及添加所需或删除不需要的行为的一种非常有效的方法。然而,微调非常大的模型非常昂贵;以 +LLaMA 65B 参数模型为例,常规的 16 bit微调需要超过 780 GB 的 GPU +内存。
+虽然最近的量化方法可以减少 LLM +的内存占用,但此类技术仅适用于推理场景。
+基于此,作者提出了QLoRA,并首次证明了可以在不降低任何性能的情况下微调量化为 +4 bit的模型。
+6.3.2 技术原理
+QLoRA(论文: QLORA: Efficient Finetuning of Quantized +LLMs),使用一种新颖的高精度技术将预训练模型量化为 4 +bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。QLORA +有一种低精度存储数据类型(4 +bit),还有一种计算数据类型(BFloat16)。实际上,这意味着无论何时使用 +QLoRA 权重张量,我们都会将张量反量化为 BFloat16,然后执行 16 +位矩阵乘法。QLoRA提出了两种技术实现高保真 4 bit微调——4 bit +NormalFloat(NF4) +量化和双量化。此外,还引入了分页优化器,以防止梯度检查点期间的内存峰值,从而导致内存不足的错误,这些错误在过去使得大型模型难以在单台机器上进行微调。具体说明如下:
+-
+
- 4bit +NormalFloat(NF4):对于正态分布权重而言,一种信息理论上最优的新数据类型,该数据类型对正态分布数据产生比 +4 bit整数和 4bit 浮点数更好的实证结果。 +
- 双量化:对第一次量化后的那些常量再进行一次量化,减少存储空间。 +
- 分页优化器:使用NVIDIA统一内存特性,该特性可以在在GPU偶尔OOM的情况下,进行CPU和GPU之间自动分页到分页的传输,以实现无错误的 +GPU 处理。该功能的工作方式类似于 CPU +内存和磁盘之间的常规内存分页。使用此功能为优化器状态(Optimizer)分配分页内存,然后在 +GPU 内存不足时将其自动卸载到 CPU +内存,并在优化器更新步骤需要时将其加载回 GPU 内存。 +
实验证明,无论是使用16bit、8bit还是4bit的适配器方法,都能够复制16bit全参数微调的基准性能。这说明,尽管量化过程中会存在性能损失,但通过适配器微调,完全可以恢复这些性能。
+7. 微调方法总结
+7.1 +当前高效微调技术的简述
+之前对一些常见的高效微调技术进行了背景介绍及技术原理剖析,下面对每一种高效微调技术的特点进行简要的总结。
+7.2 BitFit
+对微调机制的一种积极探索,也很简单,通过仅调整bias效果就能有不错的效果,但没有具体阐述原理,就是通过猜测加实验得到的结果。同时,作者提出一个观点:微调的过程不是让模型适应另外的数据分布,而是让模型更好的应用出本身的表征能力。
+特点:
+-
+
- 训练参数量极小(约0.1%)。 +
- 在大部分任务上效果会差于LoRA、Adapter等方法。 +
7.3 Prefix Tuning
+在每一个Transformer层都带上一些virtual +token作为前缀,以适应不同的任务。
+特点:
+-
+
- 前缀Token会占用序列长度,有一定的额外计算开销。 +
- Prefix Tuning的线性插值是比较复杂的。 +
7.4 Prompt Tuning
+该方法可以看着是Prefix +Tuning的简化版本,针对不同的任务,仅在输入层引入virtual +token形式的软提示(soft prompt)。
+特点:
+-
+
- 相对于Prefix +Tuning,参与训练的参数量和改变的参数量更小,更节省显存。 +
- 对一些简单的NLU +任务还不错,但对硬序列标记任务(即序列标注)表现欠佳。 +
7.5 P-Tuning
+将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对Prompt +Embedding进行一层处理。相比Prefix Tuning,仅在输入层加入的可微的virtual +token;另外,virtual token的位置也不一定是前缀,插入的位置是可选的。
+特点:
+-
+
- 引入一个prompt encoder(由一个双向的LSTM+两层MLP组成)来建模virtual +token的相互依赖会收敛更快,效果更好。 +
7.6 P-Tuning v2
+该方法在每一个Transformer层都加入了prompt +token作为输入,引入多任务学习,针对不同任务采用不同的提示长度。并且回归传统的分类标签范式,而不是映射器。
+特点:
+-
+
- 解决了Prompt Tuning无法在小模型上有效提升的问题。 +
- 移除了对模型效果改进较小的重参数化的编码器(如:Prefix +Tuning中的MLP、P-Tuning中的LSTM)。 +
- 对于一些复杂的硬序列标记任务(即序列标注)取得了不错的效果。 +
7.7 Adapter Tuning
+该方法设计了Adapter结构,并将其嵌入Transformer的结构里面,针对每一个Transformer层,增加了两个Adapter结构,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构和Layer +Norm 层进行微调。
+特点:
+-
+
- 通过在Transformer层中嵌入Adapter结构,在推理时会额外增加推理时长。 +
7.8 AdapterFusion
+一种融合多任务信息的Adapter的变体,在 Adapter +的基础上进行优化,通过将学习过程分为两阶段来提升下游任务表现。
+7.9 AdapterDrop
+该方法在不影响任务性能的情况下,对Adapter动态高效的移除,尽可能的减少模型的参数量,提高模型在反向传播(训练)和正向传播(推理)时的效率。
+特点:
+-
+
- 通过从较低的 Transformer 层删除可变数量的Adaper来提升推理速度。 +当对多个任务执行推理时,动态地减少了运行时的计算开销,并在很大程度上保持了任务性能。 +
7.10 LoRA
+该方法通过低秩分解来模拟参数的改变量,从而以极小的参数量来实现大模型的间接训练。
+特点:
+-
+
- 将BA加到W上可以消除推理延迟。 +
- 可以通过可插拔的形式切换到不同的任务。 +
- 设计的比较好,简单且效果好。 +
7.11 AdaLoRA
+对LoRA的一种改进,它根据重要性评分动态分配参数预算给权重矩阵,将关键的增量矩阵分配高秩以捕捉更精细和任务特定的信息,而将较不重要的矩阵的秩降低,以防止过拟合并节省计算预算。
+7.12 QLoRA
+使用一种新颖的高精度技术将预训练模型量化为 4 +bit,然后添加一小组可学习的低秩适配器权重,这些权重通过量化权重的反向传播梯度进行微调。
+特点:
+-
+
- 使用 QLoRA +微调模型,可以显著降低对于显存的要求。同时,模型训练的速度会慢于LoRA。 +
7.13 MAM Adapter
+一种在 Adapter、Prefix Tuning 和 LoRA +之间建立联系的统一方法。最终的模型 MAM Adapter 是用于 FFN 的并行 Adapter +和 软提示的组合。
+特点:
+-
+
- 整体上来说,最终的模型MAM Adapter效果会优于单个高效微调方法。 +
7.14 UniPELT
+一种将不同的PELT方法LoRA、Prefix +Tuning和Adapter作为子模块,并通过门控机制学习激活最适合当前数据或任务的方法。
+特点:
+-
+
- 相对于LoRA,BitFit,Prefix-tuning,训练的参数量更大;同时,推理更耗时;并且,输入会占用额外的序列长度。 +
- 多种 PELT 方法的混合涉及PLM +的不同部分对模型有效性和鲁棒性都有好处 +
7.15 总结
+本文针对之前介绍的几种参数高效微调方法进行了简单的概述,主要有如下几类:
+-
+
- 增加额外参数,如:Prefix Tuning、Prompt Tuning、Adapter +Tuning及其变体。 +
- 选取一部分参数更新,如:BitFit。 +
- 引入重参数化,如:LoRA、AdaLoRA、QLoRA。 +
- 混合高效微调,如:MAM Adapter、UniPELT。 +
并比较了不同的高效微调方法之间的差异;同时,还指出当前大多数高效微调方法存在的一些问题并给出了最佳实践。
]]>1 posts in total
+2 posts in total
@@ -210,9 +210,15 @@
2024
+ + +10 posts in total
+11 posts in total
@@ -210,15 +210,21 @@
2024
+ + +