百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

DSPy教程-第3章:DSPy的评估(Evaluation)

zhezhongyun 2025-03-19 18:34 63 浏览

3 DSPy 中的评估(Evaluation)

3.1 概述

有了初步的系统,下一步就是收集开发数据集,以便能更系统地对系统进行优化。建议数据集不低于20个(200个效果会好些)。根据开发的系统的评估指标不同,数据集可能只需要输入数据,不需要标签。也可能输入数据和最终输出都需要。

提示:可以在HuggingFace数据集或像StackExchange这样的找到与你任务相似的数据集。条件允许,建议使用这些数据。当然,你可以手动标注一些示例。

接下来,定义DSPy指标。什么样的输出是好的还是坏的。这需要投入精力来定义这些指标,并逐步优化;不然就很难持续进行改进。指标也是一个函数,它获取从数据输入,并根据输出的结果,返回一个评分。对于简单的任务,这评分可能是“准确率”,例如简单的分类或短问答任务等。对于大多数应用,系统会生成很长的输出,因此你的指标将是一个较小的DSPy程序,用于检查输出的多种属性。

有开发数据和DSPy指标函数,就可以运行评估来权衡你设计的流程控制。反复的查看输出和指标评分,来设定一个基线。

3.2 DSPy的数据对象

DSPy 是一个机器学习框架,其在工作通常用到训练集、开发集和测试集,每个示例(Example)是数据集最小组成单位。示例内部通常可以分为三类:输入、中间标签或者最终标签。示例可以没有中间标签或最终标签,但至少需要输入。接下来是我们要介绍的DSPy数据集示例:Example。

3.2.1 DSPy的 Example 对象

DSPy中的核心数据类型是Example。DSPy使用Example 来表示训练集和测试集中的项目。

Example类似于Python dict类型 ,但它可以包含一些工具。DSPy 模块返回 类型的值Prediction,是 Example 的一个特殊子类。

qa_pair = dspy.Example(question="This is a question?", answer="This is an answer.")

print(qa_pair)
print(qa_pair.question)
print(qa_pair.answer)

日志打印

Example({'question': 'This is a question?', 'answer': 'This is an answer.'}) (input_keys=None)
This is a question?
This is an answer.

Example的参数可以是任何字段键(Keys )和值类型(value),默认是字符串,单个Example如下:

object = Example(field1=value1, field2=value2, field3=value3, ...)

训练集是多个Example列表(list),如下:

trainset = [dspy.Example(report="LONG REPORT 1", summary="short summary 1"), ...]

3.2.2 Example 键的指定及访问

在传统的机器学习(Machine Learning, ML)中,数据通常被分为两部分:

  • 输入(Input):也称为特征(Features),是模型用来学习和预测的数据。例如,在图像分类任务中,输入可能是图像的像素值;在房价预测任务中,输入可能是房屋的面积、位置等信息。
  • 标签(Label):也称为目标(Target)或输出(Output),是模型需要预测的值。例如,在图像分类任务中,标签可能是图像的类别(如“猫”或“狗”);在房价预测任务中,标签可能是房屋的价格。

在 DSPy 中, Example 对象可以使用with_inputs()方法某个字段作为收入键input。(不标记则默认为元数据或标签键label)

# 单个输入,标记question为输入标签
print(qa_pair.with_inputs("question"))

# 多个输入;注意这里的answer也是输入
print(qa_pair.with_inputs("question", "answer"))

Example 对象可以通过. (点) 运算符来访问键的值。如:Example(name="John Doe", job="sleep"),可以通过object.name来访问name键的值。

也可以使用 inputs() 和 labels()方法,访问所有输入和标签的值如下:

# article已标记为inputs,summary未标记则默认为labels
article_summary = dspy.Example(article= "This is an article.", summary= "This is a summary.").with_inputs("article")

input_key_only = article_summary.inputs()
non_input_key_only = article_summary.labels()

print("Example object with Input fields only:", input_key_only)
print("Example object with Non-Input fields only:", non_input_key_only)

日志打印

Example object with Input fields only: Example({'article': 'This is an article.'}) (input_keys=None)
Example object with Non-Input fields only: Example({'summary': 'This is a summary.'}) (input_keys=None)

3.3 Metrics 指标

DSPy 是一个机器学习框架,因此需要考虑用于评估的自动指标(以跟踪进展)和用于优化的自动指标(以便 DSPy 可以使程序更有效)

3.3.1 指标概述

指标只是一个函数,它通过数据集的输入、获取系统输出,及返回评分。来衡量系统的输出效果是好是坏。

于简单的任务,如简单的分类或简短形式的问答任等,可以使用“准确率”或“精确匹配”或“F1 分数”来作为指标。

