FAQ

我可以在 X 库中使用 Optuna 吗?(X 是你喜欢的机器学习库)

Optuna 与大多数机器学习库兼容,并且易于与之结合使用。请参考 示例

如何定义带有自身参数的目标函数?

有两种方法可以实现这一点。

首先,可以使用可调用类来实现,如下所示:

import optuna


class Objective:
    def __init__(self, min_x, max_x):
        # Hold this implementation specific arguments as the fields of the class.
        self.min_x = min_x
        self.max_x = max_x

    def __call__(self, trial):
        # Calculate an objective value by using the extra arguments.
        x = trial.suggest_float("x", self.min_x, self.max_x)
        return (x - 2) ** 2


# Execute an optimization by using an `Objective` instance.
study = optuna.create_study()
study.optimize(Objective(-100, 100), n_trials=100)

其次,您可以使用 lambdafunctools.partial 来创建包含额外参数的函数(闭包)。下面是一个使用 lambda 的示例:

import optuna

# Objective function that takes three arguments.
def objective(trial, min_x, max_x):
    x = trial.suggest_float("x", min_x, max_x)
    return (x - 2) ** 2


# Extra arguments.
min_x = -100
max_x = 100

# Execute an optimization by using the above objective function wrapped by `lambda`.
study = optuna.create_study()
study.optimize(lambda trial: objective(trial, min_x, max_x), n_trials=100)

另请参阅 sklearn_additional_args.py 示例,该示例会复用数据集而不是在每次 trial 执行时加载它。

我可以不使用远程 RDB 服务器而使用 Optuna 吗?

是的,这是可能的。

最简单的形式是,Optuna 可以与 InMemoryStorage 一起工作。

study = optuna.create_study()
study.optimize(objective)

如果您想保存和恢复 study,使用 SQLite 作为本地存储会很方便。

study = optuna.create_study(study_name="foo_study", storage="sqlite:///example.db")
study.optimize(objective)  # The state of `study` will be persisted to the local SQLite file.

有关更多详细信息,请参阅 使用 RDB 后端保存/恢复 Study

如何保存和恢复 Study?

保存 Study 有两种方法,具体取决于您是使用 InMemoryStorage(默认)还是远程数据库(RDB)。内存中的 Study 可以使用 picklejoblib 像普通的 Python 对象一样保存和加载。例如,使用 joblib

study = optuna.create_study()
joblib.dump(study, "study.pkl")

然后恢复 Study:

study = joblib.load("study.pkl")
print("Best trial until now:")
print(" Value: ", study.best_trial.value)
print(" Params: ")
for key, value in study.best_trial.params.items():
    print(f"    {key}: {value}")

请注意,Optuna 不支持使用 pickle 在不同的 Optuna 版本之间保存/重新加载。要在不同的 Optuna 版本之间保存/重新加载 Study,请使用 RDB 并根据需要 升级存储 schema。如果您正在使用 RDB,请参阅 使用 RDB 后端保存/恢复 Study 以获取更多详细信息。

如何抑制 Optuna 的日志消息?

默认情况下,Optuna 会显示 optuna.logging.INFO 级别的日志消息。您可以使用 optuna.logging.set_verbosity() 来更改日志级别。

例如,您可以如下停止显示每个 trial 的结果:

optuna.logging.set_verbosity(optuna.logging.WARNING)

study = optuna.create_study()
study.optimize(objective)
# Logs like '[I 2020-07-21 13:41:45,627] Trial 0 finished with value:...' are disabled.

有关更多详细信息,请参阅 optuna.logging

如何保存目标函数中训练的机器学习模型?

Optuna 将超参数值及其对应的目标值保存到存储中,但它会丢弃中间对象,例如机器学习模型和神经网络权重。

为了保存模型或权重,我们建议利用 Optuna 内置的 ArtifactStore。例如,您可以使用 upload_artifact(),如下所示:

