Ray Tune 的关键概念#
让我们快速了解使用 Tune 所需掌握的关键概念。如果您想立即查看实用教程,请访问我们的用户指南。本质上,Tune 有六个您需要理解的关键组件。
首先,您在搜索空间
中定义想要调优的超参数,并将它们传递给指定要调优目标的可训练对象 (trainable)
。然后选择一个搜索算法
来有效地优化参数,并可选地使用调度器 (scheduler)
来提前停止搜索并加速实验。结合其他配置,您的可训练对象
、搜索算法和调度器被传递给Tuner
,Tuner
运行您的实验并创建试验 (trials)
。Tuner
返回一个ResultGrid
以检查您的实验结果。下图概述了这些组件,我们将在后续章节中详细介绍。

Ray Tune 可训练对象#
简而言之,可训练对象 (Trainable)是您可以传递给 Tune 运行的对象。Ray Tune 有两种定义可训练对象
的方式,即函数 API和类 API。两者都是定义可训练对象
的有效方式,但通常推荐使用函数 API,并且本指南的其余部分都使用了函数 API。
考虑一个优化简单目标函数(如a * (x ** 2) + b
)的示例,其中a
和b
是我们想要调优以最小化
目标的超参数。由于目标函数还包含变量x
,我们需要针对不同的x
值进行测试。给定a
、b
和x
的具体选择,我们可以评估目标函数并获得需要最小化的分数 (score)
。
使用基于函数的 API,您可以创建一个函数(此处称为trainable
),该函数接收一个超参数字典作为输入。此函数在“训练循环”中计算一个分数
,并将此分数报告
回 Tune
from ray import train
def objective(x, a, b): # Define an objective function.
return a * (x**2) + b
def trainable(config): # Pass a "config" dictionary into your trainable.
for x in range(20): # "Train" for 20 iterations and compute intermediate scores.
score = objective(x, config["a"], config["b"])
tune.report({"score": score}) # Send the score to Tune.
请注意,我们在训练循环中使用session.report(...)
来报告中间分数
,这在许多机器学习任务中非常有用。如果您只想在此循环外部报告最终分数
,只需在trainable
函数的末尾使用return {"score": score}
返回分数即可。您也可以使用yield {"score": score}
代替session.report()
。
这是使用基于类的 API指定目标函数的示例
from ray import tune
def objective(x, a, b):
return a * (x**2) + b
class Trainable(tune.Trainable):
def setup(self, config):
# config (dict): A dict of hyperparameters
self.x = 0
self.a = config["a"]
self.b = config["b"]
def step(self): # This is called iteratively.
score = objective(self.x, self.a, self.b)
self.x += 1
return {"score": score}
提示
session.report
不能在 Trainable
类中使用。
在此了解可训练对象 (Trainable)的更多详细信息,并查看我们的示例。接下来,让我们仔细看看您传递给可训练对象的config
字典是什么。
Tune 搜索空间#
为了优化您的超参数,您必须定义一个搜索空间。搜索空间定义了超参数的有效值,并可以指定这些值如何采样(例如,从均匀分布或正态分布中采样)。
Tune 提供了各种函数来定义搜索空间和采样方法。您可以在此处找到这些搜索空间定义的文档。
这是一个涵盖所有搜索空间函数的示例。同样,此处是所有这些函数的完整说明。
config = {
"uniform": tune.uniform(-5, -1), # Uniform float between -5 and -1
"quniform": tune.quniform(3.2, 5.4, 0.2), # Round to multiples of 0.2
"loguniform": tune.loguniform(1e-4, 1e-1), # Uniform float in log space
"qloguniform": tune.qloguniform(1e-4, 1e-1, 5e-5), # Round to multiples of 0.00005
"randn": tune.randn(10, 2), # Normal distribution with mean 10 and sd 2
"qrandn": tune.qrandn(10, 2, 0.2), # Round to multiples of 0.2
"randint": tune.randint(-9, 15), # Random integer between -9 and 15
"qrandint": tune.qrandint(-21, 12, 3), # Round to multiples of 3 (includes 12)
"lograndint": tune.lograndint(1, 10), # Random integer in log space
"qlograndint": tune.qlograndint(1, 10, 2), # Round to multiples of 2
"choice": tune.choice(["a", "b", "c"]), # Choose one of these options uniformly
"func": tune.sample_from(
lambda spec: spec.config.uniform * 0.01
), # Depends on other value
"grid": tune.grid_search([32, 64, 128]), # Search over all these values
}
Tune 试验 (Trials)#
您使用Tuner.fit来执行和管理超参数调优并生成您的试验
。至少,您的Tuner
调用会将可训练对象作为第一个参数,以及一个param_space
字典来定义搜索空间。
通过调用Tuner.fit()
函数可以执行和管理超参数调优,并生成您的trials
。最低限度地,您的Tuner
调用需要将一个可训练对象作为第一个参数,以及一个param_space
字典来定义搜索空间。Tuner.fit()
函数还提供了许多功能,例如日志记录、检查点和提前停止。在最小化a (x ** 2) + b
的示例中,使用简单的a
和b
搜索空间的简单 Tune 运行如下所示
# Pass in a Trainable class or function, along with a search space "config".
tuner = tune.Tuner(trainable, param_space={"a": 2, "b": 4})
tuner.fit()
Tuner.fit
将从其参数中生成多个超参数配置,并将它们封装成Trial 对象。
试验包含很多信息。例如,您可以使用 (trial.config
) 获取超参数配置,试验 ID (trial.trial_id
),试验的资源规范 (resources_per_trial
或 trial.placement_group_factory
) 以及许多其他值。
默认情况下,Tuner.fit
将一直执行,直到所有试验停止或出错。以下是试验运行的示例输出
== Status ==
Memory usage on this node: 11.4/16.0 GiB
Using FIFO scheduling algorithm.
Resources requested: 1/12 CPUs, 0/0 GPUs, 0.0/3.17 GiB heap, 0.0/1.07 GiB objects
Result logdir: /Users/foo/ray_results/myexp
Number of trials: 1 (1 RUNNING)
+----------------------+----------+---------------------+-----------+--------+--------+----------------+-------+
| Trial name | status | loc | a | b | score | total time (s) | iter |
|----------------------+----------+---------------------+-----------+--------+--------+----------------+-------|
| Trainable_a826033a | RUNNING | 10.234.98.164:31115 | 0.303706 | 0.0761 | 0.1289 | 7.54952 | 15 |
+----------------------+----------+---------------------+-----------+--------+--------+----------------+-------+
您还可以通过指定样本数量 (num_samples
) 轻松运行 10 个试验。Tune 会自动确定并行运行多少个试验。请注意,除了样本数量,您还可以通过 time_budget_s
指定以秒为单位的时间预算,前提是您将 num_samples
设置为 -1。
tuner = tune.Tuner(
trainable, param_space={"a": 2, "b": 4}, tune_config=tune.TuneConfig(num_samples=10)
)
tuner.fit()
最后,您可以使用更有趣的搜索空间通过 Tune 的搜索空间 API 来优化超参数,例如使用随机采样或网格搜索。以下是针对 a
和 b
在 [0, 1]
之间进行均匀采样的示例
space = {"a": tune.uniform(0, 1), "b": tune.uniform(0, 1)}
tuner = tune.Tuner(
trainable, param_space=space, tune_config=tune.TuneConfig(num_samples=10)
)
tuner.fit()
要了解配置 Tune 运行的各种方式,请查阅Tuner API 参考。
Tune 搜索算法#
为了优化训练过程的超参数,您可以使用搜索算法 (Search Algorithm),它会提出超参数配置。如果您不指定搜索算法,Tune 默认将使用随机搜索,这可以为您的超参数优化提供一个良好的起点。
例如,要通过bayesian-optimization
包使用简单的贝叶斯优化来使用 Tune(请确保先运行pip install bayesian-optimization
),我们可以使用BayesOptSearch
定义一个algo
。只需将search_alg
参数传递给tune.TuneConfig
,该参数会被Tuner
接收
from ray.tune.search.bayesopt import BayesOptSearch
# Define the search space
search_space = {"a": tune.uniform(0, 1), "b": tune.uniform(0, 20)}
algo = BayesOptSearch(random_search_steps=4)
tuner = tune.Tuner(
trainable,
tune_config=tune.TuneConfig(
metric="score",
mode="min",
search_alg=algo,
),
run_config=tune.RunConfig(stop={"training_iteration": 20}),
param_space=search_space,
)
tuner.fit()
Tune 集成了许多流行的优化库的搜索算法,例如HyperOpt或Optuna。Tune 会自动将提供的搜索空间转换为搜索算法和底层库所需的搜索空间。更多详细信息请参阅搜索算法 API 文档。
以下是 Tune 中所有可用搜索算法的概述
搜索算法 |
摘要 |
网站 |
代码示例 |
---|---|---|---|
随机搜索/网格搜索 |
|||
贝叶斯/强盗优化 |
[Ax] |
||
Tree-Parzen 估计器 |
[HyperOpt] |
||
贝叶斯优化 |
|||
贝叶斯优化/HyperBand |
[BOHB] |
||
无梯度优化 |
|||
Optuna 搜索算法 |
[Optuna] |
注意
与Tune 的试验调度器 (Trial Schedulers)不同,Tune 搜索算法不能影响或停止训练过程。但是,您可以将它们一起使用来提前停止对不良试验的评估。
如果您想实现自己的搜索算法,接口非常易于实现,您可以在此阅读说明。
Tune 还提供了可与搜索算法一起使用的实用工具
重复评估 (tune.search.Repeater):支持使用多个随机种子运行每个采样的超参数。
并发限制器 (ConcurrencyLimiter) (tune.search.ConcurrencyLimiter):在运行优化时限制并发试验的数量。
Shim 实例化 (tune.create_searcher):允许根据字符串创建搜索算法对象。
请注意,在上面的示例中,我们告诉 Tune 在 20
次训练迭代后停止
。这种使用明确规则停止试验的方式很有用,但在很多情况下,使用调度器
效果会更好。
Tune 调度器 (Schedulers)#
为了提高训练过程的效率,您可以使用试验调度器 (Trial Scheduler)。例如,在我们的trainable
示例中,我们在训练循环中最小化一个函数时使用了session.report()
。这报告了由搜索算法选择的超参数配置的增量
结果。基于这些报告的结果,Tune 调度器可以决定是否提前停止试验。如果您不指定调度器,Tune 默认将使用先进先出 (FIFO) 调度器,它只是按照搜索算法选择试验的顺序通过它们,并且不执行任何提前停止。
简而言之,调度器可以停止、暂停或调整正在运行的试验的超参数,从而可能使您的超参数调优过程大大加快。与搜索算法不同,试验调度器不选择评估哪些超参数配置。
以下是使用所谓的HyperBand
调度器调优实验的快速示例。所有调度器都接收一个指标 (metric)
,该指标是您的可训练对象报告的值。指标
然后根据您提供的模式 (mode)
进行最大化或最小化。要使用调度器,只需将scheduler
参数传递给tune.TuneConfig
,该参数会被Tuner
接收
from ray.tune.schedulers import HyperBandScheduler
# Create HyperBand scheduler and minimize the score
hyperband = HyperBandScheduler(metric="score", mode="max")
config = {"a": tune.uniform(0, 1), "b": tune.uniform(0, 1)}
tuner = tune.Tuner(
trainable,
tune_config=tune.TuneConfig(
num_samples=20,
scheduler=hyperband,
),
param_space=config,
)
tuner.fit()
Tune 包含了早期停止算法的分布式实现,例如中位数停止规则 (Median Stopping Rule)、HyperBand 和 ASHA。Tune 还包括基于种群训练 (Population Based Training, PBT) 和 基于种群的强盗算法 (Population Based Bandits, PB2) 的分布式实现。
提示
最容易上手的调度器是ASHAScheduler
,它会积极终止表现不佳的试验。
使用调度器时,您可能会遇到兼容性问题,如下面的兼容性矩阵所示。某些调度器不能与搜索算法一起使用,而某些调度器则要求您实现检查点 (checkpointing)。
调度器可以在调优期间动态改变试验的资源需求。这在资源更改调度器 (ResourceChangingScheduler)中实现,它可以包装任何其他调度器。
调度器 |
需要检查点? |
兼容 SearchAlg? |
示例 |
---|---|---|---|
否 |
是 |
||
否 |
是 |
||
是 |
是 |
||
是 |
仅 TuneBOHB |
||
是 |
不兼容 |
||
是 |
不兼容 |
在调度器 API 文档中了解有关试验调度器的更多信息。
Tune ResultGrid#
Tuner.fit()
返回一个ResultGrid对象,该对象包含可用于分析训练的方法。以下示例展示了如何从ResultGrid
对象访问各种指标,例如可用的最佳试验,或该试验的最佳超参数配置
tuner = tune.Tuner(
trainable,
tune_config=tune.TuneConfig(
metric="score",
mode="min",
search_alg=BayesOptSearch(random_search_steps=4),
),
run_config=tune.RunConfig(
stop={"training_iteration": 20},
),
param_space=config,
)
results = tuner.fit()
best_result = results.get_best_result() # Get best result object
best_config = best_result.config # Get best trial's hyperparameters
best_logdir = best_result.path # Get best trial's result directory
best_checkpoint = best_result.checkpoint # Get best trial's best checkpoint
best_metrics = best_result.metrics # Get best trial's last results
best_result_df = best_result.metrics_dataframe # Get best result as pandas dataframe
此对象还可以将所有训练运行作为数据帧检索,从而使您可以对结果进行即时数据分析。
# Get a dataframe with the last results for each trial
df_results = results.get_dataframe()
# Get a dataframe of results for a specific score or mode
df = results.get_dataframe(filter_metric="score", filter_mode="max")
有关更多使用示例,请参阅结果分析用户指南。
下一步是什么?#
现在您已经对 Tune 有了初步了解,请查看
用户指南:使用 Tune 与您首选的机器学习库结合使用的教程。
Ray Tune 示例:使用 Tune 与您首选的机器学习库结合使用的端到端示例和模板。
Ray Tune 入门:一个简单的教程,将引导您完成设置 Tune 实验的过程。
更多问题或疑问?#
您可以通过以下渠道发布问题、疑问或反馈
讨论区:用于关于 Ray 用法的提问或功能请求。
GitHub Issues:用于错误报告。
Ray Slack:用于与 Ray 维护者取得联系。
StackOverflow:使用 [ray] 标签进行关于 Ray 的提问。