Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 19 additions & 19 deletions docs/docs/cheatsheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ evaluate_program(your_dspy_program)
from dspy.teleprompt import LabeledFewShot

labeled_fewshot_optimizer = LabeledFewShot(k=8)
your_dspy_program_compiled = labeled_fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
your_dspy_program_optimized = labeled_fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
```

### BootstrapFewShot
Expand All @@ -188,34 +188,34 @@ from dspy.teleprompt import BootstrapFewShot

fewshot_optimizer = BootstrapFewShot(metric=your_defined_metric, max_bootstrapped_demos=4, max_labeled_demos=16, max_rounds=1, max_errors=10)

your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
your_dspy_program_optimized = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
```

#### Using another LM for compilation, specifying in teacher_settings
#### Using another LM for optimization, specifying in teacher_settings

```python
from dspy.teleprompt import BootstrapFewShot

fewshot_optimizer = BootstrapFewShot(metric=your_defined_metric, max_bootstrapped_demos=4, max_labeled_demos=16, max_rounds=1, max_errors=10, teacher_settings=dict(lm=gpt4))

your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
your_dspy_program_optimized = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset)
```

#### Compiling a compiled program - bootstrapping a bootstrapped program
#### Optimizing an optimized program - bootstrapping a bootstrapped program

```python
your_dspy_program_compiledx2 = teleprompter.compile(
your_dspy_program_optimizedx2 = teleprompter.compile(
your_dspy_program,
teacher=your_dspy_program_compiled,
teacher=your_dspy_program_optimized,
trainset=trainset,
)
```

#### Saving/loading a compiled program
#### Saving/loading an optimized program

```python
save_path = './v1.json'
your_dspy_program_compiledx2.save(save_path)
your_dspy_program_optimizedx2.save(save_path)
```

```python
Expand All @@ -232,7 +232,7 @@ from dspy.teleprompt import BootstrapFewShotWithRandomSearch

fewshot_optimizer = BootstrapFewShotWithRandomSearch(metric=your_defined_metric, max_bootstrapped_demos=2, num_candidate_programs=8, num_threads=NUM_THREADS)

your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset, valset=devset)
your_dspy_program_optimized = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset, valset=devset)

```

Expand All @@ -245,26 +245,26 @@ from dspy.teleprompt import BootstrapFewShotWithRandomSearch
from dspy.teleprompt.ensemble import Ensemble

fewshot_optimizer = BootstrapFewShotWithRandomSearch(metric=your_defined_metric, max_bootstrapped_demos=2, num_candidate_programs=8, num_threads=NUM_THREADS)
your_dspy_program_compiled = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset, valset=devset)
your_dspy_program_optimized = fewshot_optimizer.compile(student = your_dspy_program, trainset=trainset, valset=devset)

ensemble_optimizer = Ensemble(reduce_fn=dspy.majority)
programs = [x[-1] for x in your_dspy_program_compiled.candidate_programs]
your_dspy_program_compiled_ensemble = ensemble_optimizer.compile(programs[:3])
programs = [x[-1] for x in your_dspy_program_optimized.candidate_programs]
your_dspy_program_optimized_ensemble = ensemble_optimizer.compile(programs[:3])
```

### BootstrapFinetune

```python
from dspy.teleprompt import BootstrapFewShotWithRandomSearch, BootstrapFinetune

#Compile program on current dspy.settings.lm
#Optimize program on current dspy.settings.lm
fewshot_optimizer = BootstrapFewShotWithRandomSearch(metric=your_defined_metric, max_bootstrapped_demos=2, num_threads=NUM_THREADS)
your_dspy_program_compiled = tp.compile(your_dspy_program, trainset=trainset[:some_num], valset=trainset[some_num:])
your_dspy_program_optimized = tp.compile(your_dspy_program, trainset=trainset[:some_num], valset=trainset[some_num:])

#Configure model to finetune
config = dict(target=model_to_finetune, epochs=2, bf16=True, bsize=6, accumsteps=2, lr=5e-5)

#Compile program on BootstrapFinetune
#Optimize program on BootstrapFinetune
finetune_optimizer = BootstrapFinetune(metric=your_defined_metric)
finetune_program = finetune_optimizer.compile(your_dspy_program, trainset=some_new_dataset_for_finetuning_model, **config)

