"src/targets/vscode:/vscode.git/clone" did not exist on "8143e4fb9de2d0801a4210c90a65351a062af6ee"
NasInterface.md 8.61 KB
Newer Older
Chi Song's avatar
Chi Song committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# NNI NAS 编程接口

我们正在尝试通过统一的编程接口来支持各种 NAS 算法,当前处于试验阶段。 这意味着当前编程接口可能会进行重大变化。

## 模型的编程接口

在两种场景下需要用于设计和搜索模型的编程接口。

1. 在设计神经网络时,可能在层、子模型或连接上有多种选择,并且无法确定是其中一种或某些的组合的结果最好。 因此,需要简单的方法来表达候选的层或子模型。
2. 在神经网络上应用 NAS 时,需要统一的方式来表达架构的搜索空间,这样不必为不同的搜索算法来更改代码。


在用户代码中表示的神经网络搜索空间,可使用以下 API (以 PyTorch 为例):

```python
# 在 PyTorch module 类中
def __init__(self):
    ...
    # 从 ``ops`` 中选择 ``ops``, 这是 PyTorch 中的 module。
    # op_candidates: 在 PyTorch 中 ``ops`` 是 module 的 list,而在 TensorFlow 中是 Keras 层的 list。
    # key: ``LayerChoice`` 实例的名称
    self.one_layer = nni.nas.pytorch.LayerChoice([
        PoolBN('max', channels, 3, stride, 1, affine=False),
        PoolBN('avg', channels, 3, stride, 1, affine=False),
        FactorizedReduce(channels, channels, affine=False),
        SepConv(channels, channels, 3, stride, 1, affine=False),
        DilConv(channels, channels, 3, stride, 2, 2, affine=False)],
        key="layer_name")
    ...

def forward(self, x):
    ...
    out = self.one_layer(x)
    ...
```
用户可为某层指定多个候选的操作,最后从其中选择一个。 `key` 是层的标识符,可被用来在多个 `LayerChoice` 间共享选项。 例如,两个 `LayerChoice` 有相同的候选操作,并希望能使用同样的选择,(即,如果第一个选择了第 `i` 个操作,第二个也应该选择第 `i` 个操作),则可给它们相同的 key。

```python
def __init__(self):
    ...
    # 从 ``n_candidates`` 个输入中选择 ``n_selected`` 个。
    # n_candidates: 候选输入数量
    # n_chosen: 选择的数量
    # key: ``InputChoice`` 实例的名称
    self.input_switch = nni.nas.pytorch.InputChoice(
        n_candidates=3,
        n_chosen=1,
        key="switch_name")
    ...

def forward(self, x):
    ...
    out = self.input_switch([in_tensor1, in_tensor2, in_tensor3])
    ...
```
Chi Song's avatar
Chi Song committed
56
`InputChoice` 是一个 PyTorch module,初始化时需要元信息,例如,从多少个输入后选中选择多少个输入,以及初始化的 `InputChoice` 名称。 真正候选的输入张量只能在 `forward` 函数中获得。 在 `forward` 函数中,`InputChoice` 模块需要在 `__init__` 中创建 (如, `self.input_switch`),其会在有了实际候选输入 Tensor 的时候被调用。
Chi Song's avatar
Chi Song committed
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

