大家好,欢迎来到IT知识分享网。
文章目录
1. NNI简介
NNI (Neural Network Intelligence) 是微软开源的自动机器学习(AutoML)的工具包。它通过多种调优的算法来搜索最好的神经网络结构和(或)超参,并支持单机、本地多机、云等不同的运行环境。
在其中使用到的基本概念如下:
- Experiment(实验): 表示一次任务,例如,寻找模型的最佳超参组合,或最好的神经网络架构等。它由 Trial 和自动机器学习算法所组成。
- Search Space(搜索空间):是模型调优的范围。 例如,超参的取值范围。
- Configuration(配置):配置是搜索空间的实例化,从搜索空间中固定下来一定的超参数,每个超参都会有特定的值。
- Trial(尝试):是一次独立的尝试,它会使用某组配置(例如,一组超参值,或者特定的神经网络架构)。 Trial 会基于提供的配置来运行。
- Tuner(调优器):一种自动机器学习算法,会为下一个 Trial 生成新的配置。 新的 Trial 会使用这组配置来运行。
- Assessor(评估器):分析 Trial 的中间结果(例如,定期评估数据集上的精度),来确定 Trial 是否应该被提前终止。
- 训练平台:是 Trial 的执行环境。 根据 Experiment 的配置,可以是本机,远程服务器组,或其它大规模训练平台(如OpenPAI,Kubernetes等)。
最后说一下版本问题,NNI如果是在Windows系统上运行的话,我测试的是v2.7版本比较稳定,其余v2.8,v2.9,v2.10或多或少都有连接不稳的问题,Linux系统上则不存在此类问题。
官方文档地址如下:https://nni.readthedocs.io/en/v2.9/hpo/overview.html
2. 使用步骤及示例
2.1 编写程序
首先NNI只是一个自动机器学习的工具,作用是调参、神经架构搜索等,即是对已经能够训练出模型的代码文件进行参数的调节,所以,第一步,我们需要先写出能够训练出模型的代码。之后,在这基础上插入NNI的几行代码即可。
这里,我们用我文本分类文章中的程序来做示例,当然,没看过这篇文章的朋友也可以继续看下去,因为改动其实很少的。
2.2 设置参数搜索空间
NNI能够支持TensorFlow、Pytorch等很多的深度学习框架,且兼容性很好,如果需要使用NNI的参数优化,仅需要添加很少的代码,这里,假如我们需要调节的参数只有学习率 learning_rate
以及 训练轮次 epoch
,建立一个名为 search_space.json
的JSON文件,文件内容如下:
{
"learning_rate": {
"_type":"uniform", "_value": [0.0001, 0.1]}, "num_epochs":{
"_type":"choice","_value":[5, 10, 15, 20]} }
上述文件中,learning_rate,epoch
为需要优化的参数的名称,_type
为参数搜索的策略,比如如果搜索策略为 chioce
,那么参数的搜索就会在 _value
的值中选择一个值进行搜索,如果搜索策略为 uniform
,那么参数就会在 _value
所属的范围里面按照均匀分布进行参数的选择,更加详细的策略下面会讲。
2.3 更改源程序
原来的程序主函数如下所示。
# 存放数据的文件夹 dataset = 'text_classify_data' # 搜狗新闻:embedding_SougouNews.npz, 腾讯:embedding_Tencent.npz, 随机初始化:random embedding = 'embedding_SougouNews.npz' # 需要用到的所有参数 config = Config(dataset, embedding) # 得到数据的迭代器 vocab, train_data, dev_data, test_data = get_data(config, False) dataloaders = {
'train': DataLoader(TextDataset(train_data, config), 128, shuffle=True), 'dev': DataLoader(TextDataset(dev_data, config), 128, shuffle=True), 'test': DataLoader(TextDataset(test_data, config), 128, shuffle=True) } model = RNNModel(config).to(config.device) # 训练模型 train_best(config, model, dataloaders)
修改后的代码如下所示:
import nni # 存放数据的文件夹 dataset = 'text_classify_data' # 搜狗新闻:embedding_SougouNews.npz, 腾讯:embedding_Tencent.npz, 随机初始化:random embedding = 'embedding_SougouNews.npz' # 需要用到的所有参数,这里去除了需要优化的learning_rate以及epoch config = Config(dataset, embedding) vocab, train_data, dev_data, test_data = get_data(config) dataloaders = {
'train': DataLoader(TextDataset(train_data, config), config.batch_size, shuffle=True), 'dev': DataLoader(TextDataset(dev_data, config), config.batch_size, shuffle=True), 'test': DataLoader(TextDataset(test_data, config), config.batch_size, shuffle=True) } # 传入一组新的需要优化的参数 def main(super_params): model = RNNModel(config).to(config.device) # r为返回的测试集的准确率 r = train_best(config, model, dataloaders, super_params) # 这行代码必须加,意思是NNI根据传入的r的情况进行参数的选取优化 nni.report_final_result(r) if __name__ == '__main__': # 初始化需要优化的参数 super_params = {
'learning_rate': 0.001, 'num_epochs': 2} # 从NNI那里拿到一组满足搜索空间定义的参数值 super_params.update(nni.get_next_parameter()) # 传入超参数并开始训练 main(super_params)
大家看出来了,实际上我加的代码只有两行,即nni.report_final_result(r)
以及 super_params.update(nni.get_next_parameter())
两行,并将需要优化的参数与不需要优化的参数进行了分离而已,如果想要记录到每一轮训练的调优,那么可以用 nni.report_intermediate_result()
。
这样,其实就已经完成了NNI在代码中的嵌入,整个过程可以说是很简单了,二关于NNI的其与配置需要在配置文件中进行配置。
2.4 定义配置文件
创建一个名为 config.yml
的配置文件,里面需要编写NNI的各种配置信息,基本配置信息如下:
# 搜索空间的文件所在位置 searchSpaceFile: search_space.json # 运行文件使用的命令,Linux是 python3 mian.py trialCommand: python main.py # 同时运行的trial数量 trialConcurrency: 3 # 最大的trial数量 maxTrialNumber: 100 # 最大的实验时间,当最大时间或者最大trial达到时终止实验 maxExperimentDuration: 1h # 实验结果文件的存储位置,不能含有中文 experimentWorkingDirectory: "C:\\User\\nni-experiment" # 使用的调优算法 tuner: name: TPE classArgs: # 需要将传入的参数进行最大化还是最小化,若传入NNI的结果是loss就最小化,是准确率等最大化 optimize_mode: maximize trainingService: platform: local
然后切换到对应的Python环境中,使用 nnictl create --config config.yml
命令开始进行参数优化。
3. 参数空间设置
常用的参数空间搜索策略如下所示:
参数形式 | 参数意义 |
---|---|
{"_type": "choice", "_value": [item1,...]} |
从_value 中选取一个值 |
{"_type": "randint", "_value": [lower, upper]} |
从[lower, upper] 中选取一个整数值 |
{"_type": "uniform", "_value": [low, high]} |
变量值在[lower, upper] 之间均匀采样 |
{"_type": "quniform", "_value": [low, high, q]} |
变量值在[lower, upper] 且步长为q |
4. 命令行命令
4.1 创建AutoML
使用的是 nnictl create
命令,该命令中支持一些参数,支持的参数如下:
全称/缩写 | 是否必须 | 描述 |
---|---|---|
--config, -c |
是 | yaml配置文件的路径 |
--port, -p |
否 | 启动web服务的端口,默认是8080 |
--foreground, -f |
否 | 将日志文件内容打印到命令行 |
4.2 继续AutoML
使用的是 nnictl resume
命令,该命令中支持一些参数,支持的参数如下:
全称/缩写 | 是否必须 | 描述 |
---|---|---|
id |
是 | 需要继续的实验的ID名 |
--port, -p |
否 | 启动web服务的端口,默认是8080 |
--foreground, -f |
否 | 将日志文件内容打印到命令行 |
--experiment_dir, -e |
否 | 指定继续实验的外部路径 |
4.3 可视化AutoML
使用的是 nnictl view
命令,该命令中支持一些参数,支持的参数如下:
全称/缩写 | 是否必须 | 描述 |
---|---|---|
id |
是 | 需要继续的实验的ID名 |
--port, -p |
否 | 启动web服务的端口,默认是8080 |
--experiment_dir, -e |
否 | 指定继续实验的外部路径 |
5. Tuner
调优器也是十分重要的一种寻参手段,像贝叶斯调优,它会根据当前的参数信息和最终结果以及过往的参数信息和结果,预测下一个最优的参数,这样能够省去一些无用功;像随机调优,真的就是在参数空间里随机获取值,在参数范围很大的时候会有很好的效果,接下来我介绍几种常用的调优器。
5.1 BOHB
BOHB 是一种强大且高效的大规模超参数调整算法。 BO 是“Bayesian Optimization”的缩写,HB 是“Hyperband”的缩写。
BOHB 依靠 HB(Hyperband)来确定用哪个预算评估多少配置,但它通过基于模型的搜索(贝叶斯优化)取代了在每次 HB 迭代开始时随机选择配置。 一旦达到所需的迭代配置数量,就会使用这些配置执行标准的连续减半程序。 它跟踪所有预算 b b b 上配置 x x x 的所有函数评估 g ( x , b ) g(x, b) g(x,b) 的性能,以用作我们模型在以后迭代中的基础。
需要使用 pip install nni[BOHB]
先进行安装才能进行使用。
设置格式如下所示
advisor: name: 'BOHB' class_args: # 使传入的数据大好还是小好 optimize_mode: maximize # 每个trial最小预算epoch min_budget: 1 # 每个trial最大预算epoch max_budget: 27 # 必须大于等于2,每次评估后,只有1/eta进入下一轮 eta: 3 min_points_in_model: 7 # 使用15%的数据结果构建好模型 top_n_percent: 15 # 优化EI的样本数 num_samples: 64 # 在没有模型的情况下从先验中采样的纯随机配置的比例 random_fraction: 0.33 bandwidth_factor: 3.0 min_bandwidth: 0.001
5.2 Random
生成完全随机超参数的调优器。在超参数搜索范围很大时有出人意料的结果。
使用如下:
tuner: name: Random classArgs: # 设置随机种子 seed: 100
5.3 Grid Search
网格搜索调整器将搜索空间划分为均匀间隔的网格,并进行蛮力遍历。建议在搜索空间较小或想要找到严格最优的超参数时使用。
使用如下:
tuner: name: GridSearch
5.4 TPE
TPE 是一个轻量级的 Tuner,没有额外的依赖,支持所有搜索空间类型,设计为默认的 Tuner。它的缺点是 TPE 无法发现不同超参数之间的关系。
使用如下:
tuner: name: TPE classArgs: # 需要将传入的参数进行最大化还是最小化,若传入NNI的结果是loss就最小化,是准确率等最大化 optimize_mode: maximize # 随机种子 seed: 12345 tpe_args: # 并行优化的策略,一般,trail数量很多时用worst,很少时用best,其余用mean constant_liar_type: mean # 前 N 个超参数是完全随机生成的,用于预热。搜索空间大时可以增加 n_startup_jobs: 10 # 对于每次迭代,TPE 都会对 N 组参数的 EI 进行采样,并选择最佳的一个。 n_ei_candidates: 20 # 控制了试验开始衰减所需的迭代次数。 linear_forgetting: 100 prior_weight: 0 # 控制有多少试验被认为是“好”的,计算为“min(gamma * sqrt(N), linear_forgetting)” gamma: 0.5
6. NNI使用细节
- 在
nni.report_final_result(r)
中,传递的参数r
必须是基本类型,不能是tensor
类型或者pandas
类型; - 你的参数应该是个字典,比如
args['batch_size']
而非args.batch_size
; - 如果使用了
experimentWorkingDirectory
参数,那么该参数的路径中不能含有中文; - NNI工具无法根据源程序的目录寻找主目录外的文件地址,详细错误见另一位博主的博客。
config.yml
中的experimentWorkingDirectory
需要以双反斜杠\\
隔开
7. 调参结果
在详细中能够看到超参数之间的关系。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/140196.html