Trials.md 8.25 KB
Newer Older
Chi Song's avatar
Chi Song committed
1
2
3
4
# 实现 NNI 的 Trial(尝试)代码

**Trial(尝试)**是将一组参数组合(例如,超参)在模型上独立的一次尝试。

Chi Song's avatar
Chi Song committed
5
定义 NNI 的 Trial,需要首先定义参数组,并更新模型代码。 NNI 有两种方法来实现 Trial:[NNI API](#nni-api) 以及 [NNI Python annotation](#nni-annotation)。 参考[这里的](#more-examples)更多 Trial 示例。
Chi Song's avatar
Chi Song committed
6
7
8
9
10
11
12

<a name="nni-api"></a>

## NNI API

### 第一步:准备搜索空间参数文件。

Chi Song's avatar
Chi Song committed
13
示例如下:
Chi Song's avatar
Chi Song committed
14
15
16
17
18
19
20
21
22
23

```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]}
}
```

Chi Song's avatar
Chi Song committed
24
参考 [SearchSpaceSpec.md](../Tutorial/SearchSpaceSpec.md) 进一步了解搜索空间。 Tuner 会根据搜索空间来生成配置,即从每个超参的范围中选一个值。
Chi Song's avatar
Chi Song committed
25
26
27
28
29
30
31
32
33
34
35
36
37

### 第二步:更新模型代码

* Import NNI
    
    在 Trial 代码中加上 `import nni`

* 从 Tuner 获得参数值

```python
RECEIVED_PARAMS = nni.get_next_parameter()
```

Chi Song's avatar
Chi Song committed
38
39
40
`RECEIVED_PARAMS` 是一个对象,如:

`{"conv_size": 2, "hidden_size": 124, "learning_rate": 0.0307, "dropout_rate": 0.2029}`.
Chi Song's avatar
Chi Song committed
41
42
43
44
45
46
47

* 定期返回指标数据(可选)

```python
nni.report_intermediate_result(metrics)
```

Chi Song's avatar
Chi Song committed
48
`指标`可以是任意的 Python 对象。 如果使用了 NNI 内置的 Tuner/Assessor,`指标`只可以是两种类型:1) 数值类型,如 float、int, 2) dict 对象,其中必须由键名为 `default`,值为数值的项目。 `指标`会发送给 [Assessor](../Assessor/BuiltinAssessor.md)。 通常,`指标`包含了定期评估的损失值或精度。
Chi Song's avatar
Chi Song committed
49
50
51
52
53
54
55

* 返回配置的最终性能

```python
nni.report_final_result(metrics)
```

Chi Song's avatar
Chi Song committed
56
`指标`可以是任意的 Python 对象。 如果使用了内置的 Tuner/Assessor,`指标`格式和 `report_intermediate_result` 中一样,这个数值表示模型的性能,如精度、损失值等。 `指标`会发送给 [Tuner](../Tuner/BuiltinTuner.md)
Chi Song's avatar
Chi Song committed
57
58
59

### 第三步:启用 NNI API

Chi Song's avatar
Chi Song committed
60
要启用 NNI 的 API 模式,需要将 useAnnotation 设置为 *false*,并提供搜索空间文件的路径,即第一步中定义的文件:
Chi Song's avatar
Chi Song committed
61
62
63
64
65
66

```yaml
useAnnotation: false
searchSpacePath: /path/to/your/search_space.json
```

Chi Song's avatar
Chi Song committed
67
参考[这里](../Tutorial/ExperimentConfig.md)进一步了解如何配置 Experiment。
Chi Song's avatar
Chi Song committed
68

