Py学习  »  机器学习算法

浅析自动机器学习(AutoML)工具NNI

AINLP • 10 月前 • 216 次点击  

NNI 简介

NNI (Neural Network Intelligence) 是一个轻量级但功能强大的自动机器学习(AutoML)工具包,可帮助用户自动化特征工程、神经架构搜索、超参数调优和模型压缩,并支持单机、本地多机、云等不同的运行环境。

nni架构.png

NNI 的主要特性

NNI 的特性主要包括:易于使用,可扩展,灵活,高效。

  • 易于使用:NNI 可通过 pip 安装。只需要在代码中添加几行,就可以利用 NNI 来调优参数。可使用命令行工具或 Web 界面来查看 Experiment
  • 可扩展:调优超参或网络结构通常需要大量的计算资源。NNI 在设计时就支持了多种不同的计算资源,如远程服务器组,训练平台(如:OpenPAI,Kubernetes)等等。根据您配置的训练平台的能力,可以并行运行数百个 Trial
  • 灵活:除了内置的算法,NNI 中还可以轻松集成自定义的超参调优算法,神经网络架构搜索算法,提前终止算法等等。还可以将 NNI 连接到更多的训练平台上,如云环境中的虚拟机集群,Kubernetes 服务等等。此外,NNI 还可以连接到外部环境中的特殊应用和模型上。
  • 高效:NNI 在系统及算法级别上不断地进行优化。例如:通过早期的反馈来加速调优过程。

NNI 的主要概念

  • Experiment(实验):表示一次任务,例如,寻找模型的最佳超参组合,或最好的神经网络架构等。它由 Trial自动机器学习算法所组成。
  • Search Space(搜索空间):是模型调优的范围。例如,超参的取值范围。
  • Configuration(配置):配置是搜索空间的实例化,从搜索空间中固定下来一定的超参数,每个超参都会有特定的值。
  • Trial(尝试):是一次独立的尝试,它会使用某组配置(例如,一组超参值,或者特定的神经网络架构)。Trial 会基于提供的配置来运行。
  • Tuner(调优器):一种自动机器学习算法,会为下一个 Trial 生成新的配置。新的 Trial 会使用这组配置来运行。
  • Assessor(评估器):分析 Trial 的中间结果(例如,定期评估数据集上的精度),来确定 Trial 是否应该被提前终止。
  • 训练平台:是 Trial 的执行环境。根据 Experiment 的配置,可以是本机,远程服务器组,或其它大规模训练平台(如OpenPAIKubernetes等)。

NNI 体系结构

体系结构.png

NNI体系结构如上图所示,其中包括:

  • NNI Controller(nnictl): 这是个命令行工具,用于控制 Web 服务器,和其他管理功能,用户可以使用这个命令来进行管理。比如,启动 Experiment。
  • NNI Core: 这是 NNI 的核心,实现了Web UI, nnimanager,训练服务等核心功能。当 Experiment 出现严重错误时,从它的日志中才能找到原因。(例如,Web 界面无法打开,或者训练平台失败)
  • Advisor: Advisor是 NNI 的超参数调整系统,包括TunerAssessor,分别负责生成下一个trial和评估该trial
  • 训练平台:右侧的训练平台可以是本机/远程服务器/OpenPAI/Kubernetes等,可以将许多 trial 进行分配到各个平台中,完成一次尝试(trial)。

从上图中,我们也看到了 NNI Experiment 的运行过程如下:

  • Tuner 接收搜索空间并生成配置。
  • 这些配置将被提交到训练平台,如本机,远程服务器组或训练集群。
  • 执行的性能结果会被返回给 Tuner。
  • 然后,再生成并提交新的配置。

每次 Experiment 执行时,用户只需要定义搜索空间,改动几行代码,就能利用 NNI 内置的 Tuner/Assessor 和训练平台来搜索最好的超参组合以及神经网络结构。基本上分为三步:

  • 步骤一:定义搜索空间
  • 步骤二:改动模型代码
  • 步骤三:定义实验配置

NNI 的核心功能

NNI 提供了并行运行多个实例以查找最佳参数组合的能力。此功能可用于各种领域,例如,为深度学习模型查找最佳超参数,或查找具有真实数据的数据库和其他复杂系统的最佳配置。

NNI 还希望提供用于机器学习和深度学习的算法工具包,尤其是神经体系结构搜索(NAS)算法,模型压缩算法和特征工程算法。

超参数调优

这是 NNI 最核心、最基本的功能,其中提供了许多流行的自动调优算法(即 Tuner) 以及提前终止算法(即 Assessor)。

