ztxexp (ZTX-Experiment) 是一个轻量级且功能强大的Python工具库,旨在将您从繁琐的计算实验管理中解放出来。它特别适用于机器学习、深度学习和任何需要进行大量参数搜索与结果分析的研究场景。
由 ztxtech 开发,ztxexp 将实验设计的全流程——配置生成、增量运行、结果分析、目录清理 ——封装在一套优雅流畅的API中。
- 🚀 流畅的参数配置: 使用链式API轻松定义参数空间,支持网格搜索 (
Grid Search) 和独立变体 (Variants)。 - 🔧 自定义逻辑: 通过添加自定义的修改器和过滤器函数,实现任意复杂的参数调整和筛选逻辑。
- 💡 智能防重运行: 自动检测已完成的实验,避免重复计算,节省宝贵的计算时间和资源。
- ⚡️ 灵活的执行引擎: 支持多种实验执行模式,包括顺序执行、并行执行 (
ProcessPoolExecutor或joblib)。 - 📊 强大的结果分析: 一键将所有分散的实验结果聚合到 Pandas DataFrame 中,并支持生成多维数据透视表(Pivot Table)与排名。
- 🧹 安全的目录清理: 提供安全的
dry_run模式和交互式确认,帮助你轻松删除未成功或不符合预期的实验结果。 - 🛠️ 丰富的工具集: 内置一个不断丰富的
utils.py模块,提供日志设置、代码计时、模型保存、路径管理等高频实用工具。
pip install ztxexpztxexp 的设计遵循一个简单直观的三段式工作流:
- 管理 (Manage): 使用
ztxexp.ExpManager定义和生成所有需要运行的实验配置。 - 运行 (Run): 使用
ztxexp.ExpRunner来执行这些配置,支持并行化和断点续跑。 - 分析 (Analyze): 使用
ztxexp.ResultAnalyzer来聚合结果、生成报告以及清理工作目录。
为了帮助你快速上手,我们在项目中提供了几个可直接运行的示例脚本。建议你亲自运行它们,以更好地理解库的功能。
-
main_run_experiments.py: (核心示例) 展示了如何使用ExpManager的链式API组合网格搜索、变体、修改器和过滤器来生成复杂的实验配置,并使用ExpRunner进行并行执行。这是理解本库强大之处的最佳起点。# 节选自 main_run_experiments.py configs_to_run = ( manager.add_grid_search(GRID_SPACE) .add_variants(VARIANT_SPACE) .add_modifier(modifier_func) .add_filter(filter_func) .filter_completed('./results_demo') .get_configs() )
-
main_analyze_results.py: 演示了在实验运行后,如何使用ResultAnalyzer将所有成功运行的结果汇总到CSV文件,并创建一个带排名的精美Excel数据透视表。 -
main_cleanup.py: 专注于目录维护。它展示了如何使用clean_results方法安全地、有选择性地删除那些失败的、未完成的、或者结果不符合预期的实验文件夹。 -
main_utils_demo.py: 展示了ztxexp.utils模块的威力。即使不使用完整的 Manager/Runner 工作流,你也可以在任何Python脚本中单独使用这些方便的工具函数,如日志记录器、代码计时器、PyTorch模型保存等。
ztxexp 的强大之处在于其高度的可定制性。你需要提供几个关键的自定义函数,下面是它们的详细“接口契约”。
这是你的核心业务逻辑所在,由 ExpRunner 负责调用。
- 签名:
def my_experiment(args: argparse.Namespace): - 参数:
args: 一个Namespace对象,包含了本次运行所需的所有配置。ExpRunner会自动向其添加两个额外的属性:args.setting: 本次运行的唯一标识符(例如20250803_202020_a1b2c3)。args.setting_path: 本次运行的专属结果目录 (Path对象),你可以向其中保存任何文件。
- 职责:
- 执行你的实验代码(模型训练、数据处理等)。
- 必须自己保存结果。例如,将指标保存到
args.setting_path / 'results.json',将模型权重保存到args.setting_path / 'model.pth'。
- 返回值: 无需返回值。
ExpRunner通过检查_SUCCESS标记文件(在函数成功返回后自动创建)来判断成功与否。
用于在生成最终配置列表前,对参数进行动态调整。
- 签名:
def my_modifier(args: argparse.Namespace) -> argparse.Namespace: - 参数:
args: 一个待处理的Namespace配置对象。
- 职责: 根据已有参数修改
args对象。例如:if args.model == 'A': args.layers = 12。 - 返回值: 必须返回修改后的
args对象。
用于在生成最终配置列表前,剔除无效或不想运行的参数组合。
-
签名:
def my_filter(args: argparse.Namespace) -> bool: -
参数:
args: 一个待检查的Namespace配置对象。
-
职责: 根据一组规则判断该配置是否有效。
-
返回值: 必须返回一个布尔值:
True:保留这个配置。False:从待运行列表中剔除这个配置。
-
最佳实践: 为了防止因参数缺失而导致程序崩溃,请始终使用
.get()方法来安全地访问args中的属性。# 安全的写法 def my_safe_filter(args): # 如果 'lr' 存在且小于 0.001,则保留 if args_dict := vars(args): if args_dict.get('lr', 999) < 0.001: return True return False # 不安全的写法 (如果 'lr' 缺失会引发 AttributeError) # def my_unsafe_filter(args): # return args.lr < 0.001
用于 ResultAnalyzer.clean_results 方法,以编程方式决定哪些文件夹需要被删除。
-
签名:
def my_cleanup_filter(config_dict: dict) -> bool: -
参数:
config_dict: 从一个args.json文件中加载而来的字典。
-
职责: 判断这个配置是否符合被删除的条件。
-
返回值: 必须返回一个布尔值:
True:标记此文件夹为待删除。False:保留此文件夹。
-
最佳实践: 同样地,请务必使用
.get()来处理可能缺失的键。# 安全的写法:删除所有准确率低于 0.5 的实验 def cleanup_low_accuracy(config): # 如果 'accuracy' 键不存在,.get 返回 1.0,条件不成立,不会被删除 return config.get('accuracy', 1.0) < 0.5
欢迎任何形式的贡献!如果你有好的想法或发现了Bug,请随时在 GitHub Issues 中提出,或者直接提交一个 Pull Request。
该项目采用 MIT License 授权。