跳到内容

度量

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 将跟踪您的语言模型调用。跟踪将包含每个 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