Pruners

class optuna.pruners.BasePruner[源代码]

Pruner 基类

abstract prune(study, trial)[源代码]

根据报告的值判断是否应对该 trial 剪枝。

注意,该方法不应由库用户调用。相反,optuna.trial.Trial.report()optuna.trial.Trial.should_prune() 提供了接口给用户以在目标函数中实施剪枝机制。

参数
  • study -- 目标 study 的 study 对象。

  • trial -- 目标 trial 的 FrozenTrial 对象。 修改此对象之前需先对其进行复制操作。

返回

一个布尔值,表示是否应对该试验进行剪枝。

class optuna.pruners.MedianPruner(n_startup_trials=5, n_warmup_steps=0, interval_steps=1)[源代码]

使用中值停止规则 的 pruner.

如果该试验的最佳中间结果比同一步骤中先前试验的中间结果的中值差,则进行剪枝。

示例

我们用中值停止规则最小化目标函数。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import train_test_split

import optuna

X, y = load_iris(return_X_y=True)
X_train, X_valid, y_train, y_valid = train_test_split(X, y)
classes = np.unique(y)

def objective(trial):
    alpha = trial.suggest_uniform('alpha', 0.0, 1.0)
    clf = SGDClassifier(alpha=alpha)
    n_train_iter = 100

    for step in range(n_train_iter):
        clf.partial_fit(X_train, y_train, classes=classes)

        intermediate_value = clf.score(X_valid, y_valid)
        trial.report(intermediate_value, step)

        if trial.should_prune():
            raise optuna.TrialPruned()

    return clf.score(X_valid, y_valid)

study = optuna.create_study(direction='maximize',
                            pruner=optuna.pruners.MedianPruner(n_startup_trials=5,
                                                               n_warmup_steps=30,
                                                               interval_steps=10))
study.optimize(objective, n_trials=20)
参数
  • n_startup_trials -- 剪枝将被禁用,直到在同一 study 中完成给定的 trial 次数为止。

  • n_warmup_steps -- 在 trial 超过给定步骤数之前,将禁用剪枝功能。

  • interval_steps -- 不同剪枝检查之间的间隔步骤,预热步骤不算在其中。 如果在剪枝检查时未报告任何值,则该特定检查将被推迟,直到报告了一个值

class optuna.pruners.NopPruner[源代码]

不修剪 trial 的 pruner.

示例

import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import train_test_split

import optuna

X, y = load_iris(return_X_y=True)
X_train, X_valid, y_train, y_valid = train_test_split(X, y)
classes = np.unique(y)

def objective(trial):
    alpha = trial.suggest_uniform('alpha', 0.0, 1.0)
    clf = SGDClassifier(alpha=alpha)
    n_train_iter = 100

    for step in range(n_train_iter):
        clf.partial_fit(X_train, y_train, classes=classes)

        intermediate_value = clf.score(X_valid, y_valid)
        trial.report(intermediate_value, step)

        if trial.should_prune():
            assert False, "should_prune() should always return False with this pruner."
            raise optuna.TrialPruned()

    return clf.score(X_valid, y_valid)

study = optuna.create_study(direction='maximize',
                            pruner=optuna.pruners.NopPruner())
study.optimize(objective, n_trials=20)
class optuna.pruners.PercentilePruner(percentile, n_startup_trials=5, n_warmup_steps=0, interval_steps=1)[源代码]

保留指定百分位 trial 的 pruner.

如果在同一步骤的 trial 中,最佳中间值位于最低百分位数,则进行剪枝。

示例

import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import train_test_split

import optuna

X, y = load_iris(return_X_y=True)
X_train, X_valid, y_train, y_valid = train_test_split(X, y)
classes = np.unique(y)

def objective(trial):
    alpha = trial.suggest_uniform('alpha', 0.0, 1.0)
    clf = SGDClassifier(alpha=alpha)
    n_train_iter = 100

    for step in range(n_train_iter):
        clf.partial_fit(X_train, y_train, classes=classes)

        intermediate_value = clf.score(X_valid, y_valid)
        trial.report(intermediate_value, step)

        if trial.should_prune():
            raise optuna.TrialPruned()

    return clf.score(X_valid, y_valid)

study = optuna.create_study(
    direction='maximize',
    pruner=optuna.pruners.PercentilePruner(25.0, n_startup_trials=5,
                                           n_warmup_steps=30, interval_steps=10))
study.optimize(objective, n_trials=20)
参数
  • percentile -- 百分位数必须介于 0 到 100 之间(例如,如果给定 25.0,保留第25个百分位数 trial 的顶部)。

  • n_startup_trials -- 剪枝将被禁用,直到在同一 study 中完成给定的 trial 次数为止。

  • n_warmup_steps -- 在 trial 超过给定步骤数之前,将禁用剪枝功能。

  • interval_steps -- 不同剪枝检查之间的间隔步骤,预热步骤不算在其中。 如果在剪枝检查时未报告任何值,则该特定检查将被推迟,直到报告了一个值。该值最小为1.