然而,对于大多数应用来说,需要输出很长的内容。那么,指标应该是一个较小的DSPy程序,用于检查输出的多个属性(很可能使用来自LM的AI反馈)。一次做到完美不太可能,应该从简单的东西开始,然后逐步改进。

3.3.2 简单的指标

DSPy 指标是一个 Python 函数, 它传入的参数主要是数据集example(训练集或开发) 和DSPy 程序的输出pred,返回评估的结果 float分数(int 或 bool )。

指标还可以传入第三个参数 trace[可选],可以暂时忽略这个参数,在以后得高阶技能,这个参数非常重要。

下面是一个简单的示例,指标是比较 example.answer 和 pred.answer 是否相对,返回一个 bool 值。

def validate_answer(example, pred, trace=None):
    return example.answer.lower() == pred.answer.lower()

上面的例子也可以改用DSPy内置的工具进行比较:

  • dspy.evaluate.metrics.answer_exact_match

上例的指标可以改成的复杂点,例如检查多个属性。如下:

  • 当用于评估或优化时,返回一个浮点数;
  • 当用于启动示范时,返回一个布尔值。
def validate_context_and_answer(example, pred, trace=None):
    # check the gold label and the predicted answer are the same
    answer_match = example.answer.lower() == pred.answer.lower()

    # check the predicted answer comes from one of the retrieved contexts
    context_match = any((pred.answer.lower() in c) for c in pred.context)

    if trace is None: # if we're doing evaluation or optimization
        return (answer_match + context_match) / 2.0
    else: # if we're doing bootstrapping, i.e. self-generating good demonstrations of each step
        return answer_match and context_match

提示:定义一个好的指标函数是一个迭代过程,进行初步评估并查看数据和输出是关键。

3.3.3 Evaluation 评估指标

有了指标函数,现在可以进行循环评估了。

scores = []
for x in devset:
    pred = program(**x.inputs())
    score = metric(x, pred)
    scores.append(score)

Evaluate 内置了一些工具,可以帮助进行并行评估(多线程)或显示输入/输出样本以及指标评分。

from dspy.evaluate import Evaluate

# Set up the evaluator, which can be re-used in your code.
evaluator = Evaluate(devset=YOUR_DEVSET, num_threads=1, display_progress=True, display_table=5)

# Launch evaluation.
evaluator(YOUR_PROGRAM, metric=YOUR_METRIC)

3.3.4 中级:使用AI反馈优化指标

对于大多数应用,系统会输出长格式的内容,因此指标应该使用来自语言模型(LM)的AI反馈来检查输出的多个维度。下面是一个Signature的简单例子:

# Define the signature for automatic assessments.
class Assess(dspy.Signature):
    """Assess the quality of a tweet along the specified dimension."""

    assessed_text = dspy.InputField()
    assessment_question = dspy.InputField()
    assessment_answer: bool = dspy.OutputField()

例如,下面是一个简单的指标,用于检查生成的推文.评估维度为:

  1. 是否正确回答了给定的问题;
  2. 是否具有吸引力;
  3. len(tweet) <= 280 个字符。
