MLOps极致细节:12. MLFlow 超参数调参案例: hyperopt优化调参(附代码)
这里我们提供一些列案例,基于keras的深度学习框架对winequality-white
数据进行quanlity的预测。此章节的代码基于MLFlow官网GitHub链接。
本章节将详细解释如何通过hyperopt优化搜索,基于MLFlow以及keras的端到端深度学习流程。相关主要代码参见search_hyperopt.py
文件。关于整个系列案例如何运行,请参见博客:MLOps极致细节:9. MLFlow 超参数调参案例综述(附代码)。相关代码参见此Gitee链接。
文章目录
1 代码的运行结果
在MLOps极致细节:9. MLFlow 超参数调参案例综述(附代码)中,我们解释了三种运行此代码的方式:
- 我们把此案例相关代码克隆到本地:
git clone https://gitee.com/yichaoyyds/mlflow-ex-hyperparametertunning.git
。然后进入mlflow-ex-hyperparametertunning
文件夹,在terminal中运行py文件,比如python search_hyperopt.py
; - 我们把此案例相关代码克隆到本地:
git clone https://gitee.com/yichaoyyds/mlflow-ex-hyperparametertunning.git
。然后再按照下面章节的步骤运行mlrun
指令(比如mlflow run -e hyperopt --experiment-id <individual_runs_experiment_id> ./mlflow-ex-hyperparametertunning/
); - 不用把代码克隆到本地。mlflow也支持直接跑git上的代码(比如
mlflow run -e hyperopt --experiment-id <individual_runs_experiment_id> https://gitee.com/yichaoyyds/mlflow-ex-hyperparametertunning.git
)。
注意,如果你要运行起代码,请务必先参考上述文档的步骤。
假设我们已经顺利地运行代码。运行完后,我们会看到mlruns
这个文件夹。我们在terminal输入mlflow ui
,我们来看一下保存在mlruns
里面的数据。和之前一样,我们还是先去看parent run里面保存的best run的数据:
然后,我们选择几个child run,对比一下:
我们选择那个best run,看一下每一个epoch下train,validate,test的RMSE值得变化图
2 参数的设定
在search_hyperopt.py
中,参数相关的设定代码如下:
@click.command(help="Perform hyperparameter search with Hyperopt library." "Optimize dl_train target.")
@click.option("--max-runs", type=click.INT, default=20, help="Maximum number of runs to evaluate.")
@click.option("--epochs", type=click.INT, default=100, help="Number of epochs")
@click.option("--metric", type=click.STRING, default="rmse", help="Metric to optimize on.")
@click.option("--algo", type=click.STRING, default="tpe.suggest", help="Optimizer algorithm.")
@click.option("--seed", type=click.INT, default=97531, help="Seed for the random generator")
@click.option("--training-data", type=click.STRING, default="http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv",\
help="Input dataset link.")
关于click的使用说明,请参见我的博客:MLOps极致细节:10. MLFlow 超参数调参案例: 基于keras的端到端深度学习流程。
在MLproject
文件中,我们也有相关的参数赋值:
# Use Hyperopt to optimize hyperparams of the train entry_point.
hyperopt:
parameters:
training_data: {type: string, default: "http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv"}
max_runs: {type: int, default: 12}
epochs: {type: int, default: 32}
metric: {type: string, default: "rmse"}
algo: {type: string, default: "tpe.suggest"}
seed: {type: int, default: 97531}
command: "python -O search_hyperopt.py --training-data {training_data}
--max-runs {max_runs}
--epochs {epochs}
--metric {metric}
--algo {algo}
--seed {seed}"
所以,我们设定以下参数:
- training_data:训练数据的URI地址;
- max_runs:run的次数。每一个run的循环,我们将随机给
lr
和momentum
赋值; - epochs:我们需要训练多少个loop;
- algo:Hyperopt的算法选择;
- seed:一个随机数的选择,用于
np.random.seed(seed)
3 MLFlow Projects相关文件的介绍
关于MLFlow Projects
的详细介绍,请参见我之前的一篇博客。关于此案例的MLproject
以及conda.yaml
文件介绍,参见博客MLOps极致细节:10. MLFlow 超参数调参案例: 基于keras的端到端深度学习流程。
4 整体逻辑
其实search_hyperopt.py
的总体逻辑和search_random.py
几乎一样,最大的区别就在于,一个是随机选择超参数,一个是基于hyperopt
优化选择超参数。
我们先新建一个parent run
with mlflow.start_run() as run:
给lr
和momentum
这两个超参数一个范围:
space = [
hp.uniform("lr", 1e-5, 1e-1),
hp.uniform("momentum", 0.0, 1.0),
]
然后我们按照hyperopt的要求对不同的lr
和momentum
值进行模型的训练:
best = fmin(
fn=new_eval(epochs, experiment_id, train_null_loss, valid_null_loss, test_null_loss),
space=space,
algo=tpe.suggest if algo == "tpe.suggest" else rand.suggest,
max_evals=max_runs,
)
对于每一个训练,我们都会新建一个child run,然后运行train.py
的程序:
with mlflow.start_run(nested=True) as child_run:
p = mlflow.projects.run(
run_id=child_run.info.run_id,
uri=".",
entry_point="train",
parameters={
"training_data": training_data,
"epochs": str(nepochs),
"learning_rate": str(lr),
"momentum": str(momentum),
"seed": str(seed),
},
experiment_id=experiment_id,
synchronous=False,
)
运行完后,我们会选择validation rmse值最低的那个run最为best run:
for r in runs:
if r.data.metrics["val_rmse"] < best_val_valid:
best_run = r
best_val_train = r.data.metrics["train_rmse"]
best_val_valid = r.data.metrics["val_rmse"]
best_val_test = r.data.metrics["test_rmse"]
在代码中,我写了详细的注释,感兴趣的话可以过一遍代码。
5 hyperopt介绍
当我们创建好模型后,还要调整各个模型的参数,才找到最好的匹配。即使模型还可以,如果它的参数设置不匹配,同样无法输出好的结果。 常用的调参方式有Grid search 和 Random search ,Grid search 是全空间扫描,所以比较慢,Random search 虽然快,但可能错失空间上的一些重要的点,精度不够。 而Hyperopt是一种通过贝叶斯优化来调整参数的工具,该方法较快的速度,并有较好的效果。
简介我们就不赘述了,感兴趣的同学可以自行搜索,这里我找了几个简单易懂的例子。
best = fmin(
fn=lambda x: (x-1)**2,
space=hp.uniform('x', -2, 2),
algo=tpe.suggest,
max_evals=100)
print best
这个就是对y=(x-1)^2
的优化。x取值在-2到2之间,uniform分布。hyperopt的作用就是找到这个cost function的最小值,返回对应x的值。
所以,fn
实际上就是需要优化的cost function,space
就是参数搜索空间,algo
指的是搜索算法,max_evals
指的是迭代次数。关于space
的写法,下图的整理比较详细。