Ray Tune 训练 API 完全指南:Function Trainable 与 Class Trainable 实战详解
2026/9/20 18:14:31 网站建设 项目流程
  • 人工智能
  • 分布式训练
  • 强化学习
  • 任务调度
  • 模型推理服务

【免费下载链接】ray

Ray is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.

项目地址:https://gitcode.com/gh_mirrors/ra/ray
点击查看免费下载

导读

在 Ray Tune 中编写自定义超参数搜索任务,核心是回答一个问题:如何在 Tune 的调度循环中定义一次"训练"?本文基于 trainable.rst 官方参考文档,系统讲解 Tune 提供的两套训练接口——以tune.report()为核心的Function API(函数式训练接口)与以tune.Trainable子类为核心的Class API(类式训练接口)。读完本文,你将掌握:两种 API 的定义方式与适用场景、中间/最终指标的上报方法、reuse_actors复用 Actor 避免昂贵初始化、PlacementGroupFactory精细资源分配,以及二者在迭代计数、指标上报、检查点存取等关键行为上的差异对照,并得到来自仓库源码(python/ray/tune/trainable/trainable.py、python/ray/tune/trainable/function_trainable.py)的底层实现佐证。

两种训练 API 概览

Ray Tune 的训练循环(Trial)由两种方式驱动:

  • Function API:编写一个接收config: dict的普通 Python 函数,训练函数内部通过调用tune.report()上报指标,由 Tune 在 Ray Actor 进程中执行。
  • Class API:继承ray.tune.Trainable抽象类,实现setup/step/cleanup等生命周期方法,由 Tune 将其实例化为 Ray Actor 运行。

文档以一个简单目标函数贯穿始终(完整示例见 trainable.py):

def objective(x, a, b): return a * (x ** 0.5) + b

下文所有示例都围绕"最大化这个目标函数"展开,便于直观对比两种 API 的写法差异。

Function Trainable API:函数式训练接口

基本用法:在训练循环中上报中间指标

Function API 的核心约定是:训练函数接收一个config字典参数,该字典由 Tune 自动填充,对应搜索空间(search space)中为该 Trial 选中的超参数。搜索空间的定义方式参见 key-concepts.rst 中的tune-key-concepts-search-spaces章节。

from ray import tune def trainable(config: dict): intermediate_score = 0 for x in range(20): intermediate_score = objective(x, config["a"], config["b"]) tune.report({"score": intermediate_score}) # 将 score 上报给 Tune tuner = tune.Tuner(trainable, param_space={"a": 2, "b": 4}) results = tuner.fit()

每个 Trial 被放入一个独立的 Ray Actor 进程,多个 Trial 并行运行。每调用一次tune.report(),就产生一个训练结果(result),并自动推进training_iteration计数。

tip:不要在Trainable类内部调用tune.report()tune.report()是为函数式训练设计的会话上报接口,Class API 应通过step()的返回值上报指标。

自定义上报频率:仅在结束时上报最终分数

默认情况下tune.report()每次调用都会上报,但上报频率完全由你控制。例如只在训练结束时上报一次最终分数:

from ray import tune def trainable(config: dict): final_score = 0 for x in range(20): final_score = objective(x, config["a"], config["b"]) tune.report({"score": final_score}) # 仅在结束时上报 tuner = tune.Tuner(trainable, param_space={"a": 2, "b": 4}) results = tuner.fit()

通过函数返回值上报最终指标

除了tune.report(),Function API 还支持直接从函数返回值中上报一组最终指标

def trainable(config: dict): final_score = 0 for x in range(20): final_score = objective(x, config["a"], config["b"]) return {"score": final_score} # 将 score 上报给 Tune

从源码实现看,这一机制由 function_trainable.py 中的wrap_function处理:它用inspect检查训练函数的签名,要求必须包含唯一的config位置参数;函数执行完毕后,返回值如果是dict会通过get_session().report(output)上报,如果是单个数值则以默认指标(DEFAULT_METRIC)上报,最后还会上报一个RESULT_DUPLICATE标记,由 TuneController 识别为"训练函数已退出"并注入done=True,从而触发 Trial 的停止决策——这就是"返回最终指标即结束训练"的底层原理。

