random_tuner.py 2.1 KB
Newer Older
1
2
3
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

4
"""
5
Naive random tuner.
6
7
8
9

You can specify an integer seed to determine random result.
"""

10
11
12
from __future__ import annotations

__all__ = ['RandomTuner']
13

14
15
import logging

16
17
18
19
import numpy as np
import schema

from nni import ClassArgsValidator
20
from nni.common.hpo_utils import Deduplicator, format_search_space, deformat_parameters
21
22
from nni.tuner import Tuner

23
24
_logger = logging.getLogger('nni.tuner.random')

25
class RandomTuner(Tuner):
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    """
    A naive tuner that generates fully random hyperparameters.

    Examples
    --------

    .. code-block::

        config.tuner.name = 'Random'
        config.tuner.class_args = {
            'seed': 100
        }

    Parameters
    ----------
    seed
        The random seed.
    """

    def __init__(self, seed: int | None = None):
46
        self.space = None
47
48
        if seed is None:  # explicitly generate a seed to make the experiment reproducible
            seed = np.random.default_rng().integers(2 ** 31)
49
        self.rng = np.random.default_rng(seed)
50
        self.dedup = None
51
        _logger.info(f'Using random seed {seed}')
52
53
54

    def update_search_space(self, space):
        self.space = format_search_space(space)
55
        self.dedup = Deduplicator(self.space)
56
57
58

    def generate_parameters(self, *args, **kwargs):
        params = suggest(self.rng, self.space)
59
        params = self.dedup(params)
60
61
62
63
64
65
66
67
68
69
70
        return deformat_parameters(params, self.space)

    def receive_trial_result(self, *args, **kwargs):
        pass

class RandomClassArgsValidator(ClassArgsValidator):
    def validate_class_args(self, **kwargs):
        schema.Schema({schema.Optional('seed'): int}).validate(kwargs)

def suggest(rng, space):
    params = {}
71
72
73
    for key, spec in space.items():
        if spec.is_activated_in(params):
            params[key] = suggest_parameter(rng, spec)
74
    return params
75
76
77
78
79
80
81
82

def suggest_parameter(rng, spec):
    if spec.categorical:
        return rng.integers(spec.size)
    if spec.normal_distributed:
        return rng.normal(spec.mu, spec.sigma)
    else:
        return rng.uniform(spec.low, spec.high)