NetworkmorphismTuner.rst 9.97 KB
Newer Older
kvartet's avatar
kvartet 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
Network Morphism Tuner
=============================

1. 介绍
---------------

`Autokeras <https://arxiv.org/abs/1806.10282>`__ 是使用 Network Morphism 算法的流行的自动机器学习工具。 Autokeras 的基本理念是使用贝叶斯回归来预测神经网络架构的指标。 每次都会从父网络生成几个子网络。 然后使用朴素贝叶斯回归,从网络的历史训练结果来预测它的指标值。 接下来,会选择预测结果最好的子网络加入训练队列中。  `此代码 <https://github.com/jhfjhfj1/autokeras>`__ 的启发下,我们在 NNI 中实现了 Network Morphism 算法。

要了解 Network Morphism Trial 的用法,参考 :githublink:`这里 <examples/trials/network_morphism/README.md>`

2. 用法
--------

要使用 Network Morphism,需要如下配置 ``config.yml`` 文件:

.. code-block:: yaml

   tuner:
     #choice: NetworkMorphism
     builtinTunerName: NetworkMorphism
     classArgs:
       #choice: maximize, minimize
       optimize_mode: maximize
       # 当前,此 Tuner 仅支持视觉领域。
       task: cv
       # 修改以适合输入图像的宽度
       input_width: 32
       # 修改以适合输入图像的通道数
       input_channel: 3
       # 修改以适合类数
       n_output_node: 10

在训练过程中,会生成一个 JSON 文件来表示网络图。 可调用 ``json\_to\_graph()`` 函数来将 JSON 文件转化为 Pytoch  Keras 模型。

.. code-block:: python

   import nni
   from nni.networkmorphism_tuner.graph import json_to_graph

   def build_graph_from_json(ir_model_json):
       """从json构建pytorch模型
       """
       graph = json_to_graph(ir_model_json)
       model = graph.produce_torch_model()
       return model

   # Trial  Network Morphism Tuner 获取下一个参数
   RCV_CONFIG = nni.get_next_parameter()
   # 调用此函数来构建pytorch模型或keras模型
   net = build_graph_from_json(RCV_CONFIG)

   # 训练过程
   # ....

   # 将最终精度返回给 NNI
   nni.report_final_result(best_acc)

如果需要保存并读取 **最佳模型** ,推荐采用以下方法。

.. code-block:: python

   # 1. 使用 NNI API
   #  WebUI 获得最佳模型 ID
   # or 'nni-experiments/experiment_id/log/model_path/best_model.txt'

   # 从模型文件中读取 json 字符串,并用 NNI API 加载
   with open("best-model.json") as json_file:
       json_of_model = json_file.read()
   model = build_graph_from_json(json_of_model)

   # 2. # 使用框架 API
   # 2.1 Keras API

   #  Trial 代码中使用 Keras API 保存模型
   # 最好在 NNI 本地模式下保存 id
   model_id = nni.get_sequence_id()
   # 将模型序列化为 JSON
   model_json = model.to_json()
   with open("model-{}.json".format(model_id), "w") as json_file:
       json_file.write(model_json)
   # 将权重序列化为 HDF5
   model.save_weights("model-{}.h5".format(model_id))

   # 重用模型时,使用 Keras API 读取
   # 读取 JSON 文件,并创建模型
   model_id = "" # 需要重用的模型 ID
   with open('model-{}.json'.format(model_id), 'r') as json_file:
       loaded_model_json = json_file.read()
   loaded_model = model_from_json(loaded_model_json)
   # 将权重加载到新模型中
   loaded_model.load_weights("model-{}.h5".format(model_id))

   # 2.2 PyTorch API

   #  Trial 代码中使用 PyTorch API 保存
   model_id = nni.get_sequence_id()
   torch.save(model, "model-{}.pt".format(model_id))

   # 重用模型时,使用 PyTorch API 读取
   model_id = "" # id of the model you want to reuse
   loaded_model = torch.load("model-{}.pt".format(model_id))

3. 文件结构
-----------------

Tuner 有大量的文件、函数和类。 这里简单介绍最重要的文件:


* 
  ``networkmorphism_tuner.py`` 是使用 network morphism 算法的 Tuner

* 
  ``bayesian.py`` 是用来基于已经搜索到的模型来预测未知模型指标的贝叶斯算法。

* ``graph.py``  是元图数据结构。  Graph 表示了模型的神经网络图。

  * Graph 从模型中抽取神经网络。
  * 图中的每个节点都是层之间的中间张量。
  * 在图中,边表示层。
  * 注意,多条边可能会表示同一层。

* 
  ``graph_transformer.py`` 包含了一些图转换,包括变宽,变深,或在图中增加跳跃连接。

* 
  ``layers.py``  包括模型中用到的所有层。

* ``layer_transformer.py`` 包含了一些层转换,包括变宽,变深,或在层中增加跳跃连接。
* ``nn.py`` 包括生成初始网络的类。
* ``metric.py`` 包括了一些指标类,如 Accuracy  MSE
* ``utils.py`` 是使用 Keras 在数据集 ``cifar10`` 上搜索神经网络的示例。

4. 网络表示的 JSON 示例
------------------------------------------

这是样例定义的中间表示 JSON 文件,它会在架构搜索过程中从 Tuner 传到 Trial 可调用 Trial 代码中的 ``json_to_graph()`` 函数来将 JSON 文件转化为 Pytoch  Keras 模型。

