kernel-tuner 1.2.0__tar.gz → 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/PKG-INFO +2 -2
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/cupy.py +0 -1
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/hypertuner.py +82 -27
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/core.py +5 -2
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/file_utils.py +24 -1
- kernel_tuner-1.3.0/kernel_tuner/hyper.py +215 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/integration.py +4 -4
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/interface.py +95 -43
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/runners/simulation.py +22 -3
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/schema/T1/1.0.0/input-schema.json +2 -1
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/schema/T4/1.0.0/results-schema.json +5 -1
- kernel_tuner-1.3.0/kernel_tuner/searchspace.py +1509 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/basinhopping.py +2 -2
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/bayes_opt.py +1 -1
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/brute_force.py +1 -1
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/common.py +117 -37
- kernel_tuner-1.3.0/kernel_tuner/strategies/diff_evo.py +409 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/dual_annealing.py +6 -5
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/firefly_algorithm.py +10 -8
- kernel_tuner-1.3.0/kernel_tuner/strategies/genetic_algorithm.py +252 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/greedy_ils.py +9 -4
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/greedy_mls.py +2 -2
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/minimize.py +2 -2
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/pso.py +20 -14
- kernel_tuner-1.3.0/kernel_tuner/strategies/pyatf_strategies.py +125 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/random_sample.py +2 -2
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/simulated_annealing.py +72 -22
- kernel_tuner-1.3.0/kernel_tuner/strategies/wrapper.py +56 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/util.py +39 -16
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/pyproject.toml +5 -3
- kernel_tuner-1.3.0/test/conftest.py +7 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/context.py +27 -5
- kernel_tuner-1.3.0/test/strategies/test_cache_file.json +394 -0
- kernel_tuner-1.3.0/test/strategies/test_diff_evo.py +189 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/strategies/test_genetic_algorithm.py +9 -4
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/strategies/test_strategies.py +55 -17
- kernel_tuner-1.3.0/test/test_cache_file_T1_input.json +82 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_compiler_functions.py +2 -2
- kernel_tuner-1.3.0/test/test_custom_optimizer.py +174 -0
- kernel_tuner-1.3.0/test/test_hyper.py +39 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_integration.py +6 -6
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_kernelbuilder.py +2 -2
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_runners.py +10 -4
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_searchspace.py +154 -0
- kernel_tuner-1.3.0/test/utils/__init__.py +0 -0
- kernel_tuner-1.3.0/test/vector_add.cu +6 -0
- kernel_tuner-1.2.0/kernel_tuner/hyper.py +0 -98
- kernel_tuner-1.2.0/kernel_tuner/searchspace.py +0 -839
- kernel_tuner-1.2.0/kernel_tuner/strategies/diff_evo.py +0 -42
- kernel_tuner-1.2.0/kernel_tuner/strategies/genetic_algorithm.py +0 -181
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/LICENSE +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/README.md +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/accuracy.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/backend.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/compiler.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/hip.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/nvcuda.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/opencl.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/backends/pycuda.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/energy/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/energy/energy.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/kernelbuilder.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/compiler.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/cupy.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/hip.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/ncu.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/nvcuda.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/nvml.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/observer.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/opencl.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/pmt.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/powersensor.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/pycuda.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/register.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/observers/tegra.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/runners/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/runners/runner.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/runners/sequential.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/schema/T4/1.0.0/metadata-schema.json +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/hillclimbers.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/mls.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/strategies/ordered_greedy_mls.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/utils/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/kernel_tuner/utils/directives.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/convolution.cu +0 -0
- {kernel_tuner-1.2.0/test/utils → kernel_tuner-1.3.0/test/strategies}/__init__.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/strategies/test_bayesian_optimization.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/strategies/test_common.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/synthetic_fp32_cache_NVIDIA_RTX_A4000.json +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_T1_input.json +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_accuracy.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_backend.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_cache_file.json +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_common.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_core.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_cuda_functions.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_cupy_functions.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_energy.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_file_utils.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_hip_functions.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_nvml_mocked.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_observers.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_opencl_functions.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_pycuda_functions.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_pycuda_mocked.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_time_budgets.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_toml_file.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/test_util_functions.py +0 -0
- {kernel_tuner-1.2.0 → kernel_tuner-1.3.0}/test/utils/test_directives.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: kernel_tuner
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.0
|
|
4
4
|
Summary: An easy to use CUDA/OpenCL kernel tuner in Python
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: auto-tuning,gpu,computing,pycuda,cuda,pyopencl,opencl
|
|
@@ -43,7 +43,7 @@ Requires-Dist: pycuda (>=2025.1) ; extra == "cuda"
|
|
|
43
43
|
Requires-Dist: pynvml (>=11.4.1) ; extra == "cuda"
|
|
44
44
|
Requires-Dist: pyopencl ; extra == "cuda-opencl"
|
|
45
45
|
Requires-Dist: pyopencl ; extra == "opencl"
|
|
46
|
-
Requires-Dist: python-constraint2 (>=2.
|
|
46
|
+
Requires-Dist: python-constraint2 (>=2.4.0)
|
|
47
47
|
Requires-Dist: scikit-learn (>=1.0.2)
|
|
48
48
|
Requires-Dist: scipy (>=1.14.1)
|
|
49
49
|
Requires-Dist: xmltodict
|
|
@@ -17,6 +17,8 @@ except ImportError:
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class ScoreObserver(BenchmarkObserver):
|
|
20
|
+
"""BenchmarkObserver subclass for registering the hyperparameter tuning score."""
|
|
21
|
+
|
|
20
22
|
def __init__(self, dev):
|
|
21
23
|
self.dev = dev
|
|
22
24
|
self.scores = []
|
|
@@ -33,13 +35,70 @@ class HypertunerFunctions(Backend):
|
|
|
33
35
|
"""Class for executing hyperparameter tuning."""
|
|
34
36
|
units = {}
|
|
35
37
|
|
|
36
|
-
def __init__(self, iterations):
|
|
38
|
+
def __init__(self, iterations, compiler_options=None):
|
|
37
39
|
self.iterations = iterations
|
|
40
|
+
self.compiler_options = compiler_options
|
|
38
41
|
self.observers = [ScoreObserver(self)]
|
|
39
42
|
self.name = platform.processor()
|
|
40
43
|
self.max_threads = 1024
|
|
41
44
|
self.last_score = None
|
|
42
45
|
|
|
46
|
+
# set the defaults
|
|
47
|
+
self.gpus = ["A100", "A4000", "MI250X"]
|
|
48
|
+
folder = "../autotuning_methodology/benchmark_hub/kernels"
|
|
49
|
+
self.applications = [
|
|
50
|
+
{
|
|
51
|
+
"name": "dedispersion_milo",
|
|
52
|
+
"folder": folder,
|
|
53
|
+
"input_file": "dedispersion_milo.json",
|
|
54
|
+
"objective_performance_keys": ["time"]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"name": "hotspot_milo",
|
|
58
|
+
"folder": folder,
|
|
59
|
+
"input_file": "hotspot_milo.json",
|
|
60
|
+
"objective_performance_keys": ["GFLOP/s"]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "convolution_milo",
|
|
64
|
+
"folder": folder,
|
|
65
|
+
"input_file": "convolution_milo.json",
|
|
66
|
+
"objective_performance_keys": ["time"]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"name": "gemm_milo",
|
|
70
|
+
"folder": folder,
|
|
71
|
+
"input_file": "gemm_milo.json",
|
|
72
|
+
"objective_performance_keys": ["time"]
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
# any additional settings
|
|
76
|
+
self.override = {
|
|
77
|
+
"experimental_groups_defaults": {
|
|
78
|
+
"repeats": 25,
|
|
79
|
+
"samples": self.iterations,
|
|
80
|
+
"minimum_fraction_of_budget_valid": 0.1,
|
|
81
|
+
"minimum_number_of_valid_search_iterations": 3,
|
|
82
|
+
},
|
|
83
|
+
"statistics_settings": {
|
|
84
|
+
"cutoff_percentile": 0.95,
|
|
85
|
+
"cutoff_percentile_start": 0.01,
|
|
86
|
+
"cutoff_type": "time",
|
|
87
|
+
"objective_time_keys": [
|
|
88
|
+
"all"
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# override the defaults with compiler options if provided
|
|
94
|
+
if self.compiler_options is not None:
|
|
95
|
+
if "gpus" in self.compiler_options:
|
|
96
|
+
self.gpus = self.compiler_options["gpus"]
|
|
97
|
+
if "applications" in self.compiler_options:
|
|
98
|
+
self.applications = self.compiler_options["applications"]
|
|
99
|
+
if "override" in self.compiler_options:
|
|
100
|
+
self.override = self.compiler_options["override"]
|
|
101
|
+
|
|
43
102
|
# set the environment options
|
|
44
103
|
env = dict()
|
|
45
104
|
env["iterations"] = self.iterations
|
|
@@ -60,22 +119,6 @@ class HypertunerFunctions(Backend):
|
|
|
60
119
|
path = Path(__file__).parent.parent.parent / "hyperparamtuning"
|
|
61
120
|
path.mkdir(exist_ok=True)
|
|
62
121
|
|
|
63
|
-
# TODO get applications & GPUs args from benchmark
|
|
64
|
-
gpus = ["RTX_3090", "RTX_2080_Ti"]
|
|
65
|
-
applications = None
|
|
66
|
-
# applications = [
|
|
67
|
-
# {
|
|
68
|
-
# "name": "convolution",
|
|
69
|
-
# "folder": "./cached_data_used/kernels",
|
|
70
|
-
# "input_file": "convolution.json"
|
|
71
|
-
# },
|
|
72
|
-
# {
|
|
73
|
-
# "name": "pnpoly",
|
|
74
|
-
# "folder": "./cached_data_used/kernels",
|
|
75
|
-
# "input_file": "pnpoly.json"
|
|
76
|
-
# }
|
|
77
|
-
# ]
|
|
78
|
-
|
|
79
122
|
# strategy settings
|
|
80
123
|
strategy: str = kernel_instance.arguments[0]
|
|
81
124
|
hyperparams = [{'name': k, 'value': v} for k, v in kernel_instance.params.items()]
|
|
@@ -88,16 +131,9 @@ class HypertunerFunctions(Backend):
|
|
|
88
131
|
'search_method_hyperparameters': hyperparams
|
|
89
132
|
}]
|
|
90
133
|
|
|
91
|
-
# any additional settings
|
|
92
|
-
override = {
|
|
93
|
-
"experimental_groups_defaults": {
|
|
94
|
-
"samples": self.iterations
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
134
|
name = kernel_instance.name if len(kernel_instance.name) > 0 else kernel_instance.kernel_source.kernel_name
|
|
99
|
-
experiments_filepath = generate_experiment_file(name, path, searchspace_strategies, applications, gpus,
|
|
100
|
-
override=override, overwrite_existing_file=True)
|
|
135
|
+
experiments_filepath = generate_experiment_file(name, path, searchspace_strategies, self.applications, self.gpus,
|
|
136
|
+
override=self.override, generate_unique_file=True, overwrite_existing_file=True)
|
|
101
137
|
return str(experiments_filepath)
|
|
102
138
|
|
|
103
139
|
def start_event(self):
|
|
@@ -114,12 +150,27 @@ class HypertunerFunctions(Backend):
|
|
|
114
150
|
return super().synchronize()
|
|
115
151
|
|
|
116
152
|
def run_kernel(self, func, gpu_args=None, threads=None, grid=None, stream=None):
|
|
153
|
+
# from cProfile import Profile
|
|
154
|
+
|
|
155
|
+
# # generate the experiments file
|
|
156
|
+
# experiments_filepath = Path(func)
|
|
157
|
+
|
|
158
|
+
# # run the methodology to get a fitness score for this configuration
|
|
159
|
+
# with Profile() as pr:
|
|
160
|
+
# scores = get_strategy_scores(str(experiments_filepath), full_validate_on_load=False)
|
|
161
|
+
# pr.dump_stats('diff_evo_hypertune_hotspot.prof')
|
|
162
|
+
# self.last_score = scores[list(scores.keys())[0]]['score']
|
|
163
|
+
# raise ValueError(scores)
|
|
164
|
+
|
|
117
165
|
# generate the experiments file
|
|
118
166
|
experiments_filepath = Path(func)
|
|
119
167
|
|
|
120
168
|
# run the methodology to get a fitness score for this configuration
|
|
121
|
-
scores = get_strategy_scores(str(experiments_filepath))
|
|
169
|
+
scores = get_strategy_scores(str(experiments_filepath), full_validate_on_load=False)
|
|
122
170
|
self.last_score = scores[list(scores.keys())[0]]['score']
|
|
171
|
+
|
|
172
|
+
# remove the experiments file
|
|
173
|
+
experiments_filepath.unlink()
|
|
123
174
|
|
|
124
175
|
def memset(self, allocation, value, size):
|
|
125
176
|
return super().memset(allocation, value, size)
|
|
@@ -129,3 +180,7 @@ class HypertunerFunctions(Backend):
|
|
|
129
180
|
|
|
130
181
|
def memcpy_htod(self, dest, src):
|
|
131
182
|
return super().memcpy_htod(dest, src)
|
|
183
|
+
|
|
184
|
+
def refresh_memory(self, device_memory, host_arguments, should_sync):
|
|
185
|
+
"""This is a no-op for the hypertuner backend, as it does not manage memory directly."""
|
|
186
|
+
pass
|
|
@@ -315,10 +315,13 @@ class DeviceInterface(object):
|
|
|
315
315
|
observers=observers,
|
|
316
316
|
)
|
|
317
317
|
elif lang.upper() == "HYPERTUNER":
|
|
318
|
-
dev = HypertunerFunctions(
|
|
318
|
+
dev = HypertunerFunctions(
|
|
319
|
+
iterations=iterations,
|
|
320
|
+
compiler_options=compiler_options
|
|
321
|
+
)
|
|
319
322
|
self.requires_warmup = False
|
|
320
323
|
else:
|
|
321
|
-
raise
|
|
324
|
+
raise NotImplementedError(
|
|
322
325
|
"Sorry, support for languages other than CUDA, OpenCL, HIP, C, and Fortran is not implemented yet"
|
|
323
326
|
)
|
|
324
327
|
self.dev = dev
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import json
|
|
4
4
|
import subprocess
|
|
5
5
|
from importlib.metadata import PackageNotFoundError, requires, version
|
|
6
|
+
from importlib.util import spec_from_file_location, module_from_spec
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from sys import platform
|
|
8
9
|
|
|
@@ -152,7 +153,7 @@ def get_t4_results(results, tune_params, objective="time"):
|
|
|
152
153
|
|
|
153
154
|
# write output_data to a JSON file
|
|
154
155
|
version, _ = output_file_schema("results")
|
|
155
|
-
output_json = dict(results=output_data, schema_version=version, metadata={'timeunit': '
|
|
156
|
+
output_json = dict(results=output_data, schema_version=version, metadata={'timeunit': 'milliseconds'})
|
|
156
157
|
return output_json
|
|
157
158
|
|
|
158
159
|
def store_output_file(output_filename: str, results, tune_params, objective="time"):
|
|
@@ -302,3 +303,25 @@ def store_metadata_file(metadata_filename: str):
|
|
|
302
303
|
with open(metadata_filenamepath, "w+") as fh:
|
|
303
304
|
json.dump(metadata_json, fh, indent=" ")
|
|
304
305
|
|
|
306
|
+
def import_class_from_file(file_path: Path, class_name):
|
|
307
|
+
"""Import a class from a file."""
|
|
308
|
+
|
|
309
|
+
def load_module(module_name):
|
|
310
|
+
spec = spec_from_file_location(module_name, file_path)
|
|
311
|
+
if spec is None:
|
|
312
|
+
raise ImportError(f"Could not load spec from {file_path}")
|
|
313
|
+
|
|
314
|
+
# create a module from the spec and execute it
|
|
315
|
+
module = module_from_spec(spec)
|
|
316
|
+
spec.loader.exec_module(module)
|
|
317
|
+
if not hasattr(module, class_name):
|
|
318
|
+
raise ImportError(f"Module '{module_name}' has no class '{class_name}'")
|
|
319
|
+
return module
|
|
320
|
+
|
|
321
|
+
try:
|
|
322
|
+
module = load_module(file_path.stem)
|
|
323
|
+
except ImportError:
|
|
324
|
+
module = load_module(f"{file_path.parent.stem}.{file_path.stem}")
|
|
325
|
+
|
|
326
|
+
# return the class from the module
|
|
327
|
+
return getattr(module, class_name)
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""Module for functions related to hyperparameter optimization."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from random import randint
|
|
6
|
+
from argparse import ArgumentParser
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
import kernel_tuner
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_random_unique_filename(prefix = '', suffix=''):
|
|
14
|
+
"""Get a random, unique filename that does not yet exist."""
|
|
15
|
+
def randpath():
|
|
16
|
+
return Path(f"{prefix}{randint(1000, 9999)}{suffix}")
|
|
17
|
+
path = randpath()
|
|
18
|
+
while path.exists():
|
|
19
|
+
path = randpath()
|
|
20
|
+
return path
|
|
21
|
+
|
|
22
|
+
def tune_hyper_params(target_strategy: str, hyper_params: dict, restrictions: list, *args, **kwargs):
|
|
23
|
+
"""Tune hyperparameters for a given strategy and kernel.
|
|
24
|
+
|
|
25
|
+
This function is to be called just like tune_kernel, except that you specify a strategy
|
|
26
|
+
and a dictionary with hyperparameters in front of the arguments you pass to tune_kernel.
|
|
27
|
+
|
|
28
|
+
The arguments to tune_kernel should contain a cachefile. To compute the optimum the hyperparameter
|
|
29
|
+
tuner first tunes the kernel with a brute force search. If your cachefile is not yet complete
|
|
30
|
+
this may take very long.
|
|
31
|
+
|
|
32
|
+
:param target_strategy: Specify the strategy for which to tune hyperparameters
|
|
33
|
+
:type target_strategy: string
|
|
34
|
+
|
|
35
|
+
:param hyper_params: A dictionary containing the hyperparameters as keys and
|
|
36
|
+
lists the possible values per key
|
|
37
|
+
:type hyper_params: dict(string: list)
|
|
38
|
+
|
|
39
|
+
:param args: all positional arguments used to call tune_kernel
|
|
40
|
+
:type args: various
|
|
41
|
+
|
|
42
|
+
:param kwargs: other keyword arguments to pass to tune_kernel
|
|
43
|
+
:type kwargs: dict
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
# v Have the methodology as a dependency
|
|
47
|
+
# - User inputs:
|
|
48
|
+
# - a set of bruteforced cachefiles / template experiments file
|
|
49
|
+
# - an optimization algorithm
|
|
50
|
+
# - the hyperparameter values to try
|
|
51
|
+
# - overarching optimization algorithm (meta-strategy)
|
|
52
|
+
# - At each round:
|
|
53
|
+
# - The meta-strategy selects a hyperparameter configuration to try
|
|
54
|
+
# - Kernel Tuner generates an experiments file with the hyperparameter configuration
|
|
55
|
+
# - Kernel Tuner executes this experiments file using the methodology
|
|
56
|
+
# - The methodology returns the fitness metric
|
|
57
|
+
# - The fitness metric is fed back into the meta-strategy
|
|
58
|
+
|
|
59
|
+
iterations = 1
|
|
60
|
+
if "iterations" in kwargs:
|
|
61
|
+
iterations = kwargs['iterations']
|
|
62
|
+
del kwargs['iterations']
|
|
63
|
+
|
|
64
|
+
# pass a temporary cache file to avoid duplicate execution
|
|
65
|
+
if 'cache' not in kwargs:
|
|
66
|
+
cachefile = get_random_unique_filename('temp_', '.json')
|
|
67
|
+
cachefile = Path(f"hyperparamtuning_paper_bruteforce_{target_strategy}.json")
|
|
68
|
+
kwargs['cache'] = str(cachefile)
|
|
69
|
+
|
|
70
|
+
def put_if_not_present(target_dict, key, value):
|
|
71
|
+
target_dict[key] = value if key not in target_dict else target_dict[key]
|
|
72
|
+
|
|
73
|
+
# set default arguments if not provided
|
|
74
|
+
put_if_not_present(kwargs, "verbose", True)
|
|
75
|
+
put_if_not_present(kwargs, "quiet", False)
|
|
76
|
+
put_if_not_present(kwargs, "simulation_mode", False)
|
|
77
|
+
put_if_not_present(kwargs, "strategy", 'brute_force')
|
|
78
|
+
put_if_not_present(kwargs, 'verify', None)
|
|
79
|
+
arguments = [target_strategy]
|
|
80
|
+
|
|
81
|
+
# IMPORTANT when running this script in parallel, always make sure the below name is unique among your runs!
|
|
82
|
+
# e.g. when parallalizing over the hypertuning of multiple strategies, use the strategy name
|
|
83
|
+
name = f"hyperparamtuning_{target_strategy.lower()}"
|
|
84
|
+
|
|
85
|
+
# execute the hyperparameter tuning
|
|
86
|
+
result, env = kernel_tuner.tune_kernel(name, None, [], arguments, hyper_params, restrictions=restrictions, *args, lang='Hypertuner',
|
|
87
|
+
objective='score', objective_higher_is_better=True, iterations=iterations, **kwargs)
|
|
88
|
+
|
|
89
|
+
# remove the temporary cachefile and return only unique results in order
|
|
90
|
+
# cachefile.unlink()
|
|
91
|
+
result_unique = dict()
|
|
92
|
+
for r in result:
|
|
93
|
+
config_id = ",".join(str(r[k]) for k in hyper_params.keys())
|
|
94
|
+
if config_id not in result_unique:
|
|
95
|
+
result_unique[config_id] = r
|
|
96
|
+
return list(result_unique.values()), env
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
"""Main function to run the hyperparameter tuning. Run with `python hyper.py strategy_to_tune=`."""
|
|
100
|
+
|
|
101
|
+
parser = ArgumentParser()
|
|
102
|
+
parser.add_argument("strategy_to_tune", type=str, help="The strategy to tune hyperparameters for.")
|
|
103
|
+
parser.add_argument("--meta_strategy", nargs='?', default="dual_annealing", type=str, help="The meta-strategy to use for hyperparameter tuning.")
|
|
104
|
+
parser.add_argument("--max_time", nargs='?', default=60*60*24, type=int, help="The maximum time in seconds for the hyperparameter tuning.")
|
|
105
|
+
args = parser.parse_args()
|
|
106
|
+
strategy_to_tune = args.strategy_to_tune
|
|
107
|
+
|
|
108
|
+
kwargs = dict(
|
|
109
|
+
verbose=True,
|
|
110
|
+
quiet=False,
|
|
111
|
+
simulation_mode=False,
|
|
112
|
+
strategy=args.meta_strategy,
|
|
113
|
+
cache=f"hyperparamtuning_t={strategy_to_tune}_m={args.meta_strategy}.json",
|
|
114
|
+
strategy_options=dict(
|
|
115
|
+
time_limit=args.max_time,
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# select the hyperparameter parameters for the selected optimization algorithm
|
|
120
|
+
restrictions = []
|
|
121
|
+
if strategy_to_tune.lower() == "pso":
|
|
122
|
+
# exhaustive search for PSO hyperparameters
|
|
123
|
+
# hyperparams = {
|
|
124
|
+
# 'popsize': [10, 20, 30],
|
|
125
|
+
# 'maxiter': [50, 100, 150],
|
|
126
|
+
# # 'w': [0.25, 0.5, 0.75], # disabled due to low influence according to KW-test (H=0.0215) and mutual information
|
|
127
|
+
# 'c1': [1.0, 2.0, 3.0],
|
|
128
|
+
# 'c2': [0.5, 1.0, 1.5]
|
|
129
|
+
# }
|
|
130
|
+
hyperparams = {
|
|
131
|
+
'popsize': list(range(2, 50+1, 2)),
|
|
132
|
+
'maxiter': list(range(10, 200, 10)),
|
|
133
|
+
# 'w': [0.25, 0.5, 0.75], # disabled due to low influence according to KW-test (H=0.0215) and mutual information
|
|
134
|
+
'c1': [round(n, 2) for n in np.arange(1.0, 3.5+0.25, 0.25).tolist()],
|
|
135
|
+
'c2': [round(n, 2) for n in np.arange(0.5, 2.0+0.25, 0.25).tolist()]
|
|
136
|
+
}
|
|
137
|
+
elif strategy_to_tune.lower() == "firefly_algorithm":
|
|
138
|
+
hyperparams = {
|
|
139
|
+
'popsize': [10, 20, 30],
|
|
140
|
+
'maxiter': [50, 100, 150],
|
|
141
|
+
'B0': [0.5, 1.0, 1.5],
|
|
142
|
+
'gamma': [0.1, 0.25, 0.5],
|
|
143
|
+
'alpha': [0.1, 0.2, 0.3]
|
|
144
|
+
}
|
|
145
|
+
elif strategy_to_tune.lower() == "greedy_ils":
|
|
146
|
+
hyperparams = {
|
|
147
|
+
'neighbor': ['Hamming', 'adjacent'],
|
|
148
|
+
'restart': [True, False],
|
|
149
|
+
'no_improvement': [10, 25, 50, 75],
|
|
150
|
+
'random_walk': [0.1, 0.2, 0.3, 0.4, 0.5]
|
|
151
|
+
}
|
|
152
|
+
elif strategy_to_tune.lower() == "dual_annealing":
|
|
153
|
+
hyperparams = {
|
|
154
|
+
'method': ['COBYLA', 'L-BFGS-B', 'SLSQP', 'CG', 'Powell', 'Nelder-Mead', 'BFGS', 'trust-constr'],
|
|
155
|
+
}
|
|
156
|
+
elif strategy_to_tune.lower() == "diff_evo":
|
|
157
|
+
hyperparams = {
|
|
158
|
+
'method': ["best1bin", "rand1bin", "best2bin", "rand2bin", "best1exp", "rand1exp", "best2exp", "rand2exp", "currenttobest1bin", "currenttobest1exp", "randtobest1bin", "randtobest1exp"], # best1bin
|
|
159
|
+
'popsize': list(range(2, 50+1, 2)), # 50
|
|
160
|
+
'popsize_times_dimensions': [True, False], # False
|
|
161
|
+
'F': [round(n, 2) for n in np.arange(0.1, 2.0+0.1, 0.1).tolist()], # 1.3
|
|
162
|
+
'CR': [round(n, 2) for n in np.arange(0.05, 1.0+0.05, 0.05).tolist()] # 0.9
|
|
163
|
+
}
|
|
164
|
+
elif strategy_to_tune.lower() == "basinhopping":
|
|
165
|
+
hyperparams = {
|
|
166
|
+
'method': ["Nelder-Mead", "Powell", "CG", "BFGS", "L-BFGS-B", "TNC", "COBYLA", "SLSQP"],
|
|
167
|
+
'T': [0.1, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5],
|
|
168
|
+
}
|
|
169
|
+
elif strategy_to_tune.lower() == "genetic_algorithm":
|
|
170
|
+
# hyperparams = {
|
|
171
|
+
# 'method': ["single_point", "two_point", "uniform", "disruptive_uniform"],
|
|
172
|
+
# 'popsize': [10, 20, 30],
|
|
173
|
+
# 'maxiter': [50, 100, 150],
|
|
174
|
+
# 'mutation_chance': [5, 10, 20]
|
|
175
|
+
# }
|
|
176
|
+
hyperparams = {
|
|
177
|
+
'method': ["single_point", "two_point", "uniform", "disruptive_uniform"],
|
|
178
|
+
'popsize': list(range(2, 50+1, 2)),
|
|
179
|
+
'maxiter': list(range(10, 200, 10)),
|
|
180
|
+
'mutation_chance': list(range(5, 100, 5))
|
|
181
|
+
}
|
|
182
|
+
elif strategy_to_tune.lower() == "greedy_mls":
|
|
183
|
+
hyperparams = {
|
|
184
|
+
'neighbor': ["Hamming", "adjacent"],
|
|
185
|
+
'restart': [True, False],
|
|
186
|
+
'randomize': [True, False]
|
|
187
|
+
}
|
|
188
|
+
elif strategy_to_tune.lower() == "simulated_annealing":
|
|
189
|
+
# hyperparams = {
|
|
190
|
+
# 'T': [0.5, 1.0, 1.5],
|
|
191
|
+
# 'T_min': [0.0001, 0.001, 0.01],
|
|
192
|
+
# 'alpha': [0.9925, 0.995, 0.9975],
|
|
193
|
+
# 'maxiter': [1, 2, 3]
|
|
194
|
+
# }
|
|
195
|
+
hyperparams = {
|
|
196
|
+
'T': [round(n, 2) for n in np.arange(0.1, 2.0+0.1, 0.1).tolist()],
|
|
197
|
+
'T_min': [round(n, 4) for n in np.arange(0.0001, 0.1, 0.001).tolist()],
|
|
198
|
+
'alpha': [0.9925, 0.995, 0.9975],
|
|
199
|
+
'maxiter': list(range(1, 10, 1))
|
|
200
|
+
}
|
|
201
|
+
elif strategy_to_tune.lower() == "bayes_opt":
|
|
202
|
+
hyperparams = {
|
|
203
|
+
# 'covariancekernel': ["constantrbf", "rbf", "matern32", "matern52"],
|
|
204
|
+
'covariancelengthscale': [1.0, 1.5, 2.0],
|
|
205
|
+
'method': ["poi", "ei", "lcb", "lcb-srinivas", "multi", "multi-advanced", "multi-fast", "multi-ultrafast"],
|
|
206
|
+
'samplingmethod': ["random", "LHS"],
|
|
207
|
+
'popsize': [10, 20, 30]
|
|
208
|
+
}
|
|
209
|
+
else:
|
|
210
|
+
raise ValueError(f"Invalid argument {strategy_to_tune=}")
|
|
211
|
+
|
|
212
|
+
# run the hyperparameter tuning
|
|
213
|
+
result, env = tune_hyper_params(strategy_to_tune.lower(), hyperparams, restrictions=restrictions, **kwargs)
|
|
214
|
+
print(result)
|
|
215
|
+
print(env['best_config'])
|
|
@@ -4,7 +4,7 @@ import json
|
|
|
4
4
|
|
|
5
5
|
from jsonschema import validate
|
|
6
6
|
|
|
7
|
-
from kernel_tuner import
|
|
7
|
+
from kernel_tuner.util import get_instance_string, looks_like_a_filename, read_file
|
|
8
8
|
|
|
9
9
|
#specifies for a number of pre-defined objectives whether
|
|
10
10
|
#the objective should be minimized or maximized (boolean value denotes higher is better)
|
|
@@ -208,8 +208,8 @@ def store_results(results_filename, kernel_name, kernel_string, tune_params, pro
|
|
|
208
208
|
meta["version_number"] = "1.0"
|
|
209
209
|
meta["kernel_name"] = kernel_name
|
|
210
210
|
if kernel_string and not callable(kernel_string) and not isinstance(kernel_string, list):
|
|
211
|
-
if
|
|
212
|
-
meta["kernel_string"] =
|
|
211
|
+
if looks_like_a_filename(kernel_string):
|
|
212
|
+
meta["kernel_string"] = read_file(kernel_string)
|
|
213
213
|
else:
|
|
214
214
|
meta["kernel_string"] = kernel_string
|
|
215
215
|
meta["objective"] = objective
|
|
@@ -340,7 +340,7 @@ def _select_best_common_config(results, objective, objective_higher_is_better):
|
|
|
340
340
|
for config in results:
|
|
341
341
|
params = config["tunable_parameters"]
|
|
342
342
|
|
|
343
|
-
config_str =
|
|
343
|
+
config_str = get_instance_string(params)
|
|
344
344
|
#count occurances
|
|
345
345
|
results_table[config_str] = results_table.get(config_str,0) + 1
|
|
346
346
|
#add to performance
|