dspy.BetterTogether
dspy.BetterTogether
BetterTogether는 논문 Fine-Tuning and Prompt Optimization: Two Great Steps that Work Better Together(Dilara Soylu, Christopher Potts, Omar Khattab)에서 제안한 메타 옵티마이저입니다. 프롬프트 최적화와 가중치 최적화(파인튜닝)를 설정 가능한 순서로 결합해, student 프로그램이 프롬프트와 모델 파라미터를 모두 반복적으로 개선하게 합니다.
출처: 문서
본문
dspy.BetterTogether(metric: Callable, **optimizers: Teleprompter)
- Bases:
Teleprompter
프롬프트 최적화와 가중치 최적화를 설정 가능한 순서로 결합하는 메타 옵티마이저입니다.
BetterTogether는 논문 Fine-Tuning and Prompt Optimization: Two Great Steps that Work Better Together에서 제안한 메타 옵티마이저입니다. 프롬프트 최적화와 가중치 최적화(파인튜닝)를 설정 가능한 순서로 적용해, student 프로그램이 프롬프트와 모델 파라미터를 모두 반복적으로 개선하게 합니다.
핵심 통찰은 프롬프트 최적화와 가중치 최적화가 서로 보완할 수 있다는 점입니다. 프롬프트 최적화는 효과적인 작업 분해와 추론 전략을 발견할 수 있고, 가중치 최적화는 모델이 이러한 패턴을 더 효율적으로 실행하도록 특화시킬 수 있습니다. 이 둘을 시퀀스로 함께 사용하면(예: 프롬프트 최적화 후 가중치 최적화) 각각이 상대방의 개선 위에 쌓일 수 있습니다. 경험적으로 이 접근법은 최첨단 옵티마이저를 사용할 때도 단독 전략보다 자주 더 좋은 성능을 냅니다. 예를 들어 Databricks 사례 연구는 BetterTogether를 GEPA와 파인튜닝과 함께 결합한 것이 어느 한쪽 단독보다 우월함을 보여줍니다.
이 옵티마이저는 metric과 커스텀 옵티마이저로 초기화됩니다. 예를 들어 프롬프트 최적화용 GEPA와 가중치 최적화용 BootstrapFinetune을 결합할 수 있습니다: BetterTogether(metric=metric, p=GEPA(...), w=BootstrapFinetune(...)). compile() 메서드는 student 프로그램, trainset, 그리고 초기화 시 옵티마이저 이름에 대응하는 strategy 문자열을 받습니다. 지정된 순서로 각 옵티마이저를 실행합니다. 검증 세트가 주어지면 가장 좋은 성능을 낸 프로그램을 반환하고, 그렇지 않으면 마지막 프로그램을 반환합니다.
참고: BootstrapFinetune 같은 가중치 옵티마이저는 student 프로그램이 전역
dspy.settings.lm에 의존하지 않고 명시적으로 LM을 설정해야 하며, BetterTogether도 단순화를 위해 이 요구사항을 그대로 따릅니다. 그래서 컴파일 전에set_lm을 호출합니다.
>>> from dspy.teleprompt import GEPA, BootstrapFinetune
>>>
>>> # Combine GEPA for prompt optimization with BootstrapFinetune for weight optimization
>>> optimizer = BetterTogether(
... metric=metric,
... p=GEPA(metric=metric, auto="medium"),
... w=BootstrapFinetune(metric=metric)
... )
>>>
>>> student.set_lm(lm)
>>> compiled = optimizer.compile(
... student,
... trainset=trainset,
... valset=valset,
... strategy="p -> w"
... )
각 옵티마이저의 compile() 메서드에 옵티마이저 특화 인자를 optimizer_compile_args로 전달해 각 옵티마이저의 동작을 커스터마이즈할 수 있습니다:
>>> from dspy.teleprompt import MIPROv2
>>>
>>> # Use MIPROv2 for prompt optimization with custom parameters
>>> optimizer = BetterTogether(
... metric=metric,
... p=MIPROv2(metric=metric),
... w=BootstrapFinetune(metric=metric)
... )
>>>
>>> student.set_lm(lm)
>>> compiled = optimizer.compile(
... student,
... trainset=trainset,
... valset=valset,
... strategy="p -> w",
... optimizer_compile_args={
... "p": {"num_trials": 10, "max_bootstrapped_demos": 8}, # Configure MIPROv2's compile arguments
... }
... )
BetterTogether는 시퀀스로 임의의 옵티마이저를 실행할 수 있는 메타 옵티마이저이므로 어떤 옵티마이저 시퀀스든 결합할 수 있습니다. strategy 문자열에 사용되는 옵티마이저 이름은 생성자에 지정한 키워드 인자에 대응합니다. 예를 들어 서로 다른 프롬프트 옵티마이저를 여러 번 번갈아 사용할 수 있습니다(이것은 권장 설정이 아니라 BetterTogether의 유연성을 보여주는 예시입니다):
>>> from dspy.teleprompt import MIPROv2, GEPA
>>>
>>> # Chain two optimizers three times: MIPROv2 -> GEPA -> MIPROv2
>>> optimizer = BetterTogether(
... metric=metric,
... mipro=MIPROv2(metric=metric, auto="light"),
... gepa=GEPA(metric=metric, auto="light")
... )
Methods
compile(student, *, trainset, teacher=None, valset=None, num_threads=None, max_errors=None, provide_traceback=None, seed=None, valset_ratio=0.1, shuffle_trainset_between_steps=True, strategy="p -> w -> p", optimizer_compile_args=None) -> Module
def compile(
self,
student: Module,
*,
trainset: list[Example],
teacher: Module | list[Module] | None = None,
valset: list[Example] | None = None,
# often specified in init in other optimizers
num_threads: int | None = None,
max_errors: int | None = None,
provide_traceback: bool | None = None,
seed: int | None = None,
# specific to BetterTogether
valset_ratio: float = 0.1,
shuffle_trainset_between_steps: bool = True,
strategy: str = "p -> w -> p",
optimizer_compile_args: dict[str, dict[str, Any]] | None = None,
) -> Module:
"""Compile and optimize a student program using a sequence of optimization strategies.
Executes the optimizers specified...
"""
compile은 strategy 문자열("p -> w -> p" 등)에 지정된 순서로 옵티마이저들을 실행해 student 프로그램을 최적화합니다. valset이 없으면 valset_ratio(기본 0.1)만큼 trainset을 나눠 검증 세트로 씁니다. shuffle_trainset_between_steps=True면 단계 사이에 trainset을 섞습니다. 각 옵티마이저에 전달할 컴파일 인자는 optimizer_compile_args로 지정합니다. 검증 세트가 있으면 가장 좋은 프로그램을, 없으면 마지막 프로그램을 반환합니다.
get_params() -> dict[str, Any]
텔레프롬프터의 파라미터를 반환합니다.