自动填充指标(auto-filled metrics)

无论使用哪种上报方式,Ray Tune 都会在用户指标之外自动填充一批系统指标,例如iterations_since_restore。常见自动填充指标包括(详见 tune-metrics.rst 的tune-autofilled-metrics章节):

指标含义
config该 Trial 的超参数配置
training_iterationtune.report()被调用的次数(Function API)
iterations_since_restore从检查点恢复后tune.report()被调用的次数
time_this_iter_s当前训练迭代耗时(秒)
time_total_s累计运行总时长(秒)
timesteps_total/episodes_total累计时间步 / 回合数(如 RLlib Trainable)
pid/hostname/node_ip工作进程 PID、主机名、节点 IP
date/timestamp结果处理时间
doneTrial 是否结束
trial_id/experiment_id/experiment_tagTrial 与实验标识

这些指标都可以直接用作停止条件,或传递给 Trial Scheduler / Search Algorithm。其生成逻辑位于 trainable.py 的get_auto_filled_metrics方法中。

Function API 的检查点配置

函数式训练接口的检查点(checkpoint)方式与类式接口不同:CheckpointConfig中的checkpoint_frequencycheckpoint_at_end不适用于Function API 检查点,而是需要手动在训练函数中控制。核心用法:

  • 保存检查点:通过tune.report(metrics, checkpoint=checkpoint)上报,每个检查点必须与一组指标同时上报,以便按指定指标对检查点排序;
  • 加载检查点:通过tune.get_checkpoint()获取该 Trial 最近一次保存的检查点——当 Trial 失败重试、实验恢复或暂停后恢复(如 PBT)时会被自动填充。

更完整的函数式检查点配置与示例见 tune-trial-checkpoints.rst 的tune-function-trainable-checkpointing章节。底层实现上,report()get_checkpoint()定义在 trainable_fn_utils.py:report()将指标与可选的Checkpoint交给会话层上报并持久化到存储;get_checkpoint()返回会话中已加载的最新检查点。同时请注意,tune.report()不适合传输大量数据(如模型权重、数据集),这会显著拖慢 Tune 运行。

Class Trainable API:类式训练接口

子类化tune.Trainable的基本结构

Class API 要求继承ray.tune.Trainable,核心生命周期方法有三个(完整示例见 trainable.py):

from ray import tune class Trainable(tune.Trainable): def setup(self, config: dict): # config (dict): 一组超参数 self.x = 0 self.a = config["a"] self.b = config["b"] def step(self): # 会被反复调用 score = objective(self.x, self.a, self.b) self.x += 1 return {"score": score} tuner = tune.Tuner( Trainable, run_config=tune.RunConfig( # 训练 20 步 stop={"training_iteration": 20}, checkpoint_config=tune.CheckpointConfig( # 本示例尚未实现检查点,见下文 checkpoint_at_end=False ), ), param_space={"a": 2, "b": 4}, ) results = tuner.fit()

作为tune.Trainable的子类,Tune 会在独立进程中基于 Ray Actor API 创建Trainable对象,三个生命周期方法的分工为:

  1. setup:训练开始时调用一次,负责初始化(接收 Tune 自动填充的config字典,对应搜索空间中为 Trial 选中的超参数);
  2. step被多次调用,每次调用在调优进程中执行一个逻辑训练迭代(内部可包含一个或多个真实训练迭代),并通过返回值上报指标;
  3. cleanup:训练结束时调用,负责释放资源。

caution:不要在Trainable类内部调用tune.report()Class API 的指标上报方式是让step()返回指标字典。

tip:step()的执行时间需要权衡。经验法则是:单次step()应足够长以摊销调度开销(通常超过几秒),又足够短以周期性上报进度(通常不超过几分钟)。

Class API 的检查点配置

类式训练接口支持三种检查点机制:手动触发、按频率触发、训练结束时触发。用户通常只需实现Trainable.save_checkpointTrainable.load_checkpoint两个方法,并在RunConfigCheckpointConfig中设置checkpoint_frequencycheckpoint_at_end等选项,详见 tune-trial-checkpoints.rst 的tune-class-trainable-checkpointing章节。