base_path = "./artifacts"
os.makedirs(base_path, exist_ok=True)
artifact_store = optuna.artifacts.FileSystemArtifactStore(base_path=base_path)

def objective(trial):
    svc_c = trial.suggest_float("svc_c", 1e-10, 1e10, log=True)
    clf = sklearn.svm.SVC(C=svc_c)
    clf.fit(X_train, y_train)

    # Save the model using ArtifactStore
    with open("model.pickle", "wb") as fout:
        pickle.dump(clf, fout)
    artifact_id = optuna.artifacts.upload_artifact(
        artifact_store=artifact_store,
        file_path="model.pickle",
        study_or_trial=trial.study,
    )
    trial.set_user_attr("artifact_id", artifact_id)
    return 1.0 - accuracy_score(y_valid, clf.predict(X_valid))

study = optuna.create_study()
study.optimize(objective, n_trials=100)

要检索模型或权重,您可以使用 get_all_artifact_meta()download_artifact() 来列出和下载它们,如下所示:

# List all models
for artifact_meta in optuna.artifacts.get_all_artifact_meta(study_or_trial=study):
    print(artifact_meta)
# Download the best model
trial = study.best_trial
best_artifact_id = trial.user_attrs["artifact_id"]
optuna.artifacts.download_artifact(
    artifact_store=artifact_store,
    file_path='best_model.pickle',
    artifact_id=best_artifact_id,
)

有关更全面的指南,请参阅 ArtifactStore 教程

如何获得可重现的优化结果?

为了使 Optuna 建议的参数可重现,您可以通过 samplers 实例的 seed 参数指定固定的随机种子,如下所示:

sampler = TPESampler(seed=10)  # Make the sampler behave in a deterministic way.
study = optuna.create_study(sampler=sampler)
study.optimize(objective)

为了使 HyperbandPruner 的剪枝可重现,请除了 seed 参数外,还指定 Study 的固定 study_name

但是,有两个需要注意的地方。

首先,在分布式或并行模式下优化 study 时,存在固有的非确定性。因此,在这种情况下很难重现相同的结果。如果您想重现结果,建议按顺序执行 study 的优化。

其次,如果您的目标函数行为是非确定性的(即,即使建议了相同的参数,它也不会返回相同的值),则无法重现优化。为了解决这个问题,如果您的优化目标(例如,机器学习库)提供了该选项,请设置一个选项(例如,随机种子)以使行为确定。

如何处理 trials 中的异常?

没有捕获的、引发异常的 trials 将被视为失败,即状态为 FAIL

默认情况下,目标函数中引发的所有异常(除了 TrialPruned)都会传播到 optimize() 的调用者。换句话说,当引发此类异常时,study 将中止。继续使用剩余 trials 的 study 可能是可取的。要做到这一点,您可以在 optimize() 中使用 catch 参数指定要捕获的异常类型。这些类型的异常会在 study 内部捕获,不会进一步传播。

您可以在日志消息中找到失败的 trials。

[W 2018-12-07 16:38:36,889] Setting status of trial#0 as TrialState.FAIL because of \
the following error: ValueError('A sample error in objective.')

您也可以通过检查 trial 状态来找到失败的 trials,如下所示:

study.trials_dataframe()

编号

状态

参数

系统属性

0

TrialState.FAIL

0

由于 ValueError('A test error in objective.'),trial#0 的状态设置为 TrialState.FAIL。

1

TrialState.COMPLETE

1269

1

另请参阅

optimize() 中的 catch 参数。

如何处理 trials 返回的 NaN?

返回 NaN(float('nan'))的 trials 将被视为失败,但它们不会中止 study。

返回 NaN 的 trials 显示如下:

[W 2018-12-07 16:41:59,000] Setting status of trial#2 as TrialState.FAIL because the \
objective function returned nan.

动态更改搜索空间会发生什么?