def metric(gold, pred, trace=None):
    question, answer, tweet = gold.question, gold.answer, pred.output

    engaging = "Does the assessed text make for a self-contained, engaging tweet?"
    correct = f"The text should answer `{question}` with `{answer}`. Does the assessed text contain this answer?"

    correct =  dspy.Predict(Assess)(assessed_text=tweet, assessment_question=correct)
    engaging = dspy.Predict(Assess)(assessed_text=tweet, assessment_question=engaging)

    correct, engaging = [m.assessment_answer for m in [correct, engaging]]
    score = (correct + engaging) if correct and (len(tweet) <= 280 else 0 if trace is not none: return score>= 2
    return score / 2.0

当 trace is not None 为 True 时,返回 score >= 2 。否则,将返回一个介于 0 到 1 之间的分数(即, score / 2.0 )。

3.3.5 高级:使用 DSPy 程序作为指标

如果你的评估指标本身是一个 DSPy 程序(优化器optimize),它的迭代方法是编译这个评估指标本身,只需要通过收集几个例子即可。

高级:访问 trace

当你的指标在评估运行中被使用时,DSPy 不会尝试跟踪你程序的步骤。

但在编译(优化器optimize)过程中,DSPy 会跟踪你的 LM 调用。跟踪信息将包含每个 DSPy 预测器的输入/输出,你可以利用这些信息验证优化过程中的中间步骤。

def validate_hops(example, pred, trace=None):
    hops = [example.question] + [outputs.query for *_, outputs in trace if 'query' in outputs]

    if max([len(h) for h in hops]) > 100: return False
    if any(dspy.evaluate.answer_exact_match_str(hops[idx], hops[:idx], frac=0.8) for idx in range(2, len(hops))): return False

    return True

相关推荐

3 分钟!AI 从零开发五子棋全过程曝光,网友:这效率我服了

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8...

一行代码实现display&quot;过渡动画&quot;原理

作者:Peter谭老师转发链接:https://mp.weixin.qq.com/s/XhwPOv62gypzq5MhhP-5vg写本文的起因上篇文章,提到如何让display出现过渡动画,却没有仔...

脑洞:琼恩·雪诺、蝙蝠侠和魔形女的灵魂宠物了解一下

AlekseiVinogradovisaRussianfreelancedigitalartistwhoshareshisskillsandtalentwith120k...

浏览器的渲染机制、重绘、重排

1、什么是重排和重绘网页生成过程:HTML被HTML解析器解析成DOM树css则被css解析器解析成CSSOM树结合DOM树和CSSOM树,生成一棵渲染树(RenderTree)生成布局(flo...

托福写作高频考题写作思路&amp;词汇丨考虫独家

科技话题与媒体话题是托福写作的常考话题很多考生对这两类话题里的专有词汇表达也许很不了解所以今天就跟随考虫托福写作老师刘云龙老师一起来学习在这些话题的写作里你可以使用哪些有用的表达。希望大家有收获!记得...

在优麒麟上使用 Electron 开发桌面应用

使用Web标准来创建桌面GUI,上手快、成本低、跨平台、自适应分辨率,这些都是Electron的优势。作者/来源:优麒麟Electron是由Github开发,用HTML、CSS和...

php手把手教你做网站(三十八)jquery 转轮盘抽奖,开盲盒

抽奖和开盲盒性质一样的都是通过ajax读取后台的随机数据。1、转轮盘本来是想直接绘图实现轮盘,但是没有找到怎么填充文字,只好把轮盘弄成了背景图,通常用于游戏抽道具,商城积分抽奖,公司年末员工抽奖点击抽...

用 CSS 整活!3D 轮播图手把手教学,快乐代码敲出来

兄弟们,今天咱来搞点好玩的——用CSS整一个3D轮播图!咱野生程序员就是要在代码里找乐子,技术和快乐咱都得要!代码是写不完的,但咱能自己敲出快乐来,走起!一、先整个容器,搭个舞台咋先写一个...

实现一个超酷的 3D 立体卡片效 #前端开发

今天我们来实现一个超酷的3D立体卡片效果。正常情况下就是一个普通的图片展示卡片,鼠标悬停的时候图片会跳出卡片,并将影子投射到背景卡片上,在视觉上有一个3D立体感。html主要分成3个部分:容器→背景层...

Vue 3 Teleport与Suspense:解决UI难题的两个&quot;隐藏大招&quot;

模态框的"层级噩梦"与Teleport的救赎"这个模态框怎么又被父容器截断了?"团队协作开发后台系统时,小张第N次遇到这个问题。多层嵌套的组件结构里,弹窗被overfl...

让交互更加生动!有意思的鼠标跟随 3D 旋转动效

今天,群友问了这样一个问题,如下所示的鼠标跟随交互效果,如何实现:简单分析一下,这个交互效果主要有两个核心:借助了CSS3D的能力元素的旋转需要和鼠标的移动相结合本文,就将讲述如何使用纯CSS...

填坑:transform元素导致zindex失效终极方法

今天遇到了使用css3动画的元素层级被放大置顶的问题,ios浏览器上没问题,安卓原生浏览器和安卓微信上有问题。使用了css3动画的元素z-index失效,兄弟元素设置多高的z-index都盖不住解决办...

诡异的层级错乱:一个被transform隐藏的CSS陷阱

周五下午三点十七分,设计部突然发来紧急截图——原本应该悬浮在顶部的导航菜单,此刻正诡异地被下方的轮播图遮挡。我盯着屏幕上错乱的层级关系,手指下意识地敲下z-index:9999,心里清楚这不过是程序...

动画篇--碎片动画

本文授权转载,作者:Sindri的小巢(简书)前言从最开始动笔动画篇的博客,至今已经过去了四个多月。这段时间回头看了看自己之前的动画文章,发现用来讲解动画的例子确实不那么的赏心悦目。于是这段时间总是想...

Nature:大洋转换断层处的拉张构造与两阶段地壳增生

Nature:大洋转换断层处的拉张构造与两阶段地壳增生转换断层是三种基本的板块边界之一,全球总长度超过48000km(Bird,2003),它们的发现为板块构造理论的建立奠定了重要的基础(Wil...