"...git@developer.sourcefind.cn:chenpangpang/open-webui.git" did not exist on "9755cd5baa367620f6b1f08ef0565498c505e10b"
Unverified Commit 704b50e2 authored by SparkSnail's avatar SparkSnail Committed by GitHub
Browse files

Merge pull request #200 from microsoft/master

merge master
parents 755ac5f0 3a6d1372
docs/img/webui-img/over1.png

67.7 KB | W: | H:

docs/img/webui-img/over1.png

61 KB | W: | H:

docs/img/webui-img/over1.png
docs/img/webui-img/over1.png
docs/img/webui-img/over1.png
docs/img/webui-img/over1.png
  • 2-up
  • Swipe
  • Onion skin
# 神经网络架构搜索的通用编程接口(测试版) # 神经网络架构搜索的通用编程接口(测试版)
** 这是一个测试中的功能,目前只实现了通用的 NAS 编程接口。 接下来的版本会基于此接口支持权重共享和 one-shot NAS* ** 这是一个测试中的功能,目前只实现了通用的 NAS 编程接口。 在随后的版本中会支持权重共享*
自动化的神经网络架构(NAS)搜索在寻找更好的模型方面发挥着越来越重要的作用。 最近的研究工作证明了自动化 NAS 的可行性,并发现了一些超越手动设计和调整的模型。 代表算法有 [NASNet](https://arxiv.org/abs/1707.07012)[ENAS](https://arxiv.org/abs/1802.03268)[DARTS](https://arxiv.org/abs/1806.09055)[Network Morphism](https://arxiv.org/abs/1806.10282),以及 [Evolution](https://arxiv.org/abs/1703.01041) 等。 新的算法还在不断涌现。 然而,实现这些算法需要很大的工作量,且很难重用其它算法的代码库来实现。 自动化的神经网络架构(NAS)搜索在寻找更好的模型方面发挥着越来越重要的作用。 最近的研究工作证明了自动化 NAS 的可行性,并发现了一些超越手动设计和调整的模型。 代表算法有 [NASNet](https://arxiv.org/abs/1707.07012)[ENAS](https://arxiv.org/abs/1802.03268)[DARTS](https://arxiv.org/abs/1806.09055)[Network Morphism](https://arxiv.org/abs/1806.10282),以及 [Evolution](https://arxiv.org/abs/1703.01041) 等。 新的算法还在不断涌现。 然而,实现这些算法需要很大的工作量,且很难重用其它算法的代码库来实现。
要促进 NAS 创新(例如,设计实现新的 NAS 模型,并列比较不同的 NAS 模型),易于使用且灵活的编程接口非常重要。 要促进 NAS 创新(例如,设计实现新的 NAS 模型,并列比较不同的 NAS 模型),易于使用且灵活的编程接口非常重要。
<a name="ProgInterface"></a>
## 编程接口 ## 编程接口
在两种场景下需要用于设计和搜索模型的新的编程接口。 1) 在设计神经网络时,层、子模型或连接有多个可能,并且不确定哪一个或哪种组合表现最好。 如果有一种简单的方法来表达想要尝试的候选层、子模型,将会很有价值。 2) 研究自动化 NAS 时,需要统一的方式来表达神经网络架构的搜索空间, 并在不改变 Trial 代码的情况下来使用不同的搜索算法。 在两种场景下需要用于设计和搜索模型的新的编程接口。 1) 在设计神经网络时,层、子模型或连接有多个可能,并且不确定哪一个或哪种组合表现最好。 如果有一种简单的方法来表达想要尝试的候选层、子模型,将会很有价值。 2) 研究自动化 NAS 时,需要统一的方式来表达神经网络架构的搜索空间, 并在不改变 Trial 代码的情况下来使用不同的搜索算法。
本文基于 [NNI Annotation](./AnnotationSpec.md) 实现了简单灵活的编程接口 。 通过以下示例来详细说明。 本文基于 [NNI Annotation](../Tutorial/AnnotationSpec.md) 实现了简单灵活的编程接口 。 通过以下示例来详细说明。
### 示例:为层选择运算符 ### 示例:为层选择运算符
在设计此模型时,第四层的运算符有多个可能的选择,会让模型有更好的表现。 如图所示,在模型代码中可以对第四层使用 Annotation。 此 Annotation 中,共有五个字段: 在设计此模型时,第四层的运算符有多个可能的选择,会让模型有更好的表现。 如图所示,在模型代码中可以对第四层使用 Annotation。 此 Annotation 中,共有五个字段:
![](../img/example_layerchoice.png) ![](../../img/example_layerchoice.png)
* **layer_choice**:它是函数调用的 list,每个函数都要在代码或导入的库中实现。 函数的输入参数格式为:`def XXX (input, arg2, arg3, ...)`,其中输入是包含了两个元素的 list。 其中一个是 `fixed_inputs` 的 list,另一个是 `optional_inputs` 中选择输入的 list。 `conv``pool` 是函数示例。 对于 list 中的函数调用,无需写出第一个参数(即 input)。 注意,只会从这些函数调用中选择一个来执行。 * **layer_choice**:它是函数调用的 list,每个函数都要在代码或导入的库中实现。 函数的输入参数格式为:`def XXX (input, arg2, arg3, ...)`,其中输入是包含了两个元素的 list。 其中一个是 `fixed_inputs` 的 list,另一个是 `optional_inputs` 中选择输入的 list。 `conv``pool` 是函数示例。 对于 list 中的函数调用,无需写出第一个参数(即 input)。 注意,只会从这些函数调用中选择一个来执行。
* **fixed_inputs** :它是变量的 list,可以是前一层输出的张量。 也可以是此层之前的另一个 `nni.mutable_layer``layer_output`,或此层之前的其它 Python 变量。 list 中的所有变量将被输入 `layer_choice` 中选择的函数(作为输入 list 的第一个元素)。 * **fixed_inputs** :它是变量的 list,可以是前一层输出的张量。 也可以是此层之前的另一个 `nni.mutable_layer``layer_output`,或此层之前的其它 Python 变量。 list 中的所有变量将被输入 `layer_choice` 中选择的函数(作为输入 list 的第一个元素)。
...@@ -32,34 +34,37 @@ ...@@ -32,34 +34,37 @@
设计层的连接对于制作高性能模型至关重要。 通过此接口,可选择一个层可以采用哪些连接来作为输入。 可以从一组连接中选择几个。 下面的示例从三个候选输入中为 `concat` 这个函数选择两个输入 。 `concat` 还会使用 `fixed_inputs` 获取其上一层的输出 。 设计层的连接对于制作高性能模型至关重要。 通过此接口,可选择一个层可以采用哪些连接来作为输入。 可以从一组连接中选择几个。 下面的示例从三个候选输入中为 `concat` 这个函数选择两个输入 。 `concat` 还会使用 `fixed_inputs` 获取其上一层的输出 。
![](../img/example_connectchoice.png) ![](../../img/example_connectchoice.png)
### 示例:同时选择运算符和连接 ### 示例:同时选择运算符和连接
此示例从三个运算符中选择一个,并为其选择两个连接作为输入。 由于输入会有多个变量,,在函数的开头需要调用 `concat` 此示例从三个运算符中选择一个,并为其选择两个连接作为输入。 由于输入会有多个变量,,在函数的开头需要调用 `concat`
![](../img/example_combined.png) ![](../../img/example_combined.png)
### 示例:[ENAS](https://arxiv.org/abs/1802.03268) 宏搜索空间 ### 示例:[ENAS](https://arxiv.org/abs/1802.03268) 宏搜索空间
为了证明编程接口带来的便利,使用该接口来实现 “ENAS + 宏搜索空间” 的 Trial 代码。 左图是 ENAS 论文中的宏搜索空间。 为了证明编程接口带来的便利,使用该接口来实现 “ENAS + 宏搜索空间” 的 Trial 代码。 左图是 ENAS 论文中的宏搜索空间。
![](../img/example_enas.png) ![](../../img/example_enas.png)
## 统一的 NAS 搜索空间说明 ## 统一的 NAS 搜索空间说明
通过上面的 Annotation 更新 Trial 代码后,即在代码中隐式指定了神经网络架构的搜索空间。 基于该代码,NNI 将自动生成一个搜索空间文件,可作为调优算法的输入。 搜索空间文件遵循以下 JSON 格式。 通过上面的 Annotation 更新 Trial 代码后,即在代码中隐式指定了神经网络架构的搜索空间。 基于该代码,NNI 将自动生成一个搜索空间文件,可作为调优算法的输入。 搜索空间文件遵循以下 JSON 格式。
```json ```javascript
{ {
"mutable_1": { "mutable_1": {
"layer_1": { "_type": "mutable_layer",
"layer_choice": ["conv(ch=128)", "pool", "identity"], "_value": {
"optional_inputs": ["out1", "out2", "out3"], "layer_1": {
"optional_input_size": 2 "layer_choice": ["conv(ch=128)", "pool", "identity"],
}, "optional_inputs": ["out1", "out2", "out3"],
"layer_2": { "optional_input_size": 2
... },
"layer_2": {
...
}
} }
} }
} }
...@@ -67,7 +72,7 @@ ...@@ -67,7 +72,7 @@
相应生成的神经网络结构(由调优算法生成)如下: 相应生成的神经网络结构(由调优算法生成)如下:
```json ```javascript
{ {
"mutable_1": { "mutable_1": {
"layer_1": { "layer_1": {
...@@ -83,47 +88,143 @@ ...@@ -83,47 +88,143 @@
通过对搜索空间格式和体系结构选择 (choice) 表达式的说明,可以自由地在 NNI 上实现神经体系结构搜索的各种或通用的调优算法。 接下来的工作会提供一个通用的 NAS 算法。 通过对搜索空间格式和体系结构选择 (choice) 表达式的说明,可以自由地在 NNI 上实现神经体系结构搜索的各种或通用的调优算法。 接下来的工作会提供一个通用的 NAS 算法。
## 支持 One-Shot NAS
One-Shot NAS 是流行的,能在有限的时间和资源预算内找到较好的神经网络结构的方法。 本质上,它会基于搜索空间来构建完整的图,并使用梯度下降最终找到最佳子图。 它有不同的训练方法,如:[training subgraphs (per mini-batch)](https://arxiv.org/abs/1802.03268)[training full graph through dropout](http://proceedings.mlr.press/v80/bender18a/bender18a.pdf),以及 [training with architecture weights (regularization)](https://arxiv.org/abs/1806.09055)
如上所示,NNI 支持通用的 NAS。 从用户角度来看,One-Shot NAS 和 NAS 具有相同的搜索空间规范,因此,它们可以使用相同的编程接口,只是在训练模式上有所不同。 NNI 提供了四种训练模式:
***classic_mode***: [上文](#ProgInterface)对此模式有相应的描述,每个子图是一个 Trial 任务。 要使用此模式,需要启用 NNI Annotation,并在 Experiment 配置文件中为 NAS 指定一个 Tuner。 [这里](https://github.com/microsoft/nni/tree/master/examples/trials/mnist-nas)是如何实现 Trial 和配置文件的例子。 [这里](https://github.com/microsoft/nni/tree/master/examples/tuners/random_nas_tuner)是一个简单的 NAS Tuner。
***enas_mode***: 参考 [ENAS 论文](https://arxiv.org/abs/1802.03268)的训练方法。 它基于神经网络架构搜索空间来构建全图,每个 mini-batch 只激活一个子图。 [详细说明](#ENASMode)。 (当前仅支持 TensorFlow)。
要使用 enas_mode,需要在配置的 `trial` 部分增加如下字段。
```diff
trial:
command: 运行 Trial 的命令
codeDir: Trial 代码的目录
gpuNum: 每个 Trial 所需要的 GPU 数量
+ #choice: classic_mode, enas_mode, oneshot_mode
+ nasMode: enas_mode
```
与 classic_mode 类似,在 enas_mode 中,需要为 NAS 指定 Tuner,其会从 Tuner(或者论文中的术语:Controller)中接收子图。 由于 Trial 任务要从 Tuner 中接收多个子图,每个子图用于一个 mini-batch,需要在 Trial 代码中增加两行来接收下一个子图(`nni.training_update`),并返回当前子图的结果。 示例如下:
```python
for _ in range(num):
# 接收并启用一个新的子图
"""@nni.training_update(tf=tf, session=self.session)"""
loss, _ = self.session.run([loss_op, train_op])
# 返回这个 mini-batch 的损失值
"""@nni.report_final_result(loss)"""
```
在这里,`nni.training_update`用来在全图上进行更新。 在 enas_mode 中,更新表示接收一个子图,并在下一个 mini-batch 中启用它。 在 darts_mode 中,更新表示训练架构权重(参考 darts_mode 中的详细说明)。 在 enas_mode 中,需要将导入的 TensorFlow 包传入 `tf`,并将会话传入 `session`
***oneshot_mode***: 遵循[论文](http://proceedings.mlr.press/v80/bender18a/bender18a.pdf)中的训练方法。 与 enas_mode 通过训练大量子图来训练全图有所不同,oneshot_mode 中构建了全图,并将 dropout 添加到候选的输入以及候选的输出操作中。 然后像其它深度学习模型一样进行训练。 [详细说明](#OneshotMode)。 (当前仅支持 TensorFlow)。
要使用 oneshot_mode,需要在配置的 `trial` 部分增加如下字段。 此模式不需要 Tuner,因此不用在配置文件中指定 Tuner。 (注意,当前仍然需要在配置文件中指定任一一个 Tuner。)此模式下也不需要添加 `nni.training_update`,因为在训练过程中不需要特别的更新过程。
```diff
trial:
command: 运行 Trial 的命令
codeDir: Trial 代码的目录
gpuNum: 每个 Trial 所需要的 GPU 数量
+ #choice: classic_mode, enas_mode, oneshot_mode
+ nasMode: oneshot_mode
```
***darts_mode***: 参考 [论文](https://arxiv.org/abs/1806.09055)中的训练方法。 与 oneshot_mode 类似。 有两个不同之处,首先 darts_mode 只将架构权重添加到候选操作的输出中,另外是交错的来训练模型权重和架构权重。 [详细说明](#DartsMode)
要使用 darts_mode,需要在配置的 `trial` 部分增加如下字段。 此模式不需要 Tuner,因此不用在配置文件中指定 Tuner。 (注意,当前仍需要在配置文件中指定任意一个 Tuner。)
```diff
trial:
command: 运行 Trial 的命令
codeDir: Trial 代码的目录
gpuNum: 每个 Trial 所需要的 GPU 数量
+ #choice: classic_mode, enas_mode, oneshot_mode
+ nasMode: darts_mode
```
在使用 darts_mode 时,需要按照如下所示调用 `nni.training_update`,来更新架构权重。 更新架构权重时,和训练数据一样也需要`损失值`(即, `feed_dict`)。
```python
for _ in range(num):
# 训练架构权重
"""@nni.training_update(tf=tf, session=self.session, loss=loss, feed_dict=feed_dict)"""
loss, _ = self.session.run([loss_op, train_op])
```
**注意**:对于 enas_mode、oneshot_mode、以及 darts_mode,NNI 仅能在训练阶段时有用。 NNI 不处理它们的推理阶段。 对于 enas_mode,推理阶段需要通过 Controller 来生成新的子图。 对于 oneshot_mode,推理阶段会随机采样生成新的子图,并选择其中好的子图。 对于 darts_mode,推理过程会根据架构权重来修剪掉一些候选的操作。
<a name="ENASMode"></a>
### enas_mode
在 enas_mode 中,编译后的 Trial 代码会构建完整的图形(而不是子图),会接收所选择的架构,并在完整的图形上对此体系结构进行小型的批处理训练,然后再请求另一个架构。 它通过 [NNI 多阶段 Experiment](./multiPhase.md) 来支持。
具体来说,使用 TensorFlow 的 Trial,通过 TensorFlow 变量来作为信号,并使用 TensorFlow 的条件函数来控制搜索空间(全图)来提高灵活性。这意味着根据这些信号,可以变为不同的多个子图。 [这是 enas_mode]() 的示例。
<a name="OneshotMode"></a>
### oneshot_mode
下图展示了 Dropout 通过 `nni.mutable_layers` 添加在全图的位置,输入的是 1-k 个候选输入,4 个操作是候选的操作。
![](../../img/oneshot_mode.png)
[论文](http://proceedings.mlr.press/v80/bender18a/bender18a.pdf)中的建议,应该为每层的输入实现 Dropout 方法。 当 0 < r < 1 是模型超参的取值范围(默认值为 0.01),k 是某层可选超参的数量,Dropout 比率设为 r^(1/k)。 fan-in 越高,每个输入被丢弃的可能性越大。 但某层丢弃所有可选输入的概率是常数,与 fan-in 无关。 假设 r = 0.05。 如果某层有 k = 2 个可选的输入,每个输入都会以独立的 0.051/2 ≈ 0.22 的概率被丢弃,也就是说有 0.78 的概率被保留。 如果某层有 k = 7 个可选的输入,每个输入都会以独立的 0.051/7 ≈ 0.65 的概率被丢弃,也就是说有 0.35 的概率被保留。 在这两种情况下,丢弃所有可选输入的概率是 5%。 候选操作的输出会通过同样的方法被丢弃。 [这里]()是 oneshot_mode 的示例。
<a name="DartsMode"></a>
### darts_mode
下图显示了通过 `nni.mutable_layers` 在全图中为某层加入架构权重,每个候选操作的输出会乘以架构权重。
![](../../img/darts_mode.png)
`nni.training_update` 中,TensorFlow 的 MomentumOptimizer 通过传递的 `loss``feed_dict` 来训练架构权重。 [这是 darts_mode]() 的示例。
### [**待实现**] One-Shot NAS 的多 Trial 任务。
One-Shot NAS 通常只有一个带有完整图的 Trial 任务。 但是,同时运行多个 Trial 任务会很有用。 例如,在 enas_mode 中,多个 Trial 任务可以共享全图的权重来加速模型训练或收敛。 一些 One-Shot 不够稳定,运行多个 Trial 任务可以提升找到更好模型的概率。
NNI 原生支持运行多个 Trial 任务。 下图显示了 NNI 上如何运行多个 Trial 任务。
![](../../img/one-shot_training.png)
============================================================= =============================================================
## 神经网络结构搜索在 NNI 上的应用 ## NNI 上 NAS 的系统设计
### Experiment 执行的基本流程 ### Experiment 执行的基本流程
NNI 的 Annotation 编译器会将 Trial 代码转换为可以接收架构选择并构建相应模型(如图)的代码。 NAS 的搜索空间可以看作是一个完整的图(在这里,完整的图意味着允许所有提供的操作符和连接来构建图),调优算法所选择的是其子图。 默认情况下,编译时 Trial 代码仅构建并执行子图。 NNI 的 Annotation 编译器会将 Trial 代码转换为可以接收架构选择并构建相应模型(如图)的代码。 NAS 的搜索空间可以看作是一个完整的图(在这里,完整的图意味着允许所有提供的操作符和连接来构建图),调优算法所选择的是其子图。 默认情况下,编译时 Trial 代码仅构建并执行子图。
![](../img/nas_on_nni.png) ![](../../img/nas_on_nni.png)
上图显示了 Trial 代码如何在 NNI 上运行。 `nnictl` 处理 Trial 代码,并生成搜索空间文件和编译后的 Trial 代码。 前者会输入 Tuner,后者会在 Trial 代码运行时使用。 上图显示了 Trial 代码如何在 NNI 上运行。 `nnictl` 处理 Trial 代码,并生成搜索空间文件和编译后的 Trial 代码。 前者会输入 Tuner,后者会在 Trial 代码运行时使用。
[使用 NAS 的简单示例](https://github.com/microsoft/nni/tree/v0.8/examples/trials/mnist-nas) [使用 NAS 的简单示例](https://github.com/microsoft/nni/tree/master/examples/trials/mnist-nas)
### [**待实现**] 权重共享 ### [**待实现**] 权重共享
在所选择的架构(即 Trial)之间共享权重可以加速模型搜索。 例如,适当地继承已完成 Trial 的权重可加速新 Trial 的收敛。 One-shot NAS(例如,ENAS,Darts)更为激进,不同架构(即子图)的训练会在完整图中共享相同的权重。 在所选择的架构(即 Trial)之间共享权重可以加速模型搜索。 例如,适当地继承已完成 Trial 的权重可加速新 Trial 的收敛。 One-shot NAS(例如,ENAS,Darts)更为激进,不同架构(即子图)的训练会在完整图中共享相同的权重。
![](../img/nas_weight_share.png) ![](../../img/nas_weight_share.png)
权重分配(转移)在加速 NAS 中有关键作用,而找到有效的权重共享方式仍是热门的研究课题。 NNI 提供了一个键值存储,用于存储和加载权重。 Tuner 和 Trial 使用 KV 客户端库来访问存储。 权重分配(转移)在加速 NAS 中有关键作用,而找到有效的权重共享方式仍是热门的研究课题。 NNI 提供了一个键值存储,用于存储和加载权重。 Tuner 和 Trial 使用 KV 客户端库来访问存储。
NNI 上的权重共享示例。 NNI 上的权重共享示例。
### [**待实现**] 支持 One-Shot NAS ## 通用的 NAS 调优算法
One-Shot NAS 是流行的,能在有限的时间和资源预算内找到较好的神经网络结构的方法。 本质上,它会基于搜索空间来构建完整的图,并使用梯度下降最终找到最佳子图。 它有不同的训练方法,如:[training subgraphs (per mini-batch)](https://arxiv.org/abs/1802.03268)[training full graph through dropout](http://proceedings.mlr.press/v80/bender18a/bender18a.pdf),以及 [training with architecture weights (regularization)](https://arxiv.org/abs/1806.09055) 。 这里会关注第一种方法,即训练子图(ENAS)。
使用相同 Annotation Trial 代码,可选择 One-Shot NAS 作为执行模式。 具体来说,编译后的 Trial 代码会构建完整的图形(而不是上面演示的子图),会接收所选择的架构,并在完整的图形上对此体系结构进行小型的批处理训练,然后再请求另一个架构。 它通过 [NNI 多阶段 Experiment](./multiPhase.md) 来支持。 因为子图训练非常快,而每次启动子图训练时都会产生开销,所以采用此方法。
![](../img/one-shot_training.png)
One-Shot NAS 的设计如上图所示。 One-Shot NAS 通常只有一个带有完整图的 Trial 任务。 NNI 支持运行多个此类 Trial 任务,每个任务都独立运行。 由于 One-Shot NAS 不够稳定,运行多个实例有助于找到更好的模型。 此外,Trial 任务之间也能在运行时同步权重(即,只有一份权重数据,如异步的参数 — 服务器模式)。 这样有可能加速收敛。
One-Shot NAS 示例。
## [**待实现**] NAS 的一般调优算法。
与超参数调优一样,NAS 也需要相对通用的算法。 通用编程接口使其更容易。 贡献者为 NAS 提供了基于 RL 的调参算法。 期待社区努力设计和实施更好的 NAS 调优算法。
NAS 的一般调优算法。 与超参数调优一样,NAS 也需要相对通用的算法。 通用编程接口使其更容易。 这是 NAS 上[基于 PPO 算法的 RL Tuner](https://github.com/microsoft/nni/tree/master/src/sdk/pynni/nni/ppo_tuner)。 期待社区努力设计和实施更好的 NAS 调优算法。
## [**待实现**] 导出最佳神经网络架构和代码 ## [**待实现**] 导出最佳神经网络架构和代码
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
## 创建多阶段的 Experiment ## 创建多阶段的 Experiment
### 编写使用多阶段的 Trial 代码: ### 实现使用多阶段的 Trial 代码:
**1. 更新 Trial 代码** **1. 更新 Trial 代码**
...@@ -33,13 +33,34 @@ Trial 代码中使用多阶段非常容易,样例如下: ...@@ -33,13 +33,34 @@ Trial 代码中使用多阶段非常容易,样例如下:
``` ```
**2. 修改 Experiment 配置** **2. Experiment 配置**
要启用多阶段,需要在 Experiment 的 YAML 配置文件中增加 `multiPhase: true`。 如果不添加此参数,`nni.get_next_parameter()` 会一直返回同样的配置。 对于所有内置的 Tuner 和 Advisor,不需要修改任何代码,就直接支持多阶段请求配置。 要启用多阶段,需要在 Experiment 的 YAML 配置文件中增加 `multiPhase: true`。 如果不添加此参数,`nni.get_next_parameter()` 会一直返回同样的配置。
多阶段 Experiment 配置示例:
authorName: default
experimentName: multiphase experiment
trialConcurrency: 2
maxExecDuration: 1h
maxTrialNum: 8
trainingServicePlatform: local
searchSpacePath: search_space.json
multiPhase: true
useAnnotation: false
tuner:
builtinTunerName: TPE
classArgs:
optimize_mode: maximize
trial:
command: python3 mytrial.py
codeDir: .
gpuNum: 0
### 编写使用多阶段的 Tuner: ### 实现使用多阶段的 Tuner:
强烈建议首先阅读[自定义 Tuner](https://nni.readthedocs.io/en/latest/Customize_Tuner.html),再开始编写多阶段 Tuner。 与普通 Tuner 一样,需要从 `Tuner` 类继承。 当通过配置启用多阶段时(将 `multiPhase` 设为 true),Tuner 会通过下列方法得到一个新的参数 `trial_job_id` 强烈建议首先阅读[自定义 Tuner](https://nni.readthedocs.io/zh/latest/Tuner/CustomizeTuner.html),再开始实现多阶段 Tuner。 与普通 Tuner 一样,需要从 `Tuner` 类继承。 当通过配置启用多阶段时(将 `multiPhase` 设为 true),Tuner 会通过下列方法得到一个新的参数 `trial_job_id`
generate_parameters generate_parameters
generate_multiple_parameters generate_multiple_parameters
...@@ -50,6 +71,10 @@ Trial 代码中使用多阶段非常容易,样例如下: ...@@ -50,6 +71,10 @@ Trial 代码中使用多阶段非常容易,样例如下:
有了这个信息, Tuner 能够知道哪个 Trial 在请求配置信息, 返回的结果是哪个 Trial 的。 通过此信息,Tuner 能够灵活的为不同的 Trial 及其阶段实现功能。 例如,可在 generate_parameters 方法中使用 trial_job_id 来为特定的 Trial 任务生成超参。 有了这个信息, Tuner 能够知道哪个 Trial 在请求配置信息, 返回的结果是哪个 Trial 的。 通过此信息,Tuner 能够灵活的为不同的 Trial 及其阶段实现功能。 例如,可在 generate_parameters 方法中使用 trial_job_id 来为特定的 Trial 任务生成超参。
当然,要使用自定义的多阶段 Tuner ,也需要**在 Experiment 的 YAML 配置文件中增加`multiPhase: true`** ### 支持多阶段 Experiment 的 Tuner:
[TPE](../Tuner/HyperoptTuner.md), [Random](../Tuner/HyperoptTuner.md), [Anneal](../Tuner/HyperoptTuner.md), [Evolution](../Tuner/EvolutionTuner.md), [SMAC](../Tuner/SmacTuner.md), [NetworkMorphism](../Tuner/NetworkmorphismTuner.md), [MetisTuner](../Tuner/MetisTuner.md), [BOHB](../Tuner/BohbAdvisor.md), [Hyperband](../Tuner/HyperbandAdvisor.md), [ENAS Tuner ](https://github.com/countif/enas_nni/blob/master/nni/examples/tuners/enas/nni_controller_ptb.py).
### 支持多阶段 Experiment 的训练平台:
[ENAS Tuner](https://github.com/countif/enas_nni/blob/master/nni/examples/tuners/enas/nni_controller_ptb.py) 是多阶段 Tuner 的样例。 [本机](../TrainingService/LocalMode.md), [远程计算机](../TrainingService/RemoteMachineMode.md), [OpenPAI](../TrainingService/PaiMode.md)
\ No newline at end of file \ No newline at end of file
...@@ -6,15 +6,15 @@ Curve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学 ...@@ -6,15 +6,15 @@ Curve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学
此算法中,使用了 12 条曲线来拟合学习曲线,从[参考论文](http://aad.informatik.uni-freiburg.de/papers/15-IJCAI-Extrapolation_of_Learning_Curves.pdf)中选择了大量的参数曲线模型。 学习曲线的形状与先验知识是一致的:都是典型的递增的、饱和的函数。 此算法中,使用了 12 条曲线来拟合学习曲线,从[参考论文](http://aad.informatik.uni-freiburg.de/papers/15-IJCAI-Extrapolation_of_Learning_Curves.pdf)中选择了大量的参数曲线模型。 学习曲线的形状与先验知识是一致的:都是典型的递增的、饱和的函数。
![](../img/curvefitting_learning_curve.PNG) ![](../../img/curvefitting_learning_curve.PNG)
所有学习曲线模型被合并到了单个,更强大的模型中。 合并的模型通过加权线性混合: 所有学习曲线模型被合并到了单个,更强大的模型中。 合并的模型通过加权线性混合:
![](../img/curvefitting_f_comb.gif) ![](../../img/curvefitting_f_comb.gif)
合并后的参数向量 合并后的参数向量
![](../img/curvefitting_expression_xi.gif) ![](../../img/curvefitting_expression_xi.gif)
假设增加一个高斯噪声,且噪声参数初始化为最大似然估计。 假设增加一个高斯噪声,且噪声参数初始化为最大似然估计。
...@@ -30,7 +30,7 @@ Curve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学 ...@@ -30,7 +30,7 @@ Curve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学
下图显示了此算法在 MNIST Trial 历史数据上结果。其中绿点表示 Assessor 获得的数据,蓝点表示将来,但未知的数据,红色线条是 Curve fitting Assessor 的预测曲线。 下图显示了此算法在 MNIST Trial 历史数据上结果。其中绿点表示 Assessor 获得的数据,蓝点表示将来,但未知的数据,红色线条是 Curve fitting Assessor 的预测曲线。
![](../img/curvefitting_example.PNG) ![](../../img/curvefitting_example.PNG)
## 2. 用法 ## 2. 用法
......
...@@ -56,5 +56,5 @@ assessor: ...@@ -56,5 +56,5 @@ assessor:
更多样例,可参考: 更多样例,可参考:
> - [medianstop-assessor](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/medianstop_assessor) > * [medianstop-assessor](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/medianstop_assessor)
> - [curvefitting-assessor](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/curvefitting_assessor) > * [curvefitting-assessor](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/curvefitting_assessor)
\ No newline at end of file \ No newline at end of file
...@@ -6,15 +6,15 @@ ...@@ -6,15 +6,15 @@
超参数优化算法如下: 超参数优化算法如下:
- [Random Search(随机搜索)](../BuiltinTuner.md) - [Random Search(随机搜索)](../Tuner/BuiltinTuner.md)
- [Grid Search(遍历搜索)](../BuiltinTuner.md) - [Grid Search(遍历搜索)](../Tuner/BuiltinTuner.md)
- [Evolution](../BuiltinTuner.md) - [Evolution](../Tuner/BuiltinTuner.md)
- [Anneal(退火算法)](../BuiltinTuner.md) - [Anneal(退火算法)](../Tuner/BuiltinTuner.md)
- [Metis](../BuiltinTuner.md) - [Metis](../Tuner/BuiltinTuner.md)
- [TPE](../BuiltinTuner.md) - [TPE](../Tuner/BuiltinTuner.md)
- [SMAC](../BuiltinTuner.md) - [SMAC](../Tuner/BuiltinTuner.md)
- [HyperBand](../BuiltinTuner.md) - [HyperBand](../Tuner/BuiltinTuner.md)
- [BOHB](../BuiltinTuner.md) - [BOHB](../Tuner/BuiltinTuner.md)
所有算法都在 NNI 本机环境下运行。 所有算法都在 NNI 本机环境下运行。
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
### 问题描述 ### 问题描述
超参搜索上的非凸问题 [AutoGBDT](../gbdt_example.md) 超参搜索上的非凸问题 [AutoGBDT](../TrialExample/GbdtExample.md)
### 搜索空间 ### 搜索空间
......
# 并行化顺序算法:TPE
为了利用多个计算节点,TPE 方法是异步运行的,这样能避免浪费时间等待 Trial 评估的完成。 TPE 方法使用了叫做 constant liar 的方法:每次候选点 x* 生成时,会临时分配一个假的评估结果 y。在评估完成后,用返回的真实损失值 f(x*) 来替换假的评估结果。
## 介绍和问题
### 基于顺序模型的全局优化
基于顺序模型的全局优化(SMBO)算法已经用于许多应用中,但适应度函数的评估成本比较高。 在应用中,真实的适应度函数 f: X → R 评估成本较高,通过采用基于模型算法近似的 f 来替代,可降低其评估成本。 通常,在 SMBO 算法内层循环是用数值优化或其它转换方式来替代。 点 x* 最大化的替代项(或它的转换形式)作为真实函数 f 评估的替代值。 这种类似于主动学习的算法模板总结如下。 SMBO 算法的不同之处在于,给定一个 f 的模型(或替代项)的情况下,获得 x* 的优化的标准,以及通过观察历史 H 来模拟 f。
![](../../img/parallel_tpe_search4.PNG)
本算法优化了预期改进(Expected Improvement,EI)的标准。 其它建议的标准包括,概率改进(Probability of Improvement)、预期改进(Expected Improvement)最小化条件熵(minimizing the Conditional Entropy of the Minimizer)、以及 bandit-based 的标准。 在 TPE 中考虑到直观,选择了 EI,其在多种设置下都展示了较好的效果。 预期改进(EI)是在模型 M 下,当 f(x) (负向)超过某个阈值 y* 时,对 f 的预期:X → RN。
![](../../img/parallel_tpe_search_ei.PNG)
由于 p(y|x) 计算成本较高,TPE 通过 p(x|y) 和 p(y) 来为 p(y|x) 建模。TPE 通过下列两个密度来定义 p(x|y):
![](../../img/parallel_tpe_search_tpe.PNG)
l(x) 是通过观察 {x(i)} 来形成的密度,使得相应的损失 f(x(i)) 小于 y∗,而 g(x) 是使用剩余的观测值来形成的密度。 TPE 算法取决于 y∗ 大于观测到的最好的 f(x),这样可以使用一些点来形成 l(x)。 TPE 算法选择了 y* 来作为一些观测值 y 的分位数 γ,因此 p(y<`y∗`) = γ,但不需要为特定的 p(y) 建模。 l 和 g 的树形结构使得根据 l 来计算多个候选项变得容易,可根据 g(x)/l(x) 来进行评估。 在每次迭代中,算法返回了具有最大 EI 的候选 x*
这是 TPE 算法在二维搜索空间上的模拟。 不同的背景色表示了不同的值。 可以看出,TPE 在探索(exploration)和挖掘(exploitation)方面的表现都很好。 (黑色表示此轮样本的点,黄色表示历史点。)
![](../../img/parallel_tpe_search1.gif)
**由于 EI 是连续函数,因此 EI 的最高 x 在某个状态下是确定的 。** 如下图所示,蓝色三角形表示在当前状态下最有可能进行采样的点。
![](../../img/parallel_tpe_search_ei2.PNG)
TPE 在顺序执行时表现很好,但当并发性较大时,会**在相同的 EI 状态下产生大量的点**,过于集中的点会减少 Tuner 探索的能力,造成了资源的浪费。
这是当 `concurrency=60` 时的模拟图,这种现象非常明显。
![](../../img/parallel_tpe_search2.gif)
## 研究的解决方案
### 近似 q-EI 最大化
下面介绍的多点标准的新的 Experiment 设计一步解决此优化问题。
![](../../img/parallel_tpe_search_qEI.PNG)
但是,当 q 增加时,q-EI 的计算变得很密集。 研究发现,四种流行的贪心策略可在解决此问题时,减少计算成本。
#### 方案 1: Believing the OK Predictor: KB(Kriging Believer) 启发式策略
Kriging Believer 策略用等价于 Kriging 预测期望值的确定性值替换在最后一次迭代中选择的位置的响应的条件知识。 保持与上次相同的记号,此策略可归纳如下:
![](../../img/parallel_tpe_search_kb.PNG)
这种顺序策略使用了 q-points 设计,在计算量上是可承受的,因为它依赖于分析已知的 EI,在 d 维上进行了优化。 但此方法有失败的风险,因为相信 OK Predictor 可以预测超过观察到的数据,可能导致多轮迭代中的序列会陷入非最优区域。 第二种策略可降低这种风险。
#### 方案 2: CL(Constant Liar) 启发式策略
考虑一种顺序策略,在每次迭代时会更新元模型(但不会重新估计超参),其中值 L 来自外部固定值,称为”lie(谎言)”。 Constant Liar 策略在每次迭代时使用相同的值 L:最大化 EI(即找到 xn+1),将模型实现为 y(xn+1) = L,始终使用 L∈R:
![](../../img/parallel_tpe_search_cl.PNG)
L 应在逻辑上根据 y 在 X 处获取的值来确定,可考虑使用的三个值:min{Y}, mean{Y}, 以及 max{Y}。 **L 越大,算法的探索性就越大,反之亦然。**
根据上述方法进行模拟。 下图显示了使用均值 liar,来最大化 q-EI。 能看到这些点开始分散了。
![](../../img/parallel_tpe_search3.gif)
## Experiment
### Branin-Hoo
最后一章介绍的四种优化方法通过 Branin-Hoo 函数进行了比较,这是全局优化中的经典测试用例。
![](../../img/parallel_tpe_search_branin.PNG)
a, b, c, r, s 以及 t 的推荐值分别为:a = 1, b = 5.1 ⁄ (4π2), c = 5 ⁄ π, r = 6, s = 10, t = 1 ⁄ (8π)。 此函数有三个全局最小值点 (-3.14, 12.27), (3.14, 2.27), (9.42, 2.47)。
下表为给定 constant liar 策略(最小、最大值)下,比较了前 q 个点(q ∈ [1,10])。每个 q 绘制 2000 个 q 点,这 2000 个 q 点随机采用 LHS。
![](../../img/parallel_tpe_search_result.PNG)
正如图中所见,,CL[max] 和 CL[min] 与随机相比,产生了更好的 q-EI 结果,尤其是 q 值很小时。
### 高斯混合模型函数(Gaussian Mixed Model function)
以下比较了使用和不使用并行优化的情况。 二维多模的高斯混合分布的模拟结果如下:
| | concurrency=80 | concurrency=60 | concurrency=40 | concurrency=20 | concurrency=10 |
| ------- | ---------------------------- | ---------------------------- | ---------------------------- | ---------------------------- | ---------------------------- |
| 未使用并行优化 | avg = 0.4841
var = 0.1953 | avg = 0.5155
var = 0.2219 | avg = 0.5773
var = 0.2570 | avg = 0.4680
var = 0.1994 | avg = 0.2774
var = 0.1217 |
| 使用了并行优化 | avg = 0.2132
var = 0.0700 | avg = 0.2177
var = 0.0796 | avg = 0.1835
var = 0.0533 | avg = 0.1671
var = 0.0413 | avg = 0.1918
var = 0.0697 |
注意:每次测试的样本总数为 240(确保成本相等)。 每种形式下的 Trial 重复了 1000 次,表中值为 1000 个 Trial 中最好结果的平均值和方差。
## 参考
[1] James Bergstra, Remi Bardenet, Yoshua Bengio, Balazs Kegl. "Algorithms for Hyper-Parameter Optimization". [链接](https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf)
[2] Meng-Hiot Lim, Yew-Soon Ong. "Computational Intelligence in Expensive Optimization Problems". [链接](https://link.springer.com/content/pdf/10.1007%2F978-3-642-10701-6.pdf)
[3] M. Jordan, J. Kleinberg, B. Scho¨lkopf. "Pattern Recognition and Machine Learning". [链接](http://users.isr.ist.utl.pt/~wurmd/Livros/school/Bishop%20-%20Pattern%20Recognition%20And%20Machine%20Learning%20-%20Springer%20%202006.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