由于参数搜索空间是在每次调用建议 API(例如 suggest_float()suggest_int())时指定的,因此可以在单个 study 中通过在不同 trials 中采样不同的搜索空间来更改范围。更改后的行为由每个采样器单独定义。

注意

关于 TPE 采样器的讨论。https://github.com/optuna/optuna/issues/822

如何使用两个 GPU 同时评估两个 trials?

如果您的优化目标支持 GPU(CUDA)加速,并且您想在脚本 main.py 中指定要使用的 GPU,最简单的方法是设置 CUDA_VISIBLE_DEVICES 环境变量。

# On a terminal.
#
# Specify to use the first GPU, and run an optimization.
$ export CUDA_VISIBLE_DEVICES=0
$ python main.py

# On another terminal.
#
# Specify to use the second GPU, and run another optimization.
$ export CUDA_VISIBLE_DEVICES=1
$ python main.py

有关更多详细信息,请参阅 CUDA C 编程指南

如何测试我的目标函数?

在测试目标函数时,您可能更喜欢固定的参数值而不是采样的值。在这种情况下,您可以使用 FixedTrial,它根据给定的参数字典建议固定的参数值。例如,您可以像下面这样将任意值 \(x\)\(y\) 输入到目标函数 \(x + y\)

def objective(trial):
    x = trial.suggest_float("x", -1.0, 1.0)
    y = trial.suggest_int("y", -5, 5)
    return x + y


objective(FixedTrial({"x": 1.0, "y": -1}))  # 0.0
objective(FixedTrial({"x": -1.0, "y": -4}))  # -5.0

使用 FixedTrial,您可以编写单元测试,如下所示:

# A test function of pytest
def test_objective():
    assert 1.0 == objective(FixedTrial({"x": 1.0, "y": 0}))
    assert -1.0 == objective(FixedTrial({"x": 0.0, "y": -1}))
    assert 0.0 == objective(FixedTrial({"x": -1.0, "y": 1}))

如何在优化 study 时避免内存不足(OOM)?

如果内存占用随着您运行更多 trials 而增加,请尝试定期运行垃圾回收器。在调用 optimize() 时将 gc_after_trial 设置为 True,或在回调中调用 gc.collect()

def objective(trial):
    x = trial.suggest_float("x", -1.0, 1.0)
    y = trial.suggest_int("y", -5, 5)
    return x + y


study = optuna.create_study()
study.optimize(objective, n_trials=10, gc_after_trial=True)

# `gc_after_trial=True` is more or less identical to the following.
study.optimize(objective, n_trials=10, callbacks=[lambda study, trial: gc.collect()])

运行垃圾回收器存在性能权衡,这可能会带来不可忽略的开销,具体取决于您的目标函数的其他方面的速度。因此,gc_after_trial 默认设置为 False。请注意,上述示例类似于在目标函数内部运行垃圾回收器,但 gc.collect() 即使在引发错误(包括 TrialPruned)时也会被调用。

注意

ChainerMNStudy 目前不提供 gc_after_trialoptimize() 的回调。在使用此类时,您必须在目标函数内部调用垃圾回收器。

如何只在最佳值更新时输出日志?

以下是如何用您自己的日志回调函数替换 optuna 的日志记录功能。实现的 callback 可以传递给 optimize()。下面是一个示例:

import optuna


# Turn off optuna log notes.
optuna.logging.set_verbosity(optuna.logging.WARN)


def objective(trial):
    x = trial.suggest_float("x", 0, 1)
    return x ** 2


def logging_callback(study, frozen_trial):
    previous_best_value = study.user_attrs.get("previous_best_value", None)
    if previous_best_value != study.best_value:
        study.set_user_attr("previous_best_value", study.best_value)
        print(
            "Trial {} finished with best value: {} and parameters: {}. ".format(
            frozen_trial.number,
            frozen_trial.value,
            frozen_trial.params,
            )
        )