class optuna.pruners.SuccessiveHalvingPruner(min_resource='auto', reduction_factor=4, min_early_stopping_rate=0)[源代码]

使用异步连续减半算法的 pruner.

Successive Halving 是一种基于 bandit 的算法,用于识别多种配置中的最佳配置。该类实现了异步版本的 Successive Halving 详细描述请参考 Asynchronous Successive Halving

注意,该类并不关心最大资源的参数(文中以 \(R\) 来表示)。给每个 trial 分配的最大资源限制通常是在目标函数内部完成的。(e.g., simple.pystepchainer_integration.py ` 中的 ``EPOCH`.

示例

我们使用 SuccessiveHalvingPruner 来最小化目标函数。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import train_test_split

import optuna

X, y = load_iris(return_X_y=True)
X_train, X_valid, y_train, y_valid = train_test_split(X, y)
classes = np.unique(y)

def objective(trial):
    alpha = trial.suggest_uniform('alpha', 0.0, 1.0)
    clf = SGDClassifier(alpha=alpha)
    n_train_iter = 100

    for step in range(n_train_iter):
        clf.partial_fit(X_train, y_train, classes=classes)

        intermediate_value = clf.score(X_valid, y_valid)
        trial.report(intermediate_value, step)

        if trial.should_prune():
            raise optuna.TrialPruned()

    return clf.score(X_valid, y_valid)

study = optuna.create_study(direction='maximize',
                            pruner=optuna.pruners.SuccessiveHalvingPruner())
study.optimize(objective, n_trials=20)
参数
  • min_resource -- 用于指定分配给单个 trial 的最小资源 (在 paper 中 该参数是 \(r\)).默认情况下,该参数是 'auto', 此时,其值是由一个启发式算法设定的,该算法会观察完成第一个 trial 所需要的步数。除非执行了 \(\mathsf{min}\_\mathsf{resource} \times \mathsf{reduction}\_\mathsf{factor}^{ \mathsf{min}\_\mathsf{early}\_\mathsf{stopping}\_\mathsf{rate}}\) 步 (也就是第一级的完成点), 否则该 trial 不会被剪枝。 如果一个 trial 完成了第一级,它不会跳入下一级,除非该 trial 的值 处于所有已抵达该点(否则就被剪枝了)的trial \({1 \over \mathsf{reduction}\_\mathsf{factor}}\) 的顶部。如果该 trial 赢得了竞争,他就会一只运行知道下一个完成点到来 (也就是 \(\mathsf{min}\_\mathsf{resource} \times \mathsf{reduction}\_\mathsf{factor}^{ (\mathsf{min}\_\mathsf{early}\_\mathsf{stopping}\_\mathsf{rate} + \mathsf{rung})}\) 步) 并且重复上一个过程。 .. note:: 如果每个 trial 的最后中间值的步骤不同的话,请 手动设定最小的可能步骤 min_resource.

  • reduction_factor -- 用于设置可提升 trial 的缩减因子参数(在 论文 中该参数是 \(\eta\) )。在每一级的完成点,大约有 \({1 \over \mathsf{reduction}\_\mathsf{factor}}\) 的 trial会被提升。

  • min_early_stopping_rate -- 用于确定最小提前终止率的参数。 (在`论文 <http://arxiv.org/abs/1810.05934>`_ 中它是 \(s\)).

class optuna.pruners.HyperbandPruner(min_resource: int = 1, max_resource: Union[str, int] = 'auto', reduction_factor: int = 3)[源代码]

使用 hyperband 的 pruner.

由于 SuccessiveHalving (SHA) 需要配置的总数 \(n\) 作为它的超参数,对于一个有限的预算 \(B\) 来说,平均来讲所有的配置都有 \(B \over n\) 的资源。如你所见,这中间存在一个 \(B\)\(B \over n\) 之间的权衡。通过对于固定的预算尝试不同的 \(n\), <http://www.jmlr.org/papers/volume18/16-558/16-558.pdf>`_ 研究了这种权衡

注解

注解

如果你配合 TPESampler 使用 HyperbandPruner, 我们推荐你考虑设置更大的 n_trials 或者 timeout 来充分利用 TPESampler 的特性,因为,TPESampler 在开始时使用了一些 (默认情况下是 \(10\)) Trial.

由于 Hyperband 运行多个 SuccessiveHalvingPruner 并且基于当前 Trial 的 bracket ID 来收集 trial, 每一个 bracket 需要观察起码 \(10\)Trial好让 TPESampler 来调整它的搜索空间。

因此,如果 HyperbandPruner\(4\) 个 pruner 的话,在一开始时他就会用掉起码 \(4 \times 10\) 个 trial.

注解

Hyperband 有好几个 SuccessiveHalvingPruner.每一个 SuccessiveHalvingPruner 都是原文中的 "bracket". bracket 的数目是控制 Hyperband 提前终止行为的一个重要因子,它是由 min_resource, max_resourcereduction_factor 共同确定,形式是 The number of brackets = floor(log_{reduction_factor}(max_resource / min_resource)) + 1.请设置 reduction_factor 以让 bracket 的数目不要太大 (一般情况下是 4 ~ 6 )。更多细节请参考 原始论文 中的 Section 3.6.

示例

我们使用 Hyperband 剪枝算法来最小化目标函数。

import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import train_test_split

import optuna

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y)
classes = np.unique(y)
n_train_iter = 100

