![[DSPy] 08.Metric :Programming—not prompting—Language Models](http://www.tmoremore.com/wp-content/uploads/2024/06/dspy.png)
DSPy는 머신 러닝 프레임워크이므로 평가(진행 상황 추적) 및 최적화(DSPy가 프로그램을 더 효과적으로 만들 수 있도록)를 위한 automatic metrics에 대해 고려해야 합니다.
metric이란 무엇이며 내 작업에 대한 metric을 어떻게 정의하나요?
메트릭은 데이터에서 예시를 가져와 시스템의 출력을 가져와 그 출력이 얼마나 좋은지 정량화한 점수를 반환하는 함수일 뿐입니다. 무엇이 시스템의 출력을 좋거나 나쁘게 만들까요?
간단한 작업의 경우 ‘정확도’ 또는 ‘정확히 일치’ 또는 ‘F1 점수’가 될 수 있습니다. 간단한 분류나 짧은 형식의 QA 작업이 이에 해당할 수 있습니다.
그러나 대부분의 애플리케이션의 경우, 시스템은 긴 형식의 결과물을 출력합니다. 여기서 메트릭은 아마도 출력의 여러 속성을 검사하는 더 작은 DSPy 프로그램일 것입니다(아마도 LM의 AI 피드백을 사용할 수도 있습니다).
첫 번째 시도에서 이 작업을 제대로 수행하기는 어렵겠지만 간단한 것부터 시작하여 반복해야 합니다.
Simple metrics
DSPy 메트릭은 예제(예: 학습 또는 개발 세트)와 DSPy 프로그램의 출력 예측을 가져와서 플로트(또는 int 또는 bool) 점수를 출력하는 Python의 함수일 뿐입니다.
메트릭은 trace라는 선택적 세 번째 인수도 허용해야 합니다. 잠시 무시해도 되지만 최적화를 위해 메트릭을 사용하려는 경우 몇 가지 강력한 트릭을 사용할 수 있습니다.
다음은 example.answer와 pred.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
여러 프로퍼티를 확인하는 등 메트릭이 더 복잡할 수 있습니다. 아래 메트릭은 트레이스가 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
좋은 지표를 정의하는 것은 반복적인 과정이므로 초기 평가를 수행하고 데이터와 결과물을 살펴보는 것이 중요합니다.
평가
metric이 있으면 간단한 Python 루프에서 평가를 실행할 수 있습니다.
scores = []
for x in devset:
pred = program(**x.inputs())
score = metric(x, pred)
scores.append(score)
일부 유틸리티가 필요한 경우, 기본 제공 평가 유틸리티를 사용할 수도 있습니다. 병렬 평가(여러 스레드)나 입력/출력 샘플 및 메트릭 점수 표시와 같은 작업에 도움이 될 수 있습니다.
from dspy.evaluate import Evaluate
# 코드에서 재사용할 수 있는 Evaluate를 설정하세요.
evaluator = Evaluate(devset=YOUR_DEVSET, num_threads=1, display_progress=True, display_table=5)
# 평가 시작.
evaluator(YOUR_PROGRAM, metric=YOUR_METRIC)
중급: metric에 AI 피드백 사용하기
대부분의 애플리케이션에서 시스템은 긴 형식의 출력을 출력하므로 메트릭은 LM의 AI 피드백을 사용하여 출력의 여러 차원을 확인해야 합니다. 이 간단한 서명이 유용할 수 있습니다.
# 자동 평가를 위한 서명을 정의합니다.
class Assess(dspy.Signature):
"""Assess the quality of a tweet along the specified dimension."""
assessed_text = dspy.InputField()
assessment_question = dspy.InputField()
assessment_answer = dspy.OutputField(desc="Yes or No")
예를 들어, 아래는 생성된 트윗이 (1) 주어진 질문에 올바르게 답변하는지, (2) 참여도가 높은지 확인하기 위해 GPT-4-turbo를 사용하는 간단한 측정지표입니다. 또한 (3) len(트윗) <= 280자인지도 확인합니다.
gpt4T = dspy.OpenAI(model='gpt-4-1106-preview', max_tokens=1000, model_type='chat')
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?"
with dspy.context(lm=gpt4T):
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.lower() == 'yes' 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
컴파일할 때 추적은 None이 아니며, 엄격하게 판단하고 싶기 때문에 점수가 >= 2인 경우에만 True를 반환합니다. 그렇지 않으면 1.0 만점의 점수를 반환합니다(즉, 점수 / 2.0).
고급: DSPy 프로그램을 metric으로 사용하기
메트릭 자체가 DSPy 프로그램인 경우 반복하는 가장 강력한 방법 중 하나는 메트릭 자체를 컴파일(최적화)하는 것입니다. 메트릭의 출력은 보통 단순한 값(예: 5점 만점)이므로 몇 가지 예제를 수집하여 메트릭의 메트릭을 쉽게 정의하고 최적화할 수 있기 때문에 이 방법은 일반적으로 쉽습니다.
고급: trace
에 액세스하기
평가 실행 중에 메트릭이 사용되는 경우 DSPy는 프로그램의 단계를 trace
하려고 시도하지 않습니다.
하지만 컴파일(최적화) 중에는 DSPy가 LM 호출을 trace
합니다. 이 trace
에는 각 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