NNI TensorFlow HPO 快速入门:用 TPE 自动调优 Keras MNIST 模型的完整实战指南
【免费下载链接】nniAn open source AutoML toolkit for automate machine learning lifecycle, including feature engineering, neural architecture search, model compression and hyper-parameter tuning.项目地址: https://gitcode.com/gh_mirrors/nn/nni
导读
本文基于 NNI 官方教程HPO Quickstart with TensorFlow(仓库路径:examples/tutorials/hpo_quickstart_tensorflow/),完整演示如何把官方 TensorFlow 快速入门中的 Keras MNIST 分类模型改造成可自动调优的 Trial,并通过 NNI 的 Python API 配置本地实验、使用 TPE 调优器搜索 4 个超参数。读完本文,你将掌握:模型接入 NNI 所需的 3 个 API 调用、搜索空间的 3 种核心类型(choice / uniform / loguniform)、nni.experiment.Experiment的完整配置流程,以及实验启动、查看与停止的实战技巧。
教程共分 4 步:
- 为自动调优改造模型;
- 定义超参数搜索空间;
- 配置实验(Experiment);
- 运行实验。
说明:本文所述的“官方 TensorFlow 快速入门”对应 examples/tutorials/hpo_quickstart_tensorflow/model.py 中注释引用的 TensorFlow 官方 beginner 教程。教程源代码为两段式“文学编程”脚本:主控脚本 examples/tutorials/hpo_quickstart_tensorflow/main.py 与模型脚本 examples/tutorials/hpo_quickstart_tensorflow/model.py,其渲染后的文档位于 docs/source/tutorials/hpo_quickstart_tensorflow/main.rst。
Step 1:准备模型(为自动调优改造模型)
改造的第一步,是把要被调优的模型放到一个独立的脚本中。原因是:这个脚本会在实验中被并发地评估很多次,将来甚至可能被提交到分布式训练平台上运行。NNI 每次评估一组超参数称为一次trial,因此这个模型脚本也被称为trial code。
本教程中模型定义在 examples/tutorials/hpo_quickstart_tensorflow/model.py 中。这段代码本质上就是 TensorFlow 官方 MNIST 快速入门模型,只是在原版基础上额外增加了 3 个 NNI API 调用:
nni.get_next_parameter():向调优算法获取本次要评估的超参数;nni.report_intermediate_result():上报每个 epoch 的准确率等中间指标;nni.report_final_result():上报最终准确率。
模型代码逐段解读
完整的模型代码如下(节选自 model.py):
import nni import tensorflow as tf # Hyperparameters to be tuned params = { 'dense_units': 128, 'activation_type': 'relu', 'dropout_rate': 0.2, 'learning_rate': 0.001, } # Get optimized hyperparameters optimized_params = nni.get_next_parameter() params.update(optimized_params) print(params) # Load dataset mnist = tf.keras.datasets.mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() x_train, x_test = x_train / 255.0, x_test / 255.0 # Build model with hyperparameters model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(input_shape=(28, 28)), tf.keras.layers.Dense(params['dense_units'], activation=params['activation_type']), tf.keras.layers.Dropout(params['dropout_rate']), tf.keras.layers.Dense(10) ]) adam = tf.keras.optimizers.Adam(learning_rate=params['learning_rate']) loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) model.compile(optimizer=adam, loss=loss_fn, metrics=['accuracy']) # (Optional) Report intermediate results callback = tf.keras.callbacks.LambdaCallback( on_epoch_end = lambda epoch, logs: nni.report_intermediate_result(logs['accuracy']) ) # Train and evaluate the model model.fit(x_train, y_train, epochs=5, verbose=2, callbacks=[callback]) loss, accuracy = model.evaluate(x_test, y_test, verbose=2) # Report final result nni.report_final_result(accuracy)三个关键设计点
① 默认参数 + 覆盖更新的双模式设计。脚本首先用一组默认参数(dense_units=128、activation_type='relu'、dropout_rate=0.2、learning_rate=0.001)初始化params,随后用optimized_params = nni.get_next_parameter()获取调优算法生成的参数并params.update(optimized_params)覆盖默认值。这种写法让脚本具备两种运行模式:
- 直接运行:
nni.get_next_parameter()是无操作(no-op),返回空字典{},此时模型与原始 TensorFlow 快速入门行为完全一致——因此教程建议先直接运行一次脚本,验证环境是否就绪; - 在 NNI 实验内运行:调优算法会把超参数通过命令通道下发到 trial,
get_next_parameter()返回实际采样值。
从源码看,nni/trial.py 中的get_next_parameter()通过get_default_trial_command_channel().receive_parameter()接收参数;而 trial 的环境变量NNI_PLATFORM为空(即直接运行)时,各上报函数会自动退化为无操作,这正是“双模式”实现的底层依据。源码注释还强调:每个 trial 中get_next_parameter()应当且只能调用一次,否则行为未定义。
② 用 KerasLambdaCallback上报逐 epoch 指标。report_intermediate_result被挂在on_epoch_end回调里,把每个 epoch 的logs['accuracy']上报给 NNI。这些中间指标有两个用途:在 Web 门户的 Trial 详情页画出学习曲线;以及配合 NNI Assessor(早停评估器) 实现提前终止——当某个 trial 明显没有希望时及时掐掉,节省计算资源。这一部分是可选的,跳过它实验也能正常运行,但会失去上述能力。
从 nni/trial.py 的实现可以看到,report_intermediate_result会以type='PERIODICAL'的消息类型发送指标,并自动维护递增的_intermediate_seq序号,NNI 据此在 Web 门户中按顺序绘制学习曲线。
③ 最终结果决定调优方向。训练结束后,model.evaluate得到测试集准确率,通过nni.report_final_result(accuracy)上报。从 nni/trial.py 源码可见,该函数发送的指标同时携带parameter_id与trial_job_id,NNI 调优器据此把“准确率”与“这组超参数”绑定起来,从而在下一次采样时给出更优的候选。上报的指标既可以是浮点数,也可以是字典(此时必须以metric['default']存放主指标,其余键用于 Web 门户可视化)。
Step 2:定义搜索空间
模型代码里准备了 4 个待调超参数:dense_units、activation_type、dropout_rate、learning_rate。要在合理的范围内让调优算法采样,就需要为它们定义搜索空间(search space)。
假设我们具备如下先验知识:
| 超参数 | 取值范围 / 分布 | 对应 NNI 类型 |
|---|---|---|
dense_units | 64、128、256 之一 | choice |
activation_type | 'relu'、'tanh'、'swish'或None | choice |
dropout_rate | 0.5 到 0.9 之间的浮点数 | uniform |
learning_rate | 0.0001 到 0.1 之间的浮点数,服从指数分布 | loguniform |
在 NNI 中,dense_units和activation_type的取值空间叫choice(从给定列表中选一个);dropout_rate的取值空间叫uniform(区间内均匀采样);learning_rate的取值空间叫loguniform(指数分布/对数均匀采样,适合跨越多个数量级的数值,如学习率)。细心的话你会发现,这些命名来源于numpy.random的对应分布函数。
搜索空间的定义如下(即 main.py 中的代码):
search_space = { 'dense_units': {'_type': 'choice', '_value': [64, 128, 256]}, 'activation_type': {'_type': 'choice', '_value': ['relu', 'tanh', 'swish', None]}, 'dropout_rate': {'_type': 'uniform', '_value': [0.5, 0.9]}, 'learning_rate': {'_type': 'loguniform', '_value': [0.0001, 0.1]}, }每个键值对由_type(采样类型)和_value(取值范围)组成,其语义与 NumPy 对应分布一致。NNI 支持的全部搜索空间类型与详细规范,参见搜索空间参考文档。
Step 3:配置实验(Experiment)
NNI 用experiment(实验)来管理整个 HPO 过程,experiment config(实验配置)决定了“如何训练模型”与“如何探索搜索空间”。本教程使用local 模式实验——模型就在本机训练,不依赖任何专门的训练平台。
from nni.experiment import Experiment experiment = Experiment('local')接下来依次配置实验的各个组成部分。
配置 Trial 代码
在 NNI 中,每组超参数的一次评估称为一个trial,因此模型脚本被称为trial code:
experiment.config.trial_command = 'python model.py' experiment.config.trial_code_directory = '.'trial_command:trial 进程需要执行的命令;trial_code_directory:trial 代码所在的目录。当它是相对路径时,相对于当前工作目录。
路径相关注意事项:
- 如果你在其他路径下运行
main.py,可以把 trial 代码目录设置为Path(__file__).parent(注意__file__只在标准 Python 中可用,Jupyter Notebook 中不可用); - Linux 且未使用 Conda 的环境,可能要把
"python model.py"改成"python3 model.py",否则可能因找不到解释器而启动失败。
配置搜索空间
experiment.config.search_space = search_space把 Step 2 定义的search_space字典直接赋给experiment.config.search_space即可。
配置调优算法
这里使用TPE(Tree-structured Parzen Estimator)调优器:
experiment.config.tuner.name = 'TPE' experiment.config.tuner.class_args['optimize_mode'] = 'maximize'tuner.name:指定调优器类型(NNI 内置了 TPE、Random、Anneal、Evolution 等多种算法,完整清单见调优器参考);tuner.class_args['optimize_mode']:优化方向。本例目标是最大化测试集准确率,因此设为'maximize';若优化的是损失(越小越好),则应设为'minimize'。
配置要运行的 Trial 数量
experiment.config.max_trial_number = 10 experiment.config.trial_concurrency = 2max_trial_number = 10:总共评估10 组超参数;trial_concurrency = 2:同时并发评估2 组(local 模式下它们会并行占用本机资源)。
运行时长控制:还可以通过max_experiment_duration = '1h'限制总运行时长。如果既不设max_trial_number也不设max_experiment_duration,实验会一直运行下去,直到你按下 Ctrl-C。
重要提示:教程把max_trial_number设为 10 只是为了快速演示,真实场景应设得更大——TPE 调优器在默认配置下需要 20 个 trial 来热身(warm up),即先积累一定数量的随机/历史样本用于建立概率模型,样本太少时搜索效果无法体现。
Step 4:运行实验
实验配置完成后即可启动。选择一个端口(此处用 8080):
experiment.run(8080)启动后,NNI 会在本机拉起训练管理进程并启动 Web 门户,官方渲染输出(见 docs/source/tutorials/hpo_quickstart_tensorflow/main.rst)大致如下:
[2022-04-13 12:11:34] Creating experiment, Experiment ID: enw27qxj [2022-04-13 12:11:34] Starting web server... [2022-04-13 12:11:35] Setting up... [2022-04-13 12:11:35] Web portal URLs: http://127.0.0.1:8080 http://192.168.100.103:8080 True此时通过浏览器访问http://localhost:8080即可查看实验状态:Trial 列表、各 trial 的学习曲线、超参数对比、最佳 Trial 等。从 nni/experiment/experiment.py 的run方法源码可见,run(port, wait_completion=True)默认会阻塞等待实验完成;也可设置debug=True输出更详细的调试日志。
实验结束之后
一切完成后即可安全退出。以下内容均为可选操作:
- 如果使用的是标准 Python 而非 Jupyter Notebook,可以在代码末尾加上
input()或signal.pause()阻止 Python 进程退出,从而在实验结束后继续查看 Web 门户; - 显式停止实验:
# input('Press enter to quit') experiment.stop()关于stop()的两个实用细节(源码见 nni/experiment/experiment.py):
nni.experiment.Experiment.stop()会在Python 进程退出时自动被调用,因此代码中省略它也是安全的;- 实验停止后,还可以调用
nni.experiment.Experiment.view()(源码)重新启动 Web 门户,用于事后查看已结束实验的结果。
其他实验管理方式
本教程全程使用 NNI Python API(nni.experiment.Experiment)来创建和管理实验。除此之外,你也可以使用NNI 命令行工具nnictl来创建、管理、查看和停止实验,例如nnictl create --config config.yml、nnictl view、nnictl stop等,详见 nnictl 命令行工具教程。两种方式面向不同场景:Python API 适合在脚本/Notebook 中端到端编排,nnictl 适合命令行交互式管理。
小结与下一步
至此,你已走通了 NNI 上 TensorFlow HPO 的完整链路:
- 改造模型:把模型独立成脚本,接入
nni.get_next_parameter()、nni.report_intermediate_result()、nni.report_final_result()三个 API; - 定义搜索空间:用
choice/uniform/loguniform描述每个超参数的采样方式与范围; - 配置实验:通过
Experiment('local')指定 trial 命令、代码目录、搜索空间、TPE 调优器与运行规模; - 运行与监控:
experiment.run(8080)启动实验,Web 门户实时查看,stop()/view()管理生命周期。
这个示例对应的两段源码(main.py 与 model.py)同时被 docs/source/hpo/overview.rst 与 docs/source/hpo/quickstart.rst 列为官方入门教程入口,可作为后续开发自己 HPO 任务的起点模板。想要继续深入,可以阅读搜索空间规范掌握全部采样类型,通过调优器参考对比不同算法的适用场景,或借助 Assessor 参考为实验加入早停机制以加速搜索。
【免费下载链接】nniAn open source AutoML toolkit for automate machine learning lifecycle, including feature engineering, neural architecture search, model compression and hyper-parameter tuning.项目地址: https://gitcode.com/gh_mirrors/nn/nni
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考