NNI 内置的 Tuner

NNI 能用简单快速的方法来配置超参调优算法,称之为 Tuner

Tuner 从 Trial 中接收指标结果,来评估一组超参或网络结构的性能。然后 Tuner 会将下一组超参或网络结构的配置发送给新的 Trial。

NNI 内置的自动调优算法如下表格所示:

概述算法简介
TPETree-structured Parzen Estimator (TPE) 是一种 sequential model-based optimization(SMBO,即基于序列模型优化)的方法。SMBO 方法根据历史指标数据来按顺序构造模型,来估算超参的性能,随后基于此模型来选择新的超参。参考论文
Random Search(随机搜索)在超参优化时,随机搜索算法展示了其惊人的简单和效果。建议当不清楚超参的先验分布时,采用随机搜索作为基准。参考论文
Anneal(退火)这种简单的退火算法从先前的采样开始,会越来越靠近发现的最佳点取样。此算法是随机搜索的简单变体,利用了反应曲面的平滑性。退火率不是自适应的。
Naïve Evolution(朴素进化)Naïve Evolution(朴素进化算法)来自于 Large-Scale Evolution of Image Classifiers。它会基于搜索空间随机生成一个种群。在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层)。朴素进化算法需要很多次的 Trial 才能有效,但它也非常简单,也很容易扩展新功能。参考论文
SMACSMAC 基于 Sequential Model-Based Optimization (SMBO,即序列的基于模型优化方法)。它会利用使用过的突出的模型(高斯随机过程模型),并将随机森林引入到SMBO中,来处理分类参数。SMAC 算法包装了 Github 的 SMAC3。注意:SMAC 需要通过 pip install nni[SMAC] 命令来安装。参考论文 代码仓库
Batch tuner(批处理)Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。当所有配置都完成后,Experiment 即结束。Batch Tuner 仅支持 choice 类型。
Grid Search(遍历)网格搜索会穷举定义在搜索空间文件中的所有超参组合。遍历搜索可以使用的类型有 choice, quniform, randint。
HyperbandHyperband 试图用有限的资源来探索尽可能多的组合,并发现最好的结果。基本思想是生成许多配置,并通过少量的 Trial 来运行一部分。一半性能不好的配置会被抛弃,剩下的部分与新选择出的配置会进行下一步的训练。数量的多少对资源约束非常敏感(例如,分配的搜索时间)。参考论文
Network Morphism网络模态(Network Morphism)提供自动搜索深度学习体系结构的功能。它会继承父网络的知识,来生成变形的子网络。包括深度、宽度、跳连接等变化。然后使用历史的架构和指标,来估计子网络的值。然后会选择最有希望的模型进行训练。参考论文
Metis Tuner大多数调参工具仅仅预测最优配置,而 Metis 的优势在于有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 Trial 的建议。它不进行随机取样。大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。参考论文
BOHBBOHB 是 Hyperband 算法的后续工作。Hyperband 在生成新的配置时,没有利用已有的 Trial 结果,而本算法利用了 Trial 结果。BOHB 中,HB 表示 Hyperband,BO 表示贝叶斯优化(Byesian Optimization)。BOHB 会建立多个 TPE 模型,从而利用已完成的 Trial 生成新的配置。参考论文
GP TunerGaussian Process(高斯过程) Tuner 是序列化的基于模型优化(SMBO)的方法,并使用了高斯过程来替代。参考论文, Github 仓库
PPO TunerPPO Tuner 是基于 PPO 算法的强化学习 Tuner。参考论文
PBT TunerPBT Tuner 是一种简单的异步优化算法,在固定的计算资源下,它能有效的联合优化一组模型及其超参来最大化性能。参考论文

NNI 内置的 Assessor

为了节省计算资源,NNI 支持提前终止策略,并且通过叫做 Assessor 的接口来执行此操作。

Assessor 从 Trial 中接收中间结果,并通过指定的算法决定此 Trial 是否应该终止。一旦 Trial 满足了提前终止策略(这表示 Assessor 认为最终结果不会太好),Assessor 会终止此 Trial,并将其状态标志为 ==EARLY_STOPPED==

NNI 当前支持的提前终止算法如下表格:

Assessor算法简介
MedianstopMedianstop 是一个简单的提前终止算法。如果尝试 X 的在步骤 S 的最好目标值比所有已完成尝试的步骤 S 的中位数值明显低,就会停止运行尝试 X。参考论文
CurvefittingCurve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学习、预测、评估) 的算法。如果预测的 Trial X 在 step S 比性能最好的 Trial 要差,就会提前终止它。此算法中采用了 12 种曲线来拟合精度曲线。参考论文