Expand All @@ -290,7 +290,7 @@ eval_kwargs = dict(num_threads=16, display_progress=True, display_table=0)

copro_teleprompter = COPRO(prompt_model=model_to_generate_prompts, metric=your_defined_metric, breadth=num_new_prompts_generated, depth=times_to_generate_prompts, init_temperature=prompt_generation_temperature, verbose=False)

compiled_program_optimized_signature = copro_teleprompter.compile(your_dspy_program, trainset=trainset, eval_kwargs=eval_kwargs)
optimized_program_optimized_signature = copro_teleprompter.compile(your_dspy_program, trainset=trainset, eval_kwargs=eval_kwargs)
```

### MIPROv2
Expand Down Expand Up @@ -367,7 +367,7 @@ from dspy import ChainOfThought

knn_optimizer = KNNFewShot(k=3, trainset=trainset, vectorizer=Embedder(SentenceTransformer("all-MiniLM-L6-v2").encode))

qa_compiled = knn_optimizer.compile(student=ChainOfThought("question -> answer"))
qa_optimized = knn_optimizer.compile(student=ChainOfThought("question -> answer"))
```

### BootstrapFewShotWithOptuna
Expand All @@ -377,7 +377,7 @@ from dspy.teleprompt import BootstrapFewShotWithOptuna

fewshot_optuna_optimizer = BootstrapFewShotWithOptuna(metric=your_defined_metric, max_bootstrapped_demos=2, num_candidate_programs=8, num_threads=NUM_THREADS)

your_dspy_program_compiled = fewshot_optuna_optimizer.compile(student=your_dspy_program, trainset=trainset, valset=devset)
your_dspy_program_optimized = fewshot_optuna_optimizer.compile(student=your_dspy_program, trainset=trainset, valset=devset)
```

Other custom configurations are similar to customizing the `dspy.BootstrapFewShot` optimizer.
Expand Down
8 changes: 4 additions & 4 deletions docs/docs/faqs.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@ Compiling DSPy `optimizers` naturally will incur additional LM calls, but we sub
Here is an example of saving/loading a compiled module:

```python
cot_compiled = teleprompter.compile(CoT(), trainset=trainset, valset=devset)
cot_optimized = teleprompter.compile(CoT(), trainset=trainset, valset=devset)

#Saving
cot_compiled.save('compiled_cot_gsm8k.json')
cot_optimized.save('optimized_cot_gsm8k.json')

