在使用 DSPy 优化和训练复杂的程序后,保存和加载这些程序是非常重要的一步。无论是为了后续的部署,还是为了在未来复用优化成果,DSPy 提供了灵活的保存和加载机制。本教程将带你了解如何保存和加载 DSPy 程序。
🗂️ 两种保存方式
DSPy 提供了两种主要的保存方式:
- 仅保存状态(State-only Saving)
类似于 PyTorch 的权重保存,仅保存程序的内部状态(如签名、few-shot 示例、配置等),不包含程序的架构。 - 保存整个程序(Whole Program Saving)
从 DSPy 2.6.0 开始支持,保存程序的架构和状态,便于直接加载完整程序。
⚙️ 状态保存(State-only Saving)
状态保存包括程序的内部状态,例如:
- 签名(Signature)
- few-shot 示例(Demos)
- 配置(如
dspy.Predict
模块中使用的语言模型)
保存状态到 JSON 文件
以下是一个示例,展示如何保存程序的状态到 JSON 文件:
import dspy
from dspy.datasets.gsm8k import GSM8K, gsm8k_metric
# 配置语言模型
dspy.settings.configure(lm=dspy.LM("openai/gpt-4o-mini"))
# 加载数据集
gsm8k = GSM8K()
gsm8k_trainset = gsm8k.train[:10]
# 定义程序
dspy_program = dspy.ChainOfThought("question -> answer")
# 使用优化器编译程序
optimizer = dspy.BootstrapFewShot(
metric=gsm8k_metric,
max_bootstrapped_demos=4,
max_labeled_demos=4,
max_rounds=5
)
compiled_dspy_program = optimizer.compile(dspy_program, trainset=gsm8k_trainset)
# 保存状态到 JSON 文件
compiled_dspy_program.save("./dspy_program/program.json", save_program=False)
保存状态到 Pickle 文件
当程序中包含不可序列化的对象(如 dspy.Image
或 datetime.datetime
)时,可以选择保存为 Pickle 文件:
compiled_dspy_program.save("./dspy_program/program.pkl", save_program=False)
加载保存的状态
要加载保存的状态,需要重新创建相同的程序,然后使用 load
方法加载状态:
# 重新创建程序
loaded_dspy_program = dspy.ChainOfThought("question -> answer")
# 加载保存的状态
loaded_dspy_program.load("./dspy_program/program.json")
# 验证加载的状态
assert len(compiled_dspy_program.demos) == len(loaded_dspy_program.demos)
for original_demo, loaded_demo in zip(compiled_dspy_program.demos, loaded_dspy_program.demos):
assert original_demo.toDict() == loaded_demo
assert str(compiled_dspy_program.signature) == str(loaded_dspy_program.signature)
如果是从 Pickle 文件加载:
loaded_dspy_program.load("./dspy_program/program.pkl")
🏗️ 保存整个程序(Whole Program Saving)
从 DSPy 2.6.0 开始,你可以保存整个程序,包括程序的架构和状态。这种方法使用了 cloudpickle
库,可以序列化和反序列化 Python 对象。
保存整个程序
将程序保存到一个目录中:
compiled_dspy_program.save("./dspy_program/", save_program=True)
加载整个程序
直接加载保存的程序,无需重新创建架构:
loaded_dspy_program = dspy.load("./dspy_program/")
# 验证加载的程序
assert len(compiled_dspy_program.demos) == len(loaded_dspy_program.demos)
for original_demo, loaded_demo in zip(compiled_dspy_program.demos, loaded_dspy_program.demos):
assert original_demo.toDict() == loaded_demo
assert str(compiled_dspy_program.signature) == str(loaded_dspy_program.signature)
🔄 向后兼容性(Backward Compatibility)
- DSPy < 2.7:保存的程序不保证向后兼容性。如果你使用 DSPy 2.5.35 保存程序,请确保加载时使用相同版本的 DSPy。
- DSPy >= 2.7:在主要版本中保证向后兼容性,例如,使用 DSPy 2.7.0 保存的程序可以在 DSPy 2.7.10 中加载。
🎯 选择合适的保存方式
- 如果你只需要保存程序的状态(如 few-shot 示例和配置),选择 状态保存。
- 如果你需要保存整个程序的架构和状态,便于直接加载和部署,选择 保存整个程序。
通过保存和加载功能,DSPy 程序可以轻松地复用和部署。无论是简单的状态保存,还是完整的程序保存,DSPy 都为你的项目提供了灵活的解决方案。快试试吧!🎉