通用 NAS 框架

此 NAS 框架可供用户轻松指定候选的神经体系结构,例如,可以为单个层指定多个候选操作(例如,可分离的 conv、扩张 conv),并指定可能的跳过连接。NNI 将自动找到最佳候选。另一方面,NAS 框架为其他类型的用户(如,NAS 算法研究人员)提供了简单的接口,以实现新的 NAS 算法。

NNI 通过 Trial SDK 支持多种 one-shot(一次性) NAS 算法,如:ENAS、DARTS。使用这些算法时,不需要启动 NNI Experiment。在 Trial 代码中加入算法,直接运行即可。如果要调整算法中的超参数,或运行多个实例,可以使用 Tuner 并启动 NNI Experiment

除了 one-shot NAS 外,NAS 还能以 NNI 模式运行,其中每个候选的网络结构都作为独立 Trial 任务运行。在此模式下,与超参调优类似,必须启动 NNI Experiment 并为 NAS 选择 Tuner

模型压缩

NNI 提供了一个易于使用的模型压缩框架来压缩深度神经网络,压缩后的网络通常具有更小的模型尺寸更快的推理速度,模型性能也不会有明显的下降。NNI 上的模型压缩包括剪枝量化算法。这些算法通过 NNI Trial SDK 提供 。可以直接在 Trial 代码中使用,并在不启动 NNI Experiment 的情况下运行 Trial 代码。用户还可以使用 NNI 模型压缩框架集成自定义的剪枝和量化算法。

自动特征工程

自动特征工程,可以为下游任务找到最有效的特征。自动特征工程通过 NNI Trial SDK 支持,不必创建 NNI Experiment, 只需在 Trial 代码中加入内置的自动特征工程算法,然后直接运行 Trial 代码。

自动特征工程算法通常有一些超参。如果要自动调整这些超参,可以利用 NNI 的超参数调优,即选择调优算法(即 Tuner)并启动 NNI Experiment。

安装

通过pip安装

python3 -m pip install --upgrade nni

通过源码构建

# 拉取NNI源码并指定分支
git clone -b v2.0 https://github.com/Microsoft/nni.git

cd nni
# 设置环境变量
export NNI_RELEASE=2.0

# 构建
python3 -m pip install --upgrade pip setuptools wheel
python3 setup.py clean --all
python3 setup.py build_ts
python3 setup.py bdist_wheel -p manylinux1_x86_64
python3 -m pip install dist/nni-2.0-py3-none-manylinux1_x86_64.whl

Docker安装

# 拉取NNI镜像
docker pull msranni/nni:v2.2

# 启动NNI容器
docker run -i -t -p 9090:8080 msranni/nni:v2.0

备注:

在Docer中运行NNI的时候

如果直接使用 NNI 的官方镜像 msranni/nni 来启动 Experiment,可以直接使用  nnictl 命令。NNI 官方镜像有最基础的 Python 环境和深度学习框架。

如果使用自己的 Docker 镜像,需要首先安装 NNI, 如python3 -m pip install --upgrade nni

NNI 超参数调优实验的简单示例

NNI 用来帮助超参调优的伪代码如下:

  • 输入: 搜索空间, Trial 代码, 配置文件
  • 输出: 一组最优的参数配置
 1: For t = 0, 1, 2, ..., maxTrialNum,
 2:      hyperparameter = 从搜索空间选择一组参数
 3:      final result = run_trial_and_evaluate(hyperparameter)
 4:      返回最终结果给 NNI
 5:      If 时间达到上限,
 6:          停止实验
 7: 返回最好的实验结果

开发并启动一个 NNI 实验

启动 Experiment 的包含如下三个步骤:

第一步 :编写 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]}
}

第二步 :修改 Trial 代码来从 NNI 获取超参,并返回 NNI 最终结果。

mnist.py

import nni

def main(args):
# 下载数据
train_loader = torch.utils.data.DataLoader(datasets.MNIST(...), batch_size=args['batch_size'], shuffle=True)
test_loader = torch.tuils.data.DataLoader(datasets.MNIST(...), batch_size=1000, shuffle=True)
# 构造模型
model = Net(hidden_size=args['hidden_size'])
optimizer = optim.SGD(model.parameters(), lr=args['lr'], momentum=args['momentum'])
# 训练
for epoch in range(10):
train(args, model, device, train_loader, optimizer, epoch)
test_acc = test(args, model, device, test_loader)
print(test_acc)
nni.report_intermeidate_result(test_acc)
print('final accuracy:', test_acc)
# 报告评估指标
nni.report_final_result(test_acc)