#Loading:
cot = CoT()
cot.load('compiled_cot_gsm8k.json')
cot.load('optimized_cot_gsm8k.json')
```

- **How do I export for deployment?**
Expand Down Expand Up @@ -94,7 +94,7 @@ You can parallelize DSPy programs during both compilation and evaluation by spec

- **How do freeze a module?**

Modules can be frozen by setting their `._compiled` attribute to be True, indicating the module has gone through optimizer compilation and should not have its parameters adjusted. This is handled internally in optimizers such as `dspy.BootstrapFewShot` where the student program is ensured to be frozen before the teacher propagates the gathered few-shot demonstrations in the bootstrapping process.
Module parameters are automatically managed during optimization. When using optimizers like `dspy.BootstrapFewShot`, the framework ensures proper handling of parameter updates during the compilation process. The framework tracks which modules should have their parameters adjusted during different phases of optimization automatically.

- **How do I use DSPy assertions?**

Expand Down
16 changes: 5 additions & 11 deletions dspy/primitives/base_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,8 @@ def add_parameter(param_name, param_value):
named_parameters.append((param_name, param_value))

elif isinstance(param_value, dspy.Module):
# When a sub-module is pre-compiled, keep it frozen.
if not getattr(param_value, "_compiled", False):
for sub_name, param in param_value.named_parameters():
add_parameter(f"{param_name}.{sub_name}", param)
for sub_name, param in param_value.named_parameters():
add_parameter(f"{param_name}.{sub_name}", param)

if isinstance(self, Parameter):
add_parameter("self", self)
Expand All @@ -51,10 +49,8 @@ def add_parameter(param_name, param_value):
add_parameter(name, value)

elif isinstance(value, dspy.Module):
# When a sub-module is pre-compiled, keep it frozen.
if not getattr(value, "_compiled", False):
for sub_name, param in value.named_parameters():
add_parameter(f"{name}.{sub_name}", param)
for sub_name, param in value.named_parameters():
add_parameter(f"{name}.{sub_name}", param)

elif isinstance(value, (list, tuple)):
for idx, item in enumerate(value):
Expand All @@ -66,7 +62,7 @@ def add_parameter(param_name, param_value):

return named_parameters

def named_sub_modules(self, type_=None, skip_compiled=False) -> Generator[tuple[str, "BaseModule"], None, None]:
def named_sub_modules(self, type_=None) -> Generator[tuple[str, "BaseModule"], None, None]:
"""Find all sub-modules in the module, as well as their names.

Say `self.children[4]['key'].sub_module` is a sub-module. Then the name will be
Expand All @@ -91,8 +87,6 @@ def add_to_queue(name, item):
yield name, item

if isinstance(item, BaseModule):
if skip_compiled and getattr(item, "_compiled", False):
continue
for sub_name, sub_item in item.__dict__.items():
add_to_queue(f"{name}.{sub_name}", sub_item)

Expand Down
2 changes: 0 additions & 2 deletions dspy/primitives/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,11 @@ def __call__(cls, *args, **kwargs):

class Module(BaseModule, metaclass=ProgramMeta):
def _base_init(self):
self._compiled = False
self.callbacks = []
self.history = []

def __init__(self, callbacks=None):
self.callbacks = callbacks or []
self._compiled = False
# LM calling history of the module.
self.history = []

Expand Down
1 change: 0 additions & 1 deletion dspy/teleprompt/bettertogether.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ def _run_strategies(self, parsed_strategy, student, trainset, valset_ratio) -> M
# TODO: Should we reset or just deepcopy? How does resetting affect
# the predictor LMs?
student = student.deepcopy()
student._compiled = False
if step_code == "p":
student = self._compile_prompt_optimizer(student, trainset, valset_ratio)
elif step_code == "w":
Expand Down
4 changes: 1 addition & 3 deletions dspy/teleprompt/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ def compile(self, student, *, teacher=None, trainset):
self._bootstrap()

self.student = self._train()
self.student._compiled = True

return self.student

Expand All @@ -96,9 +95,8 @@ def _prepare_student_and_teacher(self, student, teacher):
# NOTE: behavior change on Oct 28, 2024. Deep copy instead of reset copy for the student-as-teacher.
self.teacher = teacher.deepcopy() if teacher is not None else student.deepcopy()

assert getattr(self.student, "_compiled", False) is False, "Student must be uncompiled."

if self.max_labeled_demos and getattr(self.teacher, "_compiled", False) is False:
if self.max_labeled_demos:
teleprompter = LabeledFewShot(k=self.max_labeled_demos)
self.teacher = teleprompter.compile(self.teacher.reset_copy(), trainset=self.trainset)

Expand Down
4 changes: 1 addition & 3 deletions dspy/teleprompt/bootstrap_finetune.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ def compile(
pred.demos = [] if self.exclude_demos else pred.demos

logger.info("BootstrapFinetune has finished compiling the student program")
student._compiled = True
return student

@staticmethod
Expand Down Expand Up @@ -254,8 +253,7 @@ def copy_program_with_lms(program: Module) -> Module:


def prepare_student(student: Module) -> Module:
if getattr(student, "_compiled", False):
raise ValueError("The student program should not be compiled.")
# Student program preparation - no compilation check needed

# TODO: Should we use reset_copy here? How would it affect the student
# program's predictor LMs, if they are set?
Expand Down
3 changes: 2 additions & 1 deletion dspy/teleprompt/ensemble.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ def forward(self, *args, **kwargs):

return outputs

return EnsembledProgram()
ensembled_program = EnsembledProgram()
return ensembled_program
1 change: 0 additions & 1 deletion dspy/teleprompt/grpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,6 @@ def compile(
recover_lm_cache(program=t, lm_cache_dict=lm_cache_dict)

logger.info("GRPO compiler has finished compiling the student program")
student._compiled = True
return student


Expand Down
10 changes: 5 additions & 5 deletions tests/examples/test_baleen.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def gold_passages_retrieved(example, pred, trace=None):

# @pytest.mark.slow_test
# TODO: Find a way to make this test run without the slow hotpotqa dataset
def _test_compiled_baleen():
def _test_optimized_baleen():
trainset, devset = load_hotpotqa()
lm = dspy.OpenAI(model="gpt-3.5-turbo")
rm = dspy.ColBERTv2(url="http://20.102.90.50:2017/wiki17_abstracts")
Expand All @@ -103,7 +103,7 @@ def _test_compiled_baleen():
uncompiled_baleen = SimplifiedBaleen() # uncompiled (i.e., zero-shot) program

teleprompter = BootstrapFewShot(metric=validate_context_and_answer_and_hops)
compiled_baleen = teleprompter.compile(
optimized_baleen = teleprompter.compile(
SimplifiedBaleen(),
teacher=SimplifiedBaleen(passages_per_hop=2),
trainset=trainset,
Expand All @@ -115,6 +115,6 @@ def _test_compiled_baleen():
)
# assert uncompiled_baleen_retrieval_score / 100 == 18 / 50

compiled_baleen_retrieval_score = evaluate_on_hotpotqa(compiled_baleen, metric=gold_passages_retrieved)
# assert compiled_baleen_retrieval_score / 100 == 27 / 50
assert uncompiled_baleen_retrieval_score < compiled_baleen_retrieval_score
optimized_baleen_retrieval_score = evaluate_on_hotpotqa(optimized_baleen, metric=gold_passages_retrieved)
# assert optimized_baleen_retrieval_score / 100 == 27 / 50
assert uncompiled_baleen_retrieval_score < optimized_baleen_retrieval_score
4 changes: 3 additions & 1 deletion tests/primitives/test_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ def forward(self, question):

def test_module_initialization():
module = Module()
assert module._compiled is False, "Module _compiled attribute should be False upon initialization"
# Module should be properly initialized with callbacks and history
assert hasattr(module, "callbacks"), "Module should have callbacks attribute"
assert hasattr(module, "history"), "Module should have history attribute"


def test_named_predictors():
Expand Down
2 changes: 1 addition & 1 deletion tests/teleprompt/test_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def test_compile_with_predict_instances():
compiled_student = bootstrap.compile(student, teacher=teacher, trainset=trainset)

assert compiled_student is not None, "Failed to compile student"
assert hasattr(compiled_student, "_compiled") and compiled_student._compiled, "Student compilation flag not set"
# Compilation successful - student module has been optimized


def test_bootstrap_effectiveness():
Expand Down
2 changes: 1 addition & 1 deletion tests/teleprompt/test_bootstrap_finetune.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def test_compile_with_predict_instances():
compiled_student = bootstrap.compile(student, teacher=teacher, trainset=trainset)

assert compiled_student is not None, "Failed to compile student"
assert hasattr(compiled_student, "_compiled") and compiled_student._compiled, "Student compilation flag not set"
# Compilation successful - student module has been fine-tuned

mock_finetune.assert_called_once()

Expand Down
10 changes: 5 additions & 5 deletions tests/utils/test_saving.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class MySignature(dspy.Signature):


@pytest.mark.extra
def test_save_compiled_model(tmp_path):
def test_save_optimized_model(tmp_path):
predict = dspy.Predict("question->answer")
dspy.settings.configure(lm=DummyLM([{"answer": "blue"}, {"answer": "white"}] * 10))

Expand All @@ -74,12 +74,12 @@ def dummy_metric(example, pred, trace=None):
return True

optimizer = dspy.BootstrapFewShot(max_bootstrapped_demos=4, max_labeled_demos=4, max_rounds=5, metric=dummy_metric)
compiled_predict = optimizer.compile(predict, trainset=trainset)
compiled_predict.save(tmp_path, save_program=True)
optimized_predict = optimizer.compile(predict, trainset=trainset)
optimized_predict.save(tmp_path, save_program=True)

loaded_predict = dspy.load(tmp_path)
assert compiled_predict.demos == loaded_predict.demos
assert compiled_predict.signature == loaded_predict.signature
assert optimized_predict.demos == loaded_predict.demos
assert optimized_predict.signature == loaded_predict.signature


def test_load_with_version_mismatch(tmp_path):
Expand Down