竞价实例(Spot Instance)是各大云厂商提供的低价 GPU 资源:你以远低于按量计费的价格使用闲置 GPU,代价是云厂商有权在需要时回收这台机器。折扣力度通常在按量价的 3-5 折区间,具体随供需实时波动。
听起来很不靠谱?但如果训练流程做好了中断容错,竞价实例能帮你把同样的预算跑出 2-3 倍的实验量。
先看实时价格,别拍脑袋
竞价折扣不是固定值,不同云、不同区域、不同时段差异很大。在 RunWhere 上,你可以直接在控制台的「价格」页按计费模式筛选竞价机型,对比各家的实时报价;或者用 CLI:
runw price recommend -f train.yaml --top 3
选中报价后把 gpuSkuKey 写回 YAML,价格就锁定了,不会提交时才发现换了价。
核心风险:随时可能被中断
云厂商回收实例前会给出短暂的通知窗口,然后强制回收。如果训练没有 checkpoint,中断就意味着从头再来。所以用竞价实例的前提只有一个:你的训练必须可恢复。
安全使用竞价实例的 3 个关键
1. 高频 Checkpoint
每 10-15 分钟保存一次,而不是每个 epoch。中断后最多丢失十几分钟的计算量:
save_interval = 900 # 每 900 秒保存一次
last_save = time.time()
for step, batch in enumerate(dataloader):
loss = train_step(model, batch)
if time.time() - last_save > save_interval:
save_checkpoint(model, optimizer, step)
last_save = time.time()
在 RunWhere 上,checkpoint 的存放位置在 YAML 的 storage.checkpoint 里声明,直接落在你自己云账号的存储里——实例被回收也不丢。更完整的写法见文档站的 checkpoint 最佳实践。
2. 监听中断信号
收到回收通知后,在强制关机前保存当前状态:
import signal
import sys
def handle_preemption(signum, frame):
print("收到中断信号,正在保存 checkpoint...")
save_checkpoint(model, optimizer, current_step)
sys.exit(0)
signal.signal(signal.SIGTERM, handle_preemption)
3. 训练脚本启动时自动恢复
脚本开头检测最新 checkpoint,存在就接着练,这样无论在新实例上重启多少次,进度都在:
latest = find_latest_checkpoint(checkpoint_dir)
if latest:
checkpoint = torch.load(latest)
model.load_state_dict(checkpoint["model_state"])
start_epoch = checkpoint["epoch"] + 1
什么任务适合竞价实例
- LoRA / QLoRA 微调(通常几小时内,checkpoint 恢复快)
- 超参搜索(本身就是多次独立实验,中断一个不影响其他)
- 数据预处理和特征工程(无状态,重跑成本低)
什么任务不适合
- 多节点分布式训练(中断一个节点拖累所有节点)
- 训练时间很短的任务(省不了多少钱,还增加复杂度)
- 对可用性敏感的推理服务(中断 = 服务中断)
一句话总结:竞价实例省钱的前提是可恢复的训练流程。checkpoint 做扎实了,竞价就是纯粹的折扣;做不扎实,省下的钱迟早以重跑的方式还回去。