Unverified Commit 91d9a797 authored by Yuge Zhang's avatar Yuge Zhang Committed by GitHub
Browse files

Adopt symbolic links in Chinese documentation (#4345)


Co-authored-by: default avatarjiahangxu <jiahangxu@microsoft.com>
parent 0e0ee86d
../../en_US/NAS/ExplorationStrategies.rst
\ No newline at end of file
FBNet
======
.. note:: 这个 One-Shot NAS 仍然在 NNI NAS 1.0 下实现,将在 v2.4 中迁移到 `Retiarii 框架 <https://github.com/microsoft/nni/issues/3814>`__。
对于 facial landmark 的移动应用,基于 PFLD 模型的基本架构,我们应用 FBNet(Block-wise DNAS)设计了一个在延迟和准确率之间权衡的简洁模型。 参考资料如下:
* `FBNet: Hardware-Aware Efficient ConvNet Design via Differentiable Neural Architecture Search <https://arxiv.org/abs/1812.03443>`__
* `PFLD: A Practical Facial Landmark Detector <https://arxiv.org/abs/1902.10859>`__
FBNet 是一种分块可微分 NAS 方法(Block-wise DNAS),通过使用 Gumbel Softmax 随机采样和可微分训练来选择最佳候选构建块。 在要搜索的每一层(或阶段),并排规划不同的候选块(就像结构重新参数化的有效性一样),从而对超网络进行充分的预训练。 对预训练的超网进一步采样来对子网进行微调,以实现更好的性能。
.. image:: ../../img/fbnet.png
:target: ../../img/fbnet.png
:alt:
PFLD 是一种用于实时应用的轻量级 facial landmark 模型。 通过使用 PeleeNet 的 stem 块、深度卷积的平均池化和 eSE 模块,PLFD 的结构首先被简化加速。
为了在延迟和准确性之间取得更好的平衡,FBNet 被进一步应用于简化的 PFLD,以便在每个特定层搜索最佳块。 搜索空间以 FBNet 空间为基础,并通过使用深度卷积的平均池化和 eSE 模块等对移动部署进行优化。
实验
------------
为了验证 FBNet 应用于 PFLD 的有效性,我们选择具有 106 个 landmark 的开源数据集作为基准:
* `106个点的 Facial Landmark Localization 大挑战 <https://arxiv.org/abs/1905.03469>`__
基线模型表示为 MobileNet-V3 PFLD(`参考基线 <https://github.com/Hsintao/pfld_106_face_landmarks>`__),搜索到的模型表示为 Subnet。 实验结果如下,其中延迟在高通625 CPU(ARMv8)上测试:
.. list-table::
:header-rows: 1
:widths: auto
* - 模型
- 大小
- 延迟
- 验证 NME
* - MobileNet-V3 PFLD
- 1.01MB
- 10ms
- 6.22%
* - Subnet
- 693KB
- 1.60ms
- 5.58%
示例
--------
`示例代码 <https://github.com/microsoft/nni/tree/master/examples/nas/oneshot/pfld>`__
请在示例目录下运行下面的脚本。
此处使用的 Python 依赖如下所示:
.. code-block:: bash
numpy==1.18.5
opencv-python==4.5.1.48
torch==1.6.0
torchvision==0.7.0
onnx==1.8.1
onnx-simplifier==0.3.5
onnxruntime==1.7.0
数据准备
-----------------
首先,您应该将数据集 `106points dataset <https://drive.google.com/file/d/1I7QdnLxAlyG2Tq3L66QYzGhiBEoVfzKo/view?usp=sharing>`__ 下载到路径 ``./data/106points`` 。 数据集包括训练集和测试集:
.. code-block:: bash
./data/106points/train_data/imgs
./data/106points/train_data/list.txt
./data/106points/test_data/imgs
./data/106points/test_data/list.txt
快速入门
-----------
1. 搜索
^^^^^^^^^^
基于简化的 PFLD 架构,以构建超网为例,首先应配置多阶段搜索空间和搜索的超参数。
.. code-block:: bash
from lib.builder import search_space
from lib.ops import PRIMITIVES
from lib.supernet import PFLDInference, AuxiliaryNet
from nni.algorithms.nas.pytorch.fbnet import LookUpTable, NASConfig,
# 超参数配置
# search_space 定义多阶段搜索空间
nas_config = NASConfig(
model_dir="./ckpt_save",
nas_lr=0.01,
mode="mul",
alpha=0.25,
beta=0.6,
search_space=search_space,
)
# 管理信息的查询表
lookup_table = LookUpTable(config=nas_config, primitives=PRIMITIVES)
# 创建超网
pfld_backbone = PFLDInference(lookup_table)
在创建了搜索空间和超参数的超网后,我们可以运行以下命令开始搜索和训练超网。
.. code-block:: bash
python train.py --dev_id "0,1" --snapshot "./ckpt_save" --data_root "./data/106points"
训练过程中会显示验证准确率,准确率最高的模型会被保存为 ``./ckpt_save/supernet/checkpoint_best.pth``。
2. 微调
^^^^^^^^^^^^
在对超网进行预训练后,我们可以运行以下命令对子网进行采样并进行微调:
.. code-block:: bash
python retrain.py --dev_id "0,1" --snapshot "./ckpt_save" --data_root "./data/106points" \
--supernet "./ckpt_save/supernet/checkpoint_best.pth"
训练过程中会显示验证准确率,准确率最高的模型会被保存为 ``./ckpt_save/subnet/checkpoint_best.pth``。
3. 导出
^^^^^^^^^^
在对子网进行微调后,我们可以运行以下命令来导出 ONNX 模型。
.. code-block:: bash
python export.py --supernet "./ckpt_save/supernet/checkpoint_best.pth" \
--resume "./ckpt_save/subnet/checkpoint_best.pth"
ONNX 模型被保存为 ``./output/subnet.onnx``,可以通过使用 `MNN <https://github.com/alibaba/MNN>`__ 进一步转换为移动推理引擎。
我们提供了预训练超网和子网的 checkpoint:
* `超网 <https://drive.google.com/file/d/1TCuWKq8u4_BQ84BWbHSCZ45N3JGB9kFJ/view?usp=sharing>`__
* `子网 <https://drive.google.com/file/d/160rkuwB7y7qlBZNM3W_T53cb6MQIYHIE/view?usp=sharing>`__
* `ONNX 模型 <https://drive.google.com/file/d/1s-v-aOiMv0cqBspPVF3vSGujTbn_T_Uo/view?usp=sharing>`__
\ No newline at end of file
../../en_US/NAS/FBNet.rst
\ No newline at end of file
../../en_US/NAS/HardwareAwareNAS.rst
\ No newline at end of file
../../en_US/NAS/Hypermodules.rst
\ No newline at end of file
模型 Evaluator
================
模型评估器(model evaluator)用于训练和验证每个生成的模型。
模型评估器的用法
------------------------------------
在 multi-NAS 中,采样模型应该能够在远程机器或训练平台(例如 AzureML、OpenPAI)上执行。 因此,模型及其模型评估器都应该正确序列化。 为了使 NNI 正确地序列化模型评估器,用户应该在他们的一些函数和对象上应用 ``serialize`` 。
.. _serializer:
`serialize <./ApiReference.rst#id7>`__ 允许在另一个进程或机器中重新实例化模型评估器。 它是通过记录用户实例化的评估器的初始化参数来实现的。
Retiarii 提供的评估器相关 API 已经支持序列化,例如 ``pl.Classification``, ``pl.DataLoader``,无需对其应用 ``serialize``。 在以下情况下,用户应该手动使用 ``serialize`` API。
如果评估器 API 的初始化参数(例如 ``pl.Classification``、``pl.DataLoader``)不是原始类型(例如 ``int``, ``string``),它们应该是与 ``serialize`` 一起应用。 如果这些参数的初始化参数不是原始类型,``serialize`` 也应该被应用。 总而言之,如果有必要,``serialize`` 应该被递归应用。
以下是一个示例,``transforms.Compose``, ``transforms.Normalize`` 和 ``MNIST`` 应该通过 ``serialize`` 手动序列化。 ``serialize`` 以一个类 ``cls`` 作为它的第一个参数,它后面的参数是初始化这个类的参数。 ``pl.Classification`` 没有应用 ``serialize`` 因为它已经被 NNI 提供的 API 序列化。
.. code-block:: python
import nni.retiarii.evaluator.pytorch.lightning as pl
from nni.retiarii import serialize
from torchvision import transforms
transform = serialize(transforms.Compose, [serialize(transforms.ToTensor()), serialize(transforms.Normalize, (0.1307,), (0.3081,))])
train_dataset = serialize(MNIST, root='data/mnist', train=True, download=True, transform=transform)
test_dataset = serialize(MNIST, root='data/mnist', train=False, download=True, transform=transform)
evaluator = pl.Classification(train_dataloader=pl.DataLoader(train_dataset, batch_size=100),
val_dataloaders=pl.DataLoader(test_dataset, batch_size=100),
max_epochs=10)
支持的模型评估器
----------------------------------------
NNI 提供了一些常用的模型评估器以方便用户使用。 如果这些模型评估器不满足用户的要求,您可以按照 `教程 <./WriteTrainer.rst>`__ 自定义新的模型评估器。
.. autoclass:: nni.retiarii.evaluator.pytorch.lightning.Classification
:noindex:
.. autoclass:: nni.retiarii.evaluator.pytorch.lightning.Regression
:noindex:
../../en_US/NAS/ModelEvaluators.rst
\ No newline at end of file
Mutation 原语
===================
为了让用户在他们的 PyTorch/TensorFlow 模型中轻松表达模型空间,NNI 提供了一些内联 mutation API,如下所示。
* `nn.LayerChoice <./ApiReference.rst#nni.retiarii.nn.pytorch.LayerChoice>`__. 它允许用户放置多个候选操作(例如,PyTorch 模块),在每个探索的模型中选择其中一个。
.. code-block:: python
# import nni.retiarii.nn.pytorch as nn
# 在 `__init__` 中声明
self.layer = nn.LayerChoice([
ops.PoolBN('max', channels, 3, stride, 1),
ops.SepConv(channels, channels, 3, stride, 1),
nn.Identity()
]))
# 在 `forward` 函数中调用
out = self.layer(x)
* `nn.InputChoice <./ApiReference.rst#nni.retiarii.nn.pytorch.InputChoice>`__. 它主要用于选择(或尝试)不同的连接。 它会从设置的几个张量中,选择 ``n_chosen`` 个张量。
.. code-block:: python
# import nni.retiarii.nn.pytorch as nn
# 在 `__init__` 中声明
self.input_switch = nn.InputChoice(n_chosen=1)
# 在 `forward` 函数中调用,三者选一
out = self.input_switch([tensor1, tensor2, tensor3])
* `nn.ValueChoice <./ApiReference.rst#nni.retiarii.nn.pytorch.ValueChoice>`__. 它用于从一些候选值中选择一个值。 它只能作为基本单元的输入参数,即 ``nni.retiarii.nn.pytorch`` 中的模块和用 ``@basic_unit`` 装饰的用户定义的模块。
.. code-block:: python
# import nni.retiarii.nn.pytorch as nn
# 在 `__init__` 中使用
self.conv = nn.Conv2d(XX, XX, kernel_size=nn.ValueChoice([1, 3, 5])
self.op = MyOp(nn.ValueChoice([0, 1]), nn.ValueChoice([-1, 1]))
* `nn.Repeat <./ApiReference.rst#nni.retiarii.nn.pytorch.Repeat>`__. 以可变次数重复某个块
* `nn.Cell <./ApiReference.rst#nni.retiarii.nn.pytorch.Cell>`__. `这种细胞结构在 NAS 文献中被普遍使用 <https://arxiv.org/abs/1611.01578>`__。 具体来说,Cell 由多个 "nodes"(节点)组成。 每个节点是多个运算符的总和。 每个运算符从用户指定的候选者中选择,并从以前的节点和前代(predecessor)中获取一个输入。 前代(Predecessor)指 Cell 的输入。 Cell 的输出是 Cell 中部分节点(目前是所有节点)的串联。
\ No newline at end of file
../../en_US/NAS/MutationPrimitives.rst
\ No newline at end of file
用 Mutators 表示 Mutations
===============================
除了在 `这里 <./MutationPrimitives.rst>`__ 演示的内联突变 API,NNI 还提供了一种更通用的方法来表达模型空间,即 *突变器(Mutator)*,以涵盖更复杂的模型空间。 那些内联突变 API在底层系统中也是用突变器实现的,这可以看作是模型突变的一个特殊情况。
.. note:: Mutator 和内联突变 API 不能一起使用。
突变器是一段逻辑,用来表达如何突变一个给定的模型。 用户可以自由地编写自己的突变器。 然后用一个基础模型和一个突变器列表来表达一个模型空间。 通过在基础模型上接连应用突变器,来对模型空间中的一个模型进行采样。 示例如下:
.. code-block:: python
applied_mutators = []
applied_mutators.append(BlockMutator('mutable_0'))
applied_mutators.append(BlockMutator('mutable_1'))
``BlockMutator`` 由用户定义,表示如何对基本模型进行突变。
编写 mutator
---------------
用户定义的 Mutator 应该继承 ``Mutator`` 类,并在成员函数 ``mutate`` 中实现突变逻辑。
.. code-block:: python
from nni.retiarii import Mutator
class BlockMutator(Mutator):
def __init__(self, target: str, candidates: List):
super(BlockMutator, self).__init__()
self.target = target
self.candidate_op_list = candidates
def mutate(self, model):
nodes = model.get_nodes_by_label(self.target)
for node in nodes:
chosen_op = self.choice(self.candidate_op_list)
node.update_operation(chosen_op.type, chosen_op.params)
``mutate`` 的输入是基本模型的 graph IR(请参考 `这里 <./ApiReference.rst>`__ 获取 IR 的格式和 API),用户可以使用其成员函数(例如, ``get_nodes_by_label``,``update_operation``)对图进行变异。 变异操作可以与 API ``self.choice`` 相结合,以表示一组可能的突变。 在上面的示例中,节点的操作可以更改为 ``candidate_op_list`` 中的任何操作。
使用占位符使突变更容易:``nn.Placeholder``。 如果要更改模型的子图或节点,可以在此模型中定义一个占位符来表示子图或节点。 然后,使用 Mutator 对这个占位符进行变异,使其成为真正的模块。
.. code-block:: python
ph = nn.Placeholder(
label='mutable_0',
kernel_size_options=[1, 3, 5],
n_layer_options=[1, 2, 3, 4],
exp_ratio=exp_ratio,
stride=stride
)
``label`` 被 Mutator 所使用,来识别此占位符。 其他参数是突变器需要的信息。 它们可以从 ``node.operations.parameters`` 作为一个 dict 被访问,包括任何用户想传递给自定义突变器的信息。 完整的示例代码可以在 :githublink:`Mnasnet base model <examples/nas/multi-trial/mnasnet/base_mnasnet.py>` 找到。
开始一个实验与使用内联突变 API 几乎是一样的。 唯一的区别是,应用的突变器应该被传递给 ``RetiariiExperiment``。 示例如下:
.. code-block:: python
exp = RetiariiExperiment(base_model, trainer, applied_mutators, simple_strategy)
exp_config = RetiariiExeConfig('local')
exp_config.experiment_name = 'mnasnet_search'
exp_config.trial_concurrency = 2
exp_config.max_trial_number = 10
exp_config.training_service.use_active_gpu = False
exp.run(exp_config, 8081)
../../en_US/NAS/Mutators.rst
\ No newline at end of file
One-shot NAS
============
在阅读本教程之前,我们强烈建议您先阅读有关如何 `定义一个模型空间 <./QuickStart.rst#id1>`__ 的教程。
使用 One-shot Trainer 进行模型搜素
--------------------------------------------------------------------
对于定义的模型空间,用户可以通过两种方式来探索。 一个是使用探索策略和单架构评估器,正如 `在这里 <./QuickStart.rst#id4>`__ 所演示的那样。 另一种是使用 one-shot trainer,与第一种相比,它消耗的计算资源要少得多。 在本教程中,我们专注于 One-Shot 方法。 One-Shot 方法的原理是将模型空间中的所有模型合并成一个大模型(通常称为超级模型或超级图)。 通过训练和评估整个超级模型,来实现搜索、训练和测试的任务。
我们在此列出已支持的 One-Shot Trainer:
* DARTS trainer
* ENAS trainer
* ProxylessNAS trainer
* Single-path (random) trainer
参见 `API 参考 <./ApiReference.rst>`__ 获得详细用法。 在这里,我们展示了一个例子来手动使用 DARTS Trainer。
.. code-block:: python
from nni.retiarii.oneshot.pytorch import DartsTrainer
trainer = DartsTrainer(
model=model,
loss=criterion,
metrics=lambda output, target: accuracy(output, target, topk=(1,)),
optimizer=optim,
num_epochs=args.epochs,
dataset=dataset_train,
batch_size=args.batch_size,
log_frequency=args.log_frequency,
unrolled=args.unrolled
)
trainer.fit()
final_architecture = trainer.export()
**导出架构的格式**:未来将会支持。
../../en_US/NAS/OneshotTrainer.rst
\ No newline at end of file
Retiarii 用于神经网络架构搜索
=======================================
.. Note:: NNI 最新的 NAS 支持都是基于 Retiarii 框架的,仍在使用早期版本 `NNI NAS v1.0 <https://nni.readthedocs.io/zh/v2.2/nas.html>`__ 的用户应尽快将工作迁移到 Retiarii 框架。
.. 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 工作来帮助开发通用的 DNN 模型是相当困难的。 因此,我们设计了 `Retiarii <https://www.usenix.org/system/files/osdi20-zhang_quanlu.pdf>`__,一个全新的 NAS/HPO 框架,并在 NNI 中实施。 它可以帮助用户轻松构建模型空间(或搜索空间,调优空间),并利用现有的 NAS 算法。 该框架还有助于 NAS 创新,用于设计新的 NAS 算法。
概述
--------
Retiarii 框架有三个主要特点:
* 提供简单的 API,用于在 PyTorch/TensorFlow 模型中定义模型搜索空间。
* 内置前沿 NAS 算法,用于探索模型搜索空间。
* 实施系统级优化以加快探索。
有两种类型的模型空间探索方法:**Multi-trial NAS** 和 **One-shot NAS**。 Mutli-trial NAS 在模型空间中独立训练每个采样模型,而 One-shot NAS 则从一个超级模型中采样。 构建模型空间后,用户可以使用探索方法来探索模型空间。
Multi-trial NAS
-----------------
Multi-trial NAS 意味着每个来自模型空间的抽样模型都是独立训练的。 一个典型的 multi-trial NAS 是 `NASNet <https://arxiv.org/abs/1707.07012>`__。 从模型空间中抽取模型的算法被称为探索策略。 NNI支持以下 multi-trial NAS 的探索策略。
.. list-table::
:header-rows: 1
:widths: auto
* - 探索策略名称
- 算法简介
* - 随机策略
- 从搜索空间中随机选择模型 (``nni.retiarii.strategy.Random``)
* - 网格搜索
- 使用网格搜索算法从用户定义的模型空间中采样新模型。 (``nni.retiarii.strategy.GridSearch``)
* - 正则进化
- 使用 `正则进化算法 <https://arxiv.org/abs/1802.01548>`__ 从生成的模型中生成新模型 (``nni.retiarii.strategy.RegularizedEvolution``)
* - TPE 策略
- 使用 `TPE 算法 <https://papers.nips.cc/paper/2011/file/86e8f7ab32cfd12577bc2619bc635690-Paper.pdf>`__ 从用户定义的模型空间中生成新模型 (``nni.retiarii.strategy.TPEStrategy``)
* - RL 策略
- 使用 `PPO 算法 <https://arxiv.org/abs/1707.06347>`__ 从用户定义的模型空间中生成新模型 (``nni.retiarii.strategy.PolicyBasedRL``)
参考 `这里 <./multi_trial_nas.rst>`__ 获取 multi-trial NAS 详细用法。
One-shot NAS
---------------------------------
One-Shot NAS意味着将模型空间构建成一个超级模型,用权重共享的方式训练超级模型,然后从超级模型中不断采样,找到最佳模型。 `DARTS <https://arxiv.org/abs/1806.09055>`__ 是一个典型的 One-Shot NAS。
以下是已经支持的 One-Shot NAS 算法。 未来将支持更多 One-Shot NAS 算法。
.. list-table::
:header-rows: 1
:widths: auto
* - One-shot 算法名称
- 算法简介
* - `ENAS <ENAS.rst>`__
- `Efficient Neural Architecture Search via Parameter Sharing <https://arxiv.org/abs/1802.03268>`__. 在 ENAS 中,Contoller 学习在大的计算图中搜索最有子图的方式来发现神经网络。 它通过在子模型间共享参数来实现加速和出色的性能指标。
* - `DARTS <DARTS.rst>`__
- `DARTS: Differentiable Architecture Search <https://arxiv.org/abs/1806.09055>`__ 介绍了一种用于双级优化的可区分网络体系结构搜索的新算法。
* - `SPOS <SPOS.rst>`__
- `Single Path One-Shot Neural Architecture Search with Uniform Sampling <https://arxiv.org/abs/1904.00420>`__ 论文构造了一个采用统一的路径采样方法来训练简化的超网络,并使用进化算法来提高搜索神经网络结构的效率。
* - `ProxylessNAS <Proxylessnas.rst>`__
- `ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware <https://arxiv.org/abs/1812.00332>`__. 它删除了代理,直接从大规模目标任务和目标硬件平台进行学习。
参考 `这里 <ClassicNas.rst>`__ ,了解如何使用经典 NAS 算法。
参考和反馈
----------------------
* `快速入门 <./QuickStart.rst>`__ ;
* `构建模型空间 <./construct_space.rst>`__ ;
* `Retiarii: 一个探索性的深度学习框架 <https://www.usenix.org/system/files/osdi20-zhang_quanlu.pdf>`__ ;
* 在 Github 中 `提交 Bug 报告 <https://github.com/microsoft/nni/issues/new?template=bug-report.rst>`__;
* 在Github 中 `提交新功能或请求改进 <https://github.com/microsoft/nni/issues/new?template=enhancement.rst>`__。
../../en_US/NAS/Overview.rst
\ No newline at end of file
NNI 上的 ProxylessNAS
======================================
介绍
------------
论文 `ProxylessNAS: Direct Neural Architecture Search on Target Task and Hardware <https://arxiv.org/pdf/1812.00332.pdf>`__ 删除了 proxy,它直接学习了用于大规模目标任务和目标硬件平台的体系结构。 它解决了可微分 NAS 大量内存消耗的问题,从而将计算成本较低到普通训练的水平,同时仍然能使用大规模的候选集。 参考论文了解详情。
用法
-----
要使用 ProxylessNAS 训练/搜索方法,用户需要使用 `NNI NAS 接口 <MutationPrimitives.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/oneshot/proxylessnas>` 使用 :githublink:`NNI NAS 接口 <nni/algorithms/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。
../../en_US/NAS/Proxylessnas.rst
\ No newline at end of file
.. 83ce1769eb03248c40c61ccae8afe4cd
快速入门 Retiarii
==============================
......
单路径 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.SPOSSupernetTrainingMutator
:members:
已知的局限
-----------------
* 仅支持 Block 搜索。 尚不支持通道搜索。
* 仅提供 GPU 版本。
当前重现结果
----------------------------
重现中。 由于官方版本和原始论文之间的不同,我们将当前结果与官方 Repo(我们运行的结果)和论文进行了比较。
* 进化阶段几乎与官方 Repo 一致。 进化算法显示出了收敛趋势,在搜索结束时达到约 65% 的精度。 但此结果与论文不一致。 详情参考 `此 issue <https://github.com/megvii-model/SinglePathOneShot/issues/6>`__。
* 重新训练阶段未匹配。 我们的重新训练代码,使用了作者发布的架构,获得了 72.14% 的准确率,与官方发布的 73.61%,和原始论文中的 74.3% 有一定差距。
../../en_US/NAS/SPOS.rst
\ 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