if __name__ == '__main__':
# 设置超参数默认值
params = {'batch_size': 32, 'hidden_size': 128, 'lr': 0.001, 'momentum': 0.5}
# 获取一次Trail的超参数
params = nni.get_next_parameter()
main(params)

第三步 : 定义 YAML 格式的 配置 文件,声明搜索空间和 Trail 文件的 路径 。它还提供其他信息,例如调整算法,最大 Trial 运行次数和最大持续时间的参数。

config.yml

authorName: default
experimentName: example_mnist
trialConcurrency: 1
maxExecDuration: 1h
maxTrialNum: 10
trainingServicePlatform: local
# 搜索空间文件路径
searchSpacePath: search_space.json
useAnnotation: false
tuner:
builtinTunerName: TPE
# 运行的命令,以及 Trial 代码的路径
trial:
command: python3 mnist.py
codeDir: .
gpuNum: 0

最后,从命令行使用 config.yml 文件启动 MNIST Experiment 。

nnictl create --config config.yml

注意

如果要使用远程服务器或集群作为训练平台,为了避免产生过大的网络压力,NNI 限制了文件的最大数量为 2000,大小为 300 MB。如果 codeDir 中包含了过多的文件,可添加 .nniignore 文件来排除部分,与 .gitignore 文件用法类似。

在命令行中等待输出 INFO: Successfully started experiment! 。此消息表明实验已成功启动。期望的输出如下:

INFO: Starting restful server...
INFO: Successfully started Restful server!
INFO: Setting local config...
INFO: Successfully set local config!
INFO: Starting experiment...
INFO: Successfully started experiment!
-----------------------------------------------------------------------
The experiment id is egchD4qy
The Web UI urls are: [Your IP]:8080
-----------------------------------------------------------------------

You can use these commands to get more information about the experiment
-----------------------------------------------------------------------
commands description
1. nnictl experiment show show the information of experiments
2. nnictl trial ls list all of trial jobs
3. nnictl top monitor the status of running experiments
4. nnictl log stderr show stderr log content
5. nnictl log stdout show stdout log content
6. nnictl stop stop an experiment
7. nnictl trial kill kill a trial job by id
8. nnictl --help get help information about nnictl
-----------------------------------------------------------------------

如果根据上述步骤准备好了相应 Trial搜索空间配置 ,并成功创建的 NNI 任务。NNI 会自动开始通过配置的搜索空间来运行不同的超参集合,搜索最好的超参。通过 Web 界面可看到 NNI 的进度。

通过Web UI 可视化实验过程

启动 Experiment 后,可以在命令行界面找到如下的 Web 界面地址 :

The Web UI urls are: [Your IP]:8080

在浏览器中打开 Web 界面地址 (即:[IP地址]:8080 ),就可以看到 Experiment 的详细信息,以及所有的 Trial 任务。

查看概要页面

Experiment 相关信息会显示在界面上,如配置和搜索空间等。NNI 还支持通过 Experiment summary 按钮下载这些信息和参数。

nni-full-oview.png

查看 Trial 详情页面

可以在此页面中看到最佳的尝试指标和超参数图。当您单击按钮 Add/Remove columns 时,表格内容包括更多列。当您单击按钮 Add/Remove columns 时,表格内容包括更多列。

尝试详情页面.png

查看 Experiment 管理页面

All experiments 页面可以查看计算机上的所有实验。

实验管理页面.png

到处为止,一次AutoML超参数调优的实验运行就已经完成。

总结

本文简单介绍了自动机器学习工具NNI的基本概念、主要功能特点以及如何使用NNI进行一个超参调优实验,希望能够帮助到你。

参考文档

  • NNI source code
  • NNI官方文档-中文版
  • NNI官方文档-英文版

进技术交流群请添加AINLP小助手微信(id: ainlp2)

请备注具体方向+所用到的相关技术点

关于AINLP

AINLP 是一个有趣有AI的自然语言处理社区,专注于 AI、NLP、机器学习、深度学习、推荐算法等相关技术的分享,主题包括文本摘要、智能问答、聊天机器人、机器翻译、自动生成、知识图谱、预训练模型、推荐系统、计算广告、招聘信息、求职经验分享等,欢迎关注!加技术交流群请添加AINLP小助手微信(id:ainlp2),备注工作/研究方向+加群目的。



阅读至此了,分享、点赞、在看三选一吧🙏

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/156160
 
216 次点击