一些 [NAS Trainer](#one-shot-training-mode) 需要知道输入张量的来源层,因此在 `InputChoice` 中添加了输入参数 `choose_from` 来表示每个候选输入张量的来源层。 `choose_from` 是 str 的 list,每个元素都是 `LayerChoice``InputChoice``key`,或者 module 的 name (详情参考[代码](https://github.com/microsoft/nni/blob/master/src/sdk/pynni/nni/nas/pytorch/mutables.py))。


除了 `LayerChoice``InputChoice`,还提供了 `MutableScope`,可以让用户标记自网络,从而给 NAS Trainer 提供更多的语义信息 (如网络结构)。 示例如下:
```python
class Cell(mutables.MutableScope):
    def __init__(self, scope_name):
        super().__init__(scope_name)
        self.layer1 = nni.nas.pytorch.LayerChoice(...)
        self.layer2 = nni.nas.pytorch.LayerChoice(...)
        self.layer3 = nni.nas.pytorch.LayerChoice(...)
        ...
```
名为 `scope_name``MutableScope` 包含了三个 `LayerChoice` 层 (`layer1`, `layer2`, `layer3`)。 NAS Trainer 可获得这样的分层结构。


## 两种训练模式

Chi Song's avatar
Chi Song committed
76
在使用上述 API 在模型中嵌入 搜索空间后,下一步是从搜索空间中找到最好的模型。 有两种训练模式:[one-shot 训练模式](#one-shot-training-mode) and [经典的分布式搜索](#classic-distributed-search)
Chi Song's avatar
Chi Song committed
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

### One-shot 训练模式

与深度学习模型的优化器相似,从搜索空间中找到最好模型的过程可看作是优化过程,称之为 `NAS Trainer`。 NAS Trainer 包括 `DartsTrainer` 使用了 SGD 来交替训练架构和模型权重,`ENASTrainer` 使用 Controller 来训练模型。 新的、更高效的 NAS Trainer 在研究界不断的涌现出来。

NNI 提供了一些流行的 NAS Trainer,要使用 NAS Trainer,用户需要在模型定义后初始化 Trainer:

```python
# 创建 DartsTrainer
trainer = DartsTrainer(model,
                       loss=criterion,
                       metrics=lambda output, target: accuracy(output, target, topk=(1,)),
                       optimizer=optim,
                       num_epochs=args.epochs,
                       dataset_train=dataset_train,
                       dataset_valid=dataset_valid,)
# 从搜索空间中找到最好的模型
trainer.train()
# 导出最好的模型
trainer.export(file='./chosen_arch')
```

不同的 Trainer 可能有不同的输入参数,具体取决于其算法。 详细参数可参考具体的 [Trainer 代码](https://github.com/microsoft/nni/tree/master/src/sdk/pynni/nni/nas/pytorch)。 训练完成后,可通过 `trainer.export()` 导出找到的最好的模型。 无需通过 `nnictl` 来启动 NNI Experiment。

Chi Song's avatar
Chi Song committed
101
[这里](Overview.md#supported-one-shot-nas-algorithms)是所有支持的 Trainer。 [这里](https://github.com/microsoft/nni/tree/master/examples/nas/simple/train.py)是使用 NNI NAS API 的简单示例。
Chi Song's avatar
Chi Song committed
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172

### 经典分布式搜索

神经网络架构搜索通过在 Trial 任务中独立运行单个子模型来实现。 NNI 同样支持这种搜索方法,其天然适用于 NNI 的超参搜索框架。Tuner 为每个 Trial 生成子模型,并在训练平台上运行。

要使用此模式,不需要修改 NNI NAS API 的搜索空间定义 (即, `LayerChoice`, `InputChoice`, `MutableScope`)。 模型初始化后,在模型上调用 `get_and_apply_next_architecture`。 One-shot NAS Trainer 不能在此模式中使用。 简单示例:
```python
class Net(nn.Module):
    # 使用 LayerChoice 和 InputChoice 的模型
    ...

model = Net()
# 从 Tuner 中选择架构,并应用到模型上
get_and_apply_next_architecture(model)
# 训练模型
train(model)
# 测试模型
acc = test(model)
# 返回此架构的性能
nni.report_final_result(acc)
```

搜索空间应自动生成,并发送给 Tuner。 通过 NNI NAS API,搜索空间嵌入在用户代码中,需要通过 "[nnictl ss_gen](../Tutorial/Nnictl.md)" 来生成搜索空间文件。 然后,将生成的搜索空间文件路径填入 `config.yml``searchSpacePath``config.yml` 中的其它字段参考[教程](../Tutorial/QuickStart.md)

可使用 [NNI Tuner](../Tuner/BuiltinTuner.md) 来搜索。

为了便于调试,其支持独立运行模式,可直接运行 Trial 命令,而不启动 NNI Experiment。 可以通过此方法来检查 Trial 代码是否可正常运行。 在独立模式下,`LayerChoice``InputChoice` 会选择最开始的候选项。

[此处](https://github.com/microsoft/nni/tree/master/examples/nas/classic_nas/config_nas.yml)是完整示例。

## NAS 算法的编程接口

通过简单的接口,可在 NNI 上实现新的 NAS Trainer。

### 在 NNI 上实现新的 NAS Trainer

要实现新的 NAS Trainer,基本上只需要继承 `BaseMutator``BaseTrainer` 这两个类。

`BaseMutator` 中,需要重载 `on_forward_layer_choice``on_forward_input_choice`,这是 `LayerChoice``InputChoice` 相应的实现。 可使用属性 `mutables` 来获得模型中所有的 `LayerChoice``InputChoice`。 然后实现新的 Trainer,来实例化新的 Mutator 并实现训练逻辑。 详细信息,可参考[代码](https://github.com/microsoft/nni/tree/master/src/sdk/pynni/nni/nas/pytorch),及支持的 Trainer,如 [DartsTrainer](https://github.com/microsoft/nni/tree/master/src/sdk/pynni/nni/nas/pytorch/darts)

### 为 NAS 实现 NNI Tuner

NNI 中的 NAS Tuner 需要自动生成搜索空间。 `LayerChoice``InputChoice` 的搜索空间格式如下:
```json
{
    "key_name": {
        "_type": "layer_choice",
        "_value": ["op1_repr", "op2_repr", "op3_repr"]
    },
    "key_name": {
        "_type": "input_choice",
        "_value": {
            "candidates": ["in1_key", "in2_key", "in3_key"],
            "n_chosen": 1
        }
    }
}
```

相应的,生成的网络架构格式如下:
```json
{
    "key_name": {
        "_value": "op1_repr",
        "_idx": 0
    },
    "key_name": {
        "_value": ["in2_key"],
        "_idex": [1]
    }
}
Chi Song's avatar
Chi Song committed
173
```