study = optuna.create_study()
study.optimize(objective, n_trials=100, callbacks=[logging_callback])

请注意,当您尝试使用 n_jobs!=1(或其他形式的分布式优化)优化目标函数时,此 callback 可能会显示不正确的值,因为它对存储的读写容易发生竞争条件。

如何建议表示比例(即符合狄利克雷分布)的变量?

当您想建议 \(n\) 个表示比例的变量,即 \(p[0], p[1], ..., p[n-1]\) 且满足 \(0 \le p[k] \le 1\) 对所有 \(k\) 以及 \(p[0] + p[1] + ... + p[n-1] = 1\),请尝试以下方法。例如,这些变量可用作插值损失函数时的权重。这些变量符合平坦的 狄利克雷分布

import numpy as np
import matplotlib.pyplot as plt
import optuna


def objective(trial):
    n = 5
    x = []
    for i in range(n):
        x.append(- np.log(trial.suggest_float(f"x_{i}", 0, 1)))

    p = []
    for i in range(n):
        p.append(x[i] / sum(x))

    for i in range(n):
        trial.set_user_attr(f"p_{i}", p[i])

    return 0

study = optuna.create_study(sampler=optuna.samplers.RandomSampler())
study.optimize(objective, n_trials=1000)

n = 5
p = []
for i in range(n):
    p.append([trial.user_attrs[f"p_{i}"] for trial in study.trials])
axes = plt.subplots(n, n, figsize=(20, 20))[1]

for i in range(n):
    for j in range(n):
        axes[j][i].scatter(p[i], p[j], marker=".")
        axes[j][i].set_xlim(0, 1)
        axes[j][i].set_ylim(0, 1)
        axes[j][i].set_xlabel(f"p_{i}")
        axes[j][i].set_ylabel(f"p_{j}")

plt.savefig("sampled_ps.png")

这种方法可以这样证明:首先,如果我们对从 \([0, 1]\) 区间上的均匀分布 \(Uni(0, 1)\) 采样的变量 \(u\) 应用变换 \(x = - \log (u)\),则变量 \(x\) 将遵循尺度参数为 \(1\) 的指数分布 \(Exp(1)\)。此外,对于 \(n\) 个独立地遵循尺度参数为 \(1\) 的指数分布的变量 \(x[0], ..., x[n-1]\),通过将它们归一化为 \(p[i] = x[i] / \sum_i x[i]\),向量 \(p\) 将遵循尺度参数为 \(\alpha = (1, ..., 1)\) 的狄利克雷分布 \(Dir(\alpha)\)。您可以通过计算雅可比矩阵的元素来验证该变换。

如何优化带有约束条件的模型?

当您想优化带有约束条件的模型时,可以使用以下类: TPESamplerNSGAIISamplerGPSamplerBoTorchSampler。下面的示例是使用 NSGAIISampler 对带有约束的 Binh 和 Korn 函数(一个多目标优化问题)进行的基准测试。它有两个约束条件 \(c_0 = (x-5)^2 + y^2 - 25 \le 0\)\(c_1 = -(x - 8)^2 - (y + 3)^2 + 7.7 \le 0\),并找到满足这些约束条件的最佳解决方案。

import optuna


def objective(trial):
    # Binh and Korn function with constraints.
    x = trial.suggest_float("x", -15, 30)
    y = trial.suggest_float("y", -15, 30)

    # Constraints which are considered feasible if less than or equal to zero.
    # The feasible region is basically the intersection of a circle centered at (x=5, y=0)
    # and the complement to a circle centered at (x=8, y=-3).
    c0 = (x - 5) ** 2 + y ** 2 - 25
    c1 = -((x - 8) ** 2) - (y + 3) ** 2 + 7.7

    # Store the constraints as user attributes so that they can be restored after optimization.
    trial.set_user_attr("constraint", (c0, c1))

    v0 = 4 * x ** 2 + 4 * y ** 2
    v1 = (x - 5) ** 2 + (y - 5) ** 2

    return v0, v1


