Unverified Commit 25db55ca authored by kvartet's avatar kvartet Committed by GitHub
Browse files

Update Chinese documents (#3243)

parent 53b565e4
在 NNI 上调优 RocksDB
=====================
概述
--------
`RocksDB <https://github.com/facebook/rocksdb>`__ 是流行的高性能、嵌入式的生产级别的键值数据库,它在 Facebook,Yahoo!,和 LinkedIn 等各种规模的网站上使用。 这是 Facebook 的 `LevelDB <https://github.com/google/leveldb>`__ 分支,为多 CPU,快速存储(如 SSD)的输入输出进行了优化。
RocksDB 的性能表现非常依赖于调优操作。 但由于其底层技术较复杂,可配置参数非常多,很难获得较好的配置。 NNI 可帮助解决此问题。 NNI 支持多种调优算法来为 RocksDB 搜索最好的配置,并支持本机、远程服务器和云服务等多种环境。
本示例展示了如何使用 NNI,通过评测工具 ``db_bench`` 来找到 ``fillrandom`` 基准的最佳配置,此工具是 RocksDB 官方提供的评测工具。 在运行示例前,需要检查 NNI 已安装, `db_bench <https://github.com/facebook/rocksdb/wiki/Benchmarking-tools>`__ 已经加入到了 ``PATH`` 中。 参考 `这里 <../Tutorial/QuickStart.rst>`__ ,了解如何安装并准备 NNI 环境,参考 `这里 <https://github.com/facebook/rocksdb/blob/master/INSTALL.rst>`__ 来编译 RocksDB 以及 ``db_bench``。
此简单脚本 :githublink:`db_bench_installation.sh <examples/trials/systems/rocksdb-fillrandom/db_bench_installation.sh>` 可帮助编译并在 Ubuntu 上安装 ``db_bench`` 及其依赖包。 可遵循相同的过程在其它系统中安装 RocksDB。
代码目录: :githublink:`example/trials/systems/rocksdb-fillrandom <examples/trials/systems/rocksdb-fillrandom>`
Experiment 设置
----------------
在 NNI 上配置调优的 Experiment 主要有三个步骤。 使用 ``json`` 文件定义搜索空间,编写评测代码,将配置传入 NNI 管理器来启动 Experiment。
搜索空间
^^^^^^^^^^^^
为简单起见,此示例仅调优三个参数,``write_buffer_size``,``min_write_buffer_num`` 以及 ``level0_file_num_compaction_trigger``,场景为测试随机写入 16M 数据的每秒写操作数(OPS),其 Key 为 20 字节,值为 100 字节。 ``write_buffer_size`` 设置单个内存表的大小。 一旦内存表超过此大小,会被标记为不可变,并创建新内存表。 ``min_write_buffer_num`` 是要合并写入存储的最小内存表数量。 一旦 Level 0 的文件数量达到了 ``level0_file_num_compaction_trigger``,就会触发 Level 0 到 Level 1 的压缩。
此示例中,下列 ``search_space.json`` 文件指定了搜索空间。 搜索空间的详细说明参考 `这里 <../Tutorial/SearchSpaceSpec.rst>`__.。
.. code-block:: json
{
"write_buffer_size": {
"_type": "quniform",
"_value": [2097152, 16777216, 1048576]
},
"min_write_buffer_number_to_merge": {
"_type": "quniform",
"_value": [2, 16, 1]
},
"level0_file_num_compaction_trigger": {
"_type": "quniform",
"_value": [2, 16, 1]
}
}
代码目录 :githublink:`example/trials/systems/rocksdb-fillrandom/search_space.json <examples/trials/systems/rocksdb-fillrandom/search_space.json>`
基准测试
^^^^^^^^^^^^^^
评测代码从 NNI 管理器接收配置,并返回相应的基准测试结果。 下列 NNI API 用于相应的操作。 此示例中,每秒写操作数(OPS)作为了性能指标。 参考 `这里 <Trials.rst>`__,了解详情。
* 使用 ``nni.get_next_parameter()`` 来获取下一个系统配置。
* 使用 ``nni.report_final_result(metric)`` 来返回测试结果。
代码目录 :githublink:`example/trials/systems/rocksdb-fillrandom/main.py <examples/trials/systems/rocksdb-fillrandom/main.py>`
配置文件
^^^^^^^^^^^
用于启动 NNI Experiment 的配置文件。 此配置文件是 ``YAML`` 格式,通常包括了 Experiment 设置 (\ ``trialConcurrency``\ , ``maxExecDuration``\ , ``maxTrialNum``\ , ``trial gpuNum``\ 等),平台设置 (\ ``trainingServicePlatform``\ 等),路径设置 (\ ``searchSpacePath``\ , ``trial codeDir``\ 等) 以及 Tuner 设置 (\ ``tuner``\ , ``tuner optimize_mode``\ 等)。 参考 `这里 <../Tutorial/QuickStart.rst>`__ 了解详情。
这是使用 SMAC 算法调优 RocksDB 的示例:
代码目录 :githublink:`example/trials/systems/rocksdb-fillrandom/config_smac.yml <examples/trials/systems/rocksdb-fillrandom/config_smac.yml>`
这是使用 TPE 算法调优 RocksDB 的示例:
代码目录 :githublink:`example/trials/systems/rocksdb-fillrandom/config_tpe.yml <examples/trials/systems/rocksdb-fillrandom/config_tpe.yml>`
其它 Tuner 算法可以通过相同的方式来使用。 参考 `这里 <../Tuner/BuiltinTuner.rst>`__ 了解详情。
最后,进入示例目录,并通过下列命令启动 Experiment:
.. code-block:: bash
# 在 NNI 上调优 RocksDB
nnictl create --config ./config_smac.yml
# 在 NNI 上使用 TPE Tuner 调优 RocksDB
nnictl create --config ./config_tpe.yml
Experiment 结果
------------------
在同一台计算机上运行这两个示例的详细信息:
* 16 * Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
* 465 GB 磁盘,安装 ext4 操作系统
* 128 GB 内存
* 内核版本: 4.15.0-58-generic
* NNI 版本: v1.0-37-g1bd24577
* RocksDB 版本: 6.4
* RocksDB DEBUG_LEVEL: 0
详细的实验结果如下图所示。 水平轴是 Trial 的顺序。 垂直轴是指标,此例中为写入的 OPS。 蓝点表示使用的是 SMAC Tuner,橙色表示使用的是 TPE Tuner。
.. image:: https://github.com/microsoft/nni/blob/v2.0/docs/img/rocksdb-fillrandom-plot.png?raw=true
下表列出了两个 Tuner 获得的最佳 Trial 以及相应的参数和指标。 不出所料,两个 Tuner 都为 ``fillrandom`` 测试找到了一样的最佳配置。
.. list-table::
:header-rows: 1
:widths: auto
* - 概述
- 最佳 Trial
- 最佳 OPS
- write_buffer_size
- min_write_buffer_number_to_merge
- level0_file_num_compaction_trigger
* - SMAC
- 255
- 779289
- 2097152
- 7.0
- 7.0
* - TPE
- 169
- 761456
- 2097152
- 7.0
- 7.0
# NNI 中使用 scikit-learn
[scikit-learn](https://github.com/scikit-learn/scikit-learn) (sklearn) 是流行的数据挖掘和分析工具。 它支持多种机器学习模型,如线性回归,逻辑回归,决策树,支持向量机等。 如何更高效的使用 scikit-learn,是一个很有价值的话题。
NNI 支持多种调优算法来为 scikit-learn 搜索最好的模型和超参,并支持本机、远程服务器和云服务等多种环境。
## 1. 如何运行此示例
安装 NNI 包,并使用命令行工具 `nnictl` 来启动 Experiment。 有关安装和环境准备的内容,参考[这里](../Tutorial/QuickStart.md)
安装完 NNI 后,进入相应的目录,输入下列命令即可启动 Experiment:
```bash
nnictl create --config ./config.yml
```
## 2. 示例概述
### 2.1 分类
示例使用了数字数据集,它是由 1797 个 8x8 的图片组成,每个图片都是一个手写数字,目标是将图片分为 10 类。
在这个示例中,使用 SVC 作为模型,并为此模型选择一些参数,包括 `"C", "kernel", "degree", "gamma" 和 "coef0"`。 关于这些参数的更多信息,可参考[这里](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html)
### 2.2 回归
此示例使用了波士顿房价数据,数据集由波士顿各地区房价所组成,还包括了房屋的周边信息,例如:犯罪率 (CRIM),非零售业务的面积 (INDUS),房主年龄 (AGE) 等等。这些信息可用来预测波士顿的房价。
本例中,尝试了不同的回归模型,包括 `"LinearRegression", "SVR", "KNeighborsRegressor", "DecisionTreeRegressor"` 和一些参数,如 `"svr_kernel", "knr_weights"`。 关于这些模型算法和参数的更多信息,可参考[这里](https://scikit-learn.org/stable/supervised_learning.html#supervised-learning)
## 3. 如何在 NNI 中使用 scikit-learn
只需要如下几步,即可在 scikit-learn 代码中使用 NNI。
* **第一步**
准备 search_space.json 文件来存储选择的搜索空间。 例如,如果要在不同的模型中选择:
```json
{
"model_name":{"_type":"choice","_value":["LinearRegression", "SVR", "KNeighborsRegressor", "DecisionTreeRegressor"]}
}
```
如果要选择不同的模型和参数,可以将它们放到同一个 search_space.json 文件中。
```json
{
"model_name":{"_type":"choice","_value":["LinearRegression", "SVR", "KNeighborsRegressor", "DecisionTreeRegressor"]},
"svr_kernel": {"_type":"choice","_value":["linear", "poly", "rbf"]},
"knr_weights": {"_type":"choice","_value":["uniform", "distance"]}
}
```
在 Python 代码中,可以将这些值作为一个 dict,读取到 Python 代码中。
* **第二步**
在代码最前面,加上 `import nni` 来导入 NNI 包。
首先,要使用 `nni.get_next_parameter()` 函数从 NNI 中获取参数。 然后在代码中使用这些参数。 例如,如果定义了如下的 search_space.json:
```json
{
"C": {"_type":"uniform","_value":[0.1, 1]},
"kernel": {"_type":"choice","_value":["linear", "rbf", "poly", "sigmoid"]},
"degree": {"_type":"choice","_value":[1, 2, 3, 4]},
"gamma": {"_type":"uniform","_value":[0.01, 0.1]},
"coef0 ": {"_type":"uniform","_value":[0.01, 0.1]}
}
```
就会获得像下面一样的 dict:
```python
params = {
'C': 1.0,
'kernel': 'linear',
'degree': 3,
'gamma': 0.01,
'coef0': 0.01
}
```
就可以使用这些变量来实现 scikit-learn 的代码。
* **第三步**
完成训练后,可以得到模型分数,如:精度,召回率,均方差等等。 NNI 需要将分数传入 Tuner 算法,并生成下一组参数,将结果回传给 NNI,并开始下一个 Trial 任务。
在运行完 scikit-learn 代码后,只需要使用 `nni.report_final_result(score)` 来与 NNI 通信即可。 或者在每一步中都有多个分值,可使用 `nni.report_intemediate_result(score)` 来将它们回传给 NNI。 注意, 可以不返回中间分数,但必须返回最终的分数。
\ No newline at end of file
NNI 中使用 scikit-learn
======================================
`Scikit-learn <https://github.com/scikit-learn/scikit-learn>`__ (sklearn) 是流行的数据挖掘和分析工具。 它支持多种机器学习模型,如线性回归,逻辑回归,决策树,支持向量机等。 如何更高效的使用 scikit-learn,是一个很有价值的话题。
NNI 支持多种调优算法来为 scikit-learn 搜索最好的模型和超参,并支持本机、远程服务器和云服务等多种环境。
1. 如何运行此示例
-------------------------
安装 NNI 包,并使用命令行工具 ``nnictl`` 来启动 Experiment。 有关安装和环境准备的内容,参考 `这里 <../Tutorial/QuickStart.rst>`__。
安装完 NNI 后,进入相应的目录,输入下列命令即可启动 Experiment:
.. code-block:: bash
nnictl create --config ./config.yml
2. 示例概述
-----------------------------
2.1 分类
^^^^^^^^^^^^^^^^^^
示例使用了数字数据集,它是由 1797 个 8x8 的图片组成,每个图片都是一个手写数字,目标是将图片分为 10 类。
在这个示例中,使用 SVC 作为模型,并为此模型选择一些参数,包括 ``"C", "kernel", "degree", "gamma" 和 "coef0"``。 关于这些参数的更多信息,可参考 `这里 <https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html>`__。
2.2 回归
^^^^^^^^^^^^^^
此示例使用了波士顿房价数据,数据集由波士顿各地区房价所组成,还包括了房屋的周边信息,例如:犯罪率 (CRIM),非零售业务的面积 (INDUS),房主年龄 (AGE) 等等。这些信息可用来预测波士顿的房价。
本例中,尝试了不同的回归模型,包括 ``"LinearRegression", "SVR", "KNeighborsRegressor", "DecisionTreeRegressor"</code> 和一些参数,如 <code>"svr_kernel", "knr_weights"``。 关于这些模型算法和参数的更多信息,可参考 `这里 <https://scikit-learn.org/stable/supervised_learning.html#supervised-learning>`__ 。
3. 如何在 NNI 中使用 scikit-learn
-------------------------------------------
只需要如下几步,即可在 scikit-learn 代码中使用 NNI。
*
**第一步**
准备 search_space.json 文件来存储选择的搜索空间。
例如,如果要在不同的模型中选择:
.. code-block:: json
{
"model_name":{"_type":"choice","_value":["LinearRegression", "SVR", "KNeighborsRegressor", "DecisionTreeRegressor"]}
}
如果要选择不同的模型和参数,可以将它们放到同一个 search_space.json 文件中。
.. code-block:: json
{
"model_name":{"_type":"choice","_value":["LinearRegression", "SVR", "KNeighborsRegressor", "DecisionTreeRegressor"]},
"svr_kernel": {"_type":"choice","_value":["linear", "poly", "rbf"]},
"knr_weights": {"_type":"choice","_value":["uniform", "distance"]}
}
在 Python 代码中,可以将这些值作为一个 dict,读取到 Python 代码中。
*
**第二步**
在代码最前面,加上 ``import nni`` 来导入 NNI 包。
首先,要使用 ``nni.get_next_parameter()`` 函数从 NNI 中获取参数。 然后在代码中使用这些参数。
例如,如果定义了如下的 search_space.json:
.. code-block:: json
{
"C": {"_type":"uniform","_value":[0.1, 1]},
"kernel": {"_type":"choice","_value":["linear", "rbf", "poly", "sigmoid"]},
"degree": {"_type":"choice","_value":[1, 2, 3, 4]},
"gamma": {"_type":"uniform","_value":[0.01, 0.1]},
"coef0": {"_type":"uniform","_value":[0.01, 0.1]}
}
就会获得像下面一样的 dict:
.. code-block:: python
params = {
'C': 1.0,
'kernel': 'linear',
'degree': 3,
'gamma': 0.01,
'coef0': 0.01
}
就可以使用这些变量来编写 scikit-learn 的代码。
*
**第三步**
完成训练后,可以得到模型分数,如:精度,召回率,均方差等等。 NNI 需要将分数传入 Tuner 算法,并生成下一组参数,将结果回传给 NNI,并开始下一个 Trial 任务。
在运行完 scikit-learn 代码后,只需要使用 ``nni.report_final_result(score)`` 来与 NNI 通信即可。 或者在每一步中都有多个分值,可使用 ``nni.report_intemediate_result(score)`` 来将它们回传给 NNI。 注意, 可以不返回中间分数,但必须返回最终的分数。
# 在阅读理解上使用自动模型架构搜索
该示例展示了如何使用遗传算法为阅读理解任务找到好的模型架构。
## 1. 搜索空间
在阅读理解领域,注意力(Attention)和循环神经网络都已被证明是非常有效的方法,因此搜索空间定义如下:
1. IDENTITY (Effectively 表示继续训练)。
2. INSERT-RNN-LAYER (插入 LSTM。 在 Experiment 中比较了 GRU 和 LSTM 的性能后,我们决定在这里采用 LSTM。)
3. REMOVE-RNN-LAYER
4. INSERT-ATTENTION-LAYER (插入注意力层。)
5. REMOVE-ATTENTION-LAYER
6. ADD-SKIP (在随机层之间一致).
7. REMOVE-SKIP (移除随机跳过).
![](../../../examples/trials/ga_squad/ga_squad.png)
### 新版本
另一个时间更快,性能更好的版本正在开发中。 很快将发布。
## 2. 如何在本机运行此示例?
### 2.1 使用下载脚本来下载数据
执行下列命令来下载所需要的数据:
```bash
chmod +x ./download.sh
./download.sh
```
或手动下载
1. 在 https://rajpurkar.github.io/SQuAD-explorer/ 下载 "dev-v1.1.json" 和 "train-v1.1.json"。
```bash
wget https://rajpurkar.github.io/SQuAD-explorer/dataset/train-v1.1.json
wget https://rajpurkar.github.io/SQuAD-explorer/dataset/dev-v1.1.json
```
2. 在 https://nlp.stanford.edu/projects/glove/ 下载 "glove.840B.300d.txt"。
```bash
wget http://nlp.stanford.edu/data/glove.840B.300d.zip
unzip glove.840B.300d.zip
```
### 2.2 更新配置
修改 `nni/examples/trials/ga_squad/config.yml`,以下是默认配置:
```yaml
authorName: default
experimentName: example_ga_squad
trialConcurrency: 1
maxExecDuration: 1h
maxTrialNum: 1
#可选项: local, remote
trainingServicePlatform: local
#可选项: true, false
useAnnotation: false
tuner:
codeDir: ~/nni/examples/tuners/ga_customer_tuner
classFileName: customer_tuner.py
className: CustomerTuner
classArgs:
optimize_mode: maximize
trial:
command: python3 trial.py
codeDir: ~/nni/examples/trials/ga_squad
gpuNum: 0
```
在 "Trial" 部分中,如果需要使用 GPU 来进行架构搜索,可将 `gpuNum``0` 改为 `1`。 根据训练时长,可以增加 `maxTrialNum``maxExecDuration`
### 2.3 提交任务
```bash
nnictl create --config ~/nni/examples/trials/ga_squad/config.yml
```
## 3 在 OpenPAI 上运行此示例
根据上传大小的限制,仅上传源代码,并在训练过程中下载数据。 本 Experiment 需要的内存 `memoryMB >= 32G`,训练过程可能需要数小时。
### 3.1 更新配置
修改 `nni/examples/trials/ga_squad/config_pai.yml`,以下是默认配置:
```yaml
authorName: default
experimentName: example_ga_squad
trialConcurrency: 1
maxExecDuration: 1h
maxTrialNum: 10
#可选项: local, remote, pai
trainingServicePlatform: pai
#可选项: true, false
useAnnotation: false
# nni_manager 的 ip
nniManagerIp: 10.10.10.10
tuner:
codeDir: ../../tuners/ga_customer_tuner
classFileName: customer_tuner.py
className: CustomerTuner
classArgs:
optimize_mode: maximize
trial:
command: chmod +x ./download.sh && ./download.sh && python3 trial.py
codeDir: https://github.com/Microsoft/nni/tree/master/examples/tuners/ga_customer_tuner
gpuNum: 0
cpuNum: 1
memoryMB: 32869
# 在 OpenPAI 上运行 NNI 的 Docker 映像
image: msranni/nni:latest
paiConfig:
# 登录 OpenPAI 的用户名
userName: username
# 登录 OpenPAI 的密码
passWord: password
# OpenPAI 的 RestFUL 服务器地址
host: 10.10.10.10
```
将默认值改为个人账户和服务器信息。 包括 `nniManagerIp`, `userName`, `passWord``host`
在 "Trial" 部分中,如果需要使用 GPU 来进行架构搜索,可将 `gpuNum``0` 改为 `1`。 根据训练时长,可以增加 `maxTrialNum``maxExecDuration`
`trialConcurrency` 是并发运行的 Trial 的数量。如果将 `gpuNum` 设置为 1,则需要与 GPU 数量一致。
### 3.2 提交任务
```bash
nnictl create --config ~/nni/examples/trials/ga_squad/config_pai.yml
```
## 4. 代码实现
### 4.1 实现方法
基于进化算法架构的问答和其它示例一样,有两个部分:Trial 和 Tuner。
### 4.2 Trial
Trial 有大量的文件、函数和类。 这里只简单介绍最重要的文件:
* `attention.py` 包含了 Tensorflow 注意力算法的实现。
* `data.py` 包含了数据处理函数。
* `evaluate.py` 包含了评估脚本。
* `graph.py` 包含了计算图的定义。
* `rnn.py` 包含了 TensorFlow 的 GRU 实现。
* `train_model.py` 是整个文档模型的封装。
这些文件中,`trial.py``graph_to_tf.py` 非常特别。
`graph_to_tf.py` 有一个叫做 `graph_to_network`的函数,其框架代码如下:
```python
def graph_to_network(input1,
input2,
input1_lengths,
input2_lengths,
graph,
dropout_rate,
is_training,
num_heads=1,
rnn_units=256):
topology = graph.is_topology()
layers = dict()
layers_sequence_lengths = dict()
num_units = input1.get_shape().as_list()[-1]
layers[0] = input1*tf.sqrt(tf.cast(num_units, tf.float32)) + \
positional_encoding(input1, scale=False, zero_pad=False)
layers[1] = input2*tf.sqrt(tf.cast(num_units, tf.float32))
layers[0] = dropout(layers[0], dropout_rate, is_training)
layers[1] = dropout(layers[1], dropout_rate, is_training)
layers_sequence_lengths[0] = input1_lengths
layers_sequence_lengths[1] = input2_lengths
for _, topo_i in enumerate(topology):
if topo_i == '|':
continue
if graph.layers[topo_i].graph_type == LayerType.input.value:
# ......
elif graph.layers[topo_i].graph_type == LayerType.attention.value:
# ......
# 处理更多层
```
正如我们看到的,这个函数实际上是个编译器。它将内部模型的 DAG 配置`图`(在`模型配置格式`章节介绍)转换为 Tensorflow 的计算图。
```python
topology = graph.is_topology()
```
将内部图表示进行拓扑排序,代码在下列循环中:
```python
for _, topo_i in enumerate(topology):
```
执行实际转换,将每层映射为 TensorFlow 计算图中的一部分。
### 4.3 Tuner
Tuner 比 Trial 代码简单很多。 它们共用了同样的 `graph.py`。 此外,Tuner 有 `customer_tuner.py`,其中最重要的类是 `CustomerTuner`
```python
class CustomerTuner(Tuner):
# ......
def generate_parameters(self, parameter_id):
"""将一组 Trial 图配置作为序列化对象返回。
parameter_id : int
"""
if len(self.population) <= 0:
logger.debug("the len of poplution lower than zero.")
raise Exception('The population is empty')
pos = -1
for i in range(len(self.population)):
if self.population[i].result == None:
pos = i
break
if pos != -1:
indiv = copy.deepcopy(self.population[pos])
self.population.pop(pos)
temp = json.loads(graph_dumps(indiv.config))
else:
random.shuffle(self.population)
if self.population[0].result > self.population[1].result:
self.population[0] = self.population[1]
indiv = copy.deepcopy(self.population[0])
self.population.pop(1)
indiv.mutation()
graph = indiv.config
temp = json.loads(graph_dumps(graph))
# ......
```
重载函数 `generate_parameters` 实现了简单的变异算法。 代码如下:
```python
if self.population[0].result > self.population[1].result:
self.population[0] = self.population[1]
indiv = copy.deepcopy(self.population[0])
```
控制突变过程。 它会在种群中随机取出两个个体,对更好结果的一个保留数据,并突变另一个。
### 4.4 模型配置格式
这是模型配置的示例,在架构搜索过程中,从 Tuner 传入 Trial 的代码。
```json
{
"max_layer_num": 50,
"layers": [
{
"input_size": 0,
"type": 3,
"output_size": 1,
"input": [],
"size": "x",
"output": [4, 5],
"is_delete": false
},
{
"input_size": 0,
"type": 3,
"output_size": 1,
"input": [],
"size": "y",
"output": [4, 5],
"is_delete": false
},
{
"input_size": 1,
"type": 4,
"output_size": 0,
"input": [6],
"size": "x",
"output": [],
"is_delete": false
},
{
"input_size": 1,
"type": 4,
"output_size": 0,
"input": [5],
"size": "y",
"output": [],
"is_delete": false
},
{"Comment": "实际图会有更多层。"}
]
}
```
每个模型配置都有一个 "layers" 部分,这是层定义的 JSON 列表。 每层的定义也是一个 JSON 对象:
* `type` 是层的类型。 0, 1, 2, 3, 4 对应注意力、自注意力、RNN、输入和输出层。
* `size` 是输出的长度。 "x", "y" 对应文档长度和问题长度。
* `input_size` 是该层的输入数量。
* `input` 表示输入层的索引。
* `output` 是输出层的索引,该层会作为这些层的输入。
* `is_delete` 表示此层是否可用。
\ No newline at end of file
在阅读理解上使用自动模型架构搜索
=============================================================
该示例展示了如何使用遗传算法为阅读理解任务找到好的模型架构。
1. Search Space
---------------
在阅读理解领域,注意力(Attention)和循环神经网络都已被证明是非常有效的方法,因此搜索空间定义如下:
#. IDENTITY (Effectively 表示继续训练)。
#. INSERT-RNN-LAYER (插入 LSTM。 在 Experiment 中比较了 GRU 和 LSTM 的性能后,我们决定在这里采用 LSTM。)
#. REMOVE-RNN-LAYER
#. INSERT-ATTENTION-LAYER (插入注意力层。)
#. REMOVE-ATTENTION-LAYER
#. ADD-SKIP (在随机层之间一致).
#. REMOVE-SKIP (移除随机跳过).
.. image:: ../../../examples/trials/ga_squad/ga_squad.png
:target: ../../../examples/trials/ga_squad/ga_squad.png
:alt:
新版本
^^^^^^^^^^^
另一个时间更快,性能更好的版本正在开发中。 很快将发布。
2. 如何在本机运行此示例?
------------------------------------
2.1 使用下载脚本来下载数据
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
执行下列命令来下载
所需要的数据:
.. code-block:: bash
chmod +x ./download.sh
./download.sh
或手动下载
#. 在 https://rajpurkar.github.io/SQuAD-explorer/ 下载 "dev-v1.1.json" 和 "train-v1.1.json"。
.. code-block:: bash
wget https://rajpurkar.github.io/SQuAD-explorer/dataset/train-v1.1.json
wget https://rajpurkar.github.io/SQuAD-explorer/dataset/dev-v1.1.json
#. 在 https://nlp.stanford.edu/projects/glove/ 下载 "glove.840B.300d.txt"。
.. code-block:: bash
wget http://nlp.stanford.edu/data/glove.840B.300d.zip
unzip glove.840B.300d.zip
2.2 更新配置
^^^^^^^^^^^^^^^^^^^^^^^^
修改 ``nni/examples/trials/ga_squad/config.yml``,以下是默认配置:
.. code-block:: yaml
authorName: default
experimentName: example_ga_squad
trialConcurrency: 1
maxExecDuration: 1h
maxTrialNum: 1
#choice: local, remote
trainingServicePlatform: local
# 选择:true, false
useAnnotation: false
tuner:
codeDir: ~/nni/examples/tuners/ga_customer_tuner
classFileName: customer_tuner.py
className: CustomerTuner
classArgs:
optimize_mode: maximize
trial:
command: python3 trial.py
codeDir: ~/nni/examples/trials/ga_squad
gpuNum: 0
在 "Trial" 部分中,如果需要使用 GPU 来进行架构搜索,可将 ``gpuNum`` 从 ``0`` 改为 ``1``。 根据训练时长,可以增加 ``maxTrialNum`` 和 ``maxExecDuration``。
2.3 提交任务
^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
nnictl create --config ~/nni/examples/trials/ga_squad/config.yml
3 在 OpenPAI 上运行此示例
-----------------------------
根据上传大小的限制,仅上传源代码,并在训练过程中下载数据。 本 Experiment 需要的内存 ``memoryMB >= 32G``,训练过程可能需要数小时。
3.1 更新配置
^^^^^^^^^^^^^^^^^^^^^^^^
修改 ``nni/examples/trials/ga_squad/config_pai.yml``,以下是默认配置:
.. code-block:: yaml
authorName: default
experimentName: example_ga_squad
trialConcurrency: 1
maxExecDuration: 1h
maxTrialNum: 10
#choice: local, remote, pai
trainingServicePlatform: pai
#choice: true, false
useAnnotation: false
# 你的 nni_manager ip 地址
nniManagerIp: 10.10.10.10
tuner:
codeDir: https://github.com/Microsoft/nni/tree/v1.9/examples/tuners/ga_customer_tuner
classFileName: customer_tuner.py
className: CustomerTuner
classArgs:
optimize_mode: maximize
trial:
command: chmod +x ./download.sh && ./download.sh && python3 trial.py
codeDir: .
gpuNum: 0
cpuNum: 1
memoryMB: 32869
# 在 OpenPAI 上运行 NNI 的 Docker 映像
image: msranni/nni:latest
paiConfig:
# 登录 OpenPAI 的用户名
userName: username
# 登录 OpenPAI 的密码
passWord: password
# OpenPAI 的 RestFUL 服务器地址
host: 10.10.10.10
将默认值改为个人账户和服务器信息。 包括 ``nniManagerIp``\ , ``userName``\ , ``passWord`` 和 ``host``。
在 "Trial" 部分中,如果需要使用 GPU 来进行架构搜索,可将 ``gpuNum`` 从 ``0`` 改为 ``1``。 根据训练时长,可以增加 ``maxTrialNum`` 和 ``maxExecDuration``。
``trialConcurrency`` 是并发运行的 Trial 的数量。如果将 ``gpuNum`` 设置为 1,则需要与 GPU 数量一致。
3.2 提交任务
^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
nnictl create --config ~/nni/examples/trials/ga_squad/config_pai.yml
4. 代码实现
------------------------------------
4.1 实现方法
^^^^^^^^^^^^^^^^^^^^^
基于进化算法架构的问答和其它示例一样,有两个部分:Trial 和 Tuner。
4.2 Trial
^^^^^^^^^^^^^
Trial 有大量的文件、函数和类。 这里只简单介绍最重要的文件:
* ``attention.py`` 包含了 Tensorflow 注意力算法的实现。
* ``data.py`` 包含了数据处理函数。
* ``evaluate.py`` 包含了评估脚本。
* ``graph.py`` 包含了计算图的定义。
* ``rnn.py`` 包含了 TensorFlow 的 GRU 实现。
* ``train_model.py`` 是整个文档模型的封装。
这些文件中,``trial.py`` 和 ``graph_to_tf.py`` 非常特别。
``graph_to_tf.py`` 有一个叫做 ``graph_to_network`` 的函数,其框架代码如下:
.. code-block:: python
def graph_to_network(input1,
input2,
input1_lengths,
input2_lengths,
graph,
dropout_rate,
is_training,
num_heads=1,
rnn_units=256):
topology = graph.is_topology()
layers = dict()
layers_sequence_lengths = dict()
num_units = input1.get_shape().as_list()[-1]
layers[0] = input1*tf.sqrt(tf.cast(num_units, tf.float32)) + \
positional_encoding(input1, scale=False, zero_pad=False)
layers[1] = input2*tf.sqrt(tf.cast(num_units, tf.float32))
layers[0] = dropout(layers[0], dropout_rate, is_training)
layers[1] = dropout(layers[1], dropout_rate, is_training)
layers_sequence_lengths[0] = input1_lengths
layers_sequence_lengths[1] = input2_lengths
for _, topo_i in enumerate(topology):
if topo_i == '|':
continue
if graph.layers[topo_i].graph_type == LayerType.input.value:
# ......
elif graph.layers[topo_i].graph_type == LayerType.attention.value:
# ......
# 处理更多层
正如我们看到的,这个函数实际上是个编译器。它将内部模型的 DAG 配置 ``图``(在 ``模型配置格式`` 章节介绍)转换为 Tensorflow 的计算图。
.. code-block:: python
topology = graph.is_topology()
将内部图表示进行拓扑排序,代码在下列循环中:
.. code-block:: python
for _, topo_i in enumerate(topology):
执行实际转换,将每层映射为 TensorFlow 计算图中的一部分。
4.3 Tuner
^^^^^^^^^^^^^
Tuner 比 Trial 代码简单很多。 它们共用了同样的 ``graph.py``。 此外,Tuner 有 ``customer_tuner.py``,其中最重要的类是 ``CustomerTuner``:
.. code-block:: python
class CustomerTuner(Tuner):
# ......
def generate_parameters(self, parameter_id):
"""以可序列化对象的形式返回一组 Trial (超)参数
parameter_id : int
"""
if len(self.population) <= 0:
logger.debug("the len of poplution lower than zero.")
raise Exception('The population is empty')
pos = -1
for i in range(len(self.population)):
if self.population[i].result == None:
pos = i
break
if pos != -1:
indiv = copy.deepcopy(self.population[pos])
self.population.pop(pos)
temp = json.loads(graph_dumps(indiv.config))
else:
random.shuffle(self.population)
if self.population[0].result > self.population[1].result:
self.population[0] = self.population[1]
indiv = copy.deepcopy(self.population[0])
self.population.pop(1)
indiv.mutation()
graph = indiv.config
temp = json.loads(graph_dumps(graph))
# ......
重载函数 ``generate_parameters`` 实现了简单的变异算法。 代码如下:
.. code-block:: python
if self.population[0].result > self.population[1].result:
self.population[0] = self.population[1]
indiv = copy.deepcopy(self.population[0])
控制突变过程。 它会在种群中随机取出两个个体,对更好结果的一个保留数据,并突变另一个。
4.4 模型配置格式
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
这是模型配置的示例,在架构搜索过程中,从 Tuner 传入 Trial 的代码。
.. code-block:: json
{
"max_layer_num": 50,
"layers": [
{
"input_size": 0,
"type": 3,
"output_size": 1,
"input": [],
"size": "x",
"output": [4, 5],
"is_delete": false
},
{
"input_size": 0,
"type": 3,
"output_size": 1,
"input": [],
"size": "y",
"output": [4, 5],
"is_delete": false
},
{
"input_size": 1,
"type": 4,
"output_size": 0,
"input": [6],
"size": "x",
"output": [],
"is_delete": false
},
{
"input_size": 1,
"type": 4,
"output_size": 0,
"input": [5],
"size": "y",
"output": [],
"is_delete": false
},
{"Comment": "More layers will be here for actual graphs."}
]
}
每个模型配置都有一个 "layers" 部分,这是层定义的 JSON 列表。 每层的定义也是一个 JSON 对象:
* ``type`` 是层的类型。 0, 1, 2, 3, 4 对应注意力、自注意力、RNN、输入和输出层。
* ``type`` 是输出的长度。 "x", "y" 对应文档长度和问题长度。
* ``type`` 是该层的输入数量。
* ``type`` 表示输入层的索引。
* ``type`` 是输出层的索引,该层会作为这些层的输入。
* ``type`` 表示此层是否可用。
# 实现 NNI 的 Trial(尝试)代码
**Trial(尝试)**是将一组参数组合(例如,超参)在模型上独立的一次尝试。
定义 NNI 的 Trial,需要首先定义参数组,并更新模型代码。 NNI 有两种方法来实现 Trial:[NNI API](#nni-api) 以及 [NNI Python annotation](#nni-annotation)。 参考[这里的](#more-examples)更多 Trial 示例。
<a name="nni-api"></a>
## NNI API
### 第一步:准备搜索空间参数文件。
示例如下:
```json
{
"dropout_rate":{"_type":"uniform","_value":[0.1,0.5]},
"conv_size":{"_type":"choice","_value":[2,3,5,7]},
"hidden_size":{"_type":"choice","_value":[124, 512, 1024]},
"learning_rate":{"_type":"uniform","_value":[0.0001, 0.1]}
}
```
参考 [SearchSpaceSpec.md](../Tutorial/SearchSpaceSpec.md) 进一步了解搜索空间。 Tuner 会根据搜索空间来生成配置,即从每个超参的范围中选一个值。
### 第二步:更新模型代码
* Import NNI
在 Trial 代码中加上 `import nni`
* 从 Tuner 获得参数值
```python
RECEIVED_PARAMS = nni.get_next_parameter()
```
`RECEIVED_PARAMS` 是一个对象,如:
`{"conv_size": 2, "hidden_size": 124, "learning_rate": 0.0307, "dropout_rate": 0.2029}`.
* 定期返回指标数据(可选)
```python
nni.report_intermediate_result(metrics)
```
`指标`可以是任意的 Python 对象。 如果使用了 NNI 内置的 Tuner/Assessor,`指标`只可以是两种类型:1) 数值类型,如 float、int, 2) dict 对象,其中必须由键名为 `default`,值为数值的项目。 `指标`会发送给 [Assessor](../Assessor/BuiltinAssessor.md)。 通常,`指标`包含了定期评估的损失值或精度。
* 返回配置的最终性能
```python
nni.report_final_result(metrics)
```
`指标`可以是任意的 Python 对象。 如果使用了内置的 Tuner/Assessor,`指标`格式和 `report_intermediate_result` 中一样,这个数值表示模型的性能,如精度、损失值等。 `指标`会发送给 [Tuner](../Tuner/BuiltinTuner.md)
### 第三步:启用 NNI API
要启用 NNI 的 API 模式,需要将 useAnnotation 设置为 *false*,并提供搜索空间文件的路径,即第一步中定义的文件:
```yaml
useAnnotation: false
searchSpacePath: /path/to/your/search_space.json
```
参考[这里](../Tutorial/ExperimentConfig.md)进一步了解如何配置 Experiment。
* 参考[这里](https://nni.readthedocs.io/zh/latest/sdk_reference.html),了解更多 NNI API (例如 `nni.get_sequence_id()`)。
<a name="nni-annotation"></a>
## NNI Annotation
另一种实现 Trial 的方法是使用 Python 注释来标记 NNI。 NN Annotation 很简单,类似于注释。 不必对现有代码进行结构更改。 只需要添加一些 NNI Annotation,就能够:
* 标记需要调整的参数变量
* 指定要在其中调整的变量的范围
* 标记哪个变量需要作为中间结果范围给 `Assessor`
* 标记哪个变量需要作为最终结果(例如:模型精度)返回给 `Tuner`
同样以 MNIST 为例,只需要两步就能用 NNI Annotation 来实现 Trial 代码。
### 第一步:在代码中加入 Annotation
下面是加入了 Annotation 的 TensorFlow 代码片段,高亮的 4 行 Annotation 用于:
1. 调优 batch\_size 和 dropout\_rate
2. 每执行 100 步返回 test\_acc
3. 最后返回 test\_acc 作为最终结果。
值得注意的是,新添加的代码都是注释,不会影响以前的执行逻辑。因此这些代码仍然能在没有安装 NNI 的环境中运行。
```diff
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
+ """@nni.variable(nni.choice(50, 250, 500), name=batch_size)"""
batch_size = 128
for i in range(10000):
batch = mnist.train.next_batch(batch_size)
+ """@nni.variable(nni.choice(0.1, 0.5), name=dropout_rate)"""
dropout_rate = 0.5
mnist_network.train_step.run(feed_dict={mnist_network.images: batch[0],
mnist_network.labels: batch[1],
mnist_network.keep_prob: dropout_rate})
if i % 100 == 0:
test_acc = mnist_network.accuracy.eval(
feed_dict={mnist_network.images: mnist.test.images,
mnist_network.labels: mnist.test.labels,
mnist_network.keep_prob: 1.0})
+ """@nni.report_intermediate_result(test_acc)"""
test_acc = mnist_network.accuracy.eval(
feed_dict={mnist_network.images: mnist.test.images,
mnist_network.labels: mnist.test.labels,
mnist_network.keep_prob: 1.0})
+ """@nni.report_final_result(test_acc)"""
```
**注意**
* `@nni.variable` 会对它的下面一行进行修改,左边被赋值变量必须与 `@nni.variable` 的关键字 `name` 相同。
* `@nni.report_intermediate_result`/`@nni.report_final_result` 会将数据发送给 Assessor、Tuner。
Annotation 的语法和用法等,参考 [Annotation](../Tutorial/AnnotationSpec.md)
### 第二步:启用 Annotation
在 YAML 配置文件中设置 *useAnnotation* 为 true 来启用 Annotation:
useAnnotation: true
## 用于调试的独立模式
NNI 支持独立模式,使 Trial 代码无需启动 NNI 实验即可运行。 这样能更容易的找出 Trial 代码中的 Bug。 NNI Annotation 天然支持独立模式,因为添加的 NNI 相关的行都是注释的形式。 NNI Trial API 在独立模式下的行为有所变化,某些 API 返回虚拟值,而某些 API 不报告值。 有关这些 API 的完整列表,请参阅下表。
```python
注意请为 Trial 代码中的超参分配默认值
nni.get_next_parameter返回 {}
nni.report_final_result已在 stdout 上打印日志但不报告
nni.report_intermediate_result已在 stdout 上打印日志但不报告
nni.get_experiment_id返回 "STANDALONE"
nni.get_trial_id返回 "STANDALONE"
nni.get_sequence_id返回 0
```
可使用 [mnist 示例](https://github.com/microsoft/nni/tree/master/examples/trials/mnist-tfv1) 来尝试独立模式。 只需在代码目录下运行 `python3 mnist.py`。 Trial 代码会使用默认超参成功运行。
更多调试的信息,可参考[调试指南](../Tutorial/HowToDebug.md)
## Trial 存放在什么地方?
### 本机模式
每个 Trial 都有单独的目录来输出自己的数据。 在每次 Trial 运行后,环境变量 `NNI_OUTPUT_DIR` 定义的目录都会被导出。 在这个目录中可以看到 Trial 的代码、数据和日志。 此外,Trial 的日志(包括 stdout)还会被重定向到此目录中的 `trial.log` 文件。
如果使用了 Annotation 方法,转换后的 Trial 代码会存放在另一个临时目录中。 可以在 `run.sh` 文件中的 `NNI_OUTPUT_DIR` 变量找到此目录。 文件中的第二行(即:`cd`)会切换到代码所在的实际路径。 参考 `run.sh` 文件示例:
```bash
#!/bin/bash
cd /tmp/user_name/nni/annotation/tmpzj0h72x6 #This is the actual directory
export NNI_PLATFORM=local
export NNI_SYS_DIR=/home/user_name/nni-experiments/$experiment_id$/trials/$trial_id$
export NNI_TRIAL_JOB_ID=nrbb2
export NNI_OUTPUT_DIR=/home/user_name/nni-experiments/$eperiment_id$/trials/$trial_id$
export NNI_TRIAL_SEQ_ID=1
export MULTI_PHASE=false
export CUDA_VISIBLE_DEVICES=
eval python3 mnist.py 2>/home/user_name/nni-experiments/$experiment_id$/trials/$trial_id$/stderr
echo $? `date +%s%3N` >/home/user_name/nni-experiments/$experiment_id$/trials/$trial_id$/.nni/state
```
### 其它模式
当 Trial 运行在 OpenPAI 这样的远程服务器上时,`NNI_OUTPUT_DIR` 仅会指向 Trial 的输出目录,而 `run.sh` 不会在此目录中。 `trial.log` 文件会被复制回本机的 Trial 目录中。目录的默认位置在 `~/nni-experiments/$experiment_id$/trials/$trial_id$/`
详细信息,可参考[调试指南](../Tutorial/HowToDebug.md)
<a name="more-examples"></a>
## 更多 Trial 的示例
* [MNIST 示例](MnistExamples.md)
* [为 CIFAR 10 分类找到最佳的 optimizer](Cifar10Examples.md)
* [如何在 NNI 调优 SciKit-learn 的参数](SklearnExamples.md)
* [在阅读理解上使用自动模型架构搜索。](SquadEvolutionExamples.md)
* [如何在 NNI 上调优 GBDT](GbdtExample.md)
* [在 NNI 上调优 RocksDB](RocksdbExamples.md)
\ No newline at end of file
.. role:: raw-html(raw)
:format: html
实现 NNI 的 Trial(尝试)代码
===========================================
**Trial(尝试)** 是将一组参数组合(例如,超参)在模型上独立的一次尝试。
定义 NNI 的 Trial,需要首先定义参数组(例如,搜索空间),并更新模型代码。 有两种方法来定义一个 Trial:`NNI API <#nni-api>`__ 和 `NNI Python annotation <#nni-annotation>`__。 参考 `这里 <#more-examples>`__ 更多 Trial 示例。
:raw-html:`<a name="nni-api"></a>`
NNI API
-------
第一步:准备搜索空间参数文件。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
样例如下:
.. code-block:: json
{
"dropout_rate":{"_type":"uniform","_value":[0.1,0.5]},
"conv_size":{"_type":"choice","_value":[2,3,5,7]},
"hidden_size":{"_type":"choice","_value":[124, 512, 1024]},
"learning_rate":{"_type":"uniform","_value":[0.0001, 0.1]}
}
参考 `SearchSpaceSpec.md <../Tutorial/SearchSpaceSpec.rst>`__ 进一步了解搜索空间。 Tuner 会根据搜索空间来生成配置,即从每个超参的范围中选一个值。
第二步:更新模型代码
^^^^^^^^^^^^^^^^^^^^^^^^^^
*
Import NNI
在 Trial 代码中加上 ``import nni`` 。
*
从 Tuner 获得参数值
.. code-block:: python
RECEIVED_PARAMS = nni.get_next_parameter()
``RECEIVED_PARAMS`` 是一个对象,如:
``{"conv_size": 2, "hidden_size": 124, "learning_rate": 0.0307, "dropout_rate": 0.2029}``
* 定期返回指标数据(可选)
.. code-block:: python
nni.report_intermediate_result(metrics)
``指标`` 可以是任意的 Python 对象。 如果使用了 NNI 内置的 Tuner/Assessor,``指标`` 只可以是两种类型:1) 数值类型,如 float、int, 2) dict 对象,其中必须由键名为 ``default`` ,值为数值的项目。 ``指标`` 会发送给 `assessor <../Assessor/BuiltinAssessor.rst>`__。 通常,``指标`` 包含了定期评估的损失值或精度。
* 返回配置的最终性能
.. code-block:: python
nni.report_final_result(metrics)
``指标`` 可以是任意的 Python 对象。 如果使用了内置的 Tuner/Assessor,``指标`` 格式和 ``report_intermediate_result`` 中一样,这个数值表示模型的性能,如精度、损失值等。 ``指标`` 会发送给 `tuner <../Tuner/BuiltinTuner.rst>`__。
第三步:启用 NNI API
^^^^^^^^^^^^^^^^^^^^^^^
要启用 NNI 的 API 模式,需要将 useAnnotation 设置为 *false*,并提供搜索空间文件的路径,即第一步中定义的文件:
.. code-block:: yaml
useAnnotation: false
searchSpacePath: /path/to/your/search_space.json
参考 `这里 <../Tutorial/ExperimentConfig.rst>`__ 进一步了解如何配置 Experiment。
参考 `这里 </sdk_reference.html>`__ ,了解更多 NNI API (例如:``nni.get_sequence_id()``)。
:raw-html:`<a name="nni-annotation"></a>`
NNI Annotation
---------------------
另一种实现 Trial 的方法是使用 Python 注释来标记 NNI。 NN Annotation 很简单,类似于注释。 不必对现有代码进行结构更改。 只需要添加一些 NNI Annotation,就能够:
* 标记需要调整的参数变量
* 指定要在其中调整的变量的范围
* 标记哪个变量需要作为中间结果范围给 ``assessor``
* 标记哪个变量需要作为最终结果(例如:模型精度) 返回给 ``tuner``
同样以 MNIST 为例,只需要两步就能用 NNI Annotation 来实现 Trial 代码。
第一步:在代码中加入 Annotation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
下面是加入了 Annotation 的 TensorFlow 代码片段,高亮的 4 行 Annotation 用于:
#. 调优 batch_size 和 dropout_rate
#. 每执行 100 步返回 test_acc
#. 最后返回 test_acc 作为最终结果。
值得注意的是,新添加的代码都是注释,不会影响以前的执行逻辑。因此这些代码仍然能在没有安装 NNI 的环境中运行。
.. code-block:: diff
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
+ """@nni.variable(nni.choice(50, 250, 500), name=batch_size)"""
batch_size = 128
for i in range(10000):
batch = mnist.train.next_batch(batch_size)
+ """@nni.variable(nni.choice(0.1, 0.5), name=dropout_rate)"""
dropout_rate = 0.5
mnist_network.train_step.run(feed_dict={mnist_network.images: batch[0],
mnist_network.labels: batch[1],
mnist_network.keep_prob: dropout_rate})
if i % 100 == 0:
test_acc = mnist_network.accuracy.eval(
feed_dict={mnist_network.images: mnist.test.images,
mnist_network.labels: mnist.test.labels,
mnist_network.keep_prob: 1.0})
+ """@nni.report_intermediate_result(test_acc)"""
test_acc = mnist_network.accuracy.eval(
feed_dict={mnist_network.images: mnist.test.images,
mnist_network.labels: mnist.test.labels,
mnist_network.keep_prob: 1.0})
+ """@nni.report_final_result(test_acc)"""
**注意**:
* ``@nni.variable`` 会对它的下面一行进行修改,左边被赋值变量必须与 ``@nni.variable`` 的关键字 ``name`` 相同。
* ``@nni.report_intermediate_result``\ /\ ``@nni.report_final_result`` 会将数据发送给 assessor/tuner。
Annotation 的语法和用法等,参考 `Annotation <../Tutorial/AnnotationSpec.rst>`__。
第二步:启用 Annotation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
在 YAML 配置文件中设置 *useAnnotation* 为 true 来启用 Annotation:
.. code-block:: bash
useAnnotation: true
用于调试的独立模式
-----------------------------
NNI 支持独立模式,使 Trial 代码无需启动 NNI 实验即可运行。 这样能更容易的找出 Trial 代码中的 Bug。 NNI Annotation 天然支持独立模式,因为添加的 NNI 相关的行都是注释的形式。 NNI Trial API 在独立模式下的行为有所变化,某些 API 返回虚拟值,而某些 API 不报告值。 有关这些 API 的完整列表,请参阅下表。
.. code-block:: python
# 注意:请为 Trial 代码中的超参分配默认值
nni.report_final_result # 已在 stdout 上打印日志,但不报告
nni.report_intermediate_result # 已在 stdout 上打印日志,但不报告
nni.get_experiment_id # 返回 "STANDALONE"
nni.get_trial_id # 返回 "STANDALONE"
nni.get_sequence_id # 返回 0
可使用 :githublink:`mnist 示例 <examples/trials/mnist-tfv1>` 来尝试独立模式。 只需在代码目录下运行 ``python3 mnist.py``。 Trial 代码会使用默认超参成功运行。
更多调试的信息,可参考 `How to Debug <../Tutorial/HowToDebug.rst>`__。
Trial 存放在什么地方?
----------------------------------------
本机模式
^^^^^^^^^^
每个 Trial 都有单独的目录来输出自己的数据。 在每次 Trial 运行后,环境变量 ``NNI_OUTPUT_DIR`` 定义的目录都会被导出。 在这个目录中可以看到 Trial 的代码、数据和日志。 此外,Trial 的日志(包括 stdout)还会被重定向到此目录中的 ``trial.log`` 文件。
如果使用了 Annotation 方法,转换后的 Trial 代码会存放在另一个临时目录中。 可以在 ``run.sh`` 文件中的 ``NNI_OUTPUT_DIR`` 变量找到此目录。 文件中的第二行(即:``cd``)会切换到代码所在的实际路径。 ``run.sh`` 文件示例:
.. code-block:: bash
#!/bin/bash
cd /tmp/user_name/nni/annotation/tmpzj0h72x6 #This is the actual directory
export NNI_PLATFORM=local
export NNI_SYS_DIR=/home/user_name/nni-experiments/$experiment_id$/trials/$trial_id$
export NNI_TRIAL_JOB_ID=nrbb2
export NNI_OUTPUT_DIR=/home/user_name/nni-experiments/$eperiment_id$/trials/$trial_id$
export NNI_TRIAL_SEQ_ID=1
export MULTI_PHASE=false
export CUDA_VISIBLE_DEVICES=
eval python3 mnist.py 2>/home/user_name/nni-experiments/$experiment_id$/trials/$trial_id$/stderr
echo $? `date +%s%3N` >/home/user_name/nni-experiments/$experiment_id$/trials/$trial_id$/.nni/state
其它模式
^^^^^^^^^^^
当 Trial 运行在 OpenPAI 这样的远程服务器上时,``NNI_OUTPUT_DIR`` 仅会指向 Trial 的输出目录,而 ``run.sh`` 不会在此目录中。 ``trial.log`` 文件会被复制回本机的 Trial 目录中。目录的默认位置在 ``~/nni-experiments/$experiment_id$/trials/$trial_id$/``。
更多调试的信息,可参考 `How to Debug <../Tutorial/HowToDebug.rst>`__。
:raw-html:`<a name="more-examples"></a>`
更多 Trial 的示例
-------------------
* `MNIST 示例 <MnistExamples.rst>`__
* `为 CIFAR 10 分类找到最佳的 optimizer <Cifar10Examples.rst>`__
* `如何在 NNI 调优 SciKit-learn 的参数 <SklearnExamples.rst>`__
* `在阅读理解上使用自动模型架构搜索。 <SquadEvolutionExamples.rst>`__
* `如何在 NNI 上调优 GBDT <GbdtExample.rst>`__
* `在 NNI 上调优 RocksDB <RocksdbExamples.rst>`__
# Batch Tuner
## Batch Tuner(批处理 Tuner)
Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。 当所有配置都执行完后,Experiment 即结束。 Batch Tuner 的[搜索空间](../Tutorial/SearchSpaceSpec.md)只支持 `choice`
建议场景:如果 Experiment 配置已确定,可通过 `choice` 将它们罗列到搜索空间文件中运行即可。
\ No newline at end of file
Batch Tuner
==================
Batch Tuner(批量调参器)
-------------------------------
Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。 当所有配置都完成后,Experiment 即结束。 Batch Tuner 的 `搜索空间 <../Tutorial/SearchSpaceSpec.rst>`__ 只支持 ``choice``。
建议场景:如果 Experiment 配置已确定,可通过 ``choice`` 将它们罗列到搜索空间文件中运行即可。
# NNI 中的 BOHB Advisor NNI 中的 BOHB Advisor
======================================
## 1. 介绍 1. 介绍
---------------
BOHB 是由[此篇论文](https://arxiv.org/abs/1807.01774)提出的一种高效而稳定的调参算法。 BO 是贝叶斯优化(Bayesian Optimization)的缩写,HB 是 Hyperband 算法的缩写。 BOHB 是由 `此篇论文 <https://arxiv.org/abs/1807.01774>`__ 提出的一种高效而稳定的调参算法。 BO 是贝叶斯优化(Bayesian Optimization)的缩写,HB 是 Hyperband 算法的缩写。
BOHB 依赖 HB(Hyperband)来决定每次跑多少组参数和每组参数分配多少资源(budget),**它的改进之处是将 Hyperband 在每个循环开始时随机选择参数的方法替换成了依赖之前的数据建立模型(贝叶斯优化)进行参数选择**。 一旦贝叶斯优化生成的参数达到迭代所需的配置数, 就会使用这些配置开始执行标准的连续减半过程(successive halving)。 观察这些参数在不同资源配置(budget)下的表现 g(x, b),用于在以后的迭代中用作我们贝叶斯优化模型选择参数的基准数据。 BOHB 依赖 HB(Hyperband)来决定每次跑多少组参数和每组参数分配多少资源(budget),**它的改进之处是将 Hyperband 在每个循环开始时随机选择参数的方法替换成了依赖之前的数据建立模型(贝叶斯优化)进行参数选择**。 一旦贝叶斯优化生成的参数达到迭代所需的配置数, 就会使用这些配置开始执行标准的连续减半过程(successive halving)。 观察这些参数在不同资源配置(budget)下的表现 g(x, b),用于在以后的迭代中用作我们贝叶斯优化模型选择参数的基准数据。
接下来分两部分来介绍 BOHB 过程涉及的原理: 接下来分两部分来介绍 BOHB 过程涉及的原理:
### HB(Hyperband) HB(Hyperband)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
按照 Hyperband 的方式来选择资源(budget),并继续使用 "连续减半(SuccessiveHalving)" 策略。 更多细节,参考 [NNI 中的 Hyperband](HyperbandAdvisor.md)[Hyperband 的参考论文](https://arxiv.org/abs/1603.06560)。 下面的伪代码描述了这个过程。 按照 Hyperband 的方式来选择资源(budget),并继续使用 "连续减半(SuccessiveHalving)" 策略。 更多细节,参考 `NNI 中的 Hyperband <HyperbandAdvisor.rst>`__`Hyperband 的参考论文 <https://arxiv.org/abs/1603.06560>`__。 下面的伪代码描述了这个过程。
![](../../img/bohb_1.png)
### BO(贝叶斯优化) .. image:: ../../img/bohb_1.png
:target: ../../img/bohb_1.png
:alt:
BO(贝叶斯优化)
^^^^^^^^^^^^^^^^^^^^^^^^^^
BOHB 的 BO 与 TPE 非常相似, 它们的主要区别是: BOHB 中使用一个多维的 KDE, 而不是 TPE 那样带有权重的一维 KDEs, 以便更好地处理搜索空间中超参之间的互相影响。 BOHB 的 BO 与 TPE 非常相似, 它们的主要区别是: BOHB 中使用一个多维的 KDE, 而不是 TPE 那样带有权重的一维 KDEs, 以便更好地处理搜索空间中超参之间的互相影响。
树形超参评估器 (TPE): 使用 KDE (核密度估计) 来对密度进行建模。 树形超参评估器 (TPE): 使用 KDE (核密度估计) 来对密度进行建模。
![](../../img/bohb_2.png)
为了建模有效的核密度估计(KDE),设置了一个建立模型所需的最小观察点数(Nmin),在 Experiment 中它的默认值为 d+1(d是搜索空间的维度),其中 d 也是一个可以设置的超参数。 因为希望尽早地建立模型,所以当 Nb = |Db|,即当已经观察到的计算资源(budget)为 b 的点数满足 q · Nb ≥ Nmin 时,立即建立模型来指导之后参数的选择。所以,在使用了刚开始Nmin + 2 个随机选择的参数之后,会按照下式将观察到的点进行分类 .. image:: ../../img/bohb_2.png
:target: ../../img/bohb_2.png
:alt:
为了建模有效的核密度估计(KDE),设置了一个建立模型所需的最小观察点数(Nmin),在 Experiment 中它的默认值为 d+1(d是搜索空间的维度),其中 d 也是一个可以设置的超参数。 因为希望尽早地建立模型,所以当 Nb = \|Db\|,即当已经观察到的计算资源(budget)为 b 的点数满足 q · Nb ≥ Nmin 时,立即建立模型来指导之后参数的选择。所以,在使用了刚开始Nmin + 2 个随机选择的参数之后,会按照下式将观察到的点进行分类
.. image:: ../../img/bohb_3.png
:target: ../../img/bohb_3.png
:alt:
![](../../img/bohb_3.png)
按照公式将观察到的点分成好与坏两类点,来分别拟合两个不同的密度分布。 按照公式将观察到的点分成好与坏两类点,来分别拟合两个不同的密度分布。
注意,为了鼓励更多的探索防止陷入局部极小,在建立模型之后仍然有**随机比例(random faction)**这样的参数是由随机选择生成的。 注意,为了鼓励更多的探索防止陷入局部极小,在建立模型之后仍然有 **随机比例(random faction)** 这样的参数是由随机选择生成的。
2. 流程
-----------
## 2. 流程 .. image:: ../../img/bohb_6.jpg
:target: ../../img/bohb_6.jpg
![](../../img/bohb_6.jpg)
以上这张图展示了 BOHB 的工作流程。 将每次训练的最大资源配置(max_budget)设为 9,最小资源配置设为(min_budget)1,逐次减半比例(eta)设为 3,其他的超参数为默认值。 那么在这个例子中,s_max 计算的值为 2, 所以会持续地进行 {s=2, s=1, s=0, s=2, s=1, s=0, ...} 的循环。 在“逐次减半”(SuccessiveHalving)算法的每一个阶段,即图中橙色框,都将选取表现最好的前 1/eta 个参数,并在赋予更多计算资源(budget)的情况下运行。不断重复“逐次减半” (SuccessiveHalving)过程,直到这个循环结束。 同时,收集这些试验的超参数组合,使用了计算资源(budget)和其表现(metrics),使用这些数据来建立一个以使用了多少计算资源(budget)为维度的多维核密度估计(KDE)模型。 这个多维的核密度估计(KDE)模型将用于指导下一个循环的参数选择。 以上这张图展示了 BOHB 的工作流程。 将每次训练的最大资源配置(max_budget)设为 9,最小资源配置设为(min_budget)1,逐次减半比例(eta)设为 3,其他的超参数为默认值。 那么在这个例子中,s_max 计算的值为 2, 所以会持续地进行 {s=2, s=1, s=0, s=2, s=1, s=0, ...} 的循环。 在“逐次减半”(SuccessiveHalving)算法的每一个阶段,即图中橙色框,都将选取表现最好的前 1/eta 个参数,并在赋予更多计算资源(budget)的情况下运行。不断重复“逐次减半” (SuccessiveHalving)过程,直到这个循环结束。 同时,收集这些试验的超参数组合,使用了计算资源(budget)和其表现(metrics),使用这些数据来建立一个以使用了多少计算资源(budget)为维度的多维核密度估计(KDE)模型。这个多维的核密度估计(KDE)模型将用于指导下一个循环的参数选择。
有关如何使用多维的 KDE 模型来指导参数选择的采样规程,用以下伪代码来描述。 有关如何使用多维的 KDE 模型来指导参数选择的采样规程,用以下伪代码来描述。
![](../../img/bohb_4.png)
## 3. 用法 .. image:: ../../img/bohb_4.png
:target: ../../img/bohb_4.png
:alt:
BOHB Advisor 需要 [ConfigSpace](https://github.com/automl/ConfigSpace) 包。 可以使用以下命令安装 ConfigSpace。
```bash 3. 用法
nnictl package install --name=SMAC --------
```
BOHB advisor 需要安装 `ConfigSpace <https://github.com/automl/ConfigSpace>`__ 包。 可以使用以下命令安装 ConfigSpace。
.. code-block:: bash
nnictl package install --name=BOHB
要使用 BOHB,需要在 Experiment 的 YAML 配置文件进行如下改动: 要使用 BOHB,需要在 Experiment 的 YAML 配置文件进行如下改动:
```yaml .. code-block:: yaml
advisor:
builtinAdvisorName: BOHB advisor:
classArgs: builtinAdvisorName: BOHB
optimize_mode: maximize classArgs:
min_budget: 1 optimize_mode: maximize
max_budget: 27 min_budget: 1
eta: 3 max_budget: 27
min_points_in_model: 7 eta: 3
top_n_percent: 15 min_points_in_model: 7
num_samples: 64 top_n_percent: 15
random_fraction: 0.33 num_samples: 64
bandwidth_factor: 3.0 random_fraction: 0.33
min_bandwidth: 0.001 bandwidth_factor: 3.0
``` min_bandwidth: 0.001
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。 * **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **min_budget** (*整数, 可选项, 默认值为 1*) - 运行一个试验给予的最低计算资源(budget),这里的计算资源通常使用mini-batches 或者 epochs。 该参数必须为正数。 * **min_budget** (*int, 可选项, 默认值为 1*) - 运行一个试验给予的最低计算资源(budget),这里的计算资源通常使用 mini-batches 或者 epochs。 该参数必须为正数。
* **max_budget** (*整数, 可选项, 默认值为 3*) - 运行一个试验给予的最计算资源(budget),这里的计算资源通常使用 mini-batches 或者 epochs。 该参数必须大于“min_budget”。 * **max_budget** (*int, 可选项, 默认值为 3*) - 运行一个试验给予的最计算资源(budget),这里的计算资源通常使用 mini-batches 或者 epochs。 该参数必须大于“min_budget”。
* **eta** (*整数, 可选项, 默认值为3*) - 在每次迭代中,执行完整的“连续减半”算法。 在这里,当一个使用相同计算资源的子集结束后,选择表现前 1/eta 好的参数,给予更高的优先级,进入下一轮比较(会获得更多计算资源)。 该参数必须大于等于 2。 * **eta** ( *int, 可选项, 默认值为3* ) - 在每次迭代中,执行完整的“连续减半”算法。 在这里,当一个使用相同计算资源的子集结束后,选择表现前 1/eta 好的参数,给予更高的优先级,进入下一轮比较(会获得更多计算资源)。 该参数必须大于等于 2。
* **min_points_in_model**(*整数, 可选项, 默认值为None*): 建立核密度估计(KDE)要求的最小观察到的点。 默认值 None 表示 dim+1,当在该计算资源(budget)下试验过的参数已经大于等于`max{dim+1, min_points_in_model}` 时,BOHB 将会开始建立这个计算资源(budget)下对应的核密度估计(KDE)模型,然后用这个模型来指导参数的选取。 该参数必须为正数。 (dim 表示搜索空间中超参的数量) * **min_points_in_model**\ (*int, 可选项, 默认值为None* ): 建立核密度估计(KDE)要求的最小观察到的点。 默认值 None 表示 dim+1,当在该计算资源(budget)下试验过的参数已经大于等于 ``max{dim+1, min_points_in_model}`` 时,BOHB 将会开始建立这个计算资源(budget)下对应的核密度估计(KDE)模型,然后用这个模型来指导参数的选取。 该参数必须为正数。 (dim 表示搜索空间中超参的数量)
* **top_n_percent**(*整数, 可选, 默认值为 15*): 认为观察点为好点的百分数 (在 1 到 99 之间)。 区分表现好的点与坏的点是为了建立树形核密度估计模型。 例如,如果有 100 个观察到的 Trial,top_n_percent 为 15,则前 15% 的点将用于构建好点模型 "l(x)"。 其余 85% 的点将用于构建坏点模型 "g(x)"。 * **top_n_percent**\ (*int, 可选, 默认值为 15* ): 认为观察点为好点的百分数 (在 1 到 99 之间)。 区分表现好的点与坏的点是为了建立树形核密度估计模型。 例如,如果有 100 个观察到的 Trial,top_n_percent 为 15,则前 15% 的点将用于构建好点模型 "l(x)"。 其余 85% 的点将用于构建坏点模型 "g(x)"。
* **num_samples** (*整数, 可选项, 默认值为64*): 用于优化 EI 值的采样个数(默认值为64)。 在这种情况下,将对 "num_samples" 点进行采样,并比较 l(x)/g(x) 的结果。 然后,如果 optimize_mode 是 `maximize`,就会返回其中 l(x)/g(x) 值最大的点作为下一个配置参数。 否则,使用值最小的点。 * **num_samples**\ (*int, 可选项, 默认值为64*): 用于优化 EI 值的采样个数(默认值为64)。 在这种情况下,将对 "num_samples" 点进行采样,并比较 l(x)/g(x) 的结果。 然后,如果 optimize_mode 是 ``maximize``,就会返回其中 l(x)/g(x) 值最大的点作为下一个配置参数。 否则,使用值最小的点。
* **random_fraction**(*浮点数, 可选项, 默认值为0.33*): 使用模型的先验(通常是均匀)来随机采样的比例。 * **random_fraction**\ (*float, 可选项, 默认值为0.33*): 使用模型的先验(通常是均匀)来随机采样的比例。
* **bandwidth_factor**(< 1>浮点数, 可选, 默认值为3.0 </em>): 为了鼓励多样性,把优化EI的点加宽,即把KDE中采样的点乘以这个因子,从而增加KDE中的带宽。 如果不熟悉 KDE,建议使用默认值。 * **bandwidth_factor**\ (*float, 可选, 默认值为 3.0* ): 为了鼓励多样性,把优化 EI 的点加宽,即把 KDE 中采样的点乘以这个因子,从而增加 KDE 中的带宽。 如果不熟悉 KDE,建议使用默认值。
* **min_bandwidth**(< 1>float, 可选, 默认值 = 0.001 </em>): 为了保持多样性, 即使所有好的样本对其中一个参数具有相同的值,使用最小带宽 (默认值: 1e-3) 而不是零。 如果不熟悉 KDE,建议使用默认值。 * **min_bandwidth**\ (*float, 可选, 默认值 = 0.001* ): 为了保持多样性, 即使所有好的样本对其中一个参数具有相同的值,使用最小带宽 (默认值: 1e-3) 而不是零。 如果不熟悉 KDE,建议使用默认值。
*请注意,浮点类型当前仅支持十进制表示。 必须使用 0.333 而不是 1/3 ,0.001 而不是 1e-3。* * 请注意,浮点类型当前仅支持十进制表示。 必须使用 0.333 而不是 1/3 ,0.001 而不是 1e-3。*
## 4. 文件结构 4. 文件结构
-----------------
Advisor 有大量的文件、函数和类。 这里只简单介绍最重要的文件: Advisor 有大量的文件、函数和类。 这里只简单介绍最重要的文件:
* `bohb_advisor.py` BOHB 类的定义, 包括与 Dispatcher 进行交互的部分,以及控制新 Trial 的生成,计算资源以及结果的处理。 还包含了 HB(Hyperband)的实现部分。
* `config_generator.py` 包含了 BO(贝叶斯优化)算法的实现。 内置函数 *get_config* 使用基于贝叶斯优化生成一个新的参数组合,内置函数 *new_result* 接受新的结果并使用这些结果来更新贝叶斯优化模型。
## 5. 实验 ``bohb_advisor.py`` BOHB 类的定义, 包括与 Dispatcher 进行交互的部分,以及控制新 Trial 的生成,计算资源以及结果的处理。 还包含了 HB(Hyperband)的实现部分。
``config_generator.py`` 包含了 BO(贝叶斯优化)算法的实现。 内置函数 *get_config* 使用基于贝叶斯优化生成一个新的参数组合,内置函数 *new_result* 接受新的结果并使用这些结果来更新贝叶斯优化模型。
### BOHB 在 MNIST 数据集上的表现 5. 实验
-------------
源码地址: [examples/trials/mnist-advisor](https://github.com/Microsoft/nni/tree/master/examples/trials/) BOHB 在 MNIST 数据集上的表现
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
源码地址: :githublink:`examples/trials/mnist-advisor <examples/trials/>`
使用 BOHB 调参算法,在 CNN 模型上跑 MNIST 数据集。 下面是实验结果: 使用 BOHB 调参算法,在 CNN 模型上跑 MNIST 数据集。 下面是实验结果:
![](../../img/bohb_5.png)
更多实验结果可以在[参考文献](https://arxiv.org/abs/1807.01774)中找到。 可以看到,BOHB 充分利用了以往的成果,在探索和挖掘方面有很好的平衡。 .. image:: ../../img/bohb_5.png
\ No newline at end of file :target: ../../img/bohb_5.png
:alt:
更多实验结果可参考 `相关论文 <https://arxiv.org/abs/1807.01774>`__。 可以看到,BOHB 充分利用了以往的成果,在探索和挖掘方面有很好的平衡。
# 使用 NNI 内置 Tuner 进行超参数调优 .. role:: raw-html(raw)
:format: html
为了让机器学习/深度学习模型适应不同的任务/问题,超参数总是需要调优。 自动化超参数调优的过程需要好的调优算法。 NNI 提供了先进的调优算法,使用上也很简单。 下面是内置 Tuner 的简单介绍:
注意:点击 **Tuner 的名称**可看到 Tuner 的安装需求,建议的场景以及示例。 算法的详细说明在每个 Tuner 建议场景的最后。 [本文](../CommunitySharings/HpoComparison.md)对比了不同 Tuner 在几个问题下的不同效果。
当前支持的算法:
| Tuner(调参器) | 算法简介 |
| ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [**TPE**](#TPE) | Tree-structured Parzen Estimator (TPE) 是一种 sequential model-based optimization(SMBO,即基于序列模型优化)的方法。 SMBO 方法根据历史指标数据来按顺序构造模型,来估算超参的性能,随后基于此模型来选择新的超参。 [参考论文](https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf) |
| [**Random Search(随机搜索)**](#Random) | 在超参优化时,随机搜索算法展示了其惊人的简单和效果。 建议当不清楚超参的先验分布时,采用随机搜索作为基准。 [参考论文](http://www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf) |
| [**Anneal(退火算法)**](#Anneal) | 这种简单的退火算法从先前的采样开始,会越来越靠近发现的最佳点取样。 此算法是随机搜索的简单变体,利用了反应曲面的平滑性。 退火率不是自适应的。 |
| [**Naïve Evolution(进化算法)**](#Evolution) | Naïve Evolution(朴素进化算法)来自于 Large-Scale Evolution of Image Classifiers。 它会基于搜索空间随机生成一个种群。 在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层)。 朴素进化算法需要很多次的 Trial 才能有效,但它也非常简单,也很容易扩展新功能。 [参考论文](https://arxiv.org/pdf/1703.01041.pdf) |
| [**SMAC**](#SMAC) | SMAC 基于 Sequential Model-Based Optimization (SMBO,即序列的基于模型优化方法)。 它利用使用过的结果好的模型(高斯随机过程模型),并将随机森林引入到 SMBO 中,来处理分类参数。 SMAC 算法包装了 Github 的 SMAC3。 注意:SMAC 需要通过 `nnictl package` 命令来安装。 [参考论文,](https://www.cs.ubc.ca/~hutter/papers/10-TR-SMAC.pdf) [Github 代码库](https://github.com/automl/SMAC3) |
| [**Batch Tuner(批处理 Tuner)**](#Batch) | Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。 当所有配置都执行完后,Experiment 即结束。 Batch Tuner 仅支持 choice 类型。 |
| [**Grid Search(遍历搜索)**](#GridSearch) | Grid Search 会穷举定义在搜索空间文件中的所有超参组合。 遍历搜索可以使用的类型有 choice, quniform, randint。 |
| [**Hyperband**](#Hyperband) | Hyperband 试图用有限的资源来探索尽可能多的组合,并发现最好的结果。 基本思想是生成许多配置,并通过少量的 Trial 来运行一部分。 一半性能不好的配置会被抛弃,剩下的部分与新选择出的配置会进行下一步的训练。 数量的多少对资源约束非常敏感(例如,分配的搜索时间)。 [参考论文](https://arxiv.org/pdf/1603.06560.pdf) |
| [**Network Morphism**](#NetworkMorphism) | 网络模态(Network Morphism)提供自动搜索深度学习体系结构的功能。 它会继承父网络的知识,来生成变形的子网络。 包括深度、宽度、跳连接等变化。 然后使用历史的架构和指标,来估计子网络的值。 然后会选择最有希望的模型进行训练。 [参考论文](https://arxiv.org/abs/1806.10282) |
| [**Metis Tuner**](#MetisTuner) | 大多数调参工具仅仅预测最优配置,而 Metis 的优势在于有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 Trial 的建议。 它不进行随机取样。 大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。 [参考论文](https://www.microsoft.com/en-us/research/publication/metis-robustly-tuning-tail-latencies-cloud-systems/) |
| [**BOHB**](#BOHB) | BOHB 是 Hyperband 算法的后续工作。 Hyperband 在生成新的配置时,没有利用已有的 Trial 结果,而本算法利用了 Trial 结果。 BOHB 中,HB 表示 Hyperband,BO 表示贝叶斯优化(Byesian Optimization)。 BOHB 会建立多个 TPE 模型,从而利用已完成的 Trial 生成新的配置。 [参考论文](https://arxiv.org/abs/1807.01774) |
| [**GP Tuner**](#GPTuner) | Gaussian Process(高斯过程) Tuner 是序列化的基于模型优化(SMBO)的方法,并使用了高斯过程来替代。 [参考论文](https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf)[Github 库](https://github.com/fmfn/BayesianOptimization) |
| [**PPO Tuner**](#PPOTuner) | PPO Tuner 是基于 PPO 算法的强化学习 Tuner。 [参考论文](https://arxiv.org/abs/1707.06347) |
| [**PBT Tuner**](#PBTTuner) | PBT Tuner 是一种简单的异步优化算法,在固定的计算资源下,它能有效的联合优化一组模型及其超参来最大化性能。 [参考论文](https://arxiv.org/abs/1711.09846v1) |
## 用法 使用 NNI 内置 Tuner 进行超参数调优
==============================================
要使用 NNI 内置的 Tuner,需要在 `config.yml` 文件中添加 **builtinTunerName****classArgs**。 本部分中,将介绍每个 Tuner 的用法和建议场景、参数要求,并提供配置示例。 为了让机器学习/深度学习模型适应不同的任务/问题,超参数总是需要调优。 自动化超参数调优的过程需要好的调优算法。 NNI 提供了先进的调优算法,使用上也很简单。 下面是内置 Tuner 的简单介绍:
注意:参考示例中的格式来创建新的 `config.yml` 文件。 一些内置的 Tuner 还需要通过 `nnictl package` 命令先安装,如 SMAC 注意:点击 ``Tuner 的名称`` 可看到 Tuner 的安装需求,建议的场景以及示例。 算法的详细说明在每个 Tuner 建议场景的最后。 `本文 <../CommunitySharings/HpoComparison.rst>`__ 对比了不同 Tuner 在几个问题下的不同效果
<a name="TPE"></a> 当前支持的算法:
### TPE .. list-table::
:header-rows: 1
:widths: auto
* - 概述
- 算法简介
* - `TPE <#TPE>`__
- Tree-structured Parzen Estimator (TPE) 是一种 sequential model-based optimization(SMBO,即基于序列模型优化)的方法。 SMBO 方法根据历史指标数据来按顺序构造模型,来估算超参的性能,随后基于此模型来选择新的超参。 `参考论文 <https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf>`__
* - `Random Search(随机搜索) <#Random>`__
- 在超参优化时,随机搜索算法展示了其惊人的简单和效果。 建议当不清楚超参的先验分布时,采用随机搜索作为基准。 `参考论文 <http://www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf>`__
* - `Anneal(退火) <#Anneal>`__
- 这种简单的退火算法从先前的采样开始,会越来越靠近发现的最佳点取样。 此算法是随机搜索的简单变体,利用了反应曲面的平滑性。 退火率不是自适应的。
* - `Naïve Evolution(朴素进化) <#Evolution>`__
- Naïve Evolution(朴素进化算法)来自于 Large-Scale Evolution of Image Classifiers。 它会基于搜索空间随机生成一个种群。 在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层)。 朴素进化算法需要很多次的 Trial 才能有效,但它也非常简单,也很容易扩展新功能。 `参考论文 <https://arxiv.org/pdf/1703.01041.pdf>`__
* - `SMAC <#SMAC>`__
- SMAC 基于 Sequential Model-Based Optimization (SMBO,即序列的基于模型优化方法)。 它会利用使用过的突出的模型(高斯随机过程模型),并将随机森林引入到SMBO中,来处理分类参数。 SMAC 算法包装了 Github 的 SMAC3。 注意:SMAC 需要通过 ``nnictl package`` 命令来安装。 `参考论文 <https://www.cs.ubc.ca/~hutter/papers/10-TR-SMAC.pdf>`__ `代码仓库 <https://github.com/automl/SMAC3>`__
* - `Batch tuner(批处理) <#Batch>`__
- Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。 当所有配置都完成后,Experiment 即结束。 Batch Tuner 仅支持 choice 类型。
* - `Grid Search(遍历) <#GridSearch>`__
- 网格搜索会穷举定义在搜索空间文件中的所有超参组合。 遍历搜索可以使用的类型有 choice, quniform, randint。
* - `Hyperband <#Hyperband>`__
- Hyperband 试图用有限的资源来探索尽可能多的组合,并发现最好的结果。 基本思想是生成许多配置,并通过少量的 Trial 来运行一部分。 一半性能不好的配置会被抛弃,剩下的部分与新选择出的配置会进行下一步的训练。 数量的多少对资源约束非常敏感(例如,分配的搜索时间)。 `参考论文 <https://arxiv.org/pdf/1603.06560.pdf>`__
* - `Network Morphism <#NetworkMorphism>`__
- 网络模态(Network Morphism)提供自动搜索深度学习体系结构的功能。 它会继承父网络的知识,来生成变形的子网络。 包括深度、宽度、跳连接等变化。 然后使用历史的架构和指标,来估计子网络的值。 然后会选择最有希望的模型进行训练。 `参考论文 <https://arxiv.org/abs/1806.10282>`__
* - `Metis Tuner <#MetisTuner>`__
- 大多数调参工具仅仅预测最优配置,而 Metis 的优势在于有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 Trial 的建议。 它不进行随机取样。 大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。 `参考论文 <https://www.microsoft.com/en-us/research/publication/metis-robustly-tuning-tail-latencies-cloud-systems/>`__
* - `BOHB <#BOHB>`__
- BOHB 是 Hyperband 算法的后续工作。 Hyperband 在生成新的配置时,没有利用已有的 Trial 结果,而本算法利用了 Trial 结果。 BOHB 中,HB 表示 Hyperband,BO 表示贝叶斯优化(Byesian Optimization)。 BOHB 会建立多个 TPE 模型,从而利用已完成的 Trial 生成新的配置。 `参考论文 <https://arxiv.org/abs/1807.01774>`__
* - `GP Tuner <#GPTuner>`__
- Gaussian Process(高斯过程) Tuner 是序列化的基于模型优化(SMBO)的方法,并使用了高斯过程来替代。 `参考论文 <https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf>`__\ , `Github 仓库 <https://github.com/fmfn/BayesianOptimization>`__
* - `PPO Tuner <#PPOTuner>`__
- PPO Tuner 是基于 PPO 算法的强化学习 Tuner。 `参考论文 <https://arxiv.org/abs/1707.06347>`__
* - `PBT Tuner <#PBTTuner>`__
- PBT Tuner 是一种简单的异步优化算法,在固定的计算资源下,它能有效的联合优化一组模型及其超参来最大化性能。 `参考论文 <https://arxiv.org/abs/1711.09846v1>`__
用法
------------------------
要使用 NNI 内置的 Assessor,需要在 ``config.yml`` 文件中添加 **builtinAssessorName** 和 **classArgs**。 本部分中,将介绍每个 Tuner 的用法和建议场景、参数要求,并提供配置示例。
注意:参考样例中的格式来创建新的 ``config.yml`` 文件。 一些内置的 Tuner 还需要通过 ``nnictl package`` 命令先安装,如 SMAC。
:raw-html:`<a name="TPE"></a>`
TPE
^^^
..
名称:**TPE**
> 名称:**TPE**
**建议场景** **建议场景**
TPE 是一种黑盒优化方法,可以使用在各种场景中,通常情况下都能得到较好的结果。 特别是在计算资源有限,只能运行少量 Trial 的情况。 大量的实验表明,TPE 的性能远远优于随机搜索。 [详细说明](./HyperoptTuner.md) TPE 是一种黑盒优化方法,可以使用在各种场景中,通常情况下都能得到较好的结果。 特别是在计算资源有限,只能运行少量 Trial 的情况。 大量的实验表明,TPE 的性能远远优于随机搜索。 `详细说明 <./HyperoptTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。 * **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
注意:为实现大规模并发 Trial,TPE 的并行性得到了优化。 有关优化原理或开启优化,参考 [TPE 文档](HyperoptTuner.md) 注意:为实现大规模并发 Trial,TPE 的并行性得到了优化。 有关优化原理或开启优化,参考 `TPE 文档 <./HyperoptTuner.rst>`__
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: TPE tuner:
classArgs: builtinTunerName: TPE
optimize_mode: maximize classArgs:
``` optimize_mode: maximize
<br /> :raw-html:`<br>`
<a name="Random"></a> :raw-html:`<a name="Random"></a>`
### Random Search(随机搜索) Random Search(随机搜索)
^^^^^^^^^^^^^^^^^^^^^^^^^^^
..
名称:**Random**
> 名称:**Random**
**建议场景** **建议场景**
随机搜索,可用于每个 Trial 运行时间不长(例如,能够非常快的完成,或者很快的被 Assessor 终止),并有充足计算资源的情况下。 如果要均衡的探索搜索空间,它也很有用。 随机搜索可作为搜索算法的基准线。 [详细说明](./HyperoptTuner.md) 随机搜索,可用于每个 Trial 运行时间不长(例如,能够非常快的完成,或者很快的被 Assessor 终止),并有充足计算资源的情况下。 如果要均衡的探索搜索空间,它也很有用。 随机搜索可作为搜索算法的基准线。 `详细说明 <./HyperoptTuner.rst>`__
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: Random tuner:
``` builtinTunerName: Random
:raw-html:`<br>`
<br /> :raw-html:`<a name="Anneal"></a>`
<a name="Anneal"></a> Anneal(退火算法)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
### Anneal(退火算法) ..
名称:**Anneal**
> 名称:**Anneal**
**建议场景** **建议场景**
退火算法,用于每个 Trial 的时间不长,并且有足够的计算资源(与随机搜索基本相同)。 当搜索空间中的变量可以从某些先前的分布中采样时,它也很有用。 [详细说明](./HyperoptTuner.md) 退火算法,用于每个 Trial 的时间不长,并且有足够的计算资源(与随机搜索基本相同)。 当搜索空间中的变量可以从某些先前的分布中采样时,它也很有用。 `详细说明 <./HyperoptTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。 * **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: Anneal tuner:
classArgs: builtinTunerName: Anneal
optimize_mode: maximize classArgs:
``` optimize_mode: maximize
:raw-html:`<br>`
<br /> :raw-html:`<a name="Evolution"></a>`
<a name="Evolution"></a> Naïve Evolution(进化算法)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
### Naïve Evolution(朴素进化) ..
名称:**Evolution**
> 名称:**Evolution**
**建议场景** **建议场景**
其计算资源要求相对较高。 特别是,它需要非常大的初始种群,以免落入局部最优中。 如果 Trial 时间很短,或使用了 Assessor,就非常合适。 如果 Trial 代码支持权重迁移,即每次 Trial 会从上一轮继承已经收敛的权重,建议使用此算法。 这会大大提高训练速度。 [详细说明](./EvolutionTuner.md) 其计算资源要求相对较高。 特别是,它需要非常大的初始种群,以免落入局部最优中。 如果 Trial 时间很短,或者利用了 Assessor,这个 Tuner 就非常合适。 如果 Trial 代码支持权重迁移,即每次 Trial 会从上一轮继承已经收敛的权重,建议使用此算法。 这会大大提高训练速度。 `详细说明 <./EvolutionTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **population_size** (*int 类型 (需要大于 0), 可选项, 默认值为 20*) - 表示遗传 Tuner 中的初始种群(Trial 数量)。 建议 `population_size``concurrency` 取值更大,这样能充分利用算法(至少要等于 `concurrency`,否则 Tuner 在生成第一代参数的时候就会失败)。 *
**optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
*
**population_size** (*int 类型 (需要大于 0), 可选项, 默认值为 20*) - 表示遗传 Tuner 中的初始种群(Trial 数量)。 建议 ``population_size`` 比 ``concurrency`` 取值更大,这样能充分利用算法(至少要等于 ``concurrency``,否则 Tuner 在生成第一代参数的时候就会失败)。
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: Evolution tuner:
classArgs: builtinTunerName: Evolution
optimize_mode: maximize classArgs:
population_size: 100 optimize_mode: maximize
``` population_size: 100
<br /> :raw-html:`<br>`
<a name="SMAC"></a> :raw-html:`<a name="SMAC"></a>`
### SMAC SMAC
^^^^
> 名称:**SMAC** ..
**当前 SMAC 不支持在 WIndows 下运行。 原因参考:[GitHub issue](https://github.com/automl/SMAC3/issues/483)。** 名称:**SMAC**
当前 SMAC 不支持在 WIndows 下运行。 原因参考:`GitHub issue <https://github.com/automl/SMAC3/issues/483>`__
**安装** **安装**
SMAC 在第一次使用前,必须用下面的命令先安装。 注意:SMAC 依赖于 `swig`,Ubuntu 下可通过 `apt` 命令来安装 `swig` SMAC 在第一次使用前,必须用下面的命令先安装。 注意:SMAC 依赖于 ``swig``,Ubuntu 下可通过 apt 命令来安装 ``swig``
```bash .. code-block:: bash
nnictl package install --name=SMAC
``` nnictl package install --name=SMAC
**建议场景** **建议场景**
与 TPE 类似,SMAC 也是一个可以被用在各种场景中的黑盒 Tuner。在计算资源有限时,也可以使用。 此算法为离散超参而优化,因此,如果大部分超参是离散值时,建议使用此算法。 [详细说明](./SmacTuner.md) 与 TPE 类似,SMAC 也是一个可以被用在各种场景中的黑盒 Tuner。在计算资源有限时,也可以使用。 此算法为离散超参而优化,因此,如果大部分超参是离散值时,建议使用此算法。 `详细说明 <./SmacTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。 * **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **config_dedup** (*True 或 False, 可选, 默认为 False*) - 如果为 True,则 Tuner 不会生成重复的配置。 如果为 False,则配置可能会重复生成,但对于相对较大的搜索空间,此概率较小。 * **config_dedup** ( *True 或 False, 可选, 默认为 False* ) - 如果为 True,则 Tuner 不会生成重复的配置。 如果为 False,则配置可能会重复生成,但对于相对较大的搜索空间,此概率较小。
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner:
builtinTunerName: SMAC
classArgs:
optimize_mode: maximize
```
<br /> # config.yml
tuner:
builtinTunerName: SMAC
classArgs:
optimize_mode: maximize
<a name="Batch"></a> :raw-html:`<br>`
### Batch Tuner(批处理 Tuner) :raw-html:`<a name="Batch"></a>`
Batch Tuner(批量调参器)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
..
名称:BatchTuner
> 名称:BatchTuner
**建议场景** **建议场景**
如果 Experiment 配置已确定,可通过 `choice` 将它们罗列到搜索空间文件中运行即可。 [详细说明](./BatchTuner.md) 如果 Experiment 配置已确定,可通过 ``choice`` 将它们罗列到搜索空间文件中运行即可。 `详细说明 <./BatchTuner.rst>`__
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: BatchTuner tuner:
``` builtinTunerName: BatchTuner
<br /> :raw-html:`<br>`
注意,BatchTuner 的搜索空间如下所示: 注意,BatchTuner 的搜索空间如下所示:
```json .. code-block:: json
{
"combine_params":
{
"_type" : "choice",
"_value" : [{"optimizer": "Adam", "learning_rate": 0.00001},
{"optimizer": "Adam", "learning_rate": 0.0001},
{"optimizer": "Adam", "learning_rate": 0.001},
{"optimizer": "SGD", "learning_rate": 0.01},
{"optimizer": "SGD", "learning_rate": 0.005},
{"optimizer": "SGD", "learning_rate": 0.0002}]
}
}
```
搜索空间文件使用了高层的键 `combine_params`。 参数类型必须是 `choice` ,并且 `values` 要包含所有需要的参数组合。 {
"combine_params":
{
"_type" : "choice",
"_value" : [{"optimizer": "Adam", "learning_rate": 0.00001},
{"optimizer": "Adam", "learning_rate": 0.0001},
{"optimizer": "Adam", "learning_rate": 0.001},
{"optimizer": "SGD", "learning_rate": 0.01},
{"optimizer": "SGD", "learning_rate": 0.005},
{"optimizer": "SGD", "learning_rate": 0.0002}]
}
}
<a name="GridSearch"></a> 搜索空间文件使用了高层的键 ``combine_params``。 参数类型必须是 ``choice`` ,并且 ``values`` 要包含所有需要的参数组合。
### Grid Search(遍历搜索) :raw-html:`<a name="GridSearch"></a>`
Grid Search(网格搜索)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
..
名称:**Grid Search**
> 名称:**Grid Search**
**建议场景** **建议场景**
注意,搜索空间仅支持 `choice`, `quniform`, `randint` 遍历搜索可以使用的类型有 ``choice, quniform, randint``
当搜索空间较小时,建议这样做。 建议使用在可以穷尽整个搜索空间的情况下。 [详细说明](./GridsearchTuner.md) 当搜索空间较小时,建议这样做。 建议使用在可以穷尽整个搜索空间的情况下。 `详细说明 <./GridsearchTuner.rst>`__
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: GridSearch tuner:
``` builtinTunerName: GridSearch
<br /> :raw-html:`<br>`
<a name="Hyperband"></a> :raw-html:`<a name="Hyperband"></a>`
### Hyperband Hyperband
^^^^^^^^^
..
名称:**Hyperband**
> 名称:**Hyperband**
**建议场景** **建议场景**
当搜索空间很大,但计算资源有限时建议使用。 中间结果能够很好的反映最终结果的情况下,此算法会非常有效。 例如,当训练初期更准确的模型在以后也更准确的情况下。 [详细说明](./HyperbandAdvisor.md) 当搜索空间很大,但计算资源有限时建议使用。 中间结果能够很好的反映最终结果的情况下,此算法会非常有效。 例如,当训练初期更准确的模型在以后也更准确的情况下。 `详细说明 <./HyperbandAdvisor.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。 * **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **R** (*int, 可选, 默认为 60*) - 分配给 Trial 的最大资源(可以是 mini-batches 或 epochs 的数值)。 每个 Trial 都需要用 TRIAL_BUDGET 来控制运行的步数。 * **R** (*int, 可选, 默认为 60*),分配给 Trial 的最大资源(可以是 mini-batches 或 epochs 的数值)。 每个 Trial 都需要用 TRIAL_BUDGET 来控制运行的步数。
* **eta** (*int, 可选, 默认为 3*) - `(eta-1)/eta` 是丢弃 Trial 的比例。 * **eta** (*int,可选,默认为 3*),``(eta-1)/eta`` 是丢弃 Trial 的比例。
* **exec_mode** (*串行或并行,可选默认值是并行*\ ),如果是“并行”, Tuner 会尝试使用可用资源立即启动新的分组。 如果是“串行”, Tuner 只会在当前分组完成后启动新的分组。
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
advisor: # config.yml
builtinAdvisorName: Hyperband advisor:
classArgs: builtinAdvisorName: Hyperband
optimize_mode: maximize classArgs:
R: 60 optimize_mode: maximize
eta: 3 R: 60
``` eta: 3
<br /> :raw-html:`<br>`
<a name="NetworkMorphism"></a> :raw-html:`<a name="NetworkMorphism"></a>`
### Network Morphism Network Morphism
^^^^^^^^^^^^^^^^
..
名称:**NetworkMorphism**
> 名称:**NetworkMorphism**
**安装** **安装**
NetworkMorphism 需要先安装 [PyTorch](https://pytorch.org/get-started/locally)[Keras](https://keras.io/#installation) 才能使用。 对应的 requirements 文件在[这里](https://github.com/microsoft/nni/blob/master/examples/trials/network_morphism/requirements.txt) NetworkMorphism 需要先安装 :githublink:`PyTorch <examples/trials/network_morphism/requirements.txt>` 才能使用
**建议场景** **建议场景**
需要将深度学习方法应用到自己的任务上,但不清楚该如何选择或设计网络。 可修改[示例](https://github.com/Microsoft/nni/tree/master/examples/trials/network_morphism/cifar10/cifar10_keras.py)来适配自己的数据集和数据增强方法。 也可以修改批处理大小,学习率或优化器。 当前,此 Tuner 仅支持视觉领域。 [详细说明](./NetworkmorphismTuner.md) 需要将深度学习方法应用到自己的任务上,但不清楚该如何选择或设计网络。 可修改 :githublink:`示例 <examples/trials/network_morphism/cifar10/cifar10_keras.py>` 来适配自己的数据集和数据增强方法。 也可以修改批处理大小,学习率或优化器。 当前,此 Tuner 仅支持视觉领域。 `详细说明 <./NetworkmorphismTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。 * **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **task** (*('cv'), 可选, 默认为 'cv'*) - 实验的领域。 当前,此 Tuner 仅支持计算机视觉(cv)领域。 * **task** (*('cv'), 可选, 默认为 'cv'*)实验的领域。 当前,此 Tuner 仅支持计算机视觉(cv)领域。
* **input_width** (*int, 可选, 默认为 = 32*) - 输入图像的宽度 * **input_width** (*int, 可选, 默认为 = 32*) 输入图像的宽度
* **input_channel** (*int, 可选, 默认为 3*) - 输入图像的通道数 * **input_channel** (*int, 可选, 默认为 = 3*) 输入图像的通道数
* **n_output_node** (*int, 可选, 默认为 10*) - 输出分类的数量 * **n_output_node** (*int, 可选, 默认为 10*)输出分类的数量
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: NetworkMorphism tuner:
classArgs: builtinTunerName: NetworkMorphism
optimize_mode: maximize classArgs:
task: cv optimize_mode: maximize
input_width: 32 task: cv
input_channel: 3 input_width: 32
n_output_node: 10 input_channel: 3
``` n_output_node: 10
<br /> :raw-html:`<br>`
<a name="MetisTuner"></a> :raw-html:`<a name="MetisTuner"></a>`
### Metis Tuner Metis Tuner
^^^^^^^^^^^
> 名称:**MetisTuner** ..
此 Tuner 搜索空间仅接受 `quniform``uniform``randint` 和数值的 `choice` 类型。 因为数值会被用来评估点之间的距离,所以只支持数值。 名称:**MetisTuner**
此 Tuner 搜索空间仅接受 ``quniform,uniform,randint`` 和数值的 ``choice`` 类型。 因为数值会被用来评估点之间的距离,所以只支持数值。
**建议场景** **建议场景**
与 TPE 和 SMAC 类似,Metis 是黑盒 Tuner。 如果系统需要很长时间才能完成一次 Trial,Metis 就比随机搜索等其它方法要更合适。 此外,Metis 还为接下来的 Trial 提供了候选。 如何使用 Metis 的[样例](https://github.com/Microsoft/nni/tree/master/examples/trials/auto-gbdt/search_space_metis.json)。 通过调用 NNI 的 SDK,用户只需要发送 `精度` 这样的最终结果给 Tuner。 [详细说明](./MetisTuner.md) 与 TPE 和 SMAC 类似,Metis 是黑盒 Tuner。 如果系统需要很长时间才能完成一次 Trial,Metis 就比随机搜索等其它方法要更合适。 此外,Metis 还为接下来的 Trial 提供了候选。 :githublink:`示例 <examples/trials/auto-gbdt/search_space_metis.json>` 。 通过调用 NNI 的 SDK,用户只需要发送 ``精度`` 这样的最终结果给 Tuner。 `详细说明 <./MetisTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*'maximize' 或 'minimize', 可选项, 默认值为 'maximize'*) - 如果为 'maximize',表示 Tuner 的目标是将指标最大化。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner:
builtinTunerName: MetisTuner
classArgs:
optimize_mode: maximize
```
<br /> # config.yml
tuner:
builtinTunerName: MetisTuner
classArgs:
optimize_mode: maximize
<a name="BOHB"></a> :raw-html:`<br>`
### BOHB Advisor :raw-html:`<a name="BOHB"></a>`
BOHB Advisor
^^^^^^^^^^^^
..
名称: **BOHB**
> 名称:**BOHB**
**安装** **安装**
BOHB Advisor 需要 [ConfigSpace](https://github.com/automl/ConfigSpace) 包。 可以使用以下命令安装 ConfigSpace。 BOHB advisor 需要安装 `ConfigSpace <https://github.com/automl/ConfigSpace>`__ 包。 可以使用以下命令安装 ConfigSpace。
.. code-block:: bash
```bash nnictl package install --name=BOHB
nnictl package install --name=BOHB
```
**建议场景** **建议场景**
与 Hyperband 类似,当计算资源有限但搜索空间相对较大时,建议使用 BOHB。 中间结果能够很好的反映最终结果的情况下,此算法会非常有效。 在这种情况下,由于使用贝叶斯优化,它可能会收敛到比 Hyperband 更好的配置。 [详细说明](./BohbAdvisor.md) 与 Hyperband 类似,当计算资源有限但搜索空间相对较大时,建议使用 BOHB。 中间结果能够很好的反映最终结果的情况下,此算法会非常有效。 在这种情况下,由于使用贝叶斯优化,它可能会收敛到比 Hyperband 更好的配置。 `详细说明 <./BohbAdvisor.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。 * **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **min_budget** (*整数, 可选项, 默认值为 1*) - 运行一个试验给予的最低计算资源(budget),这里的计算资源通常使用mini-batches 或者 epochs。 该参数必须为正数。 * **min_budget** (*int, 可选项, 默认值为 1*) - 运行一个试验给予的最低计算资源(budget),这里的计算资源通常使用 mini-batches 或者 epochs。 该参数必须为正数。
* **max_budget** (*整数, 可选项, 默认值为 3*) - 运行一个试验给予的最计算资源(budget),这里的计算资源通常使用 mini-batches 或者 epochs。 该参数必须大于“min_budget”。 * **max_budget** (*int, 可选项, 默认值为 3*) - 运行一个试验给予的最计算资源(budget),这里的计算资源通常使用 mini-batches 或者 epochs。 该参数必须大于“min_budget”。
* **eta** (*整数, 可选项, 默认值为3*) - 在每次迭代中,执行完整的“连续减半”算法。 在这里,当一个使用相同计算资源的子集结束后,选择表现前 1/eta 好的参数,给予更高的优先级,进入下一轮比较(会获得更多计算资源)。 该参数必须大于等于 2。 * **eta** ( *int, 可选项, 默认值为3* ) - 在每次迭代中,执行完整的“连续减半”算法。 在这里,当一个使用相同计算资源的子集结束后,选择表现前 1/eta 好的参数,给予更高的优先级,进入下一轮比较(会获得更多计算资源)。 该参数必须大于等于 2。
* **min_points_in_model**(*整数, 可选项, 默认值为None*): 建立核密度估计(KDE)要求的最小观察到的点。 默认值 None 表示 dim+1,当在该计算资源(budget)下试验过的参数已经大于等于`max{dim+1, min_points_in_model}` 时,BOHB 将会开始建立这个计算资源(budget)下对应的核密度估计(KDE)模型,然后用这个模型来指导参数的选取。 该参数必须为正数。 (dim 表示搜索空间中超参的数量) * **min_points_in_model**\ (*int, 可选项, 默认值为None* ): 建立核密度估计(KDE)要求的最小观察到的点。 默认值 None 表示 dim+1,当在该计算资源(budget)下试验过的参数已经大于等于 ``max{dim+1, min_points_in_model}`` 时,BOHB 将会开始建立这个计算资源(budget)下对应的核密度估计(KDE)模型,然后用这个模型来指导参数的选取。 该参数必须为正数。 (dim 表示搜索空间中超参的数量)
* **top_n_percent**(*整数, 可选, 默认值为 15*): 认为观察点为好点的百分数 (在 1 到 99 之间)。 区分表现好的点与坏的点是为了建立树形核密度估计模型。 例如,如果有 100 个观察到的 Trial,top_n_percent 为 15,则前 15% 的点将用于构建好点模型 "l(x)"。 其余 85% 的点将用于构建坏点模型 "g(x)"。 * **top_n_percent**\ (*int, 可选, 默认值为 15* ): 认为观察点为好点的百分数 (在 1 到 99 之间)。 区分表现好的点与坏的点是为了建立树形核密度估计模型。 例如,如果有 100 个观察到的 Trial,top_n_percent 为 15,则前 15% 的点将用于构建好点模型 "l(x)"。 其余 85% 的点将用于构建坏点模型 "g(x)"。
* **num_samples** (*整数, 可选项, 默认值为64*): 用于优化 EI 值的采样个数(默认值为64)。 在这种情况下,将对 "num_samples" 点进行采样,并比较 l(x)/g(x) 的结果。 然后,如果 optimize_mode 是 `maximize`,就会返回其中 l(x)/g(x) 值最大的点作为下一个配置参数。 否则,使用值最小的点。 * **num_samples**\ (*int, 可选项, 默认值为64*): 用于优化 EI 值的采样个数(默认值为64)。 在这种情况下,将对 "num_samples" 点进行采样,并比较 l(x)/g(x) 的结果。 然后,如果 optimize_mode 是 ``maximize``,就会返回其中 l(x)/g(x) 值最大的点作为下一个配置参数。 否则,使用值最小的点。
* **random_fraction**(*浮点数, 可选项, 默认值为0.33*): 使用模型的先验(通常是均匀)来随机采样的比例。 * **random_fraction**\ (*float, 可选项, 默认值为0.33*): 使用模型的先验(通常是均匀)来随机采样的比例。
* **bandwidth_factor**(*浮点数, 可选, 默认值为 3.0 *): 为了鼓励多样性,把优化 EI 的点加宽,即把 KDE 中采样的点乘以这个因子,从而增加 KDE 中的带宽。 如果不熟悉 KDE,建议使用默认值。 * **bandwidth_factor**\ (*float, 可选, 默认值为 3.0* ): 为了鼓励多样性,把优化 EI 的点加宽,即把 KDE 中采样的点乘以这个因子,从而增加 KDE 中的带宽。 如果不熟悉 KDE,建议使用默认值。
* **min_bandwidth**(< 1>float, 可选, 默认值 = 0.001 </em>): 为了保持多样性, 即使所有好的样本对其中一个参数具有相同的值,使用最小带宽 (默认值: 1e-3) 而不是零。 如果不熟悉 KDE,建议使用默认值。 * **min_bandwidth**\ (*float, 可选, 默认值 = 0.001* ): 为了保持多样性, 即使所有好的样本对其中一个参数具有相同的值,使用最小带宽 (默认值: 1e-3) 而不是零。 如果不熟悉 KDE,建议使用默认值。
*请注意,浮点类型当前仅支持十进制表示。 必须使用 0.333 而不是 1/3 ,0.001 而不是 1e-3。* * 请注意,浮点类型当前仅支持十进制表示。 必须使用 0.333 而不是 1/3 ,0.001 而不是 1e-3。*
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
advisor:
builtinAdvisorName: BOHB advisor:
classArgs: builtinAdvisorName: BOHB
optimize_mode: maximize classArgs:
min_budget: 1 optimize_mode: maximize
max_budget: 27 min_budget: 1
eta: 3 max_budget: 27
``` eta: 3
:raw-html:`<a name="GPTuner"></a>`
GP Tuner
^^^^^^^^
<a name="GPTuner"></a> ..
### GP Tuner 名称: **GPTuner**
> 名称:**GPTuner**
注意,搜索空间接受的类型包括 `randint`, `uniform`, `quniform`, `loguniform`, `qloguniform`,以及数值的 `choice`。 因为数值会被用来评估点之间的距离,所以只支持数值。 注意,搜索空间接受的类型包括 ``randint``\ , ``uniform``\ , ``quniform``\ , ``loguniform``\ , ``qloguniform``\ ,以及数值的 ``choice``。 因为数值会被用来评估点之间的距离,所以只支持数值。
**建议场景** **建议场景**
作为序列的基于模型的全局优化(SMBO)算法,GP Tuner 使用了代理优化问题(找到采集函数的最大值)。虽然这仍然是个难题,但成本更低(从计算的角度来看),并且有通用的工具。 因此,GP Tuner 适合于函数的优化成本非常高时来使用。 GP 也可在计算资源非常有限时使用。 然后,由于需要反转 Gram 矩阵,GP Tuner 的计算复杂度以 *O(N^3)* 的速度增长,因此不适合于需要大量 Trial 的情形。 [详细说明](./GPTuner.md) 作为序列的基于模型的全局优化(SMBO)算法,GP Tuner 使用了代理优化问题(找到采集函数的最大值)。虽然这仍然是个难题,但成本更低(从计算的角度来看),并且有通用的工具。 因此,GP Tuner 适合于函数的优化成本非常高时来使用。 GP 也可在计算资源非常有限时使用。 然后,由于需要反转 Gram 矩阵,GP Tuner 的计算复杂度以 *O(N^3)* 的速度增长,因此不适合于需要大量 Trial 的情形。 `详细说明 <./GPTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*'maximize' 或 'minimize', 可选项, 默认值为 'maximize'*) - 如果为 'maximize',表示 Tuner 的目标是将指标最大化。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **optimize_mode** (*maximize 或 minimize, 可选项, 默认值为 maximize*) - 如果为 'maximize',表示 Tuner 会试着最大化指标。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **utility** (*'ei', 'ucb' 或 'poi', 可选, 默认值为 'ei'*) - 工具函数的类型(采集函数)。 'ei', 'ucb' 和 'poi' 分别对应 '期望的改进(Expected Improvement)', '上限置信度边界(Upper Confidence Bound)' 和 '改进概率(Probability of Improvement)'。 * **utility** (*'ei', 'ucb' 或 'poi', 可选, 默认值为 'ei'*) - 工具函数的类型(采集函数)。 'ei', 'ucb' 和 'poi' 分别对应 '期望的改进(Expected Improvement)', '上限置信度边界(Upper Confidence Bound)' 和 '改进概率(Probability of Improvement)'。
* **kappa** (*float, 可选, 默认值为 5*) - 用于 'ucb' 函数。 `kappa` 越大, Tuner 的探索性越强。 * **kappa** (*float, 可选, 默认值为 5*) - 用于 'ucb' 函数。 ``kappa`` 越大, Tuner 的探索性越强。
* **xi** (*float, 可选, 默认为 0*) - 用于 'ei' 和 'poi' 工具函数。 `xi` 越大, Tuner 的探索性越强。 * **xi** (*float, 可选, 默认为 0*) - 用于 'ei' 和 'poi' 工具函数。 ``xi`` 越大, Tuner 的探索性越强。
* **nu** (*float, 可选, 默认为 2.5*) - 用于指定 Matern 核。 nu 越小,近似函数的平滑度越低。 * **nu** (*float, 可选, 默认为 2.5*) - 用于指定 Matern 核。 nu 越小,近似函数的平滑度越低。
* **alpha** (*float, 可选, 默认值为 1e-6*) - 用于高斯过程回归器。 值越大,表示观察中的噪声水平越高。 * **alpha** (*float, 可选, 默认值为 1e-6*) - 用于高斯过程回归器。 值越大,表示观察中的噪声水平越高。
* **cold_start_num** (*int, 可选, 默认值为 10*) - 在高斯过程前执行随机探索的数量。 随机探索可帮助提高探索空间的广泛性。 * **cold_start_num** (*int, 可选, 默认值为 10*) - 在高斯过程前执行随机探索的数量。 随机探索可帮助提高探索空间的广泛性。
* **selection_num_warm_up** (*int, 可选, 默认为 1e5*) - 用于获得最大采集函数而评估的随机点数量。 * **selection_num_warm_up** (*int, 可选, 默认为 1e5* ) - 用于获得最大采集函数而评估的随机点数量。
* **selection_num_starting_points** (*int, 可选, 默认为 250*) - 预热后,从随机七十点运行 L-BFGS-B 的次数。 * **selection_num_starting_points** (*int, 可选, 默认为 250*) - 预热后,从随机七十点运行 L-BFGS-B 的次数。
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: GPTuner tuner:
classArgs: builtinTunerName: GPTuner
optimize_mode: maximize classArgs:
utility: 'ei' optimize_mode: maximize
kappa: 5.0 utility: 'ei'
xi: 0.0 kappa: 5.0
nu: 2.5 xi: 0.0
alpha: 1e-6 nu: 2.5
cold_start_num: 10 alpha: 1e-6
selection_num_warm_up: 100000 cold_start_num: 10
selection_num_starting_points: 250 selection_num_warm_up: 100000
``` selection_num_starting_points: 250
:raw-html:`<a name="PPOTuner"></a>`
<a name="PPOTuner"></a> PPO Tuner
^^^^^^^^^
### PPO Tuner ..
> 内置 Tuner 名称**PPOTuner** 名称: **PPOTuner**
注意,搜索空间仅接受 `layer_choice``input_choice` 类型。 `input_choice`, `n_chosen` 只能是 0, 1, 或 [0, 1]。 注意,NAS 的搜索空间文件通常通过 [`nnictl ss_gen`](../Tutorial/Nnictl.md) 命令自动生成。
注意,搜索空间仅接受 ``layer_choice`` 和 ``input_choice`` 类型。 ``input_choice``\ , ``n_chosen`` 只能是 0, 1,或者 [0, 1]. 注意,NAS 的搜索空间文件通常通过 `nnictl ss_gen <../Tutorial/Nnictl.rst>`__ 命令自动生成。
**建议场景** **建议场景**
PPO Tuner 是基于 PPO 算法的强化学习 Tuner。 PPOTuner 可用于使用 NNI NAS 接口进行的神经网络结构搜索。 一般来说,尽管 PPO 算法比其它强化学习算法效率更高,但强化学习算法需要更多的计算资源。 当有大量可用的计算资源时,才建议使用此 Tuner。 以在简单的任务上尝试,如 [mnist-nas](https://github.com/microsoft/nni/tree/master/examples/trials/mnist-nas) 示例。 [查看详细信息](./PPOTuner.md) PPO Tuner 是基于 PPO 算法的强化学习 Tuner。 PPOTuner 可用于使用 NNI NAS 接口进行的神经网络结构搜索。 一般来说,尽管 PPO 算法比其它强化学习算法效率更高,但强化学习算法需要更多的计算资源。 当有大量可用的计算资源时,才建议使用此 Tuner。 以在简单的任务上尝试,如 :githublink:`mnist-nas <examples/trials/mnist-nas>` 示例。 `查看详细信息 <./PPOTuner.rst>`__。
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*'maximize' 或 'minimize'*) - 如果为 'maximize',表示 Tuner 的目标是将指标最大化。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **trials_per_update** (*int, 可选, 默认为 20*) - 每次更新的 Trial 数量。 此数字必须可被 minibatch_size 整除。 推荐将 `trials_per_update` 设为 `trialConcurrency` 的倍数,以提高 Trial 的并发效率。 * **optimize_mode** (*‘maximize' 或 'minimize'*) - 如果为 'maximize',表示 Tuner 的目标是将指标最大化。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **trials_per_update** (*int, 可选, 默认为 20*) - 每次更新的 Trial 数量。 此数字必须可被 minibatch_size 整除。 推荐将 ``trials_per_update`` 设为 ``trialConcurrency`` 的倍数,以提高 Trial 的并发效率。
* **epochs_per_update** (*int, 可选, 默认为 4*) - 每次更新的 Epoch 数量。 * **epochs_per_update** (*int, 可选, 默认为 4*) - 每次更新的 Epoch 数量。
* **minibatch_size** (*int, 可选, 默认为 4*) - mini-batch 大小 (即每个 mini-batch 的 Trial 数量)。 注意,trials_per_update 必须可被 minibatch_size 整除。 * **minibatch_size** (*int, 可选, 默认为 4*) - mini-batch 大小 (即每个 mini-batch 的 Trial 数量)。 注意,trials_per_update 必须可被 minibatch_size 整除。
* **ent_coef** (*float, 可选, 默认为 0.0*) - 优化目标中的 Policy entropy coefficient。 * **ent_coef** (*float, 可选, 默认为 0.0*) - 优化目标中的 Policy entropy coefficient。
* **lr** (*float, 可选, 默认为 3e-4*) - 模型的学习率(LSTM 网络),为常数。 * **lr** (*float, 可选, 默认为 3e-4*) - 模型的学习率(LSTM 网络),为常数。
* **vf_coef** (*float, 可选, 默认为 0.5*) - Value function loss coefficient in the optimization objective. * **vf_coef** (*float, 可选, 默认为 0.5*) - 优化目标中的价值函数损失系数
* **max_grad_norm** (*float, 可选, 默认为 0.5*) - Gradient norm clipping coefficient. * **max_grad_norm** (*float,可选,默认值是0.5*\ ) - 梯度正则裁剪系数
* **gamma** (*float, 可选, 默认为 0.99*) - Discounting factor. * **gamma** (*float, 可选,默认值是 0.99*\ ) - 损失因子
* **lam** (*float, 可选, 默认为 0.95*) - Advantage estimation discounting factor (论文中的 lambda). * **lam** (*float, 可选,默认值是 0.95*\ ) - 优势估计损失因子 (论文中的lambda)
* **cliprange** (*float, 可选, 默认为 0.2*) - PPO 算法的 cliprange, 为常数。 * **cliprange** (*float, 可选, 默认为 0.2*) - PPO 算法的 cliprange, 为常数。
**配置示例:** **配置示例:**
```yaml .. code-block:: yaml
# config.yml
tuner: # config.yml
builtinTunerName: PPOTuner tuner:
classArgs: builtinTunerName: PPOTuner
optimize_mode: maximize classArgs:
``` optimize_mode: maximize
:raw-html:`<a name="PBTTuner"></a>`
<a name="PBTTuner"></a> PBT Tuner
^^^^^^^^^
### PBT Tuner ..
名称: **PBTTuner**
> 内置 Tuner 名称:**PBTTuner**
**建议场景** **建议场景**
Population Based Training (PBT,基于种群的训练),将并扩展并行搜索方法和顺序优化方法连接在了一起。 它通过周期性的从较好的模型中继承权重来继续探索,这样所需的计算资源相对较少。 使用 PBTTuner,用户最终可以得到训练好的模型,而不是需要从头训练的配置。 这是因为模型权重会在搜索过程中周期性的继承。 PBT 也可作为训练的方法。 如果不需要配置,只需要好的模型,PBTTuner 是不错的选择。 [查看详](./PBTTuner.md) Population Based Training (PBT,基于种群的训练),将并扩展并行搜索方法和顺序优化方法连接在了一起。 它通过周期性的从较好的模型中继承权重来继续探索,这样所需的计算资源相对较少。 使用 PBTTuner,用户最终可以得到训练好的模型,而不是需要从头训练的配置。 这是因为模型权重会在搜索过程中周期性的继承。 PBT 也可作为训练的方法。 如果不需要配置,只需要好的模型,PBTTuner 是不错的选择。 `查看详细信息 <./PBTTuner.rst>`__
**classArgs 要求:** **classArgs 要求:**
* **optimize_mode** (*'maximize' 或 'minimize'*) - 如果为 'maximize',表示 Tuner 的目标是将指标最大化。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **all_checkpoint_dir** (*str, 可选, 默认为 None*) - Trial 保存读取检查点的目录,如果不指定,其为 "~/nni/checkpoint/<exp-id>". 注意,如果 Experiment 不是本机模式,用户需要提供能被所有 Trial 所访问的共享存储。 * **optimize_mode** (*‘maximize' 或 'minimize'*) - 如果为 'maximize',表示 Tuner 的目标是将指标最大化。 如果为 'minimize',表示 Tuner 的目标是将指标最小化。
* **all_checkpoint_dir** (*str,可选, 默认为 None* ) - Trial 保存读取检查点的目录,如果不指定,其为 "~/nni/checkpoint/\ :raw-html:`<exp-id>`\ "。 注意,如果 Experiment 不是本机模式,用户需要提供能被所有 Trial 所访问的共享存储。
* **population_size** (*int, 可选, 默认为 10*) - 种群的 Trial 数量。 每个步骤有此数量的 Trial。 在 NNI 的实现中,一步表示每个 Trial 运行一定次数 Epoch,此 Epoch 的数量由用户来指定。 * **population_size** (*int, 可选, 默认为 10*) - 种群的 Trial 数量。 每个步骤有此数量的 Trial。 在 NNI 的实现中,一步表示每个 Trial 运行一定次数 Epoch,此 Epoch 的数量由用户来指定。
* **factors** (*tuple, 可选, 默认为 (1.2, 0.8)*) - 超参变动量的因子。 * **factors** (*tuple, 可选, 默认为 (1.2, 0.8)*) - 超参变动量的因子。
* **fraction** (*float, 可选, 默认为 0.2*) - 选择的最低和最高 Trial 的比例。 * **fraction** (*float, 可选, 默认为 0.2*) - 选择的最低和最高 Trial 的比例。
**示例** **使用示例:**
.. code-block:: yaml
# config.yml
tuner:
builtinTunerName: PBTTuner
classArgs:
optimize_mode: maximize
```yaml 注意,要使用此 Tuner,Trial 代码也需要相应的修改,参考 `PBTTuner 文档 <./PBTTuner.rst>`__ 了解详情。
# config.yml
tuner:
builtinTunerName: PBTTuner
classArgs:
optimize_mode: maximize
```
注意,要使用此 Tuner,Trial 代码也需要相应的修改,参考 [PBTTuner 文档](./PBTTuner.md)了解详情。 **参考和反馈**
------------------------------
## **参考和反馈**
* 在 GitHub 中[提交此功能的 Bug](https://github.com/microsoft/nni/issues/new?template=bug-report.md) * 在Github 中 `提交此功能的 Bug <https://github.com/microsoft/nni/issues/new?template=bug-report.rst>`__
* 在 GitHub 中[提交新功能或改进请求](https://github.com/microsoft/nni/issues/new?template=enhancement.md) * 在Github 中 `提交新功能或请求改进 <https://github.com/microsoft/nni/issues/new?template=enhancement.rst>`__
* 了解 NNI 中[特征工程的更多信息](https://github.com/microsoft/nni/blob/master/docs/zh_CN/FeatureEngineering/Overview.md) * 了解 NNI 中 `特征工程的更多信息 <../FeatureEngineering/Overview.rst>`__
* 了解 NNI 中[ NAS 的更多信息](https://github.com/microsoft/nni/blob/master/docs/zh_CN/NAS/Overview.md) * 了解 NNI 中 `NAS 的更多信息 <../NAS/Overview.rst>`__
* 了解 NNI 中[模型自动压缩的更多信息](https://github.com/microsoft/nni/blob/master/docs/zh_CN/Compressor/Overview.md) * 了解 NNI 中 `模型压缩的更多信息 <../Compression/Overview.rst>`__
\ No newline at end of file
# **指南** - 自定义 Advisor **指南** - 自定义 Advisor
===========================================
*警告:API 可能会在将来的版本中更改。* *警告:API 可能会在将来的版本中更改。*
...@@ -8,33 +9,34 @@ Advisor 用于同时需要 Tuner 和 Assessor 方法的自动机器学习算法 ...@@ -8,33 +9,34 @@ Advisor 用于同时需要 Tuner 和 Assessor 方法的自动机器学习算法
**1. 定义从 MsgDispatcherBase 类继承的 Advisor。** 如: **1. 定义从 MsgDispatcherBase 类继承的 Advisor。** 如:
```python .. code-block:: python
from nni.msg_dispatcher_base import MsgDispatcherBase
class CustomizedAdvisor(MsgDispatcherBase): from nni.runtime.msg_dispatcher_base import MsgDispatcherBase
def __init__(self, ...):
...
```
**2. 实现所有除了 `handle_request` 外的,以 `handle_` 前缀开始的方法**[此文档](https://nni.readthedocs.io/zh/latest/sdk_reference.html#nni.msg_dispatcher_base.MsgDispatcherBase)可帮助理解 `MsgDispatcherBase` class CustomizedAdvisor(MsgDispatcherBase):
def __init__(self, ...):
...
**3. 在 Experiment 的 YAML 文件中配置好自定义的 Advisor。** **2. 实现所有除了 ``handle_request`` 外的,以 ``handle_`` 前缀开始的方法**。 `此文档 </sdk_reference.html#nni.runtime.msg_dispatcher_base.MsgDispatcherBase>`__ 可帮助理解 ``MsgDispatcherBase``。
与 Tuner 和 Assessor 类似。 NNI 需要定位到自定义的 Advisor 类,并实例化它,因此需要指定自定义 Advisor 类的文件位置,并将参数值传给 `__init__` 构造函数 **3. 在 Experiment 的 YAML 文件中配置好自定义 Advisor**
```yaml 与 Tuner 和 Assessor 类似。 NNI 需要定位到自定义的 Advisor 类,并实例化它,因此需要指定自定义 Advisor 类的文件位置,并将参数值传给 ``__init__`` 构造函数。
advisor:
codeDir: /home/abc/myadvisor
classFileName: my_customized_advisor.py
className: CustomizedAdvisor
# 任何传入 __init__ 构造函数的参数
# 都需要声明在 classArgs 字段中,如:
classArgs:
arg1: value1
```
**注意:**Advisor 的工作目录是`<home>/nni-experiments/<experiment_id>/log` 可从环境变量 `NNI_LOG_DIRECTORY` 中获取。 .. code-block:: yaml
## 示例 advisor:
codeDir: /home/abc/myadvisor
classFileName: my_customized_advisor.py
className: CustomizedAdvisor
# 所有的参数都需要传递给你 Assessor 的构造函数 __init__
# 例如,可以在可选的 classArgs 字段中指定
classArgs:
arg1: value1
参考[示例](https://github.com/microsoft/nni/tree/master/examples/tuners/mnist_keras_customized_advisor) **注意** :Assessor 的工作目录是 ``<home>/nni-experiments/<experiment_id>/log``\ ,可从环境变量 ``NNI_LOG_DIRECTORY``\ 中获取。
\ No newline at end of file
示例
-------
:githublink:`参考示例 <examples/tuners/mnist_keras_customized_advisor>`。
# 自定义 Tuner
## 自定义 Tuner
NNI 在内置的 Tuner 中提供了最新的调优算法。 NNI 同时也支持自定义 Tuner。
通过自定义 Tuner,可实现自己的调优算法。主要有三步:
1. 继承 Tuner 基类
2. 实现 receive_trial_result, generate_parameter 和 update_search_space 函数
3. 在 Experiment 的 YAML 文件中配置好自定义的 Tuner
示例如下:
**1. 继承 Tuner 基类**
```python
from nni.tuner import Tuner
class CustomizedTuner(Tuner):
def __init__(self, ...):
...
```
**2. 实现 receive_trial_result, generate_parameter 和 update_search_space 函数**
```python
from nni.tuner import Tuner
class CustomizedTuner(Tuner):
def __init__(self, ...):
...
def receive_trial_result(self, parameter_id, parameters, value, **kwargs):
'''
接收 Trial 的最终结果。
parameter_id: int
parameters: 'generate_parameters()' 创建出的对象
value: Trial 的最终指标,包括 default 指标
'''
# 代码实现位置
...
def generate_parameters(self, parameter_id, **kwargs):
'''
返回 Trial 的超参组合的序列化对象
parameter_id: int
'''
# 代码实现位置
return your_parameters
...
def update_search_space(self, search_space):
'''
在运行时,需要更新搜索空间的 Tuner 可实现此函数。
如果 Tuner 只在生成第一个超参前设置搜索空间,
需要将其行为写到文档里。
search_space: 定义 Experiment 时创建的 JSON 对象
'''
# 代码实现位置
...
```
`receive_trial_result` 从输入中会接收 `parameter_id, parameters, value` 参数。 Tuner 会收到 Trial 进程发送的完全一样的 `value` 值。
`generate_parameters` 函数返回的 `your_parameters`,会被 NNI SDK 打包为 json。 然后 SDK 会将 json 对象解包给 Trial 进程。因此,Trial 进程会收到来自 Tuner 的完全相同的 `your_parameters`
例如: 如下实现了 `generate_parameters`
```python
def generate_parameters(self, parameter_id, **kwargs):
'''
返回 Trial 的超参组合的序列化对象
parameter_id: int
'''
# 代码实现位置
return {"dropout": 0.3, "learning_rate": 0.4}
```
这表示 Tuner 会一直生成超参组合 `{"dropout": 0.3, "learning_rate": 0.4}`。 而 Trial 进程也会在调用 API `nni.get_next_parameter()` 时得到 `{"dropout": 0.3, "learning_rate": 0.4}`。 Trial 结束后的返回值(通常是某个指标),通过调用 API `nni.report_final_result()` 返回给 Tuner。如: `nni.report_final_result(0.93)`。 而 Tuner 的 `receive_trial_result` 函数会收到如下结果:
```python
parameter_id = 82347
parameters = {"dropout": 0.3, "learning_rate": 0.4}
value = 0.93
```
**注意:**Tuner 的工作目录是 `<home>/nni-experiments/<experiment_id>/log`,可使用环境变量 `NNI_LOG_DIRECTORY`,因此 ,如果要访问自己 Tuner 目录中的文件(如: `data.txt`)不能直接使用 `open('data.txt', 'r')`。 要使用:
```python
_pwd = os.path.dirname(__file__)
_fd = open(os.path.join(_pwd, 'data.txt'), 'r')
```
这是因为自定义的 Tuner 不是在自己的目录里执行的。(即,`pwd` 返回的目录不是 Tuner 的目录)。
**3. 在 Experiment 的 YAML 文件中配置好自定义的 Tuner**
NNI 需要定位到自定义的 Tuner 类,并实例化它,因此需要指定自定义 Tuner 类的文件位置,并将参数值传给 \_\_init__ 构造函数。
```yaml
tuner:
codeDir: /home/abc/mytuner
classFileName: my_customized_tuner.py
className: CustomizedTuner
# 任何传入 __init__ 构造函数的参数
# 都需要声明在 classArgs 字段中,如:
classArgs:
arg1: value1
```
更多示例,可参考:
> - [evolution-tuner](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/evolution_tuner)
> - [hyperopt-tuner](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/hyperopt_tuner)
> - [evolution-based-customized-tuner](https://github.com/Microsoft/nni/tree/master/examples/tuners/ga_customer_tuner)
### 实现更高级的自动机器学习算法
上述内容足够写出通用的 Tuner。 但有时可能需要更多的信息,例如,中间结果, Trial 的状态等等,从而能够实现更强大的自动机器学习算法。 因此,有另一个 `Advisor` 类,直接继承于 `MsgDispatcherBase`,它在 [`src/sdk/pynni/nni/msg_dispatcher_base.py`](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/msg_dispatcher_base.py)。 参考[这里](CustomizeAdvisor.md)来了解如何实现自定义的 Advisor。
\ No newline at end of file
自定义 Tuner
===============
自定义 Tuner
---------------
NNI 在内置的 Tuner 中提供了最新的调优算法。 NNI 同时也支持自定义 Tuner。
通过自定义 Tuner,可实现自己的调优算法。主要有三步:
#. 继承 Tuner 基类
#. 实现 receive_trial_result, generate_parameter 和 update_search_space 函数
#. 在 Experiment 的 YAML 文件中配置好自定义的 Tuner
示例如下:
**1. 继承 Tuner 基类**
.. code-block:: python
from nni.tuner import Tuner
class CustomizedTuner(Tuner):
def __init__(self, ...):
...
**2. 实现 receive_trial_result, generate_parameter 和 update_search_space 函数**
.. code-block:: python
from nni.tuner import Tuner
class CustomizedTuner(Tuner):
def __init__(self, ...):
...
def receive_trial_result(self, parameter_id, parameters, value, **kwargs):
'''
最终结果
parameter_id: int
parameters: 对象可由 'generate_parameters()' 创建
value: Trial 最终指标,包括默认指标
'''
# 你的代码
...
def generate_parameters(self, parameter_id, **kwargs):
'''
以可序列化对象的形式返回一组 Trial (超)参数
parameter_id: int
'''
# 你的代码
return your_parameters
...
def update_search_space(self, search_space):
'''
Tuner 支持在运行时更新搜索空间。
如果 Tuner 只在生成第一个超参前设置搜索空间,
需要将其行为写到文档里。
search_space: 定义 Experiment 时创建的 JSON 对象
'''
# 你的代码
...
``receive_trial_result`` 从输入中会接收 ``parameter_id, parameters, value`` 参数。 Tuner 会收到 Trial 进程发送的完全一样的 ``value`` 值。
``generate_parameters`` 函数返回的 ``your_parameters``,会被 NNI SDK 打包为 json。 然后 SDK 会将 json 对象解包给 Trial 进程。因此,Trial 进程会收到来自 Tuner 的完全相同的 ``your_parameters``。
例如:
如下实现了 ``generate_parameters``:
.. code-block:: python
def generate_parameters(self, parameter_id, **kwargs):
'''
以可序列化对象的形式返回一组 Trial (超)参数
parameter_id: int
'''
# 你的代码
return {"dropout": 0.3, "learning_rate": 0.4}
这表示 Tuner 会一直生成超参组合 ``{"dropout": 0.3, "learning_rate": 0.4}``。 而 Trial 进程也会在调用 API ``nni.get_next_parameter()`` 时得到 ``{"dropout": 0.3, "learning_rate": 0.4}``。 Trial 结束后的返回值(通常是某个指标),通过调用 API ``nni.report_final_result()`` 返回给 Tuner。如: ``nni.report_final_result(0.93)``。 而 Tuner 的 ``receive_trial_result`` 函数会收到如下结果:
.. code-block:: python
parameter_id = 82347
parameters = {"dropout": 0.3, "learning_rate": 0.4}
value = 0.93
**注意** :Tuner 的工作目录是 ``<home>/nni-experiments/<experiment_id>/log``,可使用环境变量 ``NNI_LOG_DIRECTORY``,因此 ,如果要访问自己 Tuner 目录中的文件(如: ``data.txt``)不能直接使用 ``open('data.txt', 'r')``。 要使用:
.. code-block:: python
_pwd = os.path.dirname(__file__)
_fd = open(os.path.join(_pwd, 'data.txt'), 'r')
这是因为自定义的 Tuner 不是在自己的目录里执行的。(即,``pwd`` 返回的目录不是 Tuner 的目录)。
**3. 在 Experiment 的 YAML 文件中配置好自定义的 Tuner**
NNI 需要定位到自定义的 Tuner 类,并实例化它,因此需要指定自定义 Tuner 类的文件位置,并将参数值传给 ``__init__`` 构造函数。
.. code-block:: yaml
tuner:
codeDir: /home/abc/mytuner
classFileName: my_customized_tuner.py
className: CustomizedTuner
# 所有的参数都需要传递给你 Assessor 的构造函数 __init__
# 例如,可以在可选的 classArgs 字段中指定
classArgs:
arg1: value1
更多示例,可参考:
..
* :githublink:`evolution-tuner <src/sdk/pynni/nni/evolution_tuner>`
* :githublink:`hyperopt-tuner <src/sdk/pynni/nni/hyperopt_tuner>`
* :githublink:`evolution-based-customized-tuner <examples/tuners/ga_customer_tuner>`
实现更高级的自动机器学习算法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
上述内容足够写出通用的 Tuner。 但有时可能需要更多的信息,例如,中间结果, Trial 的状态等等,从而能够实现更强大的自动机器学习算法。 因此,有另一个 ``Advisor`` 类,直接继承于 ``MsgDispatcherBase``,它在 :githublink:`src/sdk/pynni/nni/msg_dispatcher_base.py <src/sdk/pynni/nni/msg_dispatcher_base.py>` 。 参考 `这里 <CustomizeAdvisor.rst>`__ 来了解如何实现自定义的 Advisor。
# Naïve Evolution Tuner
## Naïve Evolution(进化算法)
进化算法来自于 [Large-Scale Evolution of Image Classifiers](https://arxiv.org/pdf/1703.01041.pdf)。 它会基于搜索空间随机生成一个种群。 在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层,等)。 进化算法需要很多次 Trial 才能有效,但它也非常简单,也很容易扩展新功能。
\ No newline at end of file
Naïve Evolution Tuner(朴素进化)
==========================================================
Naive Evolution(进化算法)
------------------------------
朴素进化算法来自于论文 `Large-Scale Evolution of Image Classifiers <https://arxiv.org/pdf/1703.01041.pdf>`__。 它会基于搜索空间随机生成一个种群。 在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层,等)。 进化算法需要很多次 Trial 才能有效,但它也非常简单,也很容易扩展新功能。
# NNI 中的 GP Tuner NNI 中的 GP Tuner
==============================
## GP Tuner GP Tuner
--------
贝叶斯优化会构建一个能最好的描述优化目标的后验分布函数(使用高斯过程)。 随着观测值的增加,后验分布会得到改善,会在参数空间中确定哪些范围值得进一步探索,哪一些不值得。 贝叶斯优化会构建一个能最好的描述优化目标的后验分布函数(使用高斯过程)。 随着观测值的增加,后验分布会得到改善,会在参数空间中确定哪些范围值得进一步探索,哪一些不值得。
GP Tuner 被设计为通过最大化或最小化步数来找到最接近最优结果的参数组合。 GP Tuner 使用了代理优化问题(找到采集函数的最大值)。虽然这仍然是个难题,但成本更低(从计算的角度来看),并且适合于作为通用工具。 因此,贝叶斯优化适合于采样函数的成本非常高时来使用。 GP Tuner 被设计为通过最大化或最小化步数来找到最接近最优结果的参数组合。 GP Tuner 使用了代理优化问题(找到采集函数的最大值)。虽然这仍然是个难题,但成本更低(从计算的角度来看),并且适合于作为通用工具。 因此,贝叶斯优化适合于采样函数的成本非常高时来使用。
注意,搜索空间接受的类型包括 `randint`, `uniform`, `quniform`, `loguniform`, `qloguniform`,以及数值的 `choice` 注意,搜索空间接受的类型包括 ``randint``\ , ``uniform``\ , ``quniform``\ , ``loguniform``\ , ``qloguniform``\ ,以及数值的 ``choice``
优化方法在 [Algorithms for Hyper-Parameter Optimization](https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf) 的第三章有详细描述。 优化方法在论文 `Algorithms for Hyper-Parameter Optimization <https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf>`__ 的第三章中有详细描述。
\ No newline at end of file
# Grid Search
## Grid Search(遍历搜索)
Grid Search 会穷举定义在搜索空间文件中的所有超参组合。
注意,搜索空间仅支持 `choice`, `quniform`, `randint`
\ No newline at end of file
Grid Search
==================
Grid Search(网格搜索)
---------------------------------
Grid Search 会穷举定义在搜索空间文件中的所有超参组合。
遍历搜索可以使用的类型有 ``choice, quniform, randint``。
# NNI 中使用 Hyperband
## 1. 介绍
[Hyperband](https://arxiv.org/pdf/1603.06560.pdf) 是一种流行的自动机器学习算法。 Hyperband 的基本思想是对配置分组,每组有 `n` 个随机生成的超参配置,每个配置使用 `r` 次资源(如,epoch 数量,批处理数量等)。 当 `n` 个配置完成后,会选择最好的 `n/eta` 个配置,并增加 `r*eta` 次使用的资源。 最后,会选择出的最好配置。
## 2. 实现并行
首先,此示例是基于 MsgDispatcherBase 来实现的自动机器学习算法,而不是基于 Tuner 和 Assessor。 这种实现方法下,Hyperband 集成了 Tuner 和 Assessor 两者的功能,因而将它叫做 Advisor。
其次,本实现完全利用了 Hyperband 内部的并行性。 具体来说,下一个分组不会严格的在当前分组结束后再运行。 只要有资源,就可以开始运行新的分组。
## 3. 用法
要使用 Hyperband,需要在 Experiment 的 YAML 配置文件进行如下改动。
advisor:
#可选项: Hyperband
builtinAdvisorName: Hyperband
classArgs:
#R: 最大的步骤
R: 100
#eta: 丢弃的 Trial 的比例
eta: 3
#可选项: maximize, minimize
optimize_mode: maximize
注意,一旦使用了 Advisor,就不能在配置文件中添加 Tuner 和 Assessor。 使用 Hyperband 时,Trial 代码收到的超参(如键值对)中,会多一个用户定义的 `TRIAL_BUDGET`**使用 `TRIAL_BUDGET`,Trial 能够控制其运行的时间。</p>
对于 Trial 代码中 `report_intermediate_result(metric)``report_final_result(metric)`**`指标` 应该是数值,或者用一个 dict,并保证其中有键值为 default 的项目,其值也为数值型**。 这是需要进行最大化或者最小化优化的数值,如精度或者损失度。
`R``eta` 是 Hyperband 中可以改动的参数。 `R` 表示可以分配给 Trial 的最大资源。 这里,资源可以代表 epoch 或 批处理数量。 `TRIAL_BUDGET` 应该被尝试代码用来控制运行的次数。 参考示例 `examples/trials/mnist-advisor/` ,了解详细信息。
`eta` 表示 `n` 个配置中的 `n/eta` 个配置会留存下来,并用更多的资源来运行。
下面是 `R=81``eta=3` 时的示例:
| | s=4 | s=3 | s=2 | s=1 | s=0 |
| - | ---- | ---- | ---- | ---- | ---- |
| i | n r | n r | n r | n r | n r |
| 0 | 81 1 | 27 3 | 9 9 | 6 27 | 5 81 |
| 1 | 27 3 | 9 9 | 3 27 | 2 81 | |
| 2 | 9 9 | 3 27 | 1 81 | | |
| 3 | 3 27 | 1 81 | | | |
| 4 | 1 81 | | | | |
`s` 表示分组, `n` 表示生成的配置数量,相应的 `r` 表示配置使用多少资源来运行。 `i` 表示轮数,如分组 4 有 5 轮,分组 3 有 4 轮。
关于如何实现 Trial 代码,参考 `examples/trials/mnist-hyperband/` 中的说明。
## 4. 未来的改进
当前实现的 Hyperband 算法可以通过改进支持的提前终止算法来提高,因为最好的 `n/eta` 个配置并不一定都表现很好。 不好的配置应该更早的终止。
在当前实现中,遵循了[此论文](https://arxiv.org/pdf/1603.06560.pdf)的设计,配置都是随机生成的。 要进一步提升,配置生成过程可以利用更高级的算法。
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment