Hydra的Ax-sweeper是如何进行内存分配与释放的?
Hydra sweeper运行逻辑与内存泄漏问题解答
1. Hydra 1.x + ax-sweeper的多轮调度逻辑
你之前的认知是部分错误的,Hydra 1.x版本的默认multirun(-m参数触发)并不会为每一轮sweep启动独立进程,它的执行流程是:
- 主进程启动后初始化Hydra、Ax优化器实例
- 循环执行以下步骤直到达到最大试验次数:
- 从Ax优化器拉取当前轮次的超参数配置
- 直接在当前主进程内调用被
@hydra.main装饰的main函数,传入对应配置 - 捕获
main函数返回的指标值,存入Ax的试验记录中 - 进入下一轮循环
- 所有试验结束后输出最终优化结果
2. 内存占用过高的根源
因为所有sweep轮次都在同一个进程里运行,所以就算main函数执行结束,几类资源不会被自动完全释放:
- PyTorch的CUDA缓存、CPU侧的张量缓存默认不会主动清理,会持续占用内存
- 如果你用的是PyTorch DataLoader的
fork启动方式(Linux默认),子进程退出后残留的内存页不会被及时回收,多次启动累加后就会占满内存 - Ax优化器本身会存储每一轮的试验配置、指标、中间状态,试验次数多了也会占用额外内存
- 全局作用域定义的变量、没有显式销毁的对象会一直留在内存中,不会随着
main函数退出被回收
3. 优化方案
优先推荐的解决方式(避免内存泄漏最彻底)
给Hydra配置hydra/launcher: joblib,指定用独立进程启动每一轮sweep,每轮运行结束后进程直接销毁,所有内存资源都会被操作系统自动回收,不需要你改业务代码,只需要安装和你Hydra版本匹配的joblib launcher依赖即可,内存泄漏问题会直接消失。
数据复用方案(适合数据加载成本极高的场景)
如果你的数据是固定的、和超参数无关,可以把数据加载逻辑放到main函数外的全局作用域,程序启动时只加载一次,所有sweep轮次复用同一份数据,完全避免重复加载的内存开销和泄漏问题。要注意以下两点:
- 确保加载的数据是只读的,多轮训练不会修改数据本身的内容
- 如果用到多进程DataLoader,建议把DataLoader的
persistent_workers参数设为True,避免每轮训练重新启动工作进程
临时修复方案(不想改调度逻辑的情况)
在main函数返回前手动清理资源:
import gc import torch def main(cfg): # 你的训练逻辑 score = 训练得到的指标 # 手动清理资源 del 数据集对象, 模型对象, 优化器对象, DataLoader对象 torch.cuda.empty_cache() # 用GPU的话加这行 gc.collect() return score
这个方案能缓解内存上涨的速度,但不能完全避免泄漏,长期运行还是可能占满内存。
内容的提问来源于stack exchange,提问作者DannyBoi
相关产品推荐
相关产品推荐

