NNI 自动调参使用。

前言

NNI是由微软研究院,开发的深度学习开发工具。
Neural Network Intelligence 是一个工具包,可以有效帮助用户设计并调优汲取学习模型的神经网络架构,以及超参数。具有易于使用、可扩展、灵活、高效的特点。
NNI (Neural Network Intelligence) 是一个轻量而强大的工具,可以帮助用户 自动化:
超参调优,架构搜索,模型压缩,特征工程。本文只简单介绍如何超参数调优。

1 原理

工作流程大概如下:

Input: 搜索空间(search space), 实验代码(trial code), 配置文件(config file)
Output: 一组最优的超级参数(hyperparameter)配置

1: For t = 0, 1, 2, ..., maxTrialNum(配置文件设置的最大实验次数),
2:      hyperparameter = chose a set of parameter from search space //从搜索空间选择对应的一组参数
3:      final result = run_trial_and_evaluate(hyperparameter) //利用这组参数进行实验,并返回最终的结果
4:      report final result to NNI //将本组超参的最终结果报告给NNI
5:      If reach the upper limit time: // 达到了设置实验运行时间的上限,
6:          Stop the experiment //停止实验
7: return hyperparameter value with best final result // 返回最佳的一组超级参数

2 安装

# 安装nni
    python3 -m pip install --upgrade nni

3 实例

一个完整的NNI 代码,需要三个文件:modle.py 即之前训练代码,config.yml 配置文件,search_space.json 超参数搜索的空间范围。
search_space.json

{
    "batch_size": {"_type":"choice", "_value": [16, 32, 64, 128]},
    "hidden_size":{"_type":"choice","_value":[128, 256, 512, 1024]},
    "lr":{"_type":"choice","_value":[0.0001, 0.001, 0.01, 0.1]},
    "momentum":{"_type":"uniform","_value":[0, 1]}
}

解释:

{"_type": "choice", "_value": options}
# dropout_rate":{"_type":"uniform","_value":[0.5, 0.9]}的结果为0.5或者0.9

{"_type": "uniform", "_value": [low, high]}

# 变量是 low 和 high 之间均匀分布的值。
# 当优化时,此变量值会在两侧区间内。

{"_type": "quniform", "_value": [low, high, q]}
# 从low开始到high结束,步长为q。
# 比如{"_type": "quniform", "_value": [0, 10, 2]}的结果为0,2,4,6,8,10

{"_type": "normal", "_value": [mu, sigma]}
# 变量值为实数,且为正态分布,均值为 mu,标准方差为 sigma。 优化时,此变量不受约束。

{"_type": "randint", "_value": [lower, upper]}
# 从 lower (包含) 到 upper (不包含) 中选择一个随机整数。

更多参考文档,详见:https://nni.readthedocs.io/zh/stable/hpo/search_space.html

config.yaml

authorName: default
experimentName: example_mnist
trialConcurrency: 1
maxExecDuration: 1h
maxTrialNum: 20
#choice: local, remote, pai
trainingServicePlatform: local
searchSpacePath: search_space.json
#choice: true, false
useAnnotation: false
tuner:
  #choice: TPE, Random, Anneal, Evolution, BatchTuner, MetisTuner, GPTuner
  #SMAC (SMAC should be installed through nnictl)
  builtinTunerName: TPE
  classArgs:
    #choice: maximize, minimize
    optimize_mode: maximize
trial:
  command: python test_nni.py
  codeDir: .
  gpuNum: 0


# 基础设置
authorName: az  # 必填
experimentName: demo  # 必填

trialConcurrency: 5 # 必填,指定同时运行的 Trial 任务的最大数量。
# ! 如果 trialGpuNum 大于空闲的 GPU 数量,并且并发的 Trial 任务数量还没达到 trialConcurrency,Trial 任务会被放入队列,等待分配 GPU 资源。

maxExecDuration: 24h #  可选。 整个调参过程最长运行时间。 默认值:999d。
maxTrialNum: 10 # 可选。 NNI 创建的最大 Trial 任务数。 默认值:99999。
trainingServicePlatform: local  # 指定运行 Experiment 的平台,包括 local, remote, pai, kubeflow, frameworkcontroller

# 搜索空间文件
searchSpacePath: search_space.json
useAnnotation: false # 如果 useAnnotation 为 true,searchSpacePath 字段会被删除。

# 日志
logDir: ./log  # 可选。 目录的路径。 默认值:/nni-experiments
logLevel: info

# 调参器
tuner:
  builtinTunerName: TPE # 指定内置的调参算法

# 运行的命令,以及 Trial 代码的路径
trial:
  command: python3 run_demo.py
  codeDir: . #  必需字符串。 指定 Trial 文件的目录。
  gpuNum: 1 #  可选、整数。 指定了运行每个 Trial 进程的 GPU 数量。 默认值为 0。

# 本机模式下配置,可选。
localConfig:
  gpuIndices: 0,3 # 默认值none。设置后,只有指定的 GPU 会被用来运行 Trial 任务。
  # ! 和CUDA_VISIBLE_DEVICE=0,3 的效果相同,在程序内部的gpu编号依旧是从0开始的
  maxTrialNumPerGpu: 2 #  默认值1。指定1个GPU上最大并发trail的数量
  useActiveGpu: false #  默认值false。是否使用已经被其他进程使用的gpu。