def constraints(trial):
    return trial.user_attrs["constraint"]


sampler = optuna.samplers.NSGAIISampler(constraints_func=constraints)
study = optuna.create_study(
    directions=["minimize", "minimize"],
    sampler=sampler,
)
study.optimize(objective, n_trials=32, timeout=600)

print("Number of finished trials: ", len(study.trials))

print("Pareto front:")

trials = sorted(study.best_trials, key=lambda t: t.values)

for trial in trials:
    print("  Trial#{}".format(trial.number))
    print(
        "    Values: Values={}, Constraint={}".format(
            trial.values, trial.user_attrs["constraint"][0]
        )
    )
    print("    Params: {}".format(trial.params))

如果您对 BoTorchSampler 的示例感兴趣,请参考 此示例代码

有两种约束优化:软约束和硬约束。软约束不一定需要满足,但如果未满足,目标函数会受到惩罚。另一方面,硬约束必须满足。

Optuna 采用软约束,**不支持**硬约束。换句话说,Optuna **不支持**硬约束的内置采样器。

如何并行化优化?

并行化的变体包括以下三种情况。

  1. 单节点多线程并行

  2. 单节点多进程并行

  3. 多节点多进程并行

1. 单节点多线程并行

可以通过在 optuna.study.Study.optimize() 中设置 n_jobs 参数来实现并行化。但是,由于 GIL 的存在,Python 代码不会变快,因为 optuna.study.Study.optimize() 使用 n_jobs!=1 时会使用多线程。

在优化过程中,在某些有限的情况下会变快,例如等待其他服务器请求或与 numpy 进行 C/C++ 处理等,但在其他情况下则不会。

有关 1. 的更多信息,请参阅 API 参考

2. 单节点多进程并行

这可以通过使用 JournalFileBackend 或客户端/服务器 RDB(如 PostgreSQL 和 MySQL)来实现。

有关 2. 的更多信息,请参阅 TutorialEasyParallelization

3. 多节点多进程并行

这可以通过使用客户端/服务器 RDB(如 PostgreSQL 和 MySQL)来实现。但是,如果您处于无法安装客户端/服务器 RDB 的环境中,则无法运行多节点多进程并行。

有关 3. 的更多信息,请参阅 TutorialEasyParallelization

如何解决使用 SQLite3 进行并行优化时出现的错误?

