跳至内容

指标

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

什么是评估指标以及如何为我的任务定义评估指标?

指标只是一个函数,它会从你的数据中获取示例和系统的输出,并返回一个分数来量化输出的好坏程度。什么使你的系统输出好或坏?

对于简单任务,这可能是"准确率"或"精确匹配"或"F1分数"。对于简单分类或短问答任务可能就是这种情况。

然而,对于大多数应用来说,你的系统会输出长格式的输出。在那里,你的指标应该是一个较小的DSPy程序,用于检查输出的多个属性(很可能会使用来自语言模型的AI反馈)。

第一次尝试就做对的可能性不大,但你应该从简单开始并迭代。

简单指标

DSPy指标只是Python中的一个函数,它接收example(例如来自您的训练集或开发集)和您的DSPy程序的输出pred,并输出一个float(或intbool)分数。

你的指标还应接受一个可选的第三个参数,称为trace。你可以暂时忽略它,但如果你想将你的指标用于优化,它将支持一些强大的技巧。

这是一个简单的指标示例,用于比较 example.answerpred.answer。该特定指标将返回一个 bool 值。

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

一些人觉得这些(内置)工具很方便:

  • dspy.evaluate.metrics.answer_exact_match
  • dspy.evaluate.metrics.answer_passage_match

您的指标可以更复杂,例如检查多个属性。如果trace is None(即用于评估或优化时),下面的指标将返回一个float,否则(即用于引导演示时)将返回一个bool

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

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

评估

一旦你有了一个指标,就可以在一个简单的 Python 循环中运行评估。

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)

中级:使用AI反馈作为你的评估指标

对于大多数应用,您的系统会输出长格式输出,因此您的指标应使用来自语言模型的AI反馈来检查输出的多个维度。

这个简单的签名可能会派上用场。

# 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,我们希望严格判断事物,因此只有当score >= 2时才返回True。否则,我们返回一个基于1.0的分数(即score / 2.0)。

高级:使用DSPY程序作为您的评估指标

如果你的评估指标本身就是一个DSPY程序,最强大的迭代方式之一就是编译(优化)你的评估指标本身。这通常很简单,因为评估指标的输出通常是一个简单的值(例如,5分制得分),因此通过收集一些示例,评估指标的评估指标很容易定义和优化。

高级:访问 trace

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

但是在编译(优化)过程中,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
优云智算