Chi Song's avatar
Chi Song committed
69
* 参考[这里](https://nni.readthedocs.io/zh/latest/sdk_reference.html),了解更多 NNI API (例如 `nni.get_sequence_id()`)。
Chi Song's avatar
Chi Song committed
70
71
72
73
74

<a name="nni-annotation"></a>

## NNI Annotation

Chi Song's avatar
Chi Song committed
75
另一种实现 Trial 的方法是使用 Python 注释来标记 NNI。 NN Annotation 很简单,类似于注释。 不必对现有代码进行结构更改。 只需要添加一些 NNI Annotation,就能够:
Chi Song's avatar
Chi Song committed
76

Chi Song's avatar
Chi Song committed
77
* 标记需要调整的参数变量
Chi Song's avatar
Chi Song committed
78
* 指定要在其中调整的变量的范围
Chi Song's avatar
Chi Song committed
79
* 标记哪个变量需要作为中间结果范围给 `Assessor`
Chi Song's avatar
Chi Song committed
80
* 标记哪个变量需要作为最终结果(例如:模型精度)返回给 `Tuner`
Chi Song's avatar
Chi Song committed
81
82
83
84
85
86
87
88
89
90
91

同样以 MNIST 为例,只需要两步就能用 NNI Annotation 来实现 Trial 代码。

### 第一步:在代码中加入 Annotation

下面是加入了 Annotation 的 TensorFlow 代码片段,高亮的 4 行 Annotation 用于:

1. 调优 batch\_size 和 dropout\_rate
2. 每执行 100 步返回 test\_acc
3. 最后返回 test\_acc 作为最终结果。

Chi Song's avatar
Chi Song committed
92
值得注意的是,新添加的代码都是注释,不会影响以前的执行逻辑。因此这些代码仍然能在没有安装 NNI 的环境中运行。
Chi Song's avatar
Chi Song committed
93
94
95
96
97
98
99
100

```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)
Chi Song's avatar
Chi Song committed
101
+       """@nni.variable(nni.choice(0.1, 0.5), name=dropout_rate)"""
Chi Song's avatar
Chi Song committed
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
        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)"""
```

**注意**

Chi Song's avatar
Chi Song committed
123
* `@nni.variable` 会对它的下面一行进行修改,左边被赋值变量必须与 `@nni.variable` 的关键字 `name` 相同。
Chi Song's avatar
Chi Song committed
124
* `@nni.report_intermediate_result`/`@nni.report_final_result` 会将数据发送给 Assessor、Tuner。
Chi Song's avatar
Chi Song committed
125

Chi Song's avatar
Chi Song committed
126
Annotation 的语法和用法等,参考 [Annotation](../Tutorial/AnnotationSpec.md)
Chi Song's avatar
Chi Song committed
127
128
129
130
131
132
133
134

### 第二步:启用 Annotation

在 YAML 配置文件中设置 *useAnnotation* 为 true 来启用 Annotation:

    useAnnotation: true
    

Chi Song's avatar
Chi Song committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
## 用于调试的独立模式

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)

Chi Song's avatar
Chi Song committed
153
154
155
156
157
158
## Trial 存放在什么地方?

### 本机模式

每个 Trial 都有单独的目录来输出自己的数据。 在每次 Trial 运行后,环境变量 `NNI_OUTPUT_DIR` 定义的目录都会被导出。 在这个目录中可以看到 Trial 的代码、数据和日志。 此外,Trial 的日志(包括 stdout)还会被重定向到此目录中的 `trial.log` 文件。

Chi Song's avatar
Chi Song committed
159
如果使用了 Annotation 方法,转换后的 Trial 代码会存放在另一个临时目录中。 可以在 `run.sh` 文件中的 `NNI_OUTPUT_DIR` 变量找到此目录。 文件中的第二行(即:`cd`)会切换到代码所在的实际路径。 参考 `run.sh` 文件示例:
Chi Song's avatar
Chi Song committed
160

Chi Song's avatar
Chi Song committed
161
```bash
Chi Song's avatar
Chi Song committed
162
163
164
#!/bin/bash
cd /tmp/user_name/nni/annotation/tmpzj0h72x6 #This is the actual directory
export NNI_PLATFORM=local
165
export NNI_SYS_DIR=/home/user_name/nni-experiments/$experiment_id$/trials/$trial_id$
Chi Song's avatar
Chi Song committed
166
export NNI_TRIAL_JOB_ID=nrbb2
167
export NNI_OUTPUT_DIR=/home/user_name/nni-experiments/$eperiment_id$/trials/$trial_id$
Chi Song's avatar
Chi Song committed
168
169
170
export NNI_TRIAL_SEQ_ID=1
export MULTI_PHASE=false
export CUDA_VISIBLE_DEVICES=
171
172
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
Chi Song's avatar
Chi Song committed
173
174
175
176
```

### 其它模式

177
当 Trial 运行在 OpenPAI 这样的远程服务器上时,`NNI_OUTPUT_DIR` 仅会指向 Trial 的输出目录,而 `run.sh` 不会在此目录中。 `trial.log` 文件会被复制回本机的 Trial 目录中。目录的默认位置在 `~/nni-experiments/$experiment_id$/trials/$trial_id$/`
Chi Song's avatar
Chi Song committed
178

Chi Song's avatar
Chi Song committed
179
详细信息,可参考[调试指南](../Tutorial/HowToDebug.md)
Chi Song's avatar
Chi Song committed
180

Chi Song's avatar
Chi Song committed
181
182
<a name="more-examples"></a>

Chi Song's avatar
Chi Song committed
183
## 更多 Trial 的示例
Chi Song's avatar
Chi Song committed
184

Chi Song's avatar
Chi Song committed
185
* [MNIST 示例](MnistExamples.md)
Chi Song's avatar
Chi Song committed
186
187
188
* [为 CIFAR 10 分类找到最佳的 optimizer](Cifar10Examples.md)
* [如何在 NNI 调优 SciKit-learn 的参数](SklearnExamples.md)
* [在阅读理解上使用自动模型架构搜索。](SquadEvolutionExamples.md)
189
* [如何在 NNI 上调优 GBDT](GbdtExample.md)
Chi Song's avatar
Chi Song committed
190
* [在 NNI 上调优 RocksDB](RocksdbExamples.md)