def objective(trial):
    alpha = trial.suggest_uniform('alpha', 0.0, 1.0)
    clf = SGDClassifier(alpha=alpha)

    for step in range(n_train_iter):
        clf.partial_fit(X_train, y_train, classes=classes)

        intermediate_value = clf.score(X_valid, y_valid)
        trial.report(intermediate_value, step)

        if trial.should_prune():
            raise optuna.TrialPruned()

    return clf.score(X_valid, y_valid)

study = optuna.create_study(
    direction='maximize',
    pruner=optuna.pruners.HyperbandPruner(
        min_resource=1,
        max_resource=n_train_iter,
        reduction_factor=3
    )
)
study.optimize(objective, n_trials=20)
参数
  • min_resource -- 用于指定分配给单个 trial 的最小资源 (在 原文中 该参数是 \(r\)).一个更小的 \(r\) 会更快返回结果,但是 一个更大的 \(r\) 能保证更佳的不同配置之间的判定。具体细节见 SuccessiveHalvingPruner.

  • max_resource -- 用于指定分配给一个 trial 的最大资源参数。原文中的 \(R\) 对应着 max_resource / min_resource. 该值代表着且应符合最大迭代步数(也就是一个神经网络的 epoch 数)。当该参数是 "auto" 时,最大资源是根据已经完成的 trial 来预估的。 .. note:: "设置成 "auto" 时,最大资源将是头一个(如果在并行优化的情况下,就是头几个中的一个)已完成的 trial 的 report() 报告的最大步数。如果每个 trial 的最后中间值的步骤不同的话,请 手动设定最大的可能步骤 max_resource.

  • reduction_factor -- A parameter for specifying reduction factor of promotable trials noted as \(\eta\) in the paper. See the details for SuccessiveHalvingPruner.

注解

在 v1.1.0 版本中作为一个试验特性被加入的,该接口可能在新版中在没有提前告知的情况下改变。参见 https://github.com/optuna/optuna/releases/tag/v1.1.0.

class optuna.pruners.ThresholdPruner(lower: Optional[float] = None, upper: Optional[float] = None, n_warmup_steps: int = 0, interval_steps: int = 1)[源代码]

用于检测 trial 的无关度量的 pruner.

如果一个度量超过了上限,低于下限或者变成了 nan, 就剪枝。

示例

from optuna import create_study
from optuna.pruners import ThresholdPruner
from optuna import TrialPruned

def objective_for_upper(trial):
    for step, y in enumerate(ys_for_upper):
        trial.report(y, step)

        if trial.should_prune():
            raise TrialPruned()
    return ys_for_upper[-1]


def objective_for_lower(trial):
    for step, y in enumerate(ys_for_lower):
        trial.report(y, step)

        if trial.should_prune():
            raise TrialPruned()
    return ys_for_lower[-1]


ys_for_upper = [0.0, 0.1, 0.2, 0.5, 1.2]
ys_for_lower = [100.0, 90.0, 0.1, 0.0, -1]
n_trial_step = 5

study = create_study(pruner=ThresholdPruner(upper=1.0))
study.optimize(objective_for_upper, n_trials=10)

study = create_study(pruner=ThresholdPruner(lower=0.0))
study.optimize(objective_for_lower, n_trials=10)
Args
lower:

一个确定 pruner 是否需要剪枝的最小值。如果某个中间值小于此值,就剪枝。

upper:

一个确定 pruner 是否需要剪枝的最大值。如果某个中间值大于此值,就剪枝。

n_warmup_steps:

在 trial 超过给定步骤数之前,将禁用剪枝功能。

interval_steps:

不同剪枝检查之间的间隔步骤,预热步骤不算在其中。 如果在剪枝检查时未报告任何值,则该特定检查将被推迟,直到报告了一个值。该值最小为1.