在源码层面,trainable.py 对检查点提供了完整支持:

  • save()(trainable.py)调用用户实现的save_checkpoint(),将返回的 dict 或路径统一整理后,通过_report_class_trainable_checkpoint()持久化到存储,返回_TrainingResult
  • restore()(trainable.py)根据load_checkpoint()的实现,将检查点还原为 dict 或本地目录形式加载,并恢复training_iterationtime_total_s等进度指标;
  • step()返回的结果中包含should_checkpoint: True(即tune.result.SHOULD_CHECKPOINT),则可手动触发检查点——这在抢占式实例(spot instance)场景下尤为实用。

此外,Trainable.__init__会在训练进程中将当前工作目录切换到该 Trial 专属的日志目录self.logdir,避免同一物理节点上多个 Trial 互相覆盖文件;可通过环境变量RAY_CHDIR_TO_TRIAL_DIR=0禁用该行为(旧的环境变量TUNE_ORIG_WORKING_DIR已弃用,见 trainable.py)。

高级:在 Tune 中复用 Actor(reuse_actors)

如果 Trainable 的初始化非常耗时(例如加载大型模型),可以为每次 Trial 都重新创建进程会带来巨大开销。Tune 提供了reuse_actors=True(通过TuneConfig传入Tuner),在多个超参数组合之间复用同一个 Trainable Python 进程与对象。该特性仅适用于 Class API。

复用的前提是你实现了Trainable.reset_config,它接收一组新的超参数并完成更新——是否正确更新超参数完全由用户负责。完整示例:

from time import sleep import ray from ray import tune from ray.tune.tuner import Tuner def expensive_setup(): print("EXPENSIVE SETUP") sleep(1) class QuadraticTrainable(tune.Trainable): def setup(self, config): self.config = config expensive_setup() # 使用 reuse_actors=True 时只执行一次 self.max_steps = 5 self.step_count = 0 def step(self): # 从 config 中提取超参数 h1 = self.config["hparam1"] h2 = self.config["hparam2"] # 计算简单二次目标函数,最优解位于 hparam1=3 和 hparam2=5 loss = (h1 - 3) ** 2 + (h2 - 5) ** 2 metrics = {"loss": loss} self.step_count += 1 if self.step_count > self.max_steps: metrics["done"] = True # 将计算出的 loss 作为指标返回 return metrics def reset_config(self, new_config): # 复用 Actor 时,为新的 Trial 更新配置 self.config = new_config return True ray.init() tuner_with_reuse = Tuner( QuadraticTrainable, param_space={ "hparam1": tune.uniform(-10, 10), "hparam2": tune.uniform(-10, 10), }, tune_config=tune.TuneConfig( num_samples=10, max_concurrent_trials=1, reuse_actors=True, # 启用 Actor 复用,避免昂贵的 setup ), run_config=ray.tune.RunConfig( verbose=0, checkpoint_config=ray.tune.CheckpointConfig(checkpoint_at_end=False), ), ) tuner_with_reuse.fit()

关键点说明:

  • setup()中的expensive_setup()只执行一次,之后通过reset_config()切换超参数,从而显著加速 PBT 等需要频繁切换配置的算法;
  • 每次复用切换时,reset_config()必须返回True表示重置成功;若返回False,Tune 将终止该 Actor 并为新 Trial 创建新进程(见 trainable.py 中reset()的实现逻辑);
  • 代码中max_concurrent_trials=1reuse_actors=True搭配,保证同一时刻只有一个 Trial 占用该 Actor,使复用路径清晰可复现。

Function API 与 Class API 对比一览

文档给出了两种 API 在关键概念上的对照表:

概念Function APIClass API
训练迭代(Training Iteration)每次调用tune.report递增每次调用Trainable.step递增
上报指标(Report metrics)tune.report(metrics)Trainable.step返回指标
保存检查点(Saving a checkpoint)tune.report(..., checkpoint=checkpoint)Trainable.save_checkpoint
加载检查点(Loading a checkpoint)tune.get_checkpoint()Trainable.load_checkpoint
访问配置(Accessing config)作为参数传入def train_func(config):通过Trainable.setup传入

