大模型系列笔记之提示工程(基础、上下文学习、思维链)。
基础提示
人工设计提示
- 任务描述
- 输入数据
- 上下文信息
- 提示策略
“你是这个任务的专家”
“让我们一步一步地思考”
“通过依次执行以下任务形成一段连贯的叙述:1. …;2. …;3. …”
对话式大模型,可以将提示拆分为多个子任务提示,以多轮对话的方法逐步输入给大模型。
提供少样本示例
使用特殊符号进行分割(###、三引号、XML标签等)
英文指令理解更好
自动提示优化
离散提示优化
离散提示通常是由一系列自然语言词元组成的完整句子表达(如“请根据提供的检索信息回答下列问题”)。在离散的词元空间中进行组合搜索,时间复杂度高且搜索结果可能不是最优。因此有以下的优化方法。
- 基于梯度的方法
通过梯度更新技术以最大化模型的似然分数来优化离散提示的搜索过程。将提示词初始化为一系列“[MASK]”标记,然后迭代地将提示中的词元替换为词典中的其它词元,通过词元替换产生的对数似然变化来近似估计梯度,进而为提示的每个位置贪心搜索出最佳的词元。由于对提示的每个位置都进行所有候选词元的替换和梯度评估,因此模型需要进行多次前向和后向计算,搜索过程效率较低。为此,可将离散词元转化为连续嵌入表示(软词元),使用梯度直接对连续嵌入参数进行优化,最后将每个连续嵌入映射为词典中最邻近的离散词元。 - 基于强化学习的方法
将预训练语言模型作为强化学习中的策略网络并依次生成提示中的词元。在提示生成结束之后,策略网络可以获得任务特定的奖励信号,该奖励信号可通过强化学习算法用于策略网络参数的训练。可设计不同类型的奖励信号,如真实便签与基于提示的预测标签是否一致、生成文本与给定条件的匹配程度。在测试阶段,基于训练好的策略网络,可采用贪心搜索策略来生成任务提示中的每个词元。 - 基于编辑的方法
特别适用于无法直接访问模型内部状态(如梯度)的情况,比如只能通过API调用的模型。这种方法需事先定义好编辑操作,然后迭代地修改提示,直到最大迭代轮次或者模型最佳性能。常用的提示编辑操作:修改任务描述、添加或删除上下文任务示例、调整输入到输出的标签映射器(二分类用‘postive/negtive’、‘正/负’)。 - 基于大语言模型的方法
该方法首先利用提示生成模型(用于生成指示指令的大语言模型)基于少量上下文示例生成一批候选的任务指令。随后,使用目标模型(用于下游测试的大语言模型)对这些候选指令在目标任务上的表现逐一评估。评估过程可采用模型困惑度或任务准确率作为衡量指令质量的指标。上述过程可通过基于蒙特卡洛搜索的多轮优化策略进行扩展。在每轮迭代中,根据模型表现对候选指令进行筛选得到高评分指令,并利用大语言模型生成与高评分指令相似的新指令,从而扩展候选指令集。迭代完成后,选择模型表现最佳的候选指令作为最终使用的提示。但是这种方法可能在提示搜索过程中陷入局部最优或者产生效果震荡,无法生成更好的提示。为解决该问题,可将所有改进的历史提示及其分数纳入提示优化过程,以指导大语言模型逐步生成更好的新提示。
连续提示优化
由一组连续空间中的嵌入向量组成,可根据下游任务的损失直接通过梯度更新进行优化。已有连续提示优化的工作主要是基于预训练语言模型开展,由于参数量巨大,受到的关注有限。已有研究通常依赖于有监督学习方法,数据稀缺时还可采用迁移学习来缓解。
- 监督学习方法
将连续提示向量视为可训练的模型参数,基于下游任务数据,通过最小化交叉熵损失来优化连续提示。Prefix-tuning在语言模型每个Transformer层预置一串前缀(即一组可训练的连续向量),而Prompt-tuning只会在输入层加入可训练的提示向量。通过固定语言模型的大规模参数而只微调这些连续的提示向量,可以有效节省训练所需要的参数量。然而这些提示优化方法通常与输入无关,缺乏对于输入语义的充分考虑。 - 迁移学习方法
为若干个具有代表性的源任务学习一个所有任务共享的连续提示,然后使用该提示初始化目标任务的提示,但它在解决目标任务的所有实例时都使用了相同提示,未必适合所有的任务实例。为此,可以为每个源任务独自学习任务特定的连续提示(而不是所有源任务共享),在解决目标任务的实例时,可以采用注意力机制等方式学习目标实例与每个源任务提示的相关性权重系数,对若干个源任务的提示向量进行加权组合,将组合后的新提示(为连续向量形式)用于帮助模型解决当前任务实例。
上下文学习
GPT3提出In-context learning(ICL),由任务描述和(或)示例所组成的自然语言文本作为提示。
首先,通过自然语言描述任务,并从任务数据集中选择一些样本作为示例。其次,根据特定的模板,将这些示例按照特定顺序组合成提示内容。最后,将测试样本添加到提示后面,整体输入到大语言模型以生成输出。基于任务描述以及示例信息,大语言模型无需显式的梯度更新即可识别和执行新的任务。
示例选择
- 基于相关度排序的方法
KNN相似度检测算法,选出与目标任务实例相关的示例。具体来说,可以使用文本嵌入模型(如 BERT)将所有候选样本映射到低维嵌入空间中,然后根据这些候选样本与测试样本的嵌入语义相似度进行排序,并选择出最相关的 𝑘 个示例,最后将筛选出的示例作为上下文学习的示例集合。 - 基于集合多样性的方法
经典启发式MMR(Maximum Margin Ranking)算法、基于行列式点过程的DPP算法(Determinantal Point Process) - 基于大语言模型的方法
将大语言模型作为评分器对候选样本进行评估,进而选择出优质的示例。一种最直接的评估方法是通过计算在加入当前示例后大语言模型性能的增益来评估示例的有效性,以此筛选出有效的示例。但是,这种方法需要大语言模型进行重复多次计算,才能选择出最优的示例集合。为了减少大语言模型评估的开销,还可以根据大语言模型的评分结果选择出少量的正负示例用于训练一个分类器,该分类器通过正负示例能够学习到如何准确地区分和筛选出高质量示例,从而更准确地来指导后续的示例选择过程。
总体来说,在上下文学习中进行示例选择时应确保所选示例包含丰富的任务信息且与测试样本保持高度的相关性。
示例格式
- 人工标注的格式
- 自动生成的格式
首先人工标注一部分的示例模板作为种子集合加入到大语言模型的输入中。然后,利用大语言模型强大的少样本学习能力,指导其为新任务生成相应的示例模版。最后,对这些生成的示例模版进行筛选与后处理,使之符合任务要求。
示例顺序
- 产生候选示例顺序
大语言模型在做出预测时,倾向于依赖于提示末端的信息。常用的方式是根据示例与测试样本之间的语义相似度进行排序,然后将与测试样例相似度更高的示例放在更靠近测试样本的位置。 - 评估示例顺序质量
在测试集样本可获得的情况下,可以直接测试大语言模型基于该示例顺序的任务性能,以此作为当前示例顺序的评分。无法获得测试样本时,需要人工创建独立的验证集进行示例顺序的评估。另一种不依赖测试数据的评估方法是采用模型对于预测结果的不确定性作为评估指标。具体来说,可以计算基于该示例顺序大语言模型预测分布的熵值,选择熵值较低的示例顺序作为较为有效的顺序。熵值越低,意味着模型预测分布越不均匀,则模型预测的置信度更高。
思维链提示
思维链提示作为上下文学习的一种扩展形式,将原始的<输入,输出>映射关系转换为<输入,思维链,输出>这一三元组形式。
“Let’s think step by step.”
“Take a deep breath and work on this problem step-by-step.”
思维链示例设计
从输入侧对思维链示例进行增强。
- 复杂化的思维链
- 推理步骤多、问题长
- 多样化的思维链
首先利用聚类算法(例如 𝑘-means 聚类)将训练集中的问题划分为 𝑘 个簇(𝑘 为所需的示例数量),簇内部的问题比较相似,而不同簇的问题差别较大。然后,预定义一系列启发式规则,从每个簇中选择距离质心最近且满足规则的问题作为该簇的代表性问题,将该问题输入给大语言模型并生成对应的思维链和答案作为示例。由于每个问题来自于不同的簇,从而保证了示例的多样性。实验发现,虽然大模型生成的思维链示例可能存在错误,但是当选择更加多样化的示例时,思维链示例中的错误对模型性能的影响会显著降低。
思维链生成方法
- 基于采样的方法
单一思维链推理容易出错,可采样多条推理路径来缓解。代表性方法:self-consistency。首先使用大语言模型生成多个推理路径和对应的答案,然后对于这些候选答案进行集成并获得最终输出。具体的集成方法可选择各条推理路径所得到答案中出现频率最高的那个答案作为最终输出,也可对所有答案进行某种形式的加权。
但问题太简单用思维链反而效果不好。例如,对于句子的情感分类任务,由于问题过于简单,加入思维链提示之后反而会使模型过度思考,从而得出错误的答案。 - 基于验证的方法
思维链提示所具有的顺序推理本质可能导致推理过程中出现错误传递或累积的现象。为了解决这一问题,可以使用专门训练的验证器或大语言模型自身来验证所生成的推理步骤的准确性。
例:DIVERSE 方法
针对整个推理路径的验证器通过如下方法训练得到:首先选择一个包含大量问题答案对的数据集,然后将问题输入给大语言模型,通过思维链提示的方法使其生成推理路径和最终答案。如果模型生成的答案和数据集标注的答案一致,则判为正例,否则判为负例。最后使用构造的<问题,推理链,答案>数据训练一个二分类器,从而可以对任意一个推理路径进行打分。训练针对中间步骤的验证器也可以采用类似的方案。然而,与整体推理路径的数据标注相比,构造面向中间步骤的正负例数据更加困难。这里可以采取一个简化处理:对于每一个训练集中的问题,我们采样多次得到多个推理路径,对于得出正确答案的推理路径,中间的每一个步骤我们都认为是正确的,作为正例;对于得出错误答案的推理路径,如果其中某个步骤和正例的推理路径相一致,也认为是正例,否则作为负例。通过这样构造出来的数据,用同样的方法训练一个二分类器,从而可以对模型输出的中间步骤进行打分。
拓展的推理结构
链式推理结构在处理较为复杂的任务时(例如需要进行前瞻和回溯探索)仍然存在一定的局限性。
- 树形推理结构
代表性工作:思维树(Tree of Thought, ToT)
它和思维链的区别在于:思维链从一个节点出发,只能生成一个节点,而思维树则可以生成多个节点。当某一个思考步骤无法得到正确答案时,可以回溯到它的父节点,选择另一个子节点继续推理。 - 图形推理结构
代表性工作:思维图(Graph of Thought, GoT)
思维图和思维树的区别在于,思维树的子节点只能进行前向搜索和回溯,而思维图的子节点可以和其他子节点进行汇聚,得到新的中间步骤,然后进行下一步的推理。