使用 Hyperopt 优化超参数

已完成

Hyperopt 是用于超参数优化的开放源代码 Python 库。 使用 Databricks Runtime 的 ML 变体创建群集时,会自动安装 Hyperopt。 要在训练模型时使用它,应执行以下步骤:

  1. 定义用于训练和评估模型的目标函数。
  2. 定义超参数搜索空间。
  3. 指定搜索算法。
  4. 运行 Hyperopt 的 fmin 函数以优化训练函数。

定义目标函数

Hyperopt 的工作原理是以迭代方式调用将返回数值的函数(通常称为“目标”函数),并优化传递给该函数的参数,使返回值最小化,这种方法通常称为“优化”。 因此,第一个要求是将模型训练和评估逻辑封装在一个函数中,该函数:

  • 接受包含超参数值列表的参数。
  • 使用提供的超参数值训练模型。
  • 根据预测性能的目标指标评估模型。
  • 返回一个反映性能指标的数值,这样,提高模型性能就会降低返回值。

例如,以下函数使用 Spark MLlib 库中的 LogisticRegression 算法训练机器学习模型。

def objective(params):
    from pyspark.ml.classification import LogisticRegression
    from pyspark.ml.evaluation import MulticlassClassificationEvaluator
    from hyperopt import STATUS_OK

    data_df = get_training_data() # This is just an example!
    splits = data_df.randomSplit([0.7, 0.3])
    training_df = splits[0]
    validation_df = splits[1]

    # Train a model using the provided hyperparameter values
    lr = LogisticRegression(labelCol="label", featuresCol="features",
                            maxIter=params['Iterations'],
                            regParam=params['Regularization'])
    model = lr.fit(training_df)

    # Evaluate the model
    predictions = model.transform(validation_df)
    eval = MulticlassClassificationEvaluator(labelCol="label",
                                             predictionCol="prediction",
                                             metricName="accuracy")
    accuracy = eval.evaluate(predictions)
    
    # Hyperopt *minimizes* the function, so return *negative* accuracy.
    return {'loss': -accuracy, 'status': STATUS_OK}

在此示例中,params 参数是一个目录,包含下面两个命名值的值:“迭代”和“正则化”。 这些值将分配给用于训练模型的逻辑回归算法的 maxIter 和 regParam 超参数。

然后,函数评估训练的模型以计算其准确度指标,该指标是一个介于 0.0 和 1.0 之间的值,指示模型进行的正确预测的比例。

最后,函数返回一个值,Hyperopt 应最小化该值以改进模型。 在这种情况下,目标指标是准确度,其值越高表示模型越好,因此,函数返回此值的负值(准确度越高,返回值越低)。

定义超参数搜索空间

每次调用目标函数时,它都需要一个包含要尝试的超参数值的参数。 若要尝试所有可能的值组合,需要为 Hyperopt 定义一个搜索空间,以便为每次试用选择值。

Hyperopt 提供了一些表达式,可用于定义每个超参数的取值范围,包括:

  • hp.choice(label, options):返回你列出的 options 之一。
  • hp.randint(label, upper):返回 [0, 上限] 范围内的一个随机整数。
  • hp.uniform(label, low, high):统一返回一个介于 lowhigh 之间的值。
  • hp.normal(label, mu, sigma):返回一个正态分布的实数值,其中均值为 mu,标准差为 sigma

提示

有关表达式的完整列表,请参阅 Hyperopt 文档

下面的示例代码为上一个示例中使用的超参数定义了一个搜索空间:

from hyperopt import hp

search_space = {
    'Iterations': hp.randint('Iterations', 10),
    'Regularization': hp.uniform('Regularization', 0.0, 1.0)
}

指定搜索算法

Hyperopt 使用搜索算法从搜索空间中选择超参数值,并尝试优化目标函数。 Hyperopt 在对搜索空间进行抽样时有两个主要选择:

  • hyperopt.tpe.suggest:Parzen 估算器树 (TPE),它是一种贝叶斯方法,根据过去的结果,自适应地选择新的超参数设置。
  • hyperopt.rand.suggest:随机搜索,这是一个对搜索空间进行随机抽样的非自适应方法。

下面的示例代码指定了 TPE 算法。

from hyperopt import tpe

algo = tpe.suggest

运行 Hyperopt 的 fmin 函数

最后,为了执行 Hyperopt 运行,可以使用 fmin 函数,该函数基于搜索算法使用搜索空间中的超参数组合重复调用目标函数。 fmin 函数的目标是最小化目标函数返回的值(从而优化模型的性能)。

以下示例代码使用 fmin 函数调用前面定义的目标函数。 使用了前面示例中定义的搜索空间和算法,在 fmin 函数返回找到的性能最佳的参数值组合之前,函数将进行多达 100 次的计算。

from hyperopt import fmin

argmin = fmin(
  fn=objective,
  space=search_space,
  algo=algo,
  max_evals=100)

print("Best param values: ", argmin)

上述代码的输出类似于以下示例。

Best param values:  {'Iterations': 6, 'Regularization': 0.5461699702338606}