出于以下原因,我们绝不推荐 SQLite3 用于并行优化。

  • 为了并发评估通过 enqueue_trial() 加入队列的 trials,RDBStorage 使用 SELECT … FOR UPDATE 语法,该语法在 SQLite3 中不受支持。

  • SQLAlchemy 的文档中所述,SQLite3(以及 pysqlite 驱动程序)不支持高级别的并发。您可能会遇到“database is locked”错误,该错误发生在某个线程或进程对数据库连接(实际上是文件句柄)持有独占锁,而另一个线程等待锁释放超时。您可以增加默认的 timeout 值,例如 optuna.storages.RDBStorage(“sqlite:///example.db”, engine_kwargs={“connect_args”: {“timeout”: 20.0}})

  • 正如 sqlite.org 的 FAQ 部分中所述,对于通过 NFS 进行的分布式优化,SQLite3 不起作用。

如果您想为此类场景使用基于文件的 Optuna 存储,请考虑使用 JournalFileBackend

import optuna
from optuna.storages import JournalStorage
from optuna.storages.journal import JournalFileBackend

storage = JournalStorage(JournalFileBackend("optuna_journal_storage.log"))

study = optuna.create_study(storage=storage)
...

有关详细信息,请参阅 Medium 博客文章

我能否监控 trials 并在它们意外被终止时自动将其标记为失败?

注意

心跳机制是实验性的。API 在未来可能会发生变化。

运行 trial 的进程可能会被意外终止,通常是在集群环境中的作业调度程序。如果 trials 被意外终止,它们将以 RUNNING 的状态留在存储中,直到我们手动删除它们或更新其状态。在这种情况下,Optuna 支持使用 心跳机制来监控 trials。使用心跳,如果运行 trial 的进程被意外终止,Optuna 将自动将该进程上运行的 trial 的状态从 RUNNING 更改为 FAIL

import optuna

def objective(trial):
    (Very time-consuming computation)

# Recording heartbeats every 60 seconds.
# Other processes' trials where more than 120 seconds have passed
# since the last heartbeat was recorded will be automatically failed.
storage = optuna.storages.RDBStorage(url="sqlite:///:memory:", heartbeat_interval=60, grace_period=120)
study = optuna.create_study(storage=storage)
study.optimize(objective, n_trials=100)

注意

心跳机制旨在与 optimize() 一起使用。如果您使用 ask()tell(),请通过显式调用 tell() 来更改被终止 trials 的状态。

您还可以执行回调函数来处理失败的 trial。Optuna 提供了一个重试失败 trial 的回调,即 RetryFailedTrialCallback。请注意,回调在每个 trial 开始时被调用,这意味着 RetryFailedTrialCallback 会在新的 trial 开始评估时重试失败的 trials。

import optuna
from optuna.storages import RetryFailedTrialCallback

storage = optuna.storages.RDBStorage(
    url="sqlite:///:memory:",
    heartbeat_interval=60,
    grace_period=120,
    failed_trial_callback=RetryFailedTrialCallback(max_retry=3),
)

study = optuna.create_study(storage=storage)

如何处理置换作为参数?

虽然使用现有 API 处理置换等组合搜索空间并不容易,但有一种方便的技术可以处理它们。它涉及将 \(n\) 个项目的置换搜索空间重新参数化为一个独立的 \(n\) 维整数搜索空间。这项技术基于 Lehmer code 的概念。

一个序列的 Lehmer code 是一个相同大小的整数序列,其 \(i\)-th 项表示其 \(i\)-th 项在其之后的逆序数量。换句话说,Lehmer code 的 \(i\)-th 项表示位于原始序列的 \(i\)-th 项之后且小于它的元素的数量。例如,置换 \((3, 1, 4, 2, 0)\) 的 Lehmer code 是 \((3, 1, 2, 1, 0)\)

Lehmer code 不仅提供了一个将置换唯一编码到整数空间的机制,而且还具有一些理想的属性。例如,Lehmer code 项的总和等于将相应置换转换为单位置换所需的最小相邻交换次数。此外,两个置换编码的字典序与其原始序列的字典序相同。因此,Lehmer code 在某种意义上保持了置换之间的“接近性”,这对优化算法很重要。以下是一个解决欧几里德 TSP 的 Optuna 实现示例:

import numpy as np

import optuna


def decode(lehmer_code: list[int]) -> list[int]:
    """Decode Lehmer code to permutation.

    This function decodes Lehmer code represented as a list of integers to a permutation.
    """
    all_indices = list(range(n))
    output = []
    for k in lehmer_code:
        value = all_indices[k]
        output.append(value)
        all_indices.remove(value)
    return output


# Euclidean coordinates of cities for TSP.
city_coordinates = np.array(
    [[0.0, 0.0], [1.0, 0.0], [0.0, 1.0], [1.0, 1.0], [2.0, 2.0], [-1.0, -1.0]]
)
n = len(city_coordinates)


def objective(trial: optuna.Trial) -> float:
    # Suggest a permutation in the Lehmer code representation.
    lehmer_code = [trial.suggest_int(f"x{i}", 0, n - i - 1) for i in range(n)]
    permutation = decode(lehmer_code)

    # Calculate the total distance of the suggested path.
    total_distance = 0.0
    for i in range(n):
        total_distance += np.linalg.norm(
            city_coordinates[permutation[i]] - city_coordinates[np.roll(permutation, 1)[i]]
        )
    return total_distance


study = optuna.create_study()
study.optimize(objective, n_trials=10)
lehmer_code = study.best_params.values()
print(decode(lehmer_code))

如何忽略重复的采样?

Optuna 有时会建议过去已评估过的参数,如果您想避免此问题,可以尝试以下解决方法:

import optuna
from optuna.trial import TrialState


def objective(trial):
    # Sample parameters.
    x = trial.suggest_int("x", -5, 5)
    y = trial.suggest_int("y", -5, 5)
    # Fetch all the trials to consider.
    # In this example, we use only completed trials, but users can specify other states
    # such as TrialState.PRUNED and TrialState.FAIL.
    states_to_consider = (TrialState.COMPLETE,)
    trials_to_consider = trial.study.get_trials(deepcopy=False, states=states_to_consider)
    # Check whether we already evaluated the sampled `(x, y)`.
    for t in reversed(trials_to_consider):
        if trial.params == t.params:
            # Use the existing value as trial duplicated the parameters.
            return t.value

    # Compute the objective function if the parameters are not duplicated.
    # We use the 2D sphere function in this example.
    return x ** 2 + y ** 2


study = optuna.create_study()
study.optimize(objective, n_trials=100)

如何删除上传到 study 的所有工件?

Optuna 支持 artifacts 用于在优化过程中进行大容量数据存储。在进行了大量实验后,您可能希望删除在优化过程中存储的工件。

我们强烈建议为每个 study 创建一个新的目录或存储桶,以便可以通过删除目录或存储桶来完全移除与 study 相关的所有工件。

但是,如果需要从 Python 脚本中删除工件,用户可以使用以下代码:

警告

add_trial()copy_study() 不会复制与 StudyTrial 关联的工件文件。请确保 **不要** 从源 study 或 trial 中删除工件。未能这样做可能会导致意外行为,因为 Optuna 不保证用户外部调用 remove() 时的行为。由于 Optuna 的软件设计,很难正式支持删除功能,我们将来也不打算支持此功能。

from optuna.artifacts import get_all_artifact_meta


def remove_artifacts(study, artifact_store):
    # NOTE: ``artifact_store.remove`` is discouraged to use because it is an internal feature.
    storage = study._storage
    for trial in study.trials:
        for artifact_meta in get_all_artifact_meta(trial, storage=storage):
            # For each trial, remove the artifacts uploaded to ``base_path``.
            artifact_store.remove(artifact_meta.artifact_id)

    for artifact_meta in get_all_artifact_meta(study):
        # Remove the artifacts uploaded to ``base_path``.
        artifact_store.remove(artifact_meta.artifact_id)

我可以在优化之前指定参数的起始点吗?

是的,这是可能的。

有关更全面的指南,请参阅 手动指定超参数

如何解决 MySQL 的大小写敏感问题?

默认情况下,MySQL 执行不区分大小写的字符串比较。但是,Optuna 以区分大小写的方式处理字符串,这在 MySQL 中如果参数名称仅因大小写而异,则会导致冲突。

例如:

def objective(trial):
    a = trial.suggest_int("a", 0, 10)
    A = trial.suggest_int("A", 0, 10)
    return a + A

在这种情况下,Optuna 将“a”和“A”视为不同的,而 MySQL 由于其默认的排序规则设置而不区分大小写。结果,只有其中一个参数会注册到 MySQL 中。

应考虑以下解决方法:

  1. 使用其他存储后端。

    请考虑使用 PostgreSQL 或 SQLite,它们支持区分大小写。

  2. 重命名参数以避免大小写冲突。

    例如,使用“a”和“b”而不是“a”和“A”。

  3. 更改 MySQL 的排序规则设置以区分大小写。

    您可以在数据库、表或列级别配置大小写敏感性。有关更多详细信息,请参阅 MySQL 文档