Unverified Commit 035d58bc authored by SparkSnail's avatar SparkSnail Committed by GitHub
Browse files

Merge pull request #121 from Microsoft/master

merge master
parents b633c265 8e732f2c
# 在多机上运行 Experiment
NNI 支持通过 SSH 通道在多台计算机上运行 Experiment,称为 `remote` 模式。 NNI 需要这些计算机的访问权限,并假定已配置好了深度学习训练环境。
例如:有三台服务器,登录账户为 `bob`(注意:账户不必在各台计算机上一致):
| IP | 用户名 | 密码 |
| -------- | --- | ------ |
| 10.1.1.1 | bob | bob123 |
| 10.1.1.2 | bob | bob123 |
| 10.1.1.3 | bob | bob123 |
## 设置 NNI 环境
按照[指南](QuickStart.md)在每台计算机上安装 NNI。
## 运行 Experiment
在另一台计算机,或在其中任何一台上安装 NNI,并运行 nnictl 工具。
`examples/trials/mnist-annotation` 为例。 `cat ~/nni/examples/trials/mnist-annotation/config_remote.yml` 来查看详细配置:
```yaml
authorName: default
experimentName: example_mnist
trialConcurrency: 1
maxExecDuration: 1h
maxTrialNum: 10
#可选项: local, remote, pai
trainingServicePlatform: remote
#可选项: true, false
useAnnotation: true
tuner:
#可选项: TPE, Random, Anneal, Evolution, BatchTuner
#SMAC (SMAC 需要通过 nnictl 安装)
builtinTunerName: TPE
classArgs:
#可选项: maximize, minimize
optimize_mode: maximize
trial:
command: python3 mnist.py
codeDir: .
gpuNum: 0
#local 模式下 machineList 可为空
machineList:
- ip: 10.1.1.1
username: bob
passwd: bob123
#使用默认端口 22 时,该配置可跳过
#port: 22
- ip: 10.1.1.2
username: bob
passwd: bob123
- ip: 10.1.1.3
username: bob
passwd: bob123
```
填好 `machineList` 部分,然后运行:
```bash
nnictl create --config ~/nni/examples/trials/mnist-annotation/config_remote.yml
```
来启动 Experiment。
\ No newline at end of file
# 在阅读理解上使用自动模型架构搜索
该样例展示了如何使用遗传算法为阅读理解任务找到好的模型架构。
## 1. 搜索空间
对于阅读理解项目,注意力和循环神经网络(RNN)已经被证明非常有效。 使用的搜索空间如下:
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 (移除随机跳过).
![](https://github.com/Microsoft/nni/tree/master/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
#在 OpenPAI 的 hdfs 目录上存储数据的目录,如:'hdfs://host:port/directory'
dataDir: hdfs://10.10.10.10:9000/username/nni
#在 OpenPAI 的 hdfs 目录上存储输出的目录,如:'hdfs://host:port/directory'
outputDir: hdfs://10.10.10.10:9000/username/nni
paiConfig:
#登录 OpenPAI 的用户名
userName: username
#登录 OpenPAI 的密码
passWord: password
# OpenPAI 的 RESTful 服务器地址
host: 10.10.10.10
```
将默认值改为个人账户和服务器信息。 包括 `nniManagerIp`, `dataDir`, `outputDir`, `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
# 搜索空间
## 概述
在 NNI 中,Tuner 会根据搜索空间来取样生成参数和网络架构。搜索空间通过 JSON 文件来定义。
要定义搜索空间,需要定义变量名称、采样策略的类型及其参数。
* 搜索空间样例如下:
```yaml
{
"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]},
"batch_size":{"_type":"choice","_value":[50, 250, 500]},
"learning_rate":{"_type":"uniform","_value":[0.0001, 0.1]}
}
```
将第一行作为样例。 `dropout_rate` 定义了一个变量,先验分布为均匀分布,范围从 `0.1``0.5`
## 类型
所有采样策略和参数如下:
* {"_type":"choice","_value":options}
* 这表示变量值应该是列表中的选项之一。 选项的元素也可以是 [nested](嵌套的)随机表达式。 在这种情况下,随机选项仅会在条件满足时出现。
* {"_type":"randint","_value":[upper]}
* 此变量为范围 [0, upper) 之间的随机整数。 这种分布的语义,在较远整数与附近整数之间的损失函数无太大关系, 这是用来描述随机种子的较好分布。 如果损失函数与较近的整数更相关,则应该使用某个"quantized"的连续分布,如quniform, qloguniform, qnormal 或 qlognormal。 注意,如果需要改动数字下限,可以使用 `quniform`
* {"_type":"uniform","_value":[low, high]}
* 变量是 low 和 high 之间均匀分布的值。
* 当优化时,此变量值会在两侧区间内。
* {"_type":"quniform","_value":[low, high, q]}
* 这表示变量值会类似于 round(uniform(low, high) / q) * q
* 适用于离散,同时反映了某种"平滑"的数值,但上下限都有限制。 如果需要从范围 [low, high] 中均匀选择整数,可以如下定义 `_value``[low, high, 1]`
* {"_type":"loguniform","_value":[low, high]}
* 变量值在范围 [low, high] 中是 loguniform 分布,如 exp(uniform(log(low), log(high))),因此返回值是对数均匀分布的。
* 当优化时,此变量必须是正数。
* {"_type":"qloguniform","_value":[low, high, q]}
* 这表示变量值会类似于 round(loguniform(low, high)) / q) * q
* 适用于值是“平滑”的离散变量,但上下限均有限制。
* {"_type":"normal","_value":[label, mu, sigma]}
* 变量值为实数,且为正态分布,均值为 mu,标准方差为 sigma。 优化时,此变量不受约束。
* {"_type":"qnormal","_value":[label, mu, sigma, q]}
* 这表示变量值会类似于 round(normal(mu, sigma) / q) * q
* 适用于在 mu 周围的离散变量,且没有上下限限制。
* {"_type":"lognormal","_value":[label, mu, sigma]}
* 变量值为 exp(normal(mu, sigma)) 分布,范围值是对数的正态分布。 当优化时,此变量必须是正数。
* {"_type":"qlognormal","_value":[label, mu, sigma, q]}
* 这表示变量值会类似于 round(exp(normal(mu, sigma)) / q) * q
* 适用于值是“平滑”的离散变量,但某一边有界。
## 每种 Tuner 支持的搜索空间类型
| | choice | randint | uniform | quniform | loguniform | qloguniform | normal | qnormal | lognormal | qlognormal |
|:-------------------:|:--------:|:--------:|:--------:|:--------:|:----------:|:-----------:|:--------:|:--------:|:---------:|:----------:|
| TPE Tuner | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; |
| Random Search Tuner | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; |
| Anneal Tuner | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; |
| Evolution Tuner | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; |
| SMAC Tuner | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | | | | | |
| Batch Tuner | &#10003; | | | | | | | | | |
| Grid Search Tuner | &#10003; | | | &#10003; | | &#10003; | | | | |
| Hyperband Advisor | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; | &#10003; |
| Metis Tuner | &#10003; | &#10003; | &#10003; | &#10003; | | | | | | |
注意,在 Grid Search Tuner 中,为了使用方便 `quniform``qloguniform` 的定义也有所改变,其中的 q 表示采样值的数量。 详情如下:
* 类型 'quniform' 接收三个值 [low, high, q], 其中 [low, high] 指定了范围,而 'q' 指定了会被均匀采样的值的数量。 注意 q 至少为 2。 它的第一个采样值为 'low',每个采样值都会比前一个大 (high-low)/q 。
* 类型 'qloguniform' 的行为与 'quniform' 类似,不同处在于首先将范围改为 [log(low), log(high)] 采样后,再将数值还原。
注意 Metis Tuner 当前仅支持在 `choice` 中使用数值。
\ No newline at end of file
**设置 NNI 开发环境**
===
## 调试 NNI 源代码的最佳实践
要调试 NNI 源代码,需要 Ubuntu 16.04 或更高版本系统的开发环境,并需要安装 Python 3.x 以及 pip3,然后遵循以下步骤。
**1. 克隆源代码**
运行命令
git clone https://github.com/Microsoft/nni.git
来克隆源代码
**2. 准备调试环境并安装依赖项**
将目录切换到源码目录,然后运行命令
make install-dependencies
来安装环境的依赖项工具
**3. 生成源代码**
运行命令
make build
来生成源代码
**4. 将 NNI 安装到开发环境中**
运行命令
make dev-install
来安装分发内容到开发环境,并创建 cli 脚本
**5. 检查环境是否正确**
Trial 启动 Experiment 来检查环境。 例如,运行命令
nnictl create --config ~/nni/examples/trials/mnist/config.yml
并打开网页界面查看
**6. 重新部署**
代码改动后,用**第 3 步**来重新生成代码,改动会立即生效。
* * *
最后,希望一切顺利。 参考[贡献](./CONTRIBUTING.md)文档,来了解更多创建拉取请求或问题的指南。
\ No newline at end of file
# 实现 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](./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](Builtin_Assessors.md)。 通常,`指标`是损失值或精度。
* 返回配置的最终性能
```python
nni.report_final_result(metrics)
```
`指标`也可以是任意的 Python 对象。 如果使用了内置的 Tuner/Assessor,`指标`格式和 `report_intermediate_result` 中一样,这个数值表示模型的性能,如精度、损失值等。 `指标`会发送给 [Tuner](Builtin_Tuner.md)
### 第三步:启用 NNI API
要启用 NNI 的 API 模式,需要将 useAnnotation 设置为 *false*,并提供搜索空间文件的路径(即第一步中定义的文件):
```yaml
useAnnotation: false
searchSpacePath: /path/to/your/search_space.json
```
参考 [这里](ExperimentConfig.md) 进一步了解如何配置实验。
*参考[这里](sdk_reference.md),了解更多 NNI API (例如:`nni.get_sequence_id()`)。
<a name="nni-annotation"></a>
## NNI Annotation
另一种实现 Trial 的方法是使用 Python 注释来标记 NNI。 就像其它 Python Annotation,NNI 的 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(1, 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](AnnotationSpec.md)
### 第二步:启用 Annotation
在 YAML 配置文件中设置 *useAnnotation* 为 true 来启用 Annotation:
useAnnotation: true
<a name="more-examples"></a>
## 更多 Trial 的样例
* [MNIST 样例](mnist_examples.md)
* [为 CIFAR 10 分类找到最佳的 optimizer](cifar10_examples.md)
* [如何在 NNI 调优 SciKit-learn 的参数](sklearn_examples.md)
* [在阅读理解上使用自动模型架构搜索。](SQuAD_evolution_examples.md)
* [如何在 NNI 上调优 GBDT](gbdt_example.md)
\ No newline at end of file
######################
教程
######################
.. toctree::
安装<Installation>
实现 Trial<Trials>
Tuner<tuners>
Assessor<assessors>
Web 界面<WebUI>
训练平台<training_services>
高级功能<advanced>
\ No newline at end of file
# Web 界面
## 查看概要页面
点击标签 "Overview"。
* 查看 Experiment 的配置和搜索空间内容。
* 支持下载 Experiment 结果。
![](./img/webui-img/over1.png)
* 查看最好结果的 Trial。
![](./img/webui-img/over2.png)
## 查看任务默认指标
点击 "Default Metric" 来查看所有 Trial 的点图。 悬停鼠标来查看默认指标和搜索空间信息。
![](./img/accuracy.png)
## 查看超参
点击 "Hyper Parameter" 标签查看图像。
* 可选择百分比查看最好的 Trial。
* 选择两个轴来交换位置。
![](./img/hyperPara.png)
## 查看 Trial 运行时间
点击 "Trial Duration" 标签来查看柱状图。
![](./img/trial_duration.png)
## 查看 Trial 状态
点击 "Trials Detail" 标签查看所有 Trial 的状态。 特别是:
* Trial 详情:Trial 的 id,持续时间,开始时间,结束时间,状态,精度和搜索空间。
![](./img/webui-img/detail-local.png)
* 如果在 OpenPAI 或 Kubeflow 平台上运行,还可以看到 hdfsLog。
![](./img/webui-img/detail-pai.png)
* Kill: 可终止正在运行的任务。
* 支持搜索某个特定的 Trial。
* 中间结果图。
![](./img/intermediate.png)
\ No newline at end of file
高级功能
=====================
.. toctree::
多阶段<multiPhase>
高级网络架构搜索(AdvancedNAS)<AdvancedNAS>
\ No newline at end of file
Assessor(评估器)
==============
为了节省计算资源,在 NNI 中可通过创建 **Assessor**,来配置提前终止策略。
Assessor 从 Trial 中接收中间结果,并通过指定的算法决定此 Trial 是否应该终止。 一旦 Trial 满足了提前终止策略(这表示 Assessor 认为最终结果不会太好),Assessor 会终止此 Trial,并将其状态标志为 `"EARLY_STOPPED"`。
这是 MNIST 在使用了 'Curvefitting' Assessor 的 'maximize' 模式后的实验结果,可以看到 Assessor 成功的将大量最终结果不好的 Trial **提前结束**了。 使用 Assessor,能在相同的计算资源下,得到更好的结果。
*实现代码:config_assessor.yml <https://github.com/Microsoft/nni/blob/master/examples/trials/mnist/config_assessor.yml>*
.. image:: ./img/Assessor.png
与 Tuner 类似,可使用内置的 Assessor,也可以自定义 Assessor。 参考下列教程,获取详细信息:
.. toctree::
内置 Assessor<Builtin_Assessors>
自定义 Assessor<Customize_Assessor>
# CIFAR-10 样例
## 概述
[CIFAR-10](https://www.cs.toronto.edu/~kriz/cifar.html) 分类是机器学习中常用的基准问题。 CIFAR-10 数据集是图像的集合。 它也是机器学习领域最常用的数据集之一,包含 60000 万张 32x32 的图像,共有 10 个分类。 因此以 CIFAR-10 分类为例来介绍 NNI 的用法。
### **目标**
总所周知,模型 optimizer (优化器)的选择直接影响了最终指标的性能。 本教程的目标是**调优出性能更好的优化器**,从而为图像识别训练出一个相对较小的卷积网络(CNN)。
本例中,选择了以下常见的深度学习优化器:
> "SGD", "Adadelta", "Adagrad", "Adam", "Adamax"
### **实验**
#### 准备
此样例需要安装 PyTorch。 PyTorch 安装包需要选择所基于的 Python 和 CUDA 版本。
这是环境 python==3.5 且 cuda == 8.0 的样例,然后用下列命令来安装 [ PyTorch](https://pytorch.org/)
```bash
python3 -m pip install http://download.pytorch.org/whl/cu80/torch-0.4.1-cp35-cp35m-linux_x86_64.whl
python3 -m pip install torchvision
```
#### NNI 与 CIFAR-10
**搜索空间**
正如本文目标,要为 CIFAR-10 找到最好的`优化器`。 使用不同的优化器时,还要相应的调整`学习率``网络架构`。 因此,选择这三个参数作为超参,并创建如下的搜索空间。
```json
{
"lr":{"_type":"choice", "_value":[0.1, 0.01, 0.001, 0.0001]},
"optimizer":{"_type":"choice", "_value":["SGD", "Adadelta", "Adagrad", "Adam", "Adamax"]},
"model":{"_type":"choice", "_value":["vgg", "resnet18", "googlenet", "densenet121", "mobilenet", "dpn92", "senet18"]}
}
```
*实现代码:[search_space.json](https://github.com/Microsoft/nni/blob/master/examples/trials/cifar10_pytorch/search_space.json)*
**Trial(尝试)**
这是超参集合的训练代码,关注以下几点:
* 使用 `nni.get_next_parameter()` 来获取下一组训练的超参组合。
* 使用 `nni.report_intermediate_result(acc)` 在每个 epoch 结束时返回中间结果。
* 使用 `nni.report_final_result(acc)` 在每个 Trial 结束时返回最终结果。
*实现代码:[main.py](https://github.com/Microsoft/nni/blob/master/examples/trials/cifar10_pytorch/main.py)*
也可以直接使用以前的代码来修改,参考:[如何编写 Trial](./Trials.md)
**配置**
这是在本机运行 Experiment 的样例(多GPU):
代码:[examples/trials/cifar10_pytorch/config.yml](https://github.com/Microsoft/nni/blob/master/examples/trials/cifar10_pytorch/config.yml)
这是在 OpenPAI 上运行 Experiment 的样例:
代码:[examples/trials/cifar10_pytorch/config_pai.yml](https://github.com/Microsoft/nni/blob/master/examples/trials/cifar10_pytorch/config_pai.yml)
*完整样例:[examples/trials/cifar10_pytorch/](https://github.com/Microsoft/nni/tree/master/examples/trials/cifar10_pytorch)*
#### 运行 Experiment
以上即为 Experiment 的代码介绍,**从命令行运行 config.yml 文件来开始 Experiment**
```bash
nnictl create --config nni/examples/trials/cifar10_pytorch/config.yml
```
\ No newline at end of file
# -*- coding: utf-8 -*-
#
# Configuration file for the Sphinx documentation builder.
#
# This file does only contain a selection of the most common options. For a
# full list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
from recommonmark.parser import CommonMarkParser
from recommonmark.transform import AutoStructify
# -- Project information ---------------------------------------------------
project = 'Neural Network Intelligence'
copyright = '2019, Microsoft'
author = 'Microsoft'
# The short X.Y version
version = ''
# The full version, including alpha/beta/rc tags
release = 'v0.5.1'
# -- General configuration ---------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.mathjax',
'sphinx_markdown_tables',
'sphinxarg.ext',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
source_parsers = {
'.md': CommonMarkParser
}
source_suffix = ['.rst', '.md']
# The master toctree document.
master_doc = 'index'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = None
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
html_theme_options = {
'logo_only': True,
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
# html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# The default sidebars (for documents that don't match any pattern) are
# defined by theme itself. Builtin themes are using these templates by
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
# 'searchbox.html']``.
#
# html_sidebars = {}
html_logo = './img/nni_logo_dark.png'
# -- Options for HTMLHelp output ---------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'NeuralNetworkIntelligencedoc'
# -- Options for LaTeX output ------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'NeuralNetworkIntelligence.tex', 'Neural Network Intelligence Documentation',
'Microsoft', 'manual'),
]
# -- Options for manual page output ------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'neuralnetworkintelligence', 'Neural Network Intelligence Documentation',
[author], 1)
]
# -- Options for Texinfo output ----------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'NeuralNetworkIntelligence', 'Neural Network Intelligence Documentation',
author, 'NeuralNetworkIntelligence', 'One line description of project.',
'Miscellaneous'),
]
# -- Options for Epub output -------------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
# -- Extension configuration -------------------------------------------------
github_doc_root = 'https://github.com/Microsoft/nni/tree/master/doc/'
def setup(app):
app.add_config_value('recommonmark_config', {
'url_resolver': lambda url: github_doc_root + url if url.startswith('..') else url,
'enable_auto_toc_tree': False,
}, True)
app.add_transform(AutoStructify)
# GBDT
梯度提升是机器学习中回归和分类问题的一种方法。它由一组弱分类模型所组成,决策树是其中的典型。 像其它提升方法一样,它也分步来构建模型,并使用可微分的损失函数来优化。
梯度决策树(gradient boosting decision tree,GBDT)有很多流行的实现,如:[LightGBM](https://github.com/Microsoft/LightGBM), [xgboost](https://github.com/dmlc/xgboost), 和 [catboost](https://github.com/catboost/catboost),等等。 GBDT 是解决经典机器学习问题的重要工具。 GBDT 也是一种鲁棒的算法,可以使用在很多领域。 GBDT 的超参越好,就能获得越好的性能。
NNI 是用来调优超参的平台,可以在 NNI 中尝试各种内置的搜索算法,并行运行多个 Trial。
## 1. GBDT 的搜索空间
GBDT 有很多超参,但哪些才会影响性能或计算速度呢? 基于实践经验,建议如下(以 lightgbm 为例):
> * 获得更好的精度
* `learning_rate`. `学习率`的范围应该是 [0.001, 0.9]。
* `num_leaves`. `num_leaves``max_depth` 有关,不必两个值同时调整。
* `bagging_freq`. `bagging_freq` 可以是 [1, 2, 4, 8, 10]。
* `num_iterations`. 如果达到期望的拟合精度,可以调整得大一些。
> * 加速
* `bagging_fraction`. `bagging_fraction` 的范围应该是 [0.7, 1.0]。
* `feature_fraction`. `feature_fraction` 的范围应该是 [0.6, 1.0]。
* `max_bin`.
> * 避免过拟合
* `min_data_in_leaf`. 取决于数据集。
* `min_sum_hessian_in_leaf`. 取决于数据集。
* `lambda_l1``lambda_l2`.
* `min_gain_to_split`.
* `num_leaves`.
更多信息可参考: [lightgbm](https://lightgbm.readthedocs.io/en/latest/Parameters-Tuning.html)[autoxgoboost](https://github.com/ja-thomas/autoxgboost/blob/master/poster_2018.pdf)
## 2. 任务描述
"auto-gbdt" 基于 LightGBM 和 NNI。 数据集有[训练数据](https://github.com/Microsoft/nni/blob/master/examples/trials/auto-gbdt/data/regression.train)[测试数据](https://github.com/Microsoft/nni/blob/master/examples/trials/auto-gbdt/data/regression.train)。 根据数据中的特征和标签,训练一个 GBDT 回归模型,用来做预测。
## 3. 如何运行 NNI
### 3.1 准备 Trial 代码
基础代码如下:
```python
...
def get_default_parameters():
...
return params
def load_data(train_path='./data/regression.train', test_path='./data/regression.test'):
'''
读取或创建数据集
'''
...
return lgb_train, lgb_eval, X_test, y_test
def run(lgb_train, lgb_eval, params, X_test, y_test):
# 训练
gbm = lgb.train(params,
lgb_train,
num_boost_round=20,
valid_sets=lgb_eval,
early_stopping_rounds=5)
# 预测
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
# 评估
rmse = mean_squared_error(y_test, y_pred) ** 0.5
print('The rmse of prediction is:', rmse)
if __name__ == '__main__':
lgb_train, lgb_eval, X_test, y_test = load_data()
PARAMS = get_default_parameters()
# train
run(lgb_train, lgb_eval, PARAMS, X_test, y_test)
```
### 3.2 准备搜索空间
如果要调优 `num_leaves`, `learning_rate`, `bagging_fraction``bagging_freq`, 可创建一个 [search_space.json](https://github.com/Microsoft/nni/blob/master/examples/trials/auto-gbdt/search_space.json) 文件:
```json
{
"num_leaves":{"_type":"choice","_value":[31, 28, 24, 20]},
"learning_rate":{"_type":"choice","_value":[0.01, 0.05, 0.1, 0.2]},
"bagging_fraction":{"_type":"uniform","_value":[0.7, 1.0]},
"bagging_freq":{"_type":"choice","_value":[1, 2, 4, 8, 10]}
}
```
参考[这里](./SearchSpaceSpec.md),了解更多变量类型。
### 3.3 在代码中使用 NNI SDK
```diff
+import nni
...
def get_default_parameters():
...
return params
def load_data(train_path='./data/regression.train', test_path='./data/regression.test'):
'''
读取或创建数据集
'''
...
return lgb_train, lgb_eval, X_test, y_test
def run(lgb_train, lgb_eval, params, X_test, y_test):
# 训练
gbm = lgb.train(params,
lgb_train,
num_boost_round=20,
valid_sets=lgb_eval,
early_stopping_rounds=5)
# 预测
y_pred = gbm.predict(X_test, num_iteration=gbm.best_iteration)
# 评估
rmse = mean_squared_error(y_test, y_pred) ** 0.5
print('The rmse of prediction is:', rmse)
+ nni.report_final_result(rmse)
if __name__ == '__main__':
lgb_train, lgb_eval, X_test, y_test = load_data()
+ RECEIVED_PARAMS = nni.get_next_parameter()
PARAMS = get_default_parameters()
+ PARAMS.update(RECEIVED_PARAMS)
PARAMS = get_default_parameters()
PARAMS.update(RECEIVED_PARAMS)
# 训练
run(lgb_train, lgb_eval, PARAMS, X_test, y_test)
```
### 3.4 编写配置文件并运行
在配置文件中,可以设置如下内容:
* Experiment 设置:`trialConcurrency`, `maxExecDuration`, `maxTrialNum`, `trial gpuNum`, 等等。
* 平台设置:`trainingServicePlatform`,等等。
* 路径设置:`searchSpacePath`, `trial codeDir`,等等。
* 算法设置:选择 `Tuner` 算法,`优化方向`,等等。
config.yml 样例:
```yaml
authorName: default
experimentName: example_auto-gbdt
trialConcurrency: 1
maxExecDuration: 10h
maxTrialNum: 10
#可选项: local, remote, pai
trainingServicePlatform: local
searchSpacePath: search_space.json
#可选项: true, false
useAnnotation: false
tuner:
#可选项: TPE, Random, Anneal, Evolution, BatchTuner
#SMAC (SMAC 需要先通过 nnictl 来安装)
builtinTunerName: TPE
classArgs:
#可选项: maximize, minimize
optimize_mode: minimize
trial:
command: python3 main.py
codeDir: .
gpuNum: 0
```
使用下面的命令启动 Experiment:
```bash
nnictl create --config ./config.yml
```
\ 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