NetworkmorphismTuner.rst 10 KB
Newer Older
kvartet's avatar
kvartet committed
1
2
3
4
5
6
7
8
Network Morphism Tuner
=============================

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

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

kvartet's avatar
kvartet committed
9
要了解 Network Morphism Trial 的用法,参考 :githublink:`Readme <examples/trials/network_morphism/README.rst>`
kvartet's avatar
kvartet committed
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

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
kvartet's avatar
kvartet committed
64
   # 或者 ``nni-experiments/experiment_id/log/model_path/best_model.txt``
kvartet's avatar
kvartet committed
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

   # 从模型文件中读取 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`` 是一个整数列表。 列表的索引是标识。
kvartet's avatar
kvartet committed
240
241
* 
  ``layer_list`` 是层的列表。 列表的索引是标识。
kvartet's avatar
kvartet committed
242
243


kvartet's avatar
kvartet committed
244
245
  * 
    对于 ``StubConv(StubConv1d, StubConv2d, StubConv3d)``,后面的数字表示节点的输入 id(或 id 列表),节点输出 idinput_channelfilterskernel_sizestride  padding
kvartet's avatar
kvartet committed
246

kvartet's avatar
kvartet committed
247
248
  * 
    对于 ``StubDense``,后面的数字表示节点的输入 id (或 id 列表),节点输出 idinput_units  units
kvartet's avatar
kvartet committed
249

kvartet's avatar
kvartet committed
250
251
  * 
    对于 ``StubBatchNormalization (StubBatchNormalization1d, StubBatchNormalization2d, StubBatchNormalization3d)``,后面的数字表示节点输入 id(或 id 列表),节点输出 id,和特征数量。
kvartet's avatar
kvartet committed
252

kvartet's avatar
kvartet committed
253
254
  * 
    对于 ``StubDropout(StubDropout1d, StubDropout2d, StubDropout3d)``,后面的数字表示节点的输入 id (或 id 列表),节点的输出 id  dropout 率。
kvartet's avatar
kvartet committed
255

kvartet's avatar
kvartet committed
256
257
  * 
    对于 ``StubPooling (StubPooling1d, StubPooling2d, StubPooling3d)`` 后面的数字表示节点的输入 id(或 id 列表),节点输出 idkernel_size, stride  padding
kvartet's avatar
kvartet committed
258

kvartet's avatar
kvartet committed
259
260
  * 
    对于其它层,后面的数字表示节点的输入 id(或 id 列表)以及节点的输出 id
kvartet's avatar
kvartet committed
261
262
263
264
265

5. TODO
-------

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