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

Update Chinese documents (#3243)

parent 53b565e4
DARTS
=====
介绍
------------
这篇论文 `DARTS: Differentiable Architecture Search <https://arxiv.org/abs/1806.09055>`__ 通过以可区分的方式制定任务来解决体系结构搜索的可伸缩性挑战。 此方法基于架构的连续放松的表示,从而允许在架构搜索时能使用梯度下降。
作者的代码可以在小批量中交替优化网络权重和体系结构权重。 还进一步探讨了使用二阶优化(unroll)来替代一阶,来提高性能的可能性。
NNI 的实现是基于 `官方实现 <https://github.com/quark0/darts>`__ 和 `热门的第三方 repo <https://github.com/khanrc/pt.darts>`__。 NNI 上的 DARTS 设计为可用于任何搜索空间。 与原始论文一样,为 CIFAR10 实现了 CNN 的搜索空间,来作为 DARTS 的实际示例。
重现结果
--------------------
上述示例旨在重现本文中的结果,我们进行了一阶和二阶优化实验。 由于时间限制,我们仅从第二阶段重新训练了 *一次最佳架构*。 我们的结果目前与论文的结果相当。 稍后会增加更多结果
.. list-table::
:header-rows: 1
:widths: auto
* -
- 论文中
- 重现
* - 一阶(CIFAR10)
- 3.00 +/- 0.14
- 2.78
* - 二阶(CIFAR10)
- 2.76 +/- 0.09
- 2.80
示例
--------
CNN 搜索空间
^^^^^^^^^^^^^^^^
:githublink:`示例代码 <examples/nas/darts>`
.. code-block:: bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最优结构
cd examples/nas/darts
python3 search.py
# 训练最优结构
python3 retrain.py --arc-checkpoint ./checkpoints/epoch_49.json
参考
---------
PyTorch
^^^^^^^
.. autoclass:: nni.algorithms.nas.pytorch.darts.DartsTrainer
:members:
.. autoclass:: nni.algorithms.nas.pytorch.darts.DartsMutator
:members:
局限性
-----------
* DARTS 不支持 DataParallel,若要支持 DistributedDataParallel,则需要定制。
# ENAS
## 介绍
论文 [Efficient Neural Architecture Search via Parameter Sharing](https://arxiv.org/abs/1802.03268) 通过在子模型之间共享参数来加速 NAS 过程。 在 ENAS 中,Contoller 学习在大的计算图中搜索最有子图的方式来发现神经网络。 Controller 通过梯度策略训练,从而选择出能在验证集上有最大期望奖励的子图。 同时对与所选子图对应的模型进行训练,以最小化规范交叉熵损失。
NNI 基于官方的 [Tensorflow](https://github.com/melodyguan/enas) 实现,包括通用的强化学习的 Controller,以及能交替训练目标网络和 Controller 的 Trainer。 根据论文,也对 CIFAR10 实现了 Macro 和 Micro 搜索空间来展示如何使用 Trainer。 NNI 中从头训练的代码还未完成,当前还没有重现结果。
## 示例
### CIFAR10 Macro/Micro 搜索空间
[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/enas)
```bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最好的网络架构
cd examples/nas/enas
# 在 Macro 搜索空间中搜索
python3 search.py --search-for macro
# 在 Micro 搜索空间中搜索
python3 search.py --search-for micro
# 查看更多选项
python3 search.py -h
```
## 参考
### PyTorch
```eval_rst
.. autoclass:: nni.nas.pytorch.enas.EnasTrainer
:members:
.. autoclass:: nni.nas.pytorch.enas.EnasMutator
:members:
```
ENAS
====
介绍
------------
`Efficient Neural Architecture Search via Parameter Sharing <https://arxiv.org/abs/1802.03268>`__ 这篇论文使用子模型之间的参数共享来加速NAS进程。 在 ENAS 中,Contoller 学习在大的计算图中搜索最有子图的方式来发现神经网络。 Controller 通过梯度策略训练,从而选择出能在验证集上有最大期望奖励的子图。 同时对与所选子图对应的模型进行训练,以最小化规范交叉熵损失。
NNI 基于官方的 `Tensorflow <https://github.com/melodyguan/enas>`_ 实现,包括通用的强化学习的 Controller,以及能交替训练目标网络和 Controller 的 Trainer。 根据论文,也对 CIFAR10 实现了 Macro 和 Micro 搜索空间来展示如何使用 Trainer。 NNI 中从头训练的代码还未完成,当前还没有重现结果。
示例
--------
CIFAR10 Macro/Micro 搜索空间
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
:githublink:`示例代码 <examples/nas/enas>`
.. code-block:: bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最优结构
cd examples/nas/enas
# 在 macro 搜索空间中搜索
python3 search.py --search-for macro
# 在 micro 搜索空间中搜索
python3 search.py --search-for micro
# 查看更多的搜索选择
python3 search.py -h
参考
---------
PyTorch
^^^^^^^
.. autoclass:: nni.algorithms.nas.pytorch.enas.EnasTrainer
:members:
.. autoclass:: nni.algorithms.nas.pytorch.enas.EnasMutator
:members:
# One-Shot NAS algorithms
除了 [经典 NAS 算法](./ClassicNas.md),还可以使用更先进的 One-Shot NAS 算法来从搜索空间中找到更好的模型。 One-Shot NAS 算法已有了大量的相关工作,如 [SMASH](https://arxiv.org/abs/1708.05344), [ENAS](https://arxiv.org/abs/1802.03268), [DARTS](https://arxiv.org/abs/1808.05377), [FBNet](https://arxiv.org/abs/1812.03443), [ProxylessNAS](https://arxiv.org/abs/1812.00332), [SPOS](https://arxiv.org/abs/1904.00420), [Single-Path NAS](https://arxiv.org/abs/1904.02877), [Understanding One-shot](http://proceedings.mlr.press/v80/bender18a) 以及 [GDAS](https://arxiv.org/abs/1910.04465)。 One-Shot NAS 算法通常会构建一个超网络,其中包含的子网作为此搜索空间的候选项。每一步,会训练一个或多个子网的组合。
当前,NNI 支持数种 One-Shot 方法。 例如,`DartsTrainer` 使用 SGD 来交替训练架构和模型权重,`ENASTrainer` [使用 Controller 来训练模型](https://arxiv.org/abs/1802.03268)。 新的、更高效的 NAS Trainer 在研究界不断的涌现出来,NNI 会在将来的版本中实现其中的一部分。
## 使用 One-Shot NAS 算法进行搜索
每个 One-Shot NAS 算法都实现了 Trainer,可在每种算法说明中找到详细信息。 这是如何使用 `EnasTrainer` 的简单示例。
```python
# 此处与普通模型训练相同
model = Net()
dataset_train = CIFAR10(root="./data", train=True, download=True, transform=train_transform)
dataset_valid = CIFAR10(root="./data", train=False, download=True, transform=valid_transform)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), 0.05, momentum=0.9, weight_decay=1.0E-4)
# 使用 NAS
def top1_accuracy(output, target):
# ENAS 使用此函数来计算奖励
batch_size = target.size(0)
_, predicted = torch.max(output.data, 1)
return (predicted == target).sum().item() / batch_size
def metrics_fn(output, target):
# 指标函数接收输出和目标,并计算出指标 dict
return {"acc1": top1_accuracy(output, target)}
from nni.nas.pytorch import enas
trainer = enas.EnasTrainer(model,
loss=criterion,
metrics=metrics_fn,
reward_function=top1_accuracy,
optimizer=optimizer,
batch_size=128
num_epochs=10, # 10 epochs
dataset_train=dataset_train,
dataset_valid=dataset_valid,
log_frequency=10) # 每 10 步打印
trainer.train() # 训练
trainer.export(file="model_dir/final_architecture.json") # 将最终架构导出到文件
```
`model` 是一个[用户定义的搜索空间](./WriteSearchSpace.md)。 然后需要准备搜索数据和模型评估指标。 要从定义的搜索空间中进行搜索,需要实例化 One-Shot 算法,即 Trainer(如,EnasTrainer)。 Trainer 会提供一些可以自定义的参数。 如,损失函数,指标函数,优化器以及数据集。 这些功能可满足大部分需求,NNI 会尽力让内置 Trainer 能够处理更多的模型、任务和数据集。
**注意**,在使用 One-Shot NAS 算法时,不需要启动 NNI Experiment。 不需要 `nnictl`,可直接运行 Python 脚本(即:`train.py`),如:`python3 train.py`。 训练完成后,可通过 `trainer.export()` 导出找到的最好的模型。
NNI 中每个 Trainer 都用其对应的场景和用法。 一些 Trainer 假定任务是分类任务;一些 Trainer 对 "epoch" 有不同的定义(如:ENAS 的每个 Epoch 是 一些子步骤加上 Controller 的步骤)。 大部分 Trainer 不支持分布式训练:没有使用 `DataParallel``DistributedDataParallel` 来包装模型。 因此,在试用后,如果要在自己的应用中使用 Trainer,需要[自定义 Trainer](./Advanced.md#extend-the-ability-of-one-shot-trainers)
此外,可以使用 NAS 可视化来显示 One-Shot NAS。 [了解详情](./Visualization.md)
### 使用导出的架构重新训练
搜索阶段后,就该训练找到的架构了。 与很多开源 NAS 算法不同,它们为重新训练专门写了新的模型。 实际上搜索模型和重新训练模型的过程非常相似,因而可直接将一样的模型代码用到最终模型上。 例如
```python
model = Net()
apply_fixed_architecture(model, "model_dir/final_architecture.json")
```
此 JSON 是从 Mutable 键值到 Choice 的映射。 Choice 可为:
* string: 根据名称来指定候选项。
* number: 根据索引来指定候选项。
* string 数组: 根据名称来指定候选项。
* number 数组: 根据索引来指定候选项。
* boolean 数组: 可直接选定多项的数组。
例如:
```json
{
"LayerChoice1": "conv5x5",
"LayerChoice2": 6,
"InputChoice3": ["layer1", "layer3"],
"InputChoice4": [1, 2],
"InputChoice5": [false, true, false, false, true]
}
```
应用后,模型会被固定,并准备好进行最终训练。 该模型作为单独的模型来工作,未使用的参数和模块已被剪除。
也可参考 [DARTS](./DARTS.md) 的重新训练代码。
One-Shot NAS 算法
=======================
除了 `经典 NAS 算法 <./ClassicNas.rst>`_,还可以使用更先进的 One-Shot NAS 算法来从搜索空间中找到更好的模型。 One-Shot NAS 算法已有了大量的相关工作,如 `SMASH <https://arxiv.org/abs/1708.05344>`__\ , `ENAS <https://arxiv.org/abs/1802.03268>`__\ , `DARTS <https://arxiv.org/abs/1808.05377>`__\ , `FBNet <https://arxiv.org/abs/1812.03443>`__\ , `ProxylessNAS <https://arxiv.org/abs/1812.00332>`__\ , `SPOS <https://arxiv.org/abs/1904.00420>`__\ , `Single-Path NAS <https://arxiv.org/abs/1904.02877>`__\ , `Understanding One-shot <http://proceedings.mlr.press/v80/bender18a>`__ and `GDAS <https://arxiv.org/abs/1910.04465>`__ One-Shot NAS 算法通常会构建一个超网络,其中包含的子网作为此搜索空间的候选项。每一步,会训练一个或多个子网的组合。
当前,NNI 支持数种 One-Shot 方法。 例如,``DartsTrainer`` 使用 SGD 迭代训练体系结构权重和模型权重,``ENASTrainer`` `使用控制器训练模型 <https://arxiv.org/abs/1802.03268>`__ 新的、更高效的 NAS Trainer 在研究界不断的涌现出来,NNI 会在将来的版本中实现其中的一部分。
使用 One-Shot NAS 算法进行搜索
-----------------------------------
每个 One-Shot NAS 算法都实现了 Trainer,可在每种算法说明中找到详细信息。 这是如何使用 ``EnasTrainer`` 的简单示例。
.. code-block:: python
# 与传统模型训练完全相同
model = Net()
dataset_train = CIFAR10(root="./data", train=True, download=True, transform=train_transform)
dataset_valid = CIFAR10(root="./data", train=False, download=True, transform=valid_transform)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), 0.05, momentum=0.9, weight_decay=1.0E-4)
# 这里使用 NAS
def top1_accuracy(output, target):
# 这是ENAS算法要求的计算奖励的函数
batch_size = target.size(0)
_, predicted = torch.max(output.data, 1)
return (predicted == target).sum().item() / batch_size
def metrics_fn(output, target):
# metrics 函数接收 output target 并计算出 dict metrics
return {"acc1": top1_accuracy(output, target)}
from nni.algorithms.nas.pytorch import enas
trainer = enas.EnasTrainer(model,
loss=criterion,
metrics=metrics_fn,
reward_function=top1_accuracy,
optimizer=optimizer,
batch_size=128
num_epochs=10, # 10 epochs
dataset_train=dataset_train,
dataset_valid=dataset_valid,
log_frequency=10) # 10s 打印一次 log
trainer.train() # training
trainer.export(file="model_dir/final_architecture.json") # 把最终的架构导出到文件
``model`` `具有用户定义搜索空间的模型 <./WriteSearchSpace.rst>`__ 然后需要准备搜索数据和模型评估指标。 要从定义的搜索空间中进行搜索,需要实例化 One-Shot 算法,即 Trainer(如,EnasTrainer)。 Trainer 会提供一些可以自定义的参数。 如,损失函数,指标函数,优化器以及数据集。 这些功能可满足大部分需求,NNI 会尽力让内置 Trainer 能够处理更多的模型、任务和数据集。
**注意** ,在使用 One-Shot NAS 算法时,不需要启动 NNI Experiment 不需要 ``nnictl`` ,可直接运行 Python 脚本(即:``train.py`` ),如:``python3 train.py`` 训练完成后,可通过 ``trainer.export()`` 导出找到的最好的模型。
NNI 中每个 Trainer 都用其对应的场景和用法。 一些 Trainer 假定任务是分类任务;一些 Trainer "epoch" 有不同的定义(如:ENAS 的每个 Epoch 一些子步骤加上 Controller 的步骤)。 大部分 Trainer 不支持分布式训练:没有使用 ``DataParallel`` ``DistributedDataParallel`` 来包装模型。 如果通过试用,想要在定制的应用中使用 Trainer,可能需要 `自定义 Trainer <./Advanced.rst>`__
此外,可以使用 NAS 可视化来显示 One-Shot NAS `请看细节。 <./Visualization.rst>`__
使用导出的架构重新训练
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
搜索阶段后,就该训练找到的架构了。 与很多开源 NAS 算法不同,它们为重新训练专门写了新的模型。 我们发现搜索模型和重新训练模型的过程非常相似,因而可直接将一样的模型代码用到最终模型上。 例如:
.. code-block:: python
model = Net()
apply_fixed_architecture(model, "model_dir/final_architecture.json")
JSON 是从 Mutable 键值到 Choice 的映射。 Choice 可为:
* string: 根据名称来指定候选项。
* number: 根据索引来指定候选项。
* string 数组: 根据名称来指定候选项。
* number 数组: 根据索引来指定候选项。
* boolean 数组: 可直接选定多项的数组。
例如:
.. code-block:: json
{
"LayerChoice1": "conv5x5",
"LayerChoice2": 6,
"InputChoice3": ["layer1", "layer3"],
"InputChoice4": [1, 2],
"InputChoice5": [false, true, false, false, true]
}
应用后,模型会被固定,并准备好进行最终训练。 该模型作为单独的模型来工作,未使用的参数和模块已被剪除。
也可参考 `DARTS <./DARTS.rst>`__ 的重新训练代码。
# NAS 参考
NAS 参考
=============
```eval_rst
.. contents::
```
## Mutable
Mutables
--------
```eval_rst
.. autoclass:: nni.nas.pytorch.mutables.Mutable
:members:
......@@ -18,71 +17,64 @@
.. autoclass:: nni.nas.pytorch.mutables.MutableScope
:members:
```
### 工具
工具
^^^^^^^^^
```eval_rst
.. autofunction:: nni.nas.pytorch.utils.global_mutable_counting
```
## Mutator
Mutator
--------
```eval_rst
.. autoclass:: nni.nas.pytorch.base_mutator.BaseMutator
:members:
.. autoclass:: nni.nas.pytorch.mutator.Mutator
:members:
```
### Random Mutator
Random Mutator
^^^^^^^^^^^^^^
```eval_rst
.. autoclass:: nni.nas.pytorch.random.RandomMutator
.. autoclass:: nni.algorithms.nas.pytorch.random.RandomMutator
:members:
```
### 工具
工具
^^^^^^^^^
```eval_rst
.. autoclass:: nni.nas.pytorch.utils.StructuredMutableTreeNode
:members:
```
## Trainer
Trainer
--------
### Trainer
Trainer
^^^^^^^
```eval_rst
.. autoclass:: nni.nas.pytorch.base_trainer.BaseTrainer
:members:
.. autoclass:: nni.nas.pytorch.trainer.Trainer
:members:
```
### 重新训练
重新训练
^^^^^^^^^^^
```eval_rst
.. autofunction:: nni.nas.pytorch.fixed.apply_fixed_architecture
.. autoclass:: nni.nas.pytorch.fixed.FixedArchitecture
:members:
```
### 分布式 NAS
分布式 NAS
^^^^^^^^^^^^^^^
```eval_rst
.. autofunction:: nni.nas.pytorch.classic_nas.get_and_apply_next_architecture
.. autofunction:: nni.algorithms.nas.pytorch.classic_nas.get_and_apply_next_architecture
.. autoclass:: nni.nas.pytorch.classic_nas.mutator.ClassicMutator
.. autoclass:: nni.algorithms.nas.pytorch.classic_nas.mutator.ClassicMutator
:members:
```
### 回调
回调
^^^^^^^^^
```eval_rst
.. autoclass:: nni.nas.pytorch.callbacks.Callback
:members:
......@@ -94,11 +86,10 @@
.. autoclass:: nni.nas.pytorch.callbacks.ModelCheckpoint
:members:
```
### 工具
工具
^^^^^^^^^
```eval_rst
.. autoclass:: nni.nas.pytorch.utils.AverageMeterGroup
:members:
......@@ -106,4 +97,3 @@
:members:
.. autofunction:: nni.nas.pytorch.utils.to_device
```
# 神经网络结构搜索在 NNI 上的应用
```eval_rst
.. contents::
```
## 概述
自动化的神经网络架构(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 模型),易于使用且灵活的编程接口非常重要。
以此为动力,NNI 的目标是提供统一的体系结构,以加速NAS上的创新,并将最新的算法更快地应用于现实世界中的问题上。
通过统一的接口,有两种方法来使用神经网络架构搜索。 [一种](#supported-one-shot-nas-algorithms)称为 one-shot NAS,基于搜索空间构建了一个超级网络,并使用 one-shot 训练来生成性能良好的子模型。 <a href="#支持的经典-nas-算法"">第二种</a>是经典的搜索方法,搜索空间中每个子模型作为独立的 Trial 运行。 称之为经典的 NAS。
NNI 还提供了专门的[可视化工具](#nas-可视化),用于查看神经网络架构搜索的过程。
## 支持的经典 NAS 算法
经典 NAS 算法的过程类似于超参调优,通过 `nnictl` 来启动 Experiment,每个子模型会作为 Trial 运行。 不同之处在于,搜索空间文件是通过运行 `nnictl ss_gen`,从用户模型(已包含搜索空间)中自动生成。 下表列出了经典 NAS 模式支持的算法。 将来版本会支持更多算法。
| 名称 | 算法简介 |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| [Random Search(随机搜索)](https://github.com/microsoft/nni/tree/master/examples/tuners/random_nas_tuner) | 从搜索空间中随机选择模型 |
| [PPO Tuner](https://nni.readthedocs.io/zh/latest/Tuner/BuiltinTuner.html#PPOTuner) | PPO Tuner 是基于 PPO 算法的强化学习 Tuner。 [参考论文](https://arxiv.org/abs/1707.06347) |
参考[这里](ClassicNas.md),了解如何使用经典 NAS 算法。
## 支持的 One-shot NAS 算法
NNI 目前支持下面列出的 One-Shot NAS 算法,并且正在添加更多算法。 用户可以重现算法或在自己的数据集上使用它。 鼓励用户使用 [NNI API](#use-nni-api) 实现其它算法,以使更多人受益。
| 名称 | 算法简介 |
| -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [ENAS](https://nni.readthedocs.io/zh/latest/NAS/ENAS.html) | [Efficient Neural Architecture Search via Parameter Sharing](https://arxiv.org/abs/1802.03268). 在 ENAS 中,Contoller 学习在大的计算图中搜索最有子图的方式来发现神经网络。 它通过在子模型间共享参数来实现加速和出色的性能指标。 |
| [DARTS](https://nni.readthedocs.io/zh/latest/NAS/DARTS.html) | [DARTS: Differentiable Architecture Search](https://arxiv.org/abs/1806.09055) 引入了一种在两级网络优化中使用的可微分算法。 |
| [P-DARTS](https://nni.readthedocs.io/zh/latest/NAS/PDARTS.html) | [Progressive Differentiable Architecture Search: Bridging the Depth Gap between Search and Evaluation](https://arxiv.org/abs/1904.12760) 基于DARTS。 它引入了一种有效的算法,可在搜索过程中逐渐增加搜索的深度。 |
| [SPOS](https://nni.readthedocs.io/zh/latest/NAS/SPOS.html) | 论文 [Single Path One-Shot Neural Architecture Search with Uniform Sampling](https://arxiv.org/abs/1904.00420) 构造了一个采用统一的路径采样方法来训练简化的超网络,并使用进化算法来提高搜索神经网络结构的效率。 |
| [CDARTS](https://nni.readthedocs.io/zh/latest/NAS/CDARTS.html) | [Cyclic Differentiable Architecture Search](https://arxiv.org/abs/****) 在搜索和评估的网络见构建了循环反馈的机制。 通过引入的循环的可微分架构搜索框架将两个网络集成为一个架构。 |
| [ProxylessNAS](https://nni.readthedocs.io/zh/latest/NAS/Proxylessnas.html) | [ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware](https://arxiv.org/abs/1812.00332). 它删除了代理,直接从大规模目标任务和目标硬件平台进行学习。 |
| [TextNAS](https://nni.readthedocs.io/zh/latest/NAS/TextNAS.html) | [TextNAS: A Neural Architecture Search Space tailored for Text Representation](https://arxiv.org/pdf/1912.10729.pdf)。 这是专门用于文本表示的神经网络架构搜索算法。 |
One-shot 算法**不需要 nnictl,可单独运行**。 NNI 支持 PyTorch 和 TensorFlow 2.x。
这是运行示例的一些常见依赖项。 PyTorch 需要高于 1.2 才能使用 `BoolTensor`.
* tensorboard
* PyTorch 1.2+
* git
参考[这里](NasGuide.md),了解如何使用 One-Shot NAS 算法。
One-Shot NAS 可以通过可视化工具来查看。 点击[这里](./Visualization.md),了解详情。
## 搜索空间集合
NNI 提供了一些预定义的、可被重用的搜索空间。 通过堆叠这些抽取出的单元,用户可以快速复现 NAS 模型。
搜索空间集合包含了以下 NAS 单元:
* [DartsCell](./SearchSpaceZoo.md#DartsCell)
* [ENAS micro](./SearchSpaceZoo.md#ENASMicroLayer)
* [ENAS macro](./SearchSpaceZoo.md#ENASMacroLayer)
## 使用 NNI API 来编写搜索空间
在两种场景下需要用于设计和搜索模型的编程接口。
1. 在设计神经网络时,可能在层、子模型或连接上有多种选择,并且无法确定是其中一种或某些的组合的结果最好。 因此,需要简单的方法来表达候选的层或子模型。
2. 在神经网络上应用 NAS 时,需要统一的方式来表达架构的搜索空间,这样不必为不同的搜索算法来更改代码。
要使用 NNI NAS,建议先阅读[用 NAS API 构建搜索空间](./WriteSearchSpace.md)的教程。
## NAS 可视化
为了帮助用户跟踪指定搜索空间下搜索模型的过程和状态,开发了此可视化工具。 它将搜索空间可视化为超网络,并显示子网络、层和操作的重要性,同时还能显示重要性是如何在搜索过程中变化的。 参考 [NAS 可视化](./Visualization.md)文档了解详情。
## 参考和反馈
* 在 GitHub 中[提交此功能的 Bug](https://github.com/microsoft/nni/issues/new?template=bug-report.md)
* 在 GitHub 中[提交新功能或改进请求](https://github.com/microsoft/nni/issues/new?template=enhancement.md)
神经网络结构搜索在 NNI 上的应用
=======================================
.. contents::
概述
--------
自动化的神经网络架构(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 模型),易于使用且灵活的编程接口非常重要。
以此为动力,NNI 的目标是提供统一的体系结构,以加速 NAS 上的创新,并将最新的算法更快地应用于现实世界中的问题上。
通过统一的接口,有两种方法来使用神经网络架构搜索。 一种称为 `one-shot NAS <#supported-one-shot-nas-algorithms>`__ ,基于搜索空间构建了一个超级网络,并使用 one-shot 训练来生成性能良好的子模型。 `第二种 <#supported-classic-nas-algorithms>`__ 是经典的搜索方法,搜索空间中每个子模型作为独立的 Trial 运行。 称之为经典的 NAS。
NNI 还提供了专门的 `可视化工具 <#nas-visualization>`__,用于查看神经网络架构搜索的过程。
支持的经典 NAS 算法
--------------------------------
经典 NAS 算法的过程类似于超参调优,通过 ``nnictl`` 来启动 Experiment,每个子模型会作为 Trial 运行。 不同之处在于,搜索空间文件是通过运行 ``nnictl ss_gen``,从用户模型(已包含搜索空间)中自动生成。 下表列出了经典 NAS 模式支持的算法。 将来版本会支持更多算法。
.. list-table::
:header-rows: 1
:widths: auto
* - 名称
- 算法简介
* - :githublink:`Random Search <examples/tuners/random_nas_tuner>`
- 从搜索空间中随机选择模型
* - `PPO Tuner </Tuner/BuiltinTuner.html#PPOTuner>`__
- PPO Tuner 是基于 PPO 算法的强化学习 Tuner。 `参考论文 <https://arxiv.org/abs/1707.06347>`__
参考 `这里 <ClassicNas.rst>`__ ,了解如何使用经典 NAS 算法。
支持的 One-shot NAS 算法
---------------------------------
NNI 目前支持下面列出的 One-Shot NAS 算法,并且正在添加更多算法。 用户可以重现算法或在自己的数据集上使用它。 鼓励用户使用 `NNI API <#use-nni-api>`__, 实现其它算法,以使更多人受益。
.. list-table::
:header-rows: 1
:widths: auto
* - Name
- 算法简介
* - `ENAS </NAS/ENAS.html>`__
- `Efficient Neural Architecture Search via Parameter Sharing <https://arxiv.org/abs/1802.03268>`__. 在 ENAS 中,Contoller 学习在大的计算图中搜索最有子图的方式来发现神经网络。 它通过在子模型间共享参数来实现加速和出色的性能指标。
* - `DARTS </NAS/DARTS.html>`__
- `DARTS: Differentiable Architecture Search <https://arxiv.org/abs/1806.09055>`__ 介绍了一种用于双级优化的可区分网络体系结构搜索的新算法。
* - `P-DARTS </NAS/PDARTS.html>`__
- `Progressive Differentiable Architecture Search: Bridging the Depth Gap between Search and Evaluation <https://arxiv.org/abs/1904.12760>`__ 这篇论文是基于 DARTS 的. 它引入了一种有效的算法,可在搜索过程中逐渐增加搜索的深度。
* - `SPOS </NAS/SPOS.html>`__
- 论文 `Single Path One-Shot Neural Architecture Search with Uniform Sampling <https://arxiv.org/abs/1904.00420>`__ 构造了一个采用统一的路径采样方法来训练简化的超网络,并使用进化算法来提高搜索神经网络结构的效率。
* - `CDARTS </NAS/CDARTS.html>`__
- `Cyclic Differentiable Architecture Search <https://arxiv.org/abs/****>`__ 在搜索和评估网络之间建立循环反馈机制。 通过引入的循环的可微分架构搜索框架将两个网络集成为一个架构。
* - `ProxylessNAS </NAS/Proxylessnas.html>`__
- `ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware <https://arxiv.org/abs/1812.00332>`__. 它删除了代理,直接从大规模目标任务和目标硬件平台进行学习。
* - `TextNAS </NAS/TextNAS.html>`__
- `TextNAS: A Neural Architecture Search Space tailored for Text Representation <https://arxiv.org/pdf/1912.10729.pdf>`__. 这是专门用于文本表示的神经网络架构搜索算法。
One-shot 算法 **独立运行,不需要 nnictl**。 NNI 支持 PyTorch 和 TensorFlow 2.x。
这是运行示例的一些常见依赖项。 PyTorch 需要高于 1.2 才能使用 ``BoolTensor``。
* tensorboard
* PyTorch 1.2+
* git
参考 `这里 <NasGuide.rst>`__,了解如何使用 one-shot NAS 算法。
一次性 NAS 可以通过可视化工具来查看。 点 `这里 <./Visualization.rst>`__ 了解更多细节。
搜索空间集合
----------------
NNI 提供了一些预定义的、可被重用的搜索空间。 通过堆叠这些抽取出的单元,用户可以快速复现 NAS 模型。
搜索空间集合包含了以下 NAS 单元:
* `DartsCell <./SearchSpaceZoo.rst#DartsCell>`__
* `ENAS micro <./SearchSpaceZoo.rst#ENASMicroLayer>`__
* `ENAS macro <./SearchSpaceZoo.rst#ENASMacroLayer>`__
* `NAS Bench 201 <./SearchSpaceZoo.rst#nas-bench-201>`__
使用 NNI API 来编写搜索空间
----------------------------------------
在两种场景下需要用于设计和搜索模型的编程接口。
#. 在设计神经网络时,可能在层、子模型或连接上有多种选择,并且无法确定是其中一种或某些的组合的结果最好。 因此,需要简单的方法来表达候选的层或子模型。
#. 在神经网络上应用 NAS 时,需要统一的方式来表达架构的搜索空间,这样不必为不同的搜索算法来更改代码。
为了使用 NNI NAS, 建议用户先通读这篇文档 `the tutorial of NAS API for building search space <./WriteSearchSpace.rst>`__。
NAS 可视化
-----------------
为了帮助用户跟踪指定搜索空间下搜索模型的过程和状态,开发了此可视化工具。 它将搜索空间可视化为超网络,并显示子网络、层和操作的重要性,同时还能显示重要性是如何在搜索过程中变化的。 请参阅 `the document of NAS visualization <./Visualization.rst>`__ 。
参考和反馈
----------------------
* 在Github 中 `提交此功能的 Bug <https://github.com/microsoft/nni/issues/new?template=bug-report.rst>`__;
* 在Github 中 `提交新功能或请求改进 <https://github.com/microsoft/nni/issues/new?template=enhancement.rst>`__。
# P-DARTS
## 示例
[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/pdarts)
```bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最好的架构
cd examples/nas/pdarts
python3 search.py
# 训练最好的架构,过程与 darts 相同。
cd ../darts
python3 retrain.py --arc-checkpoint ../pdarts/checkpoints/epoch_2.json
```
P-DARTS
=======
示例
--------
:githublink:`示例代码 <examples/nas/pdarts>`
.. code-block:: bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最优结构
cd examples/nas/pdarts
python3 search.py
# 训练最优架构,跟 darts 一样的步骤
cd ../darts
python3 retrain.py --arc-checkpoint ../pdarts/checkpoints/epoch_2.json
# NNI 上的 ProxylessNAS
## 介绍
论文 [ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware](https://arxiv.org/pdf/1812.00332.pdf) 去掉了代理,直接从大规模目标任务和目标硬件平台上学习架构。 它解决了可微分 NAS 大量内存消耗的问题,从而将计算成本较低到普通训练的水平,同时仍然能使用大规模的候选集。 参考论文了解详情。
## 用法
要使用 ProxylessNAS 训练、搜索方法,用户要在模型中使用 [NNI NAS interface](NasGuide.md) 来指定搜索空间,例如,`LayerChoice``InputChoice`。 定义并实例化模型,然后实例化 ProxylessNasTrainer,并将模型传入,剩下的工作由 Trainer 来完成。
```python
trainer = ProxylessNasTrainer(model,
model_optim=optimizer,
train_loader=data_provider.train,
valid_loader=data_provider.valid,
device=device,
warmup=True,
ckpt_path=args.checkpoint_path,
arch_path=args.arch_path)
trainer.train()
trainer.export(args.arch_path)
```
[此处](https://github.com/microsoft/nni/tree/master/examples/nas/proxylessnas)是完整示例。
**ProxylessNasTrainer 的输入参数**
* **model** (*PyTorch 模型, 必需*) - 需要调优、搜索的模型。 它具有可变项以指定搜索空间。
* **model_optim** (*PyTorch 优化器, 必需*) - 训练模型所需要的优化器。
* **device** (*device, 必需*) - 用于训练、搜索的 device。 Trainer 会使用数据并行化。
* **train_loader** (*PyTorch DataLoader, 必需*) - 训练数据集的 DataLoader。
* **valid_loader** (*PyTorch DataLoader, 必需*) - 验证数据集的 DataLoader。
* **label_smoothing** (*float, 可选, 默认为 0.1*) - 标签平滑度。
* **n_epochs** (*int, 可选, 默认为 120*) - 训练、搜索的 Epoch 数量。
* **init_lr** (*float, 可选, 默认为 0.025*) - 训练的初始学习率。
* **binary_mode** (*'two', 'full', 或 'full_v2', 可选, 默认为 'full_v2'*) - Mutabor 中二进制权重的 forward, backword 模式。 'full' 表示前向传播所有候选操作,'two' 表示仅前向传播两个采样操作,'full_v2' 表示在反向传播时重新计算非激活的操作。
* **arch_init_type** (*'normal' 或 'uniform', 可选, 默认为 'normal'*) - 初始化架构参数的方法。
* **arch_init_ratio** (*float, 可选, 默认为 1e-3*) - 初始化架构参数的比例。
* **arch_optim_lr** (*float, 可选, 默认为 1e-3*) - 架构参数优化器的学习率。
* **arch_weight_decay** (*float, 可选, 默认为 0*) - 架构参数优化器的权重衰减。
* **grad_update_arch_param_every** (*int, 可选, 默认为 5*) - 多少个迷你批处理后更新权重。
* **grad_update_steps** (*int, 可选, 默认为 1*) - 在每次权重更新时,训练架构权重的次数。
* **warmup** (*bool, 可选, 默认为 True*) - 是否需要热身。
* **warmup_epochs** (*int, 可选, 默认为 25*) - 热身的 Epoch 数量。
* **arch_valid_frequency** (*int, 可选, 默认为 = 1*) - 输出验证集结果的频率。
* **load_ckpt** (*bool, 可选, 默认为 False*) - 是否加载检查点。
* **ckpt_path** (*str, 可选, 默认为 None*) - 检查点路径。如果 load_ckpt 为 True,ckpt_path 不能为 None。
* **arch_path** (*str, 可选, 默认为 None*) - 选择架构的路径。
## 实现
NNI 上的实现基于[官方实现](https://github.com/mit-han-lab/ProxylessNAS)。 官方实现支持两种搜索方法:梯度下降和强化学习,还支持不同的硬件,包括 'mobile', 'cpu', 'gpu8', 'flops'。 在当前的 NNI 实现中,支持梯度下降训练方法,不支持不同的硬件。 完整支持正在进行中。
下面将介绍实现的细节。 像 NNI 上其它 one-shot NAS 算法一样,ProxylessNAS 由两部分组成:*搜索空间**训练方法*。 为了用户能灵活的定义自己的搜索空间,并使用内置的 ProxylessNAS 训练方法,将使用 [NNI NAS 接口](NasGuide.md)定制的搜索空间放在了[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/proxylessnas)中,并将搜索方法放在了 [SDK](https://github.com/microsoft/nni/tree/master/src/sdk/pynni/nni/nas/pytorch/proxylessnas) 中。
![](../../img/proxylessnas.png)
ProxylessNAS 搜索方法由 ProxylessNasMutator 和 ProxylessNasTrainer 组成。 ProxylessNasMutator 为每个可变量初始化了 MixedOp (即, LayerChoice),并会在 MixedOp 中管理架构权重。 **对于数据并行化**,架构权重会在用户模型中。 具体地说,在 ProxylessNAS 视线中,为可变变量 (即, LayerChoice) 添加了 MixedOp 作为成员变量。 Mutator 也公开了两个成员函数:`arch_requires_grad``arch_disable_grad`,用于 Trainer 来控制架构权重的训练。
ProxylessNasMutator 还实现了可变量的前向逻辑 (即, LayerChoice)。
## 重现结果
为了重现结果,首先运行了搜索过程。我们发现虽然需要跑许多 Epoch,但选择的架构会在头几个 Epoch 就收敛了。 这可能是由超参或实现造成的,正在分析中。 找到架构的测试精度为 top1: 72.31, top5: 90.26。
NNI 上的 ProxylessNAS
======================================
介绍
------------
论文 `ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware <https://arxiv.org/pdf/1812.00332.pdf>`__ 删除了 proxy,它直接学习了用于大规模目标任务和目标硬件平台的体系结构。 它解决了可微分 NAS 大量内存消耗的问题,从而将计算成本较低到普通训练的水平,同时仍然能使用大规模的候选集。 参考论文了解详情。
用法
-----
要使用 ProxylessNAS 训练/搜索方法,用户需要使用 `NNI NAS 接口 <NasGuide.rst>`__ 在其模型中指定搜索空间,例如, ``LayerChoice``\ , ``InputChoice``。 定义并实例化模型,然后实例化 ProxylessNasTrainer,并将模型传入,剩下的工作由 Trainer 来完成。
.. code-block:: python
trainer = ProxylessNasTrainer(model,
model_optim=optimizer,
train_loader=data_provider.train,
valid_loader=data_provider.valid,
device=device,
warmup=True,
ckpt_path=args.checkpoint_path,
arch_path=args.arch_path)
trainer.train()
trainer.export(args.arch_path)
完整的示例代码参考 :githublink:`这里 <examples/nas/proxylessnas>`。
**ProxylessNasTrainer 的输入参数**
* **model** (*PyTorch model, 必填*\ ) - 用户要调整/搜索的模型。 它具有可变项以指定搜索空间。
* **model_optim** (*PyTorch optimizer, 必填*\ ) - optimizer 用户希望训练模型。
* **device** (*device, 必填*\ ) - 用户提供的用于进行训练/搜索的设备。 Trainer 会使用数据并行化。
* **train_loader** (*PyTorch data loader, 必填*\ ) - 用于训练集的数据加载器。
* **valid_loader** (*PyTorch data loader, 必填*\ ) - 用于验证集的数据加载器。
* **label_smoothing** (*float, 可选, 默认值为 0.1*\ ) - 标签平滑度。
* **n_epochs** (*int, 可选, 默认值为 120*\ ) - 要训练/搜索的 Epoch 数量。
* **init_lr** (*float, 可选, 默认值为 0.025*\ ) - 训练模型的初始学习率。
* **binary_mode** (*'two', 'full', 或 'full_v2', 可选, 默认为 'full_v2'*\ ) - Mutabor 中二进制权重的 forward, backword 模式。 'full' 表示前向传播所有候选操作,'two' 表示仅前向传播两个采样操作,'full_v2' 表示在反向传播时重新计算非激活的操作。
* **arch_init_type** (*'normal' 或 'uniform', 可选, 默认为 'normal'*\ ) - 初始化架构参数的方法。
* **arch_init_ratio** (*float, 可选, 默认值为 1e-3*\ ) - 初始架构参数的比率。
* **arch_optim_lr** (*float, 可选, 默认值为 1e-3*\ ) - 架构参数优化器的学习率。
* **arch_weight_decay** (*float, 可选, 默认值为 0*\ ) - 架构参数优化器的权重衰减。
* **grad_update_arch_param_every** (*int, 可选, 默认值为 5*\ ) - 多少个迷你批处理后更新权重。
* **grad_update_steps** (*int, 可选, 默认为 1*) - 在每次权重更新时,训练架构权重的次数。
* **warmup** (*bool, 可选, 默认值是 True*\ ) - 是否做热身。
* **warmup_epochs** (*int, 可选, 默认值是 25*\ ) - 预热期间要进行的时期数。
* **arch_valid_frequency** (*int, 可选, 默认值为 1*\ ) - 打印确认结果的频率。
* **load_ckpt** (*bool, 可选, 默认值为 False*\ ) - 是否加载 checkpoint。
* **ckpt_path** (*str, 可选, 默认为 None*\ ) - 检查点路径。如果 load_ckpt 为 True,ckpt_path 不能为 None。
* **arch_path** (*str, 可选, 默认值为 None*\ ) - 存储所选架构的路径。
实现
--------------
在NNI上的实现基于 `官方实现 <https://github.com/mit-han-lab/ProxylessNAS>`__ 。 官方实现支持两种搜索方法:梯度下降和强化学习,还支持不同的硬件,包括 'mobile', 'cpu', 'gpu8', 'flops'。 在当前的 NNI 实现中,支持梯度下降训练方法,不支持不同的硬件。 完整支持正在进行中。
下面将介绍实现的细节。 像 NNI 上其它 one-shot NAS 算法一样,ProxylessNAS 由两部分组成:*搜索空间* 和 *训练方法*。 为了让用户灵活地定义自己的搜索空间并使用内置的 ProxylessNAS 训练方法,我们将指定的搜索空间放在 :githublink:`示例代码 <examples/nas/proxylessnas>` 使用 :githublink:`NNI NAS 接口<src/sdk/pynni/nni/nas/pytorch/proxylessnas>`。
.. image:: ../../img/proxylessnas.png
:target: ../../img/proxylessnas.png
:alt:
ProxylessNAS 搜索方法由 ProxylessNasMutator 和 ProxylessNasTrainer 组成。 ProxylessNasMutator 为每个可变量初始化了 MixedOp (即, LayerChoice),并会在 MixedOp 中管理架构权重。 **对于数据并行化**,架构权重会在用户模型中。 具体地说,在 ProxylessNAS 视线中,为可变变量 (即, LayerChoice) 添加了 MixedOp 作为成员变量。 Mutator 也公开了两个成员函数:``arch_requires_grad`` 和 ``arch_disable_grad``,用于 Trainer 来控制架构权重的训练。
ProxylessNasMutator 还实现了可变量的前向逻辑 (即, LayerChoice)。
重现结果
-----------------
为了重现结果,首先运行了搜索过程。我们发现虽然需要跑许多 Epoch,但选择的架构会在头几个 Epoch 就收敛了。 这可能是由超参或实现造成的,正在分析中。 找到架构的测试精度为 top1: 72.31, top5: 90.26。
# 单路径 One-Shot (SPOS)
## 介绍
[Single Path One-Shot Neural Architecture Search with Uniform Sampling](https://arxiv.org/abs/1904.00420) 中提出的 one-shot NAS 方法,通过构造简化的通过统一路径采样方法训练的超网络来解决 One-Shot 模型训练的问题。这样所有架构(及其权重)都得到了完全且平等的训练。 然后,采用进化算法无需任何微调即可有效的搜索出性能最佳的体系结构。
在 NNI 上的实现基于 [官方 Repo](https://github.com/megvii-model/SinglePathOneShot). 实现了一个训练超级网络的 Trainer,以及一个利用 NNI 框架能力来加速进化搜索阶段的进化 Tuner。 还展示了
## 示例
此示例是论文中的搜索空间,使用 flops 限制来执行统一的采样方法。
[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/spos)
### 必需组件
由于使用了 DALI 来加速 ImageNet 的数据读取,需要 NVIDIA DALI >= 0.16。 [安装指南](https://docs.nvidia.com/deeplearning/sdk/dali-developer-guide/docs/installation.html)
[这里](https://1drv.ms/u/s!Am_mmG2-KsrnajesvSdfsq_cN48?e=aHVppN) ( [Megvii](https://github.com/megvii-model) 维护) 下载 flops 查找表。 将 `op_flops_dict.pkl``checkpoint-150000.pth.tar` (如果不需要重新训练超网络) 放到 `data` 目录中。
准备标准格式的 ImageNet (参考[这里的脚本](https://gist.github.com/BIGBALLON/8a71d225eff18d88e469e6ea9b39cef4))。 将其链接到 `data/imagenet` 会更方便。
准备好后,应具有以下代码结构:
```
spos
├── architecture_final.json
├── blocks.py
├── config_search.yml
├── data
│ ├── imagenet
│ │ ├── train
│ │ └── val
│ └── op_flops_dict.pkl
├── dataloader.py
├── network.py
├── readme.md
├── scratch.py
├── supernet.py
├── tester.py
├── tuner.py
└── utils.py
```
### 步骤 1. 训练超网络
```
python supernet.py
```
会将检查点导出到 `checkpoints` 目录中,为下一步做准备。
注意:数据加载的官方 Repo [与通常的方法有所不同](https://github.com/megvii-model/SinglePathOneShot/issues/5),使用了 BGR 张量,以及 0 到 255 之间的值来与自己的深度学习框架对齐。 选项 `--spos-preprocessing` 会模拟原始的使用行为,并能使用预训练的检查点。
### 步骤 2. 进化搜索
单路径 One-Shot 利用进化算法来搜索最佳架构。 tester 负责通过训练图像的子集来测试采样的体系结构,重新计算所有批处理规范,并在完整的验证集上评估架构。
为了使 Tuner 识别 flops 限制并能计算 flops,在 `tuner.py` 中创建了新的 `EvolutionWithFlops` Tuner,其继承于 SDK 中的 tuner。
要为 NNI 框架准备好搜索空间,首先运行
```
nnictl ss_gen -t "python tester.py"
```
将生成 `nni_auto_gen_search_space.json` 文件,这是搜索空间的序列化形式。
默认情况下,它将使用前面下载的 `checkpoint-150000.pth.tar`。 如果要使用从自行训练的检查点,在 `config_search.yml` 中的命令上指定 `---checkpoint`
然后使用进化 Tuner 搜索。
```
nnictl create --config config_search.yml
```
从每个 Epoch 导出的最终架构可在 Tuner 工作目录下的 `checkpoints` 中找到,默认值为 `$HOME/nni-experiments/your_experiment_id/log`
### 步骤 3. 从头开始训练
```
python scratch.py
```
默认情况下,它将使用 `architecture_final.json`. 该体系结构由官方仓库提供(转换成了 NNI 格式)。 通过 `--fixed-arc` 选项,可使用任何结构(例如,步骤 2 中找到的结构)。
## 参考
### PyTorch
```eval_rst
.. autoclass:: nni.nas.pytorch.spos.SPOSEvolution
:members:
.. autoclass:: nni.nas.pytorch.spos.SPOSSupernetTrainer
:members:
.. autoclass:: nni.nas.pytorch.spos.SPOSSupernetTrainingMutator
:members:
```
## 已知的局限
* 仅支持 Block 搜索。 尚不支持通道搜索。
* 仅提供 GPU 版本。
## 当前重现结果
重现中。 由于官方版本和原始论文之间的不同,我们将当前结果与官方 Repo(我们运行的结果)和论文进行了比较。
* 进化阶段几乎与官方 Repo 一致。 进化算法显示出了收敛趋势,在搜索结束时达到约 65% 的精度。 但此结果与论文不一致。 详情参考[此 issue](https://github.com/megvii-model/SinglePathOneShot/issues/6)
* 重新训练阶段未匹配。 我们的重新训练代码,使用了作者发布的架构,获得了 72.14% 的准确率,与官方发布的 73.61%,和原始论文中的 74.3% 有一定差距。
单路径 One-Shot (SPOS)
===========================
介绍
------------
在 `Single Path One-Shot Neural Architecture Search with Uniform Sampling <https://arxiv.org/abs/1904.00420>`__ 中提出的 one-shot NAS 方法,通过构造简化的通过统一路径采样方法训练的超网络来解决 One-Shot 模型训练的问题。这样所有架构(及其权重)都得到了完全且平等的训练。 然后,采用进化算法无需任何微调即可有效的搜索出性能最佳的体系结构。
在 NNI 上的实现基于 `官方 Repo <https://github.com/megvii-model/SinglePathOneShot>`__。 实现了一个训练超级网络的 Trainer,以及一个利用 NNI 框架能力来加速进化搜索阶段的进化 Tuner。 还展示了
示例
--------
此示例是论文中的搜索空间,使用 flops 限制来执行统一的采样方法。
:githublink:`示例代码 <examples/nas/spos>`
必需组件
^^^^^^^^^^^^
由于使用了 DALI 来加速 ImageNet 的数据读取,需要 NVIDIA DALI >= 0.16。 `安装指导 <https://docs.nvidia.com/deeplearning/sdk/dali-developer-guide/docs/installation.html>`__。
从 `这里 <https://1drv.ms/u/s!Am_mmG2-KsrnajesvSdfsq_cN48?e=aHVppN>`__ (由 `Megvii <https://github.com/megvii-model>`__\ 维护) 下载 flops 查找表。
将 ``op_flops_dict.pkl`` 和 ``checkpoint-150000.pth.tar`` (如果不需要重新训练超网络) 放到 ``data`` 目录中。
准备标准格式的 ImageNet (参考 `这里的脚本
<https://gist.github.com/BIGBALLON/8a71d225eff18d88e469e6ea9b39cef4>`__\)。 将其链接到 ``data/imagenet`` 会更方便。
准备好后,应具有以下代码结构:
.. code-block:: bash
spos
├── architecture_final.json
├── blocks.py
├── config_search.yml
├── data
│ ├── imagenet
│ │ ├── train
│ │ └── val
│ └── op_flops_dict.pkl
├── dataloader.py
├── network.py
├── readme.md
├── scratch.py
├── supernet.py
├── tester.py
├── tuner.py
└── utils.py
步骤 1. 训练超网络
^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
python supernet.py
会将检查点导出到 ``checkpoints`` 目录中,为下一步做准备。
注意:数据加载的官方 Repo `与通常的方法有所不同 <https://github.com/megvii-model/SinglePathOneShot/issues/5>`__\ ,使用了 BGR 张量,以及 0 到 255 之间的值来与自己的深度学习框架对齐。 选项 ``--spos-preprocessing`` 会模拟原始的使用行为,并能使用预训练的检查点。
步骤 2. 进化搜索
^^^^^^^^^^^^^^^^^^^^^^^^
单路径 One-Shot 利用进化算法来搜索最佳架构。 tester 负责通过训练图像的子集来测试采样的体系结构,重新计算所有批处理规范,并在完整的验证集上评估架构。
为了使 Tuner 识别 flops 限制并能计算 flops,在 ``tuner.py`` 中创建了新的 ``EvolutionWithFlops`` Tuner,其继承于 SDK 中的 tuner。
要为 NNI 框架准备好搜索空间,首先运行
.. code-block:: bash
nnictl ss_gen -t "python tester.py"
将生成 ``nni_auto_gen_search_space.json`` 文件,这是搜索空间的序列化形式。
默认情况下,它将使用前面下载的 ``checkpoint-150000.pth.tar``。 如果要使用从自行训练的检查点,在 ``config_search.yml`` 中的命令上指定 ``---checkpoint``。
然后使用进化 Tuner 搜索。
.. code-block:: bash
nnictl create --config config_search.yml
从每个 Epoch 导出的最终架构可在 Tuner 工作目录下的 ``checkpoints`` 中找到,默认值为 ``$HOME/nni-experiments/your_experiment_id/log``。
步骤 3. 从头开始训练
^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: bash
python scratch.py
默认情况下,它将使用 ``architecture_final.json``. 该体系结构由官方仓库提供(转换成了 NNI 格式)。 通过 ``--fixed-arc`` 选项,可使用任何结构(例如,步骤 2 中找到的结构)。
参考
---------
PyTorch
^^^^^^^
.. autoclass:: nni.algorithms.nas.pytorch.spos.SPOSEvolution
:members:
.. autoclass:: nni.algorithms.nas.pytorch.spos.SPOSSupernetTrainer
:members:
.. autoclass:: nni.algorithms.nas.pytorch.spos.SPOSSupernetTrainingMutator
:members:
已知的局限
-----------------
* 仅支持 Block 搜索。 尚不支持通道搜索。
* 仅提供 GPU 版本。
当前重现结果
----------------------------
重现中。 由于官方版本和原始论文之间的不同,我们将当前结果与官方 Repo(我们运行的结果)和论文进行了比较。
* 进化阶段几乎与官方 Repo 一致。 进化算法显示出了收敛趋势,在搜索结束时达到约 65% 的精度。 但此结果与论文不一致。 详情参考 `此 issue <https://github.com/megvii-model/SinglePathOneShot/issues/6>`__。
* 重新训练阶段未匹配。 我们的重新训练代码,使用了作者发布的架构,获得了 72.14% 的准确率,与官方发布的 73.61%,和原始论文中的 74.3% 有一定差距。
# 搜索空间集合
## DartsCell
DartsCell 是从[这里](https://github.com/microsoft/nni/tree/master/examples/nas/darts)[CNN 模型](./DARTS.md)中提取出来的。 一个 DartsCell 是一个包含 N 个节点的序列的有向无环图 ,其中每个节点代表一个潜在特征的表示(例如卷积网络中的特征图)。 从节点1到节点2的有向边表示一些将节点1转换为节点2的操作。这些操作获取节点1的值并将转换的结果储存在节点2上。 节点之间的[操作](#darts-predefined-operations)是预定义的且不可更改。 一条边表示从预定义的操作中选择的一项,并将该操作将应用于边的起始节点。 一个 cell 包括两个输入节点,一个输出节点和其他 `n_node` 个节点。 输入节点定义为前两个 cell 的输出。 Cell 的输出是通过对所有中间节点进行归约运算(例如连接)而获得的。 为了使搜索空间连续,在所有可能的操作上通过softmax对特定操作选择进行松弛。 通过调整每个节点上softmax的权重,选择概率最高的操作作为最终结构的一部分。 可以通过堆叠多个cell组成一个CNN模型,从而构建一个搜索空间。 值得注意的是,在DARTS论文中,模型中的所有cell都具有相同的结构。
Darts的搜索空间如下图所示。 请注意,在NNI的实现中将最后一个中间节点与输出节点进行了合并。
![](../../img/NAS_Darts_cell.svg)
预定义的操作在[参考](#predefined-operations-darts)中列出。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.DartsCell
:members:
```
### 示例代码
[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/search_space_zoo/darts_example.py)
```bash
git clone https://github.com/Microsoft/nni.git
cd nni/examples/nas/search_space_zoo
# search the best structure
python3 darts_example.py
```
<a name="predefined-operations-darts"></a>
### 参考
所有Darts支持的操作如下。
* 最大池化 / 平均池化
* 最大池化:调用`torch.nn.MaxPool2d`。 这个操作对所有输入的通道进行最大池化。 操作的参数固定,`kernel_size=3``padding=1`。 在池化操作后通过BatchNorm2d得到最终结果。
* 平均池化:调用`torch.nn.AvgPool2d`。 这个操作对所有输入的通道进行平均池化。 操作的参数固定,`kernel_size=3``padding=1`。 在池化操作后通过BatchNorm2d得到最终结果。
参数为`kernel_size=3`和`padding=1` 的最大池化操作和平均池化操作后均有BatchNorm2d操作。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.darts_ops.PoolBN
```
* 跳过连接
两个节点之间没有任何操作。 调用` torch.nn.Identity `将其获取的内容转发到输出。
* 零操作
两个节点之间没有连接。
* DilConv3x3 / DilConv5x5
<a name="DilConv"></a>深度可分离卷积。 3x3深度可分离卷积是由 `C_in` 组的3x3深度卷积和1x1的卷积串联组成。 这个操作减少了参数的数量。 输入首先通过RelLU,然后通过DilConv,最后是batchNorm2d。 **请注意这个操作不是扩散卷积,但是我们按照NAS论文中的约定命名为DilConv。**3x3深度可分离卷积的参数是 `kernel_size=3`, `padding=1` 。5x5深度可分离卷积的参数是 `kernel_size=5`, `padding=4`。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.darts_ops.DilConv
```
* SepConv3x3 / SepConv5x5
由两个参数为`kernel_size=3`, `padding=1`或`kernel_size=5`, `padding=2` 的深度可分离卷积串联组成。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.darts_ops.SepConv
```
## ENASMicroLayer
这个层是由[这里](https://github.com/microsoft/nni/tree/master/examples/nas/enas)的模型提取出来的。 一个模型包含共享结构的多个块。 一个块由一些常规层和约简层组成,`ENASMicroLayer`是这两型层的统一实现。 这两类层之间的唯一区别是约简层的所有操作`stride=2`
ENAS Micro的一个cell是含有N个节点的有向无环图。其中节点表示张量,边表示N个节点间的信息流。 一个cell包含两个输入节点和一个输出节点。 接下来节点选择前两个之前的节点作为输入,并从[预定义的的操作集](#predefined-operations-enas)中选择两个操作,分别应用到输入上,然后将它们相加为该节点的输出。 例如,节点4选择节点1和节点3作为输入,然后分别对输入应用` MaxPool `` AvgPool `,然后将它们相加作为节点4的输出。 未用作任何其他节点输入的节点将被视为该层的输出。 如果有多个输出节点,则模型将计算这些节点的平均值作为当前层的输出。
ENAS Micro的搜索空间如下图所示。
![](../../img/NAS_ENAS_micro.svg)
预定义的操作在[参考](#predefined-operations-enas)中列出。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.ENASMicroLayer
:members:
```
归约层由两个卷积操作和之后的BatchNorm组成,每个卷积操作都将输出` C_out//2`个通道并将它们在通道方向上串联作为输出。 卷积的参数是`kernel_size=1``stride=2`,并且它们对输入进行交替采样以降低分辨率而不会丢失信息。 该层封装在`ENASMicroLayer`中。
### 示例代码
[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/search_space_zoo/enas_micro_example.py)
```bash
git clone https://github.com/Microsoft/nni.git
cd nni/examples/nas/search_space_zoo
# search the best cell structure
python3 enas_micro_example.py
```
<a name="predefined-operations-enas"></a>
### 参考
所有ENAS Micro支持的操作如下。
* 最大池化 / 平均池化
* 最大池化:调用`torch.nn.MaxPool2d`。 这个操作对所有输入的通道进行最大池化,之后进行BatchNorm2d。 池化操作的参数为`kernel_size=3`,,`stride=1``padding=1`
* 平均池化:调用`torch.nn.AvgPool2d`。 这个操作对所有输入的通道进行最大池化,之后进行BatchNorm2d。 池化操作的参数为`kernel_size=3`,,`stride=1``padding=1`
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.Pool
```
* SepConv
* SepConvBN3x3:首先进行ReLU,之后进行[DilConv](#DilConv),最后是BatchNorm2d。 卷积操作的参数为`kernel_size=3`,,`stride=1``padding=1`
* SepConvBN5x5:进行与之前相同的操作,但是它具有不同的内核大小和填充,分别设置为5和2。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.SepConvBN
```
* 跳过连接
调用`torch.nn.Identity`直接连接到一个cell。
## ENASMacroLayer
在宏搜索中,控制器为每个层做出两个决定:i)对上一层的结果执行的[操作](#macro-operations),ii)通过跳过连接,连接到之前的那个层。 ENAS使用控制器来设计整个模型结构而不是模型的某一部分。 操作的输出将与跳过连接的所选层的张量连接在一起。 NNI提供了宏搜索中使用的[预定义的操作](#macro-operations),在[参考](#macro-operations)中列出。
ENAS Macro的搜索空间如下图所示。
![](../../img/NAS_ENAS_macro.svg)
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.ENASMacroLayer
:members:
```
为了描述整个搜索空间,NNI提供了一个模型,该模型是通过堆叠ENASMacroLayer构成的。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.ENASMacroGeneralModel
:members:
```
### 示例代码
[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/search_space_zoo/enas_macro_example.py)
```bash
git clone https://github.com/Microsoft/nni.git
cd nni/examples/nas/search_space_zoo
# search the best cell structure
python3 enas_macro_example.py
```
<a name="macro-operations"></a>
### 参考
所有ENAS Macro支持的操作如下。
* ConvBranch
首先将所有输入传递到StdConv,该操作由1x1Conv,BatchNorm2d和ReLU组成。 然后进行下列的操作之一。 最终结果通过后处理,包括BatchNorm2d和ReLU。
* Separable Conv3x3:如果`separable=True`,则cell将使用[ SepConv](#DilConv)而不是常规的卷积操作。 卷积操作的参数为`kernel_size=3`,`stride=1` ,`padding=1`。
* Separable Conv5x5:卷积操作的参数为`kernel_size=5`,,`stride=1` ,`padding=2`。
* Normal Conv3x3:如果`separable=False`,cell将使用参数为` kernel_size=3`,`stride=1`,` padding=1`的一般卷积。
* Separable Conv5x5:卷积操作的参数为`kernel_size=5`,,`stride=1` ,`padding=2`。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.ConvBranch
```
* PoolBranch
首先将所有输入传递到StdConv,该操作由1x1Conv,BatchNorm2d和ReLU组成。 然后对中间结果进行池化操作和BatchNorm。
* 平均池化:调用`torch.nn.AvgPool2d`。 这个操作对所有输入的通道进行平均池化。 池化操作的参数为`kernel_size=3`,,`stride=1` ,`padding=1`。
* 最大池化:调用`torch.nn.MaxPool2d`。 这个操作对所有输入的通道进行最大池化。 池化操作的参数为`kernel_size=3`,,`stride=1` ,`padding=1`。
```eval_rst
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.PoolBranch
```
<!-- push -->
.. role:: raw-html(raw)
:format: html
搜索空间集合
================
DartsCell
---------
DartsCell 是从 :githublink:`CNN 模型<examples/nas/darts>` 中提取的。 一个 DartsCell 是一个包含 N 个节点的序列的有向无环图 ,其中每个节点代表一个潜在特征的表示(例如, 卷积网络中的特征图)。 从节点 1 到节点 2 的有向边表示一些将节点 1 转换为节点 2 的操作。这些操作获取节点 1 的值并将转换的结果储存在节点 2 上。 节点之间的 `Candidate <#predefined-operations-darts>`__ 是预定义的且不可更改。 一条边表示从预定义的操作中选择的一项,并将该操作将应用于边的起始节点。 一个 cell 包括两个输入节点,一个输出节点和其他 ``n_node`` 个节点。 输入节点定义为前两个 cell 的输出。 cell 的输出是通过应用归约运算到所有中间节点(例如, 级联)。 为了使搜索空间连续,在所有可能的操作上通过 softmax 对特定操作选择进行松弛。 通过调整每个节点上 softmax 的权重,选择概率最高的操作作为最终结构的一部分。 可以通过堆叠多个 cell 组成一个 CNN 模型,从而构建一个搜索空间。 值得注意的是,在 DARTS 论文中,模型中的所有 cell 都具有相同的结构。
ENAS Micro 的搜索空间如下图所示。 请注意,在 NNI 的实现中将最后一个中间节点与输出节点进行了合并。
.. image:: ../../img/NAS_Darts_cell.svg
:target: ../../img/NAS_Darts_cell.svg
:alt:
预定义的操作在 `参考 <#predefined-operations-darts>`__ 中列出。
.. autoclass:: nni.nas.pytorch.search_space_zoo.DartsCell
:members:
示例代码
^^^^^^^^^^^^
:githublink:`示例代码 <examples/nas/search_space_zoo/darts_example.py>`
.. code-block:: bash
git clone https://github.com/Microsoft/nni.git
cd nni/examples/nas/search_space_zoo
# 搜索最优结构
python3 darts_example.py
:raw-html:`<a name="predefined-operations-darts"></a>`
候选运算符
^^^^^^^^^^^^^^^^^^^
所有 Darts 支持的操作如下。
*
最大池化 / 平均池化
* 最大池化:调用 ``torch.nn.MaxPool2d``。 这个操作对所有输入的通道进行最大池化。 参数 ``kernel_size = 3`` 和 ``padding = 1`` 是固定的。 在池化操作后通过 BatchNorm2d 得到最终结果。
*
平均池化:调用 ``torch.nn.AvgPool2d``。 这个操作对所有输入的通道进行平均池化。 参数 ``kernel_size = 3`` 和 ``padding = 1`` 是固定的。 在池化操作后通过 BatchNorm2d 得到最终结果。
参数为 ``kernel_size=3`` 和 ``padding=1`` 的最大池化操作和平均池化操作后均有 BatchNorm2d 操作。
.. autoclass:: nni.nas.pytorch.search_space_zoo.darts_ops.PoolBN
*
跳过连接
两个节点之间没有任何操作。 调用 ``torch.nn.Identity`` 将其获取的内容转发到输出。
*
零操作
两个节点之间没有连接。
*
DilConv3x3 / DilConv5x5
:raw-html:`<a name="DilConv"></a>`\ DilConv3x3: (Dilated) depthwise separable Conv. 3x3 深度可分离卷积是由 ``C_in`` 组的 3x3 深度卷积和 1x1 的卷积串联组成。 这个操作减少了参数的数量。 输入首先通过 RelLU,然后通过 DilConv,最后是 batchNorm2d。 **请注意这个操作不是扩散卷积,但是按照 NAS 论文中的约定命名为 DilConv。** 3x3 深度可分离卷积的参数是 ``kernel_size=3``, ``padding=1`` 。5x5 深度可分离卷积的参数是 ``kernel_size=5``, ``padding=4``。
.. autoclass:: nni.nas.pytorch.search_space_zoo.darts_ops.DilConv
*
SepConv3x3 / SepConv5x5
由两个顺序固定为 ``kernel_size = 3``,``padding = 1`` 或 ``kernel_size = 5``,``padding = 2`` 的 DilConv 组成。
.. autoclass:: nni.nas.pytorch.search_space_zoo.darts_ops.SepConv
ENASMicroLayer
--------------
该层是从设计的模型中提取的 :githublink:`这里 <examples/nas/enas>`. 一个模型包含共享结构的多个块。 一个块由一些常规层和约简层组成,``ENASMicroLayer`` 是这两型层的统一实现。 这两类层之间的唯一区别是约简层的所有操作 ``stride=2``。
ENAS Micro 的一个 cell 是含有 N 个节点的有向无环图。其中节点表示张量,边表示 N 个节点间的信息流。 一个 cell 包含两个输入节点和一个输出节点。 接下来节点选择前两个之前的节点作为输入,并从 `预定义的的操作集 <#predefined-operations-enas>`__ 中选择两个操作,分别应用到输入上,然后将它们相加为该节点的输出。 例如,节点 4 选择节点 1 和节点 3 作为输入,然后分别对输入应用
``MaxPool`` 和 ``AvgPool``,然后将它们相加作为节点 4 的输出。 未用作任何其他节点输入的节点将被视为该层的输出。 如果有多个输出节点,则模型将计算这些节点的平均值作为当前层的输出。
ENAS Micro 的搜索空间如下图所示。
.. image:: ../../img/NAS_ENAS_micro.svg
:target: ../../img/NAS_ENAS_micro.svg
:alt:
预定义的操作在 `参考 <#predefined-operations-enas>`__ 中列出。
.. autoclass:: nni.nas.pytorch.search_space_zoo.ENASMicroLayer
:members:
归约层由两个卷积操作和之后的 BatchNorm 组成,每个卷积操作都将输出 ``C_out//2`` 个通道并将它们在通道方向上串联作为输出。 卷积的参数是 ``kernel_size=1``,``stride=2``,并且它们对输入进行交替采样以降低分辨率而不会丢失信息。 该层封装在 ``ENASMicroLayer`` 中。
示例代码
^^^^^^^^^^^^
:githublink:`示例代码 <examples/nas/search_space_zoo/enas_micro_example.py>`
.. code-block:: bash
git clone https://github.com/Microsoft/nni.git
cd nni/examples/nas/search_space_zoo
# 搜索最优结构
python3 enas_micro_example.py
:raw-html:`<a name="predefined-operations-enas"></a>`
候选运算符
^^^^^^^^^^^^^^^^^^^
所有 ENAS Micro 支持的操作如下。
*
最大池化 / 平均池化
* 最大池化:调用 ``torch.nn.MaxPool2d``。 这个操作对所有输入的通道进行最大池化,之后进行 BatchNorm2d。 参数固定为 ``kernel_size=3``\ , ``stride=1`` 和 ``padding=1``。
* 平均池化:调用 ``torch.nn.AvgPool2d``。 这个操作对所有输入的通道进行最大池化,之后进行 BatchNorm2d。 参数固定为 ``kernel_size=3``\ , ``stride=1`` 和 ``padding=1``。
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.Pool
*
SepConv
* SepConvBN3x3:首先进行ReLU,之后进行 `DilConv <#DilConv>`__ ,最后是BatchNorm2d。 卷积参数固定为 ``kernel_size=3``\ , ``stride=1`` 和 ``padding=1``。
*
SepConvBN5x5:进行与之前相同的操作,但是它具有不同的内核大小和填充,分别设置为 5 和 2。
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.SepConvBN
*
跳过连接
调用 ``torch.nn.Identity`` 直接连接到一个 cell。
ENASMacroLayer
--------------
在宏搜索中,控制器为每个层做出两个决定:i)对上一层的结果执行的 `操作 <#macro-operations>`__ ,ii)通过跳过连接,连接到之前的那个层。 ENAS 使用控制器来设计整个模型结构而不是模型的某一部分。 操作的输出将与跳过连接的所选层的张量连接在一起。 NNI 为宏搜索提供 `预定义运算符 <#macro-operations>`__,这些宏在 `候选运算符 <#macro-operations>`__ 中列出。
ENAS Macro 的搜索空间如下图所示。
.. image:: ../../img/NAS_ENAS_macro.svg
:target: ../../img/NAS_ENAS_macro.svg
:alt:
.. autoclass:: nni.nas.pytorch.search_space_zoo.ENASMacroLayer
:members:
为了描述整个搜索空间,NNI 提供了一个模型,该模型是通过堆叠 ENASMacroLayer 构成的。
.. autoclass:: nni.nas.pytorch.search_space_zoo.ENASMacroGeneralModel
:members:
示例代码
^^^^^^^^^^^^
:githublink:`示例代码 <examples/nas/search_space_zoo/enas_macro_example.py>`
.. code-block:: bash
git clone https://github.com/Microsoft/nni.git
cd nni/examples/nas/search_space_zoo
# search the best cell structure
python3 enas_macro_example.py
:raw-html:`<a name="macro-operations"></a>`
候选运算符
^^^^^^^^^^^^^^^^^^^
所有 ENAS Macro 支持的操作如下。
*
ConvBranch
首先将所有输入传递到 StdConv,该操作由 1x1Conv,BatchNorm2d 和 ReLU 组成。 然后进行下列的操作之一。 最终结果通过后处理,包括BatchNorm2d和ReLU。
Separable Conv3x3:如果 ``separable=True``,则 cell 将使用 `SepConv <#DilConv>`__ 而不是常规的卷积操作。 SepConv 固定为 ``kernel_size=3``\ , ``stride=1`` 和 ``padding=1``。
* Separable Conv5x5: SepConv 固定为 ``kernel_size=5``\ , ``stride=1`` 和 ``padding=2``。
* 普通的 Conv3x3: 如果 ``separable=False``\ , cell 将使用常规的转化操作 ``kernel_size=3``\ , ``stride=1`` 和 ``padding=1``。
* 普通的 Conv5x5:Conv 固定为 ``kernel_size=5``\ , ``stride=1`` 和 ``padding=2``。
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.ConvBranch
*
PoolBranch
首先将所有输入传递到 StdConv,该操作由 1x1Conv,BatchNorm2d 和 ReLU 组成。 然后对中间结果进行池化操作和 BatchNorm。
* 平均池化:调用 ``torch.nn.AvgPool2d``。 这个操作对所有输入的通道进行平均池化。 参数固定为 ``kernel_size=3``\ , ``stride=1`` 和 ``padding=1``。
*
最大池化:调用 ``torch.nn.MaxPool2d``。 这个操作对所有输入的通道进行最大池化。 参数固定为 ``kernel_size=3``\ , ``stride=1`` 和 ``padding=1``。
.. autoclass:: nni.nas.pytorch.search_space_zoo.enas_ops.PoolBranch
NAS-Bench-201
-------------
NAS Bench 201 定义了与算法无关的统一搜索空间。 预定义的骨架由共享相同体系结构的 cell 堆栈组成。 每个 cell 包含四个节点,并且通过连接它们之间的边来形成 DAG,其中该节点表示特征图的总和,并且边表示将张量从源节点转换为目标节点的操作。 预定义的候选运算符可以在 `候选运算符 <#nas-bench-201-reference>`__ 中找到。
NAS Bench 201 的搜索空间如下所示。
.. image:: ../../img/NAS_Bench_201.svg
:target: ../../img/NAS_Bench_201.svg
:alt:
.. autoclass:: nni.nas.pytorch.nasbench201.NASBench201Cell
:members:
示例代码
^^^^^^^^^^^^
:githublink:`示例代码 <examples/nas/search_space_zoo/nas_bench_201.py>`
.. code-block:: bash
# for structure searching
git clone https://github.com/Microsoft/nni.git
cd nni/examples/nas/search_space_zoo
python3 nas_bench_201.py
:raw-html:`<a name="nas-bench-201-reference"></a>`
候选运算符
^^^^^^^^^^^^^^^^^^^
所有 NAS Bench 201 支持的操作如下。
*
AvgPool
如果输入通道数不等于输出通道数,则输入会首先通过 ``kernel_size = 1``,``stride = 1``,``padding = 0`` 和 ``dilation = 0`` 的 ``ReLUConvBN`` 层 。
调用 ``torch.nn.AvgPool2d``。 这个操作对所有输入的通道进行最大池化,之后进行BatchNorm2d。 参数固定为 ``kernel_size=3`` 和 ``padding=1``。
.. autoclass:: nni.nas.pytorch.nasbench201.nasbench201_ops.Pooling
:members:
*
Conv
* Conv1x1: 由一些列 ReLU,``nn.Cinv2d`` 和 BatchNorm 组成。 Conv 操作的参数固定为 ``kernal_size = 1``,``padding = 0`` 和 ``dilation = 1``。
* Conv3x3: 由一些列 ReLU,``nn.Cinv2d`` 和 BatchNorm 组成。 Conv 操作的参数固定为 ``kernal_size = 3``,``padding = 1`` 和 ``dilation = 1``。
.. autoclass:: nni.nas.pytorch.nasbench201.nasbench201_ops.ReLUConvBN
:members:
*
跳过连接
调用 ``torch.nn.Identity`` 直接连接到一个 cell。
*
归零
没有生成 tensors 表示从源节点到目标节点之间没有连接。
.. autoclass:: nni.nas.pytorch.nasbench201.nasbench201_ops.Zero
:members:
# TextNAS
## 介绍
这是论文 [TextNAS: A Neural Architecture Search Space tailored for Text Representation](https://arxiv.org/pdf/1912.10729.pdf) 中 TextNAS 算法的实现。 TextNAS 是用于文本表示的神经网络架构搜索算法,具体来说,TextNAS 基于由适配各种自然语言任务的操作符所组成的新的搜索空间,TextNAS 还支持单个网络中的多路径集成,来平衡网络的宽度和深度。
TextNAS 的搜索空间包含:
* 滤波器尺寸为 1, 3, 5, 7 的一维卷积操作
* 循环操作符(双向 GRU)
* 自注意操作符
* 池化操作符(最大值、平均值)
遵循 ENAS 算法,TextNAS 也用了参数共享来加速搜索速度,并采用了强化学习的 Controller 来进行架构采样和生成。 参考 TextNAS 论文了解更多细节。
## 准备
准备词向量和 SST 数据集,并按如下结构放到 data 目录中:
```
textnas
├── data
│ ├── sst
│ │ └── trees
│ │ ├── dev.txt
│ │ ├── test.txt
│ │ └── train.txt
│ └── glove.840B.300d.txt
├── dataloader.py
├── model.py
├── ops.py
├── README.md
├── search.py
└── utils.py
```
以下链接有助于查找和下载相应的数据集:
* [GloVe: Global Vectors for Word Representation](https://nlp.stanford.edu/projects/glove/)
* [glove.840B.300d.txt](http://nlp.stanford.edu/data/glove.840B.300d.zip)
* [Recursive Deep Models for Semantic Compositionality Over a Sentiment Treebank](https://nlp.stanford.edu/sentiment/)
* [trainDevTestTrees_PTB.zip](https://nlp.stanford.edu/sentiment/trainDevTestTrees_PTB.zip)
## 示例
### 搜索空间
[示例代码](https://github.com/microsoft/nni/tree/master/examples/nas/textnas)
```bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最佳网络结构
cd examples/nas/textnas
# 查看搜索的更多选项
python3 search.py -h
```
在每个搜索 Epoch 后,会直接测试 10 个采样的结构。 10 个 Epoch 后的性能预计为 40% - 42%。
默认情况下,20 个采样结构会被导出到 `checkpoints` 目录中,以便进行下一步处理。
### 重新训练
```bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最佳网络结构
cd examples/nas/textnas
# 默认在 sst-2 上训练
sh run_retrain.sh
```
## 参考
TextNAS 直接使用了 EnasTrainer,参考 [ENAS](./ENAS.md) 了解 Trainer 的 API。
TextNAS
=======
介绍
------------
这是 `TextNAS: A Neural Architecture Search Space tailored for Text Representation <https://arxiv.org/pdf/1912.10729.pdf>`__ 提出的 TextNAS 算法的实现。 TextNAS 是用于文本表示的神经网络架构搜索算法,具体来说,TextNAS 基于由适配各种自然语言任务的操作符所组成的新的搜索空间,TextNAS 还支持单个网络中的多路径集成,来平衡网络的宽度和深度。
TextNAS 的搜索空间包含:
.. code-block:: bash
* 滤波器尺寸为 1, 3, 5, 7 的一维卷积操作
* 循环操作符(双向 GRU)
* 自注意操作符
* 池化操作符(最大值、平均值)
遵循 ENAS 算法,TextNAS 也用了参数共享来加速搜索速度,并采用了强化学习的 Controller 来进行架构采样和生成。 参考 TextNAS 论文了解更多细节。
准备
-----------
准备词向量和 SST 数据集,并按如下结构放到 data 目录中:
.. code-block:: bash
textnas
├── data
│ ├── sst
│ │ └── trees
│ │ ├── dev.txt
│ │ ├── test.txt
│ │ └── train.txt
│ └── glove.840B.300d.txt
├── dataloader.py
├── model.py
├── ops.py
├── README.md
├── search.py
└── utils.py
以下链接有助于查找和下载相应的数据集:
* `GloVe: Global Vectors for Word Representation <https://nlp.stanford.edu/projects/glove/>`__
* `glove.840B.300d.txt <http://nlp.stanford.edu/data/glove.840B.300d.zip>`__
* `Recursive Deep Models for Semantic Compositionality Over a Sentiment Treebank <https://nlp.stanford.edu/sentiment/>`__
* `trainDevTestTrees_PTB.zip <https://nlp.stanford.edu/sentiment/trainDevTestTrees_PTB.zip>`__
示例
--------
搜索空间
^^^^^^^^^^^^
:githublink:`示例代码 <examples/nas/textnas>`
.. code-block:: bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最优结构
cd examples/nas/textnas
# 查看更多的搜索选择
python3 search.py -h
在每个搜索 Epoch 后,会直接测试 10 个采样的结构。 10 个 Epoch 后的性能预计为 40% - 42%。
默认情况下,20 个采样结构会被导出到 ``checkpoints`` 目录中,以便进行下一步处理。
重新训练
^^^^^^^^^^^^
.. code-block:: bash
#如果未克隆 NNI 代码。 如果代码已被克隆,请忽略此行并直接进入代码目录。
git clone https://github.com/Microsoft/nni.git
# 搜索最优结构
cd examples/nas/textnas
# default to retrain on sst-2
sh run_retrain.sh
参考
---------
TextNAS 直接使用了 EnasTrainer,参考 `ENAS <./ENAS.rst>`__ 了解 Trainer 的 API。
# NAS 可视化(测试版)
## 内置 Trainer 支持
当前,仅 ENAS 和 DARTS 支持可视化。 [ENAS](./ENAS.md)[DARTS](./DARTS.md) 的示例演示了如何在代码中启用可视化,其需要在 `trainer.train()` 前添加代码。
```python
trainer.enable_visualization()
```
此代码会在当前目录中创建新目录 `logs/<current_time_stamp>`,并创建两个新文件 `graph.json``log`
不必等到程序运行完后,再启动 NAS 界面,但需要确保这两个文件产生后,再启动。 启动 NAS 界面:
```bash
nnictl webui nas --logdir logs/<current_time_stamp> --port <port>
```
## 可视化定制的 Trainer
如果要定制 Trainer,参考[文档](./Advanced.md#extend-the-ability-of-one-shot-trainers)
需要对已有 Trainer 代码做两处改动来支持可视化:
1. 在训练前导出图:
```python
vis_graph = self.mutator.graph(inputs)
# `inputs` 是模型的虚拟输入。 例如,torch.randn((1, 3, 32, 32)).cuda()
# 如果模型有多个输入,则要使用 tuple。
with open("/path/to/your/logdir/graph.json", "w") as f:
json.dump(vis_graph, f)
```
2. 记录选择的 Choice。 可以每个 Epoch,批处理或任何频率下做次记录。
```python
def __init__(self):
# ...
self.status_writer = open("/path/to/your/logdir/log", "w") # create a writer
def train(self):
# ...
print(json.dumps(self.mutator.status()), file=self.status_writer, flush=True) # 保存状态
```
如果继承 `Trainer`,实现定制的 Trainer。 NNI 提供了 `enable_visualization()``_write_graph_status()` 来简化可视化。 只需要在开始前调用 `trainer.enable_visualization()`,并在每次要记录日志前调用 `trainer._write_graph_status()`。 注意,这两个 API 还处于试用阶段,未来可能会有所更改。
最后,启动 NAS 界面:
```bash
nnictl webui nas --logdir /path/to/your/logdir
```
## NAS 界面预览
![](../../img/nasui-1.png)
![](../../img/nasui-2.png)
## 局限性
* NAS 可视化仅适用于 PyTorch >=1.4。PyTorch 1.3.1 无法正常工作。
* 其依赖于 PyTorch 对 tensorboard 导出图的支持,即依赖于 `torch.jit`。 如果模型不支持 `jit`,也无法使用。
* 在加载中等大小,但有许多 Choice 的模型时(如 DARTS 的搜索空间),会遇到性能问题。
## 反馈
NAS UI 目前是测试版。 欢迎提交反馈。 [这里](https://github.com/microsoft/nni/pull/2085)列出了 NAS UI 接下来的工作。 欢迎直接评论,如果有其它建议,也可以[提交新问题](https://github.com/microsoft/nni/issues/new?template=enhancement.md)
NAS 可视化(测试版)
================================
内置 Trainer 支持
-------------------------
当前,仅 ENAS 和 DARTS 支持可视化。 `ENAS <./ENAS.rst>`__ 和 `DARTS <./DARTS.rst>`__ 的示例演示了如何在代码中启用可视化,其需要在 ``trainer.train()`` 前添加代码。
.. code-block:: python
trainer.enable_visualization()
此代码会在当前目录中创建新目录 ``logs/<current_time_stamp>``,并创建两个新文件 ``graph.json`` 和 ``log``。
不必等到程序运行完后,再启动 NAS 界面,但需要确保这两个文件产生后,再启动。 启动 NAS 界面:
.. code-block:: bash
nnictl webui nas --logdir logs/<current_time_stamp> --port <port>
可视化定制的 Trainer
------------------------------
如果要定制 Trainer,参考 `文档 <./Advanced.rst>`__。
需要对已有 Trainer 代码做两处改动来支持可视化:
#. 在训练前导出图:
.. code-block:: python
vis_graph = self.mutator.graph(inputs)
# `inputs` is a dummy input to your model. For example, torch.randn((1, 3, 32, 32)).cuda()
# If your model has multiple inputs, it should be a tuple.
with open("/path/to/your/logdir/graph.json", "w") as f:
json.dump(vis_graph, f)
#. 记录选择的 Choice。 可以每个 Epoch,批处理或任何频率下做次记录。
.. code-block:: python
def __init__(self):
# ...
self.status_writer = open("/path/to/your/logdir/log", "w") # create a writer
def train(self):
# ...
print(json.dumps(self.mutator.status()), file=self.status_writer, flush=True) # dump a record of status
如果继承 ``Trainer``,实现定制的 Trainer。 NNI 提供了 ``enable_visualization()`` 和 ``_write_graph_status()`` 来简化可视化。 只需要在开始前调用 ``trainer.enable_visualization()``,并在每次要记录日志前调用 ``trainer._write_graph_status()``。 注意,这两个 API 还处于试用阶段,未来可能会有所更改。
最后,启动 NAS 界面:
.. code-block:: bash
nnictl webui nas --logdir /path/to/your/logdir
NAS 界面预览
--------------
.. image:: ../../img/nasui-1.png
:target: ../../img/nasui-1.png
:alt:
.. image:: ../../img/nasui-2.png
:target: ../../img/nasui-2.png
:alt:
局限性
-----------
* NAS 可视化仅适用于 PyTorch >= 1.4。 PyTorch 1.3.1 上无法使用。
* 其依赖于 PyTorch 对 tensorboard 导出图的支持,即依赖于 ``torch.jit``。 如果模型不支持 ``jit``,也无法使用。
* 在加载中等大小,但有许多 Choice 的模型时(如 DARTS 的搜索空间),会遇到性能问题。
反馈
--------
NAS UI 目前是测试版。 欢迎提交反馈。 `这里 <https://github.com/microsoft/nni/pull/2085>`__ 列出了 NAS UI 接下来的工作。 欢迎直接评论,如果有其它建议,也可以 `提交新问题 <https://github.com/microsoft/nni/issues/new?template=enhancement.rst>`__。
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