- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
一晃24年已经过了一半,我们来重新看下大模型应用中最脆弱的一环Prompt Engineering有了哪些新的解决方案。这一章我们先看看大火的DSPy框架,会先梳理DSPy相关的几篇核心论文了解下框架背后的设计思想和原理,然后以FinEval的单选题作为任务,从简单指令,COT指令,到采样Few-shot和优化指令给出代码示例和效果评估.
- DEMONSTRATE–SEARCH–PREDICT:
Composing retrieval and language models for knowledge-intensive NLP- DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines
- In-Context Learning for Extreme Multi-Label Classification
- Optimizing Instructions and Demonstrations for Multi-Stage Language Model Programs
- DSPy Assertions:
Computational Constraints for Self-Refining Language Model Pipelines
DSPY这个prompt框架着实火了一阵了,项目也发了上面的许多论文,每篇论文都对应了项目中的一个或几个模块。我们来串一遍以上论文的核心思想.
DEMONSTRATE–SEARCH–PREDICT是DSPy的第一篇,核心思想和现在coze这类流程控制软件很相似(哈哈现在大模型领域的名词异常的多,这个workflow其实和agent,chain,pipeline,bot啥的意思也很相似)。核心在固定流程,模块化推理过程和指令(few-shot)生成过程.
虽然是在RAG任务上提出的DSP框架,但我们抛开RAG的search,predict的流程,论文的核心其实是把任务拆分成多个原子节点,每个原子节点是一个不可再分割的function,通过整体的control flow来串联原子节点。同时这种流程化的框架,使得每个节点都可以基于训练数据生成demonstation,并且可以通过不同的召回逻辑,在推理时进行few-shot的动态选择,来优化每一个节点的效果.
以下是OpenQA任务上的一个workflow的示例,整个流程有三个部分,生成Demonstration,并基于示例,进行检索和推理.
其中示例的生成,会使用训练数据在相同的流程上,取运行过程中每一步的结果作为实例,这里选择了k=3的3-shot示例 。
在上面DSP的基础上,DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines对流程进一步做了抽象和重构,提出了以三个核心模块为基础的prompt生成和优化框架 。
其中Telepropmter提供了BootstrapFewShot, BootstrapFewShotWithRandomSearch,Ensemble等prompt优化器。这篇论文的重心是放在prompt中few-shot选择和优化 。
以BootstrapFewShotWithRandomSearch为例,Teleprompter会先基于训练集生成一批Demonstration,再基于指定任务的metric,从中采样得到在验证集上效果表现最优的few-shot来构建最终的prompt.
In-Context Learning for Extreme Multi-Label Classification其实是利用了DSPy的框架,在标签超大(≥10,000)的分类任务上构建了一个新的workflow,叫做Infer-Retrieve-Rank。也就是想让模型猜测N个可能的分类标签,然后召回这些标签.
Optimizing Instructions and Demonstrations for Multi-Stage Language Model Programs把重心放在了端到端的对任务prompt进行整体优化,除了few-shot之外,还包括对任务指令和任务条件的优化。这里有两个技术难点,一个是prompt空间的搜索范围极大,另一个是整体优化时指标的归因问题.
为解决prompt搜索空间问题,论文借鉴APE,也就是大模型基于input-output样本来分析任务本质,生成任务指令的思路。并且在描述任务时除了必须的训练样本,还提供了多个可选择的任务信息,包括 。
模型生成指令的代码如下 。
TIPS = {
"none": "",
"creative": "Don't be afraid to be creative when creating the new instruction!",
"simple": "Keep the instruction clear and concise.",
"description": "Make sure your instruction is very informative and descriptive.",
"high_stakes": "The instruction should include a high stakes scenario in which the LM must solve the task!",
"persona": 'Include a persona that is relevant to the task in the instruction (ie. "You are a ...")',
}
class GenerateSingleModuleInstruction(dspy.Signature):
(
"""Use the information below to learn about a task that we are trying to solve using calls to an LM, then generate a new instruction that will be used to prompt a Language Model to better solve the task."""
)
if use_dataset_summary:
dataset_description = dspy.InputField(
desc="A description of the dataset that we are using.",
prefix="DATASET SUMMARY:",
)
if program_aware:
program_code = dspy.InputField(
format=str,
desc="Language model program designed to solve a particular task.",
prefix="PROGRAM CODE:",
)
program_description = dspy.InputField(
desc="Summary of the task the program is designed to solve, and how it goes about solving it.",
prefix="PROGRAM DESCRIPTION:",
)
module = dspy.InputField(
desc="The module to create an instruction for.", prefix="MODULE:",
)
task_demos = dspy.InputField(
format=str,
desc="Example inputs/outputs of our module.",
prefix="TASK DEMO(S):",
)
if use_instruct_history:
previous_instructions = dspy.InputField(
format=str,
desc="Previous instructions we've attempted, along with their associated scores.",
prefix="PREVIOUS INSTRUCTIONS:",
)
basic_instruction = dspy.InputField(
format=str, desc="Basic instruction.", prefix="BASIC INSTRUCTION:",
)
if use_tip:
tip = dspy.InputField(
format=str,
desc="A suggestion for how to go about generating the new instruction.",
prefix="TIP:",
)
proposed_instruction = dspy.OutputField(
desc="Propose an instruction that will be used to prompt a Language Model to perform this task.",
prefix="PROPOSED INSTRUCTION:",
)
基于以上大模型生成的指令候选,以及前面BootstrapFewShot生成的众多示例,下一步就是基于训练集选择最优的指令。这里论文构建了包括randomSearch等多个优化器,论文主推的MIPRO(Multi-prompt Instruction Proposal Optimizer)使用常见的超参优化的TPE算法来拟合以上指令中的多个超参对最终prompt效果的正负面影响,基于训练集上的评估指标最终选出最优的指令。所以是生成指令的超参(包括采样生成的指令)选择,并非直接去迭代更新指令本身.
其实这里也可以使用各类模型可解释算法。核心难点是整个任务中有多个节点,每个节点prompt有多个超参,彼此间互相影响,并最终影响任务的完成效果,但我们只能拿到最终任务完成的标签,无法获得中间节点的输出反馈。和决策树之类的归因算法难点相似.
DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines是DSPy新出的一个子功能-条件判断。考虑常见的prompt构成基本就包括三个部分,任务描述,few-shot示例,还有针对任务完成细节的requirement,前面两篇论文分别给出了生成优化任务描述和采样筛选few-shot的方案,那Assert就是面向requirements的优化方案.
而现实任务中requirement往往是最琐碎的部分,例如像Query改写任务,我们可能需要要求改写query和原始query相似度不能太高,但又不能丢失核心主体,不能丢失或者改写时间实体,query不能太长,不能对query中无关细节等等 。
论文给出了硬性要求(Assert)和软性建议(Suggest)两种方法,直接加入到前面编写的任务module中,这样任务推理的过程会根据Assert和Suggest直接生成建议,而使用也有两种,一种是模型在推理时命中assert和suggest后,对应建议会直接加入到prompt中用于模型self-refine,另一种是assert可以直接打断模型施法进行重试.
论文就简单说这么多,下面我们以金融单选题任务为示例尝试对prompt进行优化.
- https://github.com/stanfordnlp/dspy
- https://dspy-docs.vercel.app/
下面我们以FinEval的单选题作为任务,尝试使用DSPy进行Prompt生成,Prompt优化,和效果评估。考虑成本这里只使用了100条样本.
首先定义LLM模型,这里我使用的Azure的GPT4 。
import dspy
model = dspy.AzureOpenAI(**kwargs)
dspy.settings.configure(lm=model)
使用DSPy定义prompt,就是定义一个Pydantic模型,包括任务描述,输入描述和输出描述,称之为Signature,如下 。
class SingleChoiceQA(dspy.Signature):
"""单项选择题,给定题目和ABCD四个选项,输出正确的选项"""
question = dspy.InputField(desc='问题和选项')
answer = dspy.OutputField(desc="[ABCD]之一的正确选项")
然后我们把数据导入并转化成DSPy规定的样本格式,同样只要注明输入,Example会自动把剩余字段都当做输出 。
def format_example(line):
input = line['question']
for choice in ['A', 'B', 'C', 'D']:
input += f'\n{choice}. {line[f"{choice}"]}'
output = line["answer"]
example = dspy.Example(question=input, answer=output).with_inputs('question')
return example
下一步我们来定义任务,DSPy称之为Module,也就是定义任务流,像RAG就是retrieve-read,multihop QA就是多轮的QA,而这里因为是简单的单选题,因此Module定义非常简单.
class SQA(dspy.Module):
def __init__(self):
self.generate_answer = dspy.Predict(SingleChoiceQA)
def forward(self, question):
return self.generate_answer(question=question)
singlechoice_qa = SQA()
pred = singlechoice_qa(question=examples[0]['question'])
print('以下为DSPy生成Prompt')
print(model.inspect_history(n=1))
同时我们可以使用inspect_history很方便的查看,DSPy生成的具体Prompt,和对应模型的推理效果,如下 。
在上面基础任务定义的基础上,下一步我们看看能否简单使用COT就能优化任务效果.
加入COT定义的Module如下,DSPy提供了常见的ReACT,POT等思考Prompt.
class SQACOT(dspy.Module):
def __init__(self):
self.generate_answer = dspy.ChainOfThought(SingleChoiceQA)
def forward(self, question):
return self.generate_answer(question=question)
singlechoice_qa_cot = SQACOT()
加入COT后的prompt和推理效果如下 。
接下来我们来定义下任务的评估指标,然后批量评估下使用基础Prompt和COT Prompt的效果差异.
DSPy提供了一些Exact Match,Passage Match之类的指标,但其实自己定义指标最方便。只要和DSPy Metric的输入输出对齐即可。这里我们简单抽取答案中的ABCD和标准答案计算Accuracy。评估代码如下,DSPy支持在返回打分的同时,返回每一条预测的具体结果 。
from dspy.evaluate.evaluate import Evaluate
def choice_match(example, pred, trace=None):
def extract_choice(gen_ans):
m = re.findall(r'[ABCD]', gen_ans, re.M)
if len(m) >= 1:
answer = m[0]
return answer
return random.choice('ABCD')
return extract_choice(pred.answer) == example.answer
evaluate_on_qa = Evaluate(devset=test, num_threads=1,
display_progress=True, display_table=True)
output1 = evaluate_on_qa(singlechoice_qa, metric=choice_match,return_outputs=True,return_all_scores=True)
output2 = evaluate_on_qa(singlechoice_qa_cot, metric=choice_match,return_outputs=True,return_all_scores=True)
以上评估,基础Prompt的准确率在50%,而COT Prompt的准确率在60% 。
再进一步我们使用DSPy最重点打造的FewShot采样优化,看下能否进一步提升效果。这里DSPy提供了多种优化器,适配不同的样本量级,这里考虑成本我们使用了基础的BootstrapFewShot,样本更多可以尝试BootstrapFewShotWithRandomSearch,或者BootstrapFewShotWithOptuna.
BootstrapFewShot可以指定few-shot中包含几个模型预测生成的样本(max_bootstrapped_demos),和几个真实标签的训练样本(max_labeld_demos) 。
teleprompter = BootstrapFewShot(metric=choice_match,
max_bootstrapped_demos=4,
max_labeled_demos=16)
compiled_qa = teleprompter.compile(singlechoice_qa_cot, trainset=train)
score3, results3, output3, df3 = evaluate_on_qa(compiled_qa, metric=choice_match,
return_outputs=True,
return_all_scores=True)
加入采样Few-Shot后的推理准确率提升到了75% ,使用2个推理Demos,和4个真实标签的Demos拼接而成的模型Prompt如下 。
再看下指令优化,这里使用的是COPRO优化器,也就是使用prompt让大模型基于原有prompt优化生成新的prompt,优化指令和第一轮优化生成的prompt如下 。
第二轮之后指令优化会给出之前尝试过的所有指令,和每个指令在验证集上的打分,并让模型进行有针对性的优化,称之为GenerateInstructionGivenAttempts,指令如下 。
在0.7的temperature下,每一轮模型会基于上一轮的最优prompt生成breadth=5个新的prompt,并重复以上过程depth=3轮,最后选取在验证集上效果最优的prompt.
COPRO_teleprompter = COPRO(prompt_model=model ,
metric=choice_match,
breadth=5,
depth=3,
init_temperature=0.7,
track_stats=True)
kwargs = dict(num_threads=1, display_progress=True, display_table=5)
COPRO_compiled_qa = COPRO_teleprompter.compile(singlechoice_qa_cot,
trainset=train,
eval_kwargs=kwargs)
print(model.inspect_history(n=1))
最终优化后的最优的prompt指令如下 。
但在测试集上最终并没有提升准确率还是60%,其中一个主要原因也是单选QA任务本身比较基础,在指令上可以优化的空间不算太大,指令优化再更复杂,非常规任务上的效果会更显著些.
整体上DSPy确实提供了模块化,标准化设计Prompt的方案,但是在任务描述上的优化方案现在还比较有限,上面GenerateInstructionGivenAttempts虽然提供了历史尝试过的指令和验证集打分,但缺少了模型从历史prompt的回答中总结模型当前指令存在什么问题的步骤,后面可能可以考虑更多reflection相关的指令优化方案像TextGrad,这个等我玩过再来总结吧~ 。
想看更全的大模型相关论文梳理·微调及预训练数据和框架·AIGC应用,移步Github >> DecryPrompt 。
最后此篇关于解密prompt系列35.标准化Prompt进行时!DSPy论文串烧和代码示例的文章就讲到这里了,如果你想了解更多关于解密prompt系列35.标准化Prompt进行时!DSPy论文串烧和代码示例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
某人在 Silverlight posted MVVM 目前缺乏标准化,所以每个人都有自己的风格.. 这就是为什么我和 WPF Disciples 的一些人正在积极讨论每个人都同意的 MVVM 元素。
我有以下数据集: dat tests2 * 20 Score 1 13.333333 2 10.666667 3 2.666667 4 9.333333 5 13.3333
我有一个 double 组,表示某些事件发生的概率,[25,25,25,10,15] 表示事件 A,B..E。这些数字加起来是 100。 通过我的分析,我希望能够排除某个事件发生或不发生的可能性。 所
USPS webtools 很贵,而且 Google Maps 没有某些地址。有没有免费或开源的解决方案? 最佳答案 根据您的业务性质,或者如果您是非营利或教育机构,有一家在线提供商可为您提供 fre
我有一个 json 对象,里面有对象例如 user: {"name": "tim"} 并希望有一种方法将其转换为 "user.name": 'tim' 我已经尝试过:Javascript Recurs
我有一个名为 spam 的数据集,其中包含与垃圾邮件相关的 58 列和大约 3500 行数据。 我计划将来对此数据集运行一些线性回归,但我想事先进行一些预处理并将列标准化为均值和单位方差为零。 我被告
我试图找到一种方法来强调音频中高点和低点之间的差异。我似乎找不到有关如何执行此操作的文档-也许可以使用ffmpeg完成。非常感谢来自对信号处理了解更多的人的一些指导。 最佳答案 从根本上讲,膨胀器与压
如何缩放/规范化每行数据(观察)?像 [-1:1] 这样的 z 分数? 我看过之前的帖子,其中涉及整个数据集的标准化,如下所示 https://stats.stackexchange.com/ques
例如: http://www.google.co.uk www.google.co.uk google.co.uk 将全部转换为: google.co.uk 我本来想使用 System.Uri 类,但
我可以使用此代码从 json 文件导入数据... import requests from pandas.io.json import json_normalize url = "https://da
规范化 Prolog 原子中空白字符(空格、换行符、制表符)的最佳方法是什么,例如在 SWI-Prolog 中。IE。我想要一个规则: normalize_space_in_atom(+Atom1,
如何缩放/规范化每行数据(观察)?像 [-1:1] 这样的 z 分数? 我看过之前的帖子,其中涉及整个数据集的标准化,如下所示 https://stats.stackexchange.com/ques
我正在尝试阅读代码片段,但它对我来说没有任何意义。请帮助我 /** * To make it easy to query for the exact date, we normalize all
我是一名研究人员,拥有大约 17,000 份自由文本文档,其中大约 30-40% 与我的结果相关。是否有一个开源工具可以用来确定与结果相关的最常见的单词(甚至短语,但不是必需的),并对已经出现的单词的
我正在尝试使用 L2 范数(单位长度)对 numpy 矩阵的行进行标准化。 当我这样做时,我发现了一个问题。 假设我的矩阵“b”如下: 现在,当我对第一行进行标准化时,如下所示,它工作正常。 但是当我
我有一个 3 列数组。数组的第一列的值介于 1 和 10 之间。我需要提取第一列为 1 的所有行,并规范化该数组切片的第三列。然后对第一列等于 2 等的所有行重复相同的操作。 如果我运行此代码,它会使
如果我通过许多不同的文件/脚本使用这个结构当需要更改时,如何才能只更改一个地方,而不必在每个文件中更改它。 u = contents incomingUrl = urlparse(u).query o
我有 1MB 的文本文件。我想删除空格、换行符、制表符,并以 4KB 迭代方式将 1MB 文件的字符大小写从小写转换为大写。 我写了这段代码: for (i = 0, j= 0; i 首先,让我们定
这实际上是一个机器学习分类问题,但我想有一种非常好的快速而肮脏的方法来做到这一点。我想将描述 NFL 球队的字符串(例如“San Francisco”或“49ers”或“San Francisco 4
我正在创建游戏评论数据库。我对此很陌生,但我正在尽力。关于数据库的一点点:系统很简单,用户填写 php 表单,在其中插入他的姓名、电子邮件,然后选择反馈是好还是坏并留下评论/建议。我正在添加照片的视觉
我是一名优秀的程序员,十分优秀!