选型建议:Function API 代码量少、上手快,适合大多数超参搜索场景;Class API 结构化更强,适合需要精细控制生命周期、手动管理检查点、复用 Actor 或需要实现default_resource_request声明资源需求的场景。

高级资源分配:让 Trainable 自身分布式化

Trainable 自身也可以被分布式执行。如果你的训练函数/类会进一步创建消耗 CPU/GPU 资源的 Ray Actor 或 Task,就需要在PlacementGroupFactory中添加更多 bundle,为它们预留额外的资源槽位。

例如,某个 Trainable 类自身需要 1 个 GPU,同时还会启动 4 个各占 1 个 GPU 的 Actor,则应通过tune.with_resources指定资源(强调行为核心写法):

tuner = tune.Tuner( tune.with_resources(my_trainable, tune.PlacementGroupFactory([ {"CPU": 1, "GPU": 1}, {"GPU": 1}, {"GPU": 1}, {"GPU": 1}, {"GPU": 1} ])), run_config=RunConfig(name="my_trainable") )

要点补充:

  • 第一个 bundle{"CPU": 1, "GPU": 1}是 Trainable 自身所在的主 bundle,其后每个{"GPU": 1}为该 Trainable 启动的子 Actor 预留资源;
  • 除 CPU/GPU 外,还可以指定"memory"(单位:字节)以及自定义资源类型(custom resources);
  • Class API 还提供default_resource_request类方法,允许 Trainable 根据给定配置自动声明每个 Trial 所需的资源,从而免去用户在Tuner中手动设置;其基类默认返回None(见 trainable.py),子类可覆写为PlacementGroupFactory
  • 对于 Function API,tune.with_resources是请求资源的主要方式,其实现位于 util.py:资源参数既可以是普通资源字典(自动转换为PlacementGroupFactory)、PlacementGroupFactory实例,也可以是接收 config 并返回工厂的可调用对象;with_resources会覆盖已有的资源请求,使用时需注意。

相关 API 索引

围绕本节文档,Tune 提供了以下配套 API(均可在ray命名空间下导入):

Function API 相关

  • 类:tune.Checkpointtune.TuneContext
  • 函数:tune.get_checkpointtune.get_contexttune.report

Trainable(Class API)相关

  • 构造函数:tune.Trainable
  • 需要实现的方法:Trainable.setupTrainable.save_checkpointTrainable.load_checkpointTrainable.stepTrainable.reset_configTrainable.cleanupTrainable.default_resource_request

Tune Trainable 工具函数

  • 数据注入:tune.with_parameters(将大型参数以引用方式注入训练函数,避免序列化开销)
  • 资源分配:tune.with_resourcestune.execution.placement_groups.PlacementGroupFactorytune.utils.wait_for_gpu
  • 调试工具:tune.utils.diagnose_serializationtune.utils.validate_save_restoretune.utils.util.validate_warmstart

总结

  • Function APItune.report()驱动迭代与指标上报,支持上报中间指标、最终指标以及通过返回值上报,配置检查点时需手动通过tune.report(..., checkpoint=...)tune.get_checkpoint()完成;
  • Class API通过子类化tune.Trainable实现setup/step/cleanup生命周期,支持reuse_actors复用 Actor、reset_config热切换超参数、default_resource_request自动声明资源,检查点通过save_checkpoint/load_checkpoint管理;
  • 资源分配借助tune.with_resourcesPlacementGroupFactory,可以精确表达 Trainable 自身及其衍生 Actor 的 CPU/GPU/内存/自定义资源需求。

本文所有代码示例均可直接复制运行(需安装 Ray 并具备对应计算资源)。更多细节可继续阅读 tune-metrics.rst(自动填充指标)、tune-trial-checkpoints.rst(检查点配置)以及 Tune 核心概念(搜索空间与训练循环)等文档。

  • 人工智能
  • 分布式训练
  • 强化学习
  • 任务调度
  • 模型推理服务

【免费下载链接】ray

Ray is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.

项目地址:https://gitcode.com/gh_mirrors/ra/ray
点击查看免费下载
上一篇:解锁Playnite潜能:10个被忽略的高级设置与隐藏功能
下一篇:Tomcat性能调优终极指南:10个实用技巧提升服务器响应速度

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询