除了command,maxExecDuration,trialConcurrency,gpuNum,optimize_mode需要更改,这里的参数一般不需要更改。
command是nni的运行后将要执行的指令,mnist.py改为你的main.py或者train.py等等主程序。
maxExecDuration是整个NNI自动调参的时间,注意不是一次训练的时间。
trialConcurrency是trail的并发数,这个需要根据自己的GPU数量设置,而不是下面的gpuNum,trail代表一次调参的过程,理解为用一种超参数在运行你的train.py,并发数设为x,就有x个trainer在训练!
gpuNum是每个trail所需要的gpu个数,而不是整个nni调参所需要的gpu个数。对于大型任务,单独训练一次需要N个GPU的话,这个值就设置为N;如果单次训练,一个GPU就足够,请把这个值设置为1。
需要的GPU总数为trialConcurrencygpuNum,即 trail的个数每个trail需要的gpu个数
optimize_mode对应着优化的方向,有最大和最小两种方式,具体如何设置在下一步中提到。

NNI 是怎么组合这些参数的呢?这是 tuner 参数干的事,为了让机器学习和深度学习模型适应不同的任务和问题,我们需要进行超参数调优,而自动化调优依赖于优秀的调优算法。NNI 内置了先进的调优算法,并且提供了易于使用的 API。

在 NNI 中,Tuner 向 trial 发送超参数,接收运行结果从而评估这组超参的性能,然后将下一组超参发送给新的 trial。

下表简要介绍了 NNI 内置的调优算法。

Tuner 算法简介
TPE Tree-structured Parzen Estimator (TPE) 是一种基于序列模型的优化方法。SMBO方法根据历史数据来顺序地构造模型,从而预估超参性能,并基于此模型来选择新的超参。
Random Search (随机搜索) 随机搜索在超算优化中表现出了令人意外的性能。如果没有对超参分布的先验知识,我们推荐使用随机搜索作为基线方法。
Anneal (退火) 朴素退火算法首先基于先验进行采样,然后逐渐逼近实际性能较好的采样点。该算法是随即搜索的变体,利用了反应曲面的平滑性。该实现中退火率不是自适应的。
Naive Evolution(朴素进化) 朴素进化算法来自于 Large-Scale Evolution of Image Classifiers。它基于搜索空间随机生成一个种群,在每一代中选择较好的结果,并对其下一代进行变异。朴素进化算法需要很多 Trial 才能取得最优效果,但它也非常简单,易于扩展。
SMAC SMAC 是基于序列模型的优化方法 (SMBO)。它利用使用过的最突出的模型(高斯随机过程模型),并将随机森林引入到SMBO中,来处理分类参数。NNI 的 SMAC tuner 封装了 GitHub 上的 SMAC3。参考论文注意:SMAC 算法需要使用 pip install nni[SMAC] 安装依赖,暂不支持 Windows 操作系统。
Batch(批处理) 批处理允许用户直接提供若干组配置,为每种配置运行一个 trial。
Grid Search(网格遍历) 网格遍历会穷举搜索空间中的所有超参组合。
Hyperband Hyperband 试图用有限的资源探索尽可能多的超参组合。该算法的思路是,首先生成大量超参配置,将每组超参运行较短的一段时间,随后抛弃其中效果较差的一半,让较好的超参继续运行,如此重复多轮。参考论文
Metis 大多数调参工具仅仅预测最优配置,而 Metis 的优势在于它有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 trial 的建议。大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。参考论文
BOHB BOHB 是 Hyperband 算法的后续工作。Hyperband 在生成新的配置时,没有利用已有的 trial 结果,而本算法利用了 trial 结果。BOHB 中,HB 表示 Hyperband,BO 表示贝叶斯优化(Byesian Optimization)。BOHB 会建立多个 TPE 模型,从而利用已完成的 Trial 生成新的配置。参考论文
GP (高斯过程) GP Tuner 是基于序列模型的优化方法 (SMBO),使用高斯过程进行 surrogate。参考论文
PBT PBT Tuner 是一种简单的异步优化算法,在固定的计算资源下,它能有效的联合优化一组模型及其超参来最优化性能。参考论文
DNGO DNGO 是基于序列模型的优化方法 (SMBO),该算法使用神经网络(而不是高斯过程)去建模贝叶斯优化中所需要的函数分布。
可以看到本示例中,选择的是TPE tuner.

其他的参数比如 trialGpuNumber,指的是使用的gpu数量,trialConcurrency 指的是并发数。trainingService 中 platform 为 local,指的是本地训练。

当然,还有许多参数可以选,比如:

trialConcurrency: 2 # 同时运行 2 个 trial
maxTrialNumber: 10 # 最多生成 10 个 trial
maxExperimentDuration: 1h # 1 小时后停止生成 trial
不过这些参数在调优开始时的web页面上是可以进行调整的。

所以其实NNI干的事情就很清楚了,也很简单。你只需要在你的模型训练文件中增加你想要调优的参数作为输入,就能使用NNI内置的调优算法对不同的参数进行调优,而且允许从页面UI上观察调优的整个过程,相对而言还是很方便的。

4 查看训练过程

NNI 自动调参使用。_第1张图片

这里表示实验正在继续,需要等待实验跑完。
NNI 自动调参使用。_第2张图片

你可能感兴趣的:(python,机器学习,深度学习)