Chapter 5

CoPA Method

Combined Fine-Tuning and Prompt Optimization: Discover how to achieve 2-26x performance gains by synergizing model weight updates with prompt optimization.

Introduction

COPA (Compiler and Prompt Optimization Algorithm) represents the cutting edge of DSPy optimization by combining two powerful techniques: fine-tuning and prompt optimization. While each technique individually provides significant improvements, COPA demonstrates that combining them creates synergistic effects that exceed additive improvements, often achieving 2-26x performance gains.

The Joint Optimization Problem

Traditional DSPy optimization operates at a single level: either you fine-tune model weights OR you optimize prompts. COPA treats this as a two-level parameter problem:

  • Level 1 - Weights (W): Model parameters modified through fine-tuning.
  • Level 2 - Prompts (P): Instructions and demonstrations optimized by DSPy.
# The joint optimization objective:
# argmax_{W, P} E[metric(program(W, P), examples)]

💻 Implementing COPA

A basic COPA implementation optimizes in two stages: first fine-tuning the base model, then applying prompt optimization.

class COPAOptimizer:
    def optimize(self, program, trainset, valset, finetune_data=None):
        """
        Two-stage optimization:
        1. Fine-tune the base model
        2. Apply prompt optimization to the fine-tuned model
        """
        # Stage 1: Fine-tuning
        print("Stage 1: Fine-tuning base model...")
        finetuned_model = self._finetune(
            trainset if finetune_data is None else finetune_data
        )

        # Configure DSPy to use fine-tuned model
        finetuned_lm = self._create_dspy_lm(finetuned_model)
        dspy.settings.configure(lm=finetuned_lm)

        # Stage 2: Prompt optimization
        print("Stage 2: Applying prompt optimization...")
        if self.prompt_optimizer == "mipro":
            optimizer = MIPRO(
                metric=self.metric,
                num_candidates=15,
                auto="medium"
            )
        else:
            optimizer = BootstrapFewShot(
                metric=self.metric,
                max_bootstrapped_demos=8
            )

        compiled_program = optimizer.compile(
            program,
            trainset=trainset,
            valset=valset
        )

        return compiled_program, finetuned_model

Monte Carlo Methods

COPA can use Monte Carlo methods to efficiently explore the vast space of possible prompt configurations.

class MonteCarloPromptExplorer:
    def explore(self, program, prompt_templates, demo_pool, metric, trainset):
        results = []
        for _ in range(self.num_samples):
            # Sample instruction and demonstrations
            instruction = np.random.choice(prompt_templates)
            demos = np.random.choice(demo_pool, size=num_demos, replace=False)
            
            # Configure and evaluate
            config = {"instruction": instruction, "demonstrations": demos}
            score = self._evaluate_config(program, config, metric, trainset)
            results.append({"config": config, "score": score})
            
        return max(results, key=lambda x: x["score"])

Bayesian Optimization

For even more efficiency, Bayesian optimization uses a Gaussian Process surrogate model to intelligently search the prompt configuration space.

# Bayesian optimization loop
for iteration in range(n_iterations):
    # Fit surrogate model
    surrogate = self._fit_surrogate()

    # Find next point using acquisition function (e.g., Expected Improvement)
    next_config = self._maximize_acquisition(surrogate, prompt_space)

    # Evaluate and update observations
    score = self._evaluate(program, next_config, metric, valset)
    self.observed_configs.append(next_config)
    self.observed_scores.append(score)

🚀 Performance Benchmarks

Combining fine-tuning and prompt optimization yields impressive results:

Model Baseline Fine-Tuning Only Prompt Opt Only COPA Improvement
Llama-7B 12.3% 28.5% 19.7% 45.2% 3.7x
Mistral-7B 18.7% 35.2% 31.4% 62.8% 3.4x