Coverage for mlos_bench/mlos_bench/tests/tunables/tunable_to_configspace_test.py: 100%
49 statements
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-05 00:36 +0000
« prev ^ index » next coverage.py v7.5.1, created at 2024-05-05 00:36 +0000
1#
2# Copyright (c) Microsoft Corporation.
3# Licensed under the MIT License.
4#
5"""
6Unit tests for Tunable to ConfigSpace conversion.
7"""
9import pytest
11from ConfigSpace import (
12 CategoricalHyperparameter,
13 ConfigurationSpace,
14 EqualsCondition,
15 UniformFloatHyperparameter,
16 UniformIntegerHyperparameter,
17)
19from mlos_bench.tunables.tunable import Tunable
20from mlos_bench.tunables.tunable_groups import TunableGroups
21from mlos_bench.optimizers.convert_configspace import (
22 TunableValueKind,
23 _tunable_to_configspace,
24 special_param_names,
25 tunable_groups_to_configspace,
26)
28# pylint: disable=redefined-outer-name
31@pytest.fixture
32def configuration_space() -> ConfigurationSpace:
33 """
34 A test fixture that produces a mock ConfigurationSpace object
35 matching the tunable_groups fixture.
37 Returns
38 -------
39 configuration_space : ConfigurationSpace
40 A new ConfigurationSpace object for testing.
41 """
42 (kernel_sched_migration_cost_ns_special,
43 kernel_sched_migration_cost_ns_type) = special_param_names("kernel_sched_migration_cost_ns")
45 spaces = ConfigurationSpace(space={
46 "vmSize": ["Standard_B2s", "Standard_B2ms", "Standard_B4ms"],
47 "idle": ["halt", "mwait", "noidle"],
48 "kernel_sched_migration_cost_ns": (0, 500000),
49 kernel_sched_migration_cost_ns_special: [-1, 0],
50 kernel_sched_migration_cost_ns_type: [TunableValueKind.SPECIAL, TunableValueKind.RANGE],
51 "kernel_sched_latency_ns": (0, 1000000000),
52 })
54 # NOTE: FLAML requires distribution to be uniform
55 spaces["vmSize"].default_value = "Standard_B4ms"
56 spaces["idle"].default_value = "halt"
57 spaces["kernel_sched_migration_cost_ns"].default_value = 250000
58 spaces[kernel_sched_migration_cost_ns_special].default_value = -1
59 spaces[kernel_sched_migration_cost_ns_special].probabilities = (0.5, 0.5)
60 spaces[kernel_sched_migration_cost_ns_type].default_value = TunableValueKind.SPECIAL
61 spaces[kernel_sched_migration_cost_ns_type].probabilities = (0.5, 0.5)
62 spaces["kernel_sched_latency_ns"].default_value = 2000000
64 spaces.add_condition(EqualsCondition(
65 spaces[kernel_sched_migration_cost_ns_special],
66 spaces[kernel_sched_migration_cost_ns_type], TunableValueKind.SPECIAL))
67 spaces.add_condition(EqualsCondition(
68 spaces["kernel_sched_migration_cost_ns"],
69 spaces[kernel_sched_migration_cost_ns_type], TunableValueKind.RANGE))
71 return spaces
74def _cmp_tunable_hyperparameter_categorical(
75 tunable: Tunable, space: ConfigurationSpace) -> None:
76 """
77 Check if categorical Tunable and ConfigSpace Hyperparameter actually match.
78 """
79 param = space[tunable.name]
80 assert isinstance(param, CategoricalHyperparameter)
81 assert set(param.choices) == set(tunable.categories)
82 assert param.default_value == tunable.value
85def _cmp_tunable_hyperparameter_numerical(
86 tunable: Tunable, space: ConfigurationSpace) -> None:
87 """
88 Check if integer Tunable and ConfigSpace Hyperparameter actually match.
89 """
90 param = space[tunable.name]
91 assert isinstance(param, (UniformIntegerHyperparameter, UniformFloatHyperparameter))
92 assert (param.lower, param.upper) == tuple(tunable.range)
93 if tunable.in_range(tunable.value):
94 assert param.default_value == tunable.value
97def test_tunable_to_configspace_categorical(tunable_categorical: Tunable) -> None:
98 """
99 Check the conversion of Tunable to CategoricalHyperparameter.
100 """
101 cs_param = _tunable_to_configspace(tunable_categorical)
102 _cmp_tunable_hyperparameter_categorical(tunable_categorical, cs_param)
105def test_tunable_to_configspace_int(tunable_int: Tunable) -> None:
106 """
107 Check the conversion of Tunable to UniformIntegerHyperparameter.
108 """
109 cs_param = _tunable_to_configspace(tunable_int)
110 _cmp_tunable_hyperparameter_numerical(tunable_int, cs_param)
113def test_tunable_to_configspace_float(tunable_float: Tunable) -> None:
114 """
115 Check the conversion of Tunable to UniformFloatHyperparameter.
116 """
117 cs_param = _tunable_to_configspace(tunable_float)
118 _cmp_tunable_hyperparameter_numerical(tunable_float, cs_param)
121_CMP_FUNC = {
122 "int": _cmp_tunable_hyperparameter_numerical,
123 "float": _cmp_tunable_hyperparameter_numerical,
124 "categorical": _cmp_tunable_hyperparameter_categorical,
125}
128def test_tunable_groups_to_hyperparameters(tunable_groups: TunableGroups) -> None:
129 """
130 Check the conversion of TunableGroups to ConfigurationSpace.
131 Make sure that the corresponding Tunable and Hyperparameter objects match.
132 """
133 space = tunable_groups_to_configspace(tunable_groups)
134 for (tunable, _group) in tunable_groups:
135 _CMP_FUNC[tunable.type](tunable, space)
138def test_tunable_groups_to_configspace(
139 tunable_groups: TunableGroups, configuration_space: ConfigurationSpace) -> None:
140 """
141 Check the conversion of the entire TunableGroups collection
142 to a single ConfigurationSpace object.
143 """
144 space = tunable_groups_to_configspace(tunable_groups)
145 assert space == configuration_space