CustomizeTuner.rst 4.84 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
自定义 Tuner
===============

自定义 Tuner
---------------

NNI 在内置的 Tuner 中提供了最新的调优算法。 NNI 同时也支持自定义 Tuner。

通过自定义 Tuner,可实现自己的调优算法。主要有三步:


#. 继承 Tuner 基类
#. 实现 receive_trial_result, generate_parameter 和 update_search_space 函数
#. 在 Experiment 的 YAML 文件中配置好自定义的 Tuner

示例如下:

**1. 继承 Tuner 基类**

.. code-block:: python

   from nni.tuner import Tuner

   class CustomizedTuner(Tuner):
       def __init__(self, ...):
           ...

**2. 实现 receive_trial_result, generate_parameter 和 update_search_space 函数**

.. code-block:: python

   from nni.tuner import Tuner

   class CustomizedTuner(Tuner):
       def __init__(self, ...):
           ...

       def receive_trial_result(self, parameter_id, parameters, value, **kwargs):
           '''
           最终结果
           parameter_id: int
           parameters: 对象可由 'generate_parameters()' 创建
           value: Trial 最终指标,包括默认指标
           '''
           # 你的代码
       ...

       def generate_parameters(self, parameter_id, **kwargs):
           '''
           以可序列化对象的形式返回一组 Trial (超)参数
           parameter_id: int
           '''
           # 你的代码
           return your_parameters
       ...

       def update_search_space(self, search_space):
           '''
           Tuner 支持在运行时更新搜索空间。
           如果 Tuner 只在生成第一个超参前设置搜索空间,
           需要将其行为写到文档里。
           search_space: 定义 Experiment 时创建的 JSON 对象
           '''
           # 你的代码
       ...

``receive_trial_result`` 从输入中会接收 ``parameter_id, parameters, value`` 参数。 Tuner 会收到 Trial 进程发送的完全一样的 ``value`` 值。

``generate_parameters`` 函数返回的 ``your_parameters``,会被 NNI SDK 打包为 json。 然后 SDK 会将 json 对象解包给 Trial 进程。因此,Trial 进程会收到来自 Tuner 的完全相同的 ``your_parameters``。

例如:
如下实现了 ``generate_parameters``:

.. code-block:: python

   def generate_parameters(self, parameter_id, **kwargs):
       '''
       以可序列化对象的形式返回一组 Trial (超)参数
       parameter_id: int
       '''
       # 你的代码
       return {"dropout": 0.3, "learning_rate": 0.4}

这表示 Tuner 会一直生成超参组合 ``{"dropout": 0.3, "learning_rate": 0.4}``。 而 Trial 进程也会在调用 API ``nni.get_next_parameter()`` 时得到 ``{"dropout": 0.3, "learning_rate": 0.4}``。 Trial 结束后的返回值(通常是某个指标),通过调用 API ``nni.report_final_result()`` 返回给 Tuner。如: ``nni.report_final_result(0.93)``。 而 Tuner 的 ``receive_trial_result`` 函数会收到如下结果:

.. code-block:: python

   parameter_id = 82347
   parameters = {"dropout": 0.3, "learning_rate": 0.4}
   value = 0.93

**注意** :Tuner 的工作目录是 ``<home>/nni-experiments/<experiment_id>/log``,可使用环境变量 ``NNI_LOG_DIRECTORY``,因此 ,如果要访问自己 Tuner 目录中的文件(如: ``data.txt``)不能直接使用 ``open('data.txt', 'r')``。 要使用:

.. code-block:: python

   _pwd = os.path.dirname(__file__)
   _fd = open(os.path.join(_pwd, 'data.txt'), 'r')

这是因为自定义的 Tuner 不是在自己的目录里执行的。(即,``pwd`` 返回的目录不是 Tuner 的目录)。

**3. 在 Experiment 的 YAML 文件中配置好自定义的 Tuner**

NNI 需要定位到自定义的 Tuner 类,并实例化它,因此需要指定自定义 Tuner 类的文件位置,并将参数值传给 ``__init__`` 构造函数。

.. code-block:: yaml

   tuner:
     codeDir: /home/abc/mytuner
     classFileName: my_customized_tuner.py
     className: CustomizedTuner
     # 所有的参数都需要传递给你 Assessor 的构造函数 __init__
     # 例如,可以在可选的 classArgs 字段中指定
     classArgs:
       arg1: value1

更多示例,可参考:

..

kvartet's avatar
kvartet committed
120
121
   * :githublink:`evolution-tuner <nni/algorithms/hpo/evolution_tuner.py>`
   * :githublink:`hyperopt-tuner <nni/algorithms/hpo/hyperopt_tuner.py>`
kvartet's avatar
kvartet committed
122
123
124
125
126
127
   * :githublink:`evolution-based-customized-tuner <examples/tuners/ga_customer_tuner>`


实现更高级的自动机器学习算法
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

kvartet's avatar
kvartet committed
128
上述内容足够写出通用的 Tuner。 但有时可能需要更多的信息,例如,中间结果, Trial 的状态等等,从而能够实现更强大的自动机器学习算法。 因此,有另一个 ``Advisor`` 类,直接继承于 ``MsgDispatcherBase``,它在 :githublink:`src/sdk/pynni/nni/msg_dispatcher_base.py <nni/runtime/msg_dispatcher_base.py>` 。 参考 `这里 <CustomizeAdvisor.rst>`__ 来了解如何实现自定义的 Advisor。