.. code-block:: json

   {
        "input_shape": [32, 32, 3],
        "weighted": false,
        "operation_history": [],
        "layer_id_to_input_node_ids": {"0": [0],"1": [1],"2": [2],"3": [3],"4": [4],"5": [5],"6": [6],"7": [7],"8": [8],"9": [9],"10": [10],"11": [11],"12": [12],"13": [13],"14": [14],"15": [15],"16": [16]
        },
        "layer_id_to_output_node_ids": {"0": [1],"1": [2],"2": [3],"3": [4],"4": [5],"5": [6],"6": [7],"7": [8],"8": [9],"9": [10],"10": [11],"11": [12],"12": [13],"13": [14],"14": [15],"15": [16],"16": [17]
        },
        "adj_list": {
            "0": [[1, 0]],
            "1": [[2, 1]],
            "2": [[3, 2]],
            "3": [[4, 3]],
            "4": [[5, 4]],
            "5": [[6, 5]],
            "6": [[7, 6]],
            "7": [[8, 7]],
            "8": [[9, 8]],
            "9": [[10, 9]],
            "10": [[11, 10]],
            "11": [[12, 11]],
            "12": [[13, 12]],
            "13": [[14, 13]],
            "14": [[15, 14]],
            "15": [[16, 15]],
            "16": [[17, 16]],
            "17": []
        },
        "reverse_adj_list": {
            "0": [],
            "1": [[0, 0]],
            "2": [[1, 1]],
            "3": [[2, 2]],
            "4": [[3, 3]],
            "5": [[4, 4]],
            "6": [[5, 5]],
            "7": [[6, 6]],
            "8": [[7, 7]],
            "9": [[8, 8]],
            "10": [[9, 9]],
            "11": [[10, 10]],
            "12": [[11, 11]],
            "13": [[12, 12]],
            "14": [[13, 13]],
            "15": [[14, 14]],
            "16": [[15, 15]],
            "17": [[16, 16]]
        },
        "node_list": [
            [0, [32, 32, 3]],
            [1, [32, 32, 3]],
            [2, [32, 32, 64]],
            [3, [32, 32, 64]],
            [4, [16, 16, 64]],
            [5, [16, 16, 64]],
            [6, [16, 16, 64]],
            [7, [16, 16, 64]],
            [8, [8, 8, 64]],
            [9, [8, 8, 64]],
            [10, [8, 8, 64]],
            [11, [8, 8, 64]],
            [12, [4, 4, 64]],
            [13, [64]],
            [14, [64]],
            [15, [64]],
            [16, [64]],
            [17, [10]]
        ],
        "layer_list": [
            [0, ["StubReLU", 0, 1]],
            [1, ["StubConv2d", 1, 2, 3, 64, 3]],
            [2, ["StubBatchNormalization2d", 2, 3, 64]],
            [3, ["StubPooling2d", 3, 4, 2, 2, 0]],
            [4, ["StubReLU", 4, 5]],
            [5, ["StubConv2d", 5, 6, 64, 64, 3]],
            [6, ["StubBatchNormalization2d", 6, 7, 64]],
            [7, ["StubPooling2d", 7, 8, 2, 2, 0]],
            [8, ["StubReLU", 8, 9]],
            [9, ["StubConv2d", 9, 10, 64, 64, 3]],
            [10, ["StubBatchNormalization2d", 10, 11, 64]],
            [11, ["StubPooling2d", 11, 12, 2, 2, 0]],
            [12, ["StubGlobalPooling2d", 12, 13]],
            [13, ["StubDropout2d", 13, 14, 0.25]],
            [14, ["StubDense", 14, 15, 64, 64]],
            [15, ["StubReLU", 15, 16]],
            [16, ["StubDense", 16, 17, 64, 10]]
        ]
    }

可将模型视为 `有向无环图 <https://zh.wikipedia.org/wiki/Directed_acyclic_graph>`__ 每个模型的定义都是一个 JSON 对象:


* ``input_shape`` 是整数的列表,不包括批量维度。
* ``weighted`` 表示是否权重和偏移值应该包含在此神经网络图中。
* ``operation_history`` 是保存了所有网络形态操作的列表。
* ``layer_id_to_input_node_ids`` 是字典,将层的标识映射到输入节点标识。
* ``layer_id_to_output_node_ids`` 是字典,将层的标识映射到输出节点标识。
* ``adj_list`` 是二维列表,是图的邻接表。 第一维是张量标识。 在每条边的列表中,元素是两元组(张量标识,层标识)。
* ``reverse_adj_list`` 是与 adj_list 格式一样的反向邻接列表。
* ``node_list`` 是一个整数列表。 列表的索引是标识。
* ``layer_list`` 是层的列表。 列表的索引是标识。


  * 对于 ``StubConv(StubConv1d, StubConv2d, StubConv3d)``,后面的数字表示节点的输入 id(或 id 列表),节点输出 idinput_channelfilterskernel_sizestride  padding

  * 对于 ``StubDense``,后面的数字表示节点的输入 id (或 id 列表),节点输出 idinput_units  units

  * 对于 ``StubBatchNormalization (StubBatchNormalization1d, StubBatchNormalization2d, StubBatchNormalization3d)``,后面的数字表示节点输入 id(或 id 列表),节点输出 id,和特征数量。

  * 对于 ``StubDropout(StubDropout1d, StubDropout2d, StubDropout3d)``,后面的数字表示节点的输入 id (或 id 列表),节点的输出 id  dropout 率。

  * 对于 ``StubPooling (StubPooling1d, StubPooling2d, StubPooling3d)`` 后面的数字表示节点的输入 id(或 id 列表),节点输出 idkernel_size, stride  padding

  * 对于其它层,后面的数字表示节点的输入 id(或 id 列表)以及节点的输出 id

5. TODO
-------

下一步,会将 API 从固定网络生成器,改为有更多可用操作的网络生成器。 会使用 ONNX 格式来替代 JSON 作为中间表示结果。