kernel-tuner 0.1.9__tar.gz → 0.2.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-0.1.9 → kernel_tuner-0.2.0}/PKG-INFO +38 -18
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/README.rst +30 -16
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/c.py +31 -9
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/cuda.py +16 -11
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/interface.py +26 -1
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/basinhopping.py +0 -1
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/diff_evo.py +8 -27
- kernel_tuner-0.2.0/kernel_tuner/strategies/firefly_algorithm.py +116 -0
- kernel_tuner-0.2.0/kernel_tuner/strategies/genetic_algorithm.py +117 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/minimize.py +2 -4
- kernel_tuner-0.2.0/kernel_tuner/strategies/pso.py +113 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/random_sample.py +6 -2
- kernel_tuner-0.2.0/kernel_tuner/strategies/simulated_annealing.py +117 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/util.py +26 -23
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/PKG-INFO +38 -18
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/SOURCES.txt +4 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/setup.py +1 -1
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_cuda_mocked.py +19 -11
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_interface.py +3 -3
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_util_functions.py +1 -1
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/LICENSE +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/MANIFEST.in +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/__init__.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/core.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/opencl.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/runners/__init__.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/runners/noodles.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/runners/sequential.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/__init__.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/brute_force.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/wrappers.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/dependency_links.txt +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/requires.txt +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/top_level.txt +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/setup.cfg +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_c_functions.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_cuda_functions.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_device_interface.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_minimize.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_opencl_functions.py +0 -0
- {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_runners.py +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
Metadata-Version:
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
2
|
Name: kernel_tuner
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: A simple CUDA/OpenCL kernel tuner in Python
|
|
5
5
|
Home-page: http://benvanwerkhoven.github.io/kernel_tuner/
|
|
6
6
|
Author: Ben van Werkhoven
|
|
7
7
|
Author-email: b.vanwerkhoven@esciencecenter.nl
|
|
8
8
|
License: Apache 2.0
|
|
9
|
-
Description: Kernel Tuner
|
|
10
|
-
|
|
9
|
+
Description: Kernel Tuner
|
|
10
|
+
============
|
|
11
11
|
|
|
12
12
|
|Build Status| |Codacy Badge| |Codacy Badge2| |PyPi Badge|
|
|
13
13
|
|
|
@@ -99,6 +99,23 @@ Description: Kernel Tuner: A Search-Optimizing GPU Code Auto-Tuner
|
|
|
99
99
|
and in the `Kernel Tuner
|
|
100
100
|
documentation pages <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__.
|
|
101
101
|
|
|
102
|
+
Search strategies for tuning
|
|
103
|
+
----------------------------
|
|
104
|
+
|
|
105
|
+
Kernel Tuner supports many optimization algorithms to accelerate the auto-tuning process. Currently
|
|
106
|
+
implemented search algorithms are: Brute Force (default), Nelder-Mead, Powell, CG, BFGS, L-BFGS-B, TNC,
|
|
107
|
+
COBYLA, SLSQP, Random Search, Basinhopping, Differential Evolution, a Genetic Algorithm, Particle Swarm
|
|
108
|
+
Optimization, the Firefly Algorithm, and Simulated Annealing.
|
|
109
|
+
|
|
110
|
+
.. image:: doc/gemm-amd-summary.png
|
|
111
|
+
:width: 100%
|
|
112
|
+
:align: center
|
|
113
|
+
|
|
114
|
+
Using a search strategy is easy, you only need to specify to ``tune_kernel`` which strategy and method
|
|
115
|
+
you would like to use, for example ``strategy="genetic_algorithm"`` or ``strategy="basinhopping",
|
|
116
|
+
method="Powell"``. For a full overview of the supported search strategies and methods please see the `user
|
|
117
|
+
api documentation <http://benvanwerkhoven.github.io/kernel_tuner/user-api.html>`__.
|
|
118
|
+
|
|
102
119
|
Tuning host and kernel code
|
|
103
120
|
---------------------------
|
|
104
121
|
|
|
@@ -113,12 +130,6 @@ Description: Kernel Tuner: A Search-Optimizing GPU Code Auto-Tuner
|
|
|
113
130
|
`documentation <http://benvanwerkhoven.github.io/kernel_tuner/hostcode.html>`__
|
|
114
131
|
for a detailed explanation of the kernel tuner Python script.
|
|
115
132
|
|
|
116
|
-
Search strategies for tuning
|
|
117
|
-
----------------------------
|
|
118
|
-
|
|
119
|
-
Kernel Tuner supports several strategies: brute_force (default), random_sample, minimize, basinhopping, and diff_evo (differential
|
|
120
|
-
evolution). Using different strategies is easy, you only need to specify to ``tune_kernel`` which strategy you would like to use, for example: ``strategy="basinhopping", method="TNC"``. For a full overview of the supported search strategies and methods please see the
|
|
121
|
-
`user api <http://benvanwerkhoven.github.io/kernel_tuner/user-api.html>`__.
|
|
122
133
|
|
|
123
134
|
Correctness verification
|
|
124
135
|
------------------------
|
|
@@ -140,23 +151,26 @@ Description: Kernel Tuner: A Search-Optimizing GPU Code Auto-Tuner
|
|
|
140
151
|
|
|
141
152
|
Citation
|
|
142
153
|
--------
|
|
143
|
-
A scientific paper about
|
|
154
|
+
A scientific paper about Kernel Tuner has been accepted for publication, please cite
|
|
155
|
+
Kernel Tuner as follows:
|
|
144
156
|
|
|
145
157
|
.. code:: latex
|
|
146
158
|
|
|
147
|
-
@
|
|
148
|
-
author
|
|
149
|
-
title
|
|
150
|
-
|
|
159
|
+
@article{kerneltuner,
|
|
160
|
+
author = {Ben van Werkhoven},
|
|
161
|
+
title = {Kernel Tuner: A search-optimizing GPU code auto-tuner},
|
|
162
|
+
journal = {Future Generation Computer Systems},
|
|
163
|
+
year = {2019},
|
|
164
|
+
volume = {90},
|
|
165
|
+
pages = {347-358},
|
|
166
|
+
doi = {https://doi.org/10.1016/j.future.2018.08.004},
|
|
151
167
|
}
|
|
152
168
|
|
|
153
169
|
Related work
|
|
154
170
|
------------
|
|
155
171
|
|
|
156
172
|
You may also like `CLTune <https://github.com/CNugteren/CLTune>`__ by
|
|
157
|
-
Cedric Nugteren. CLTune is a C++ library for kernel tuning
|
|
158
|
-
various advanced features like machine learning to optimize the time
|
|
159
|
-
spent on tuning kernels.
|
|
173
|
+
Cedric Nugteren. CLTune is a C++ library for kernel tuning.
|
|
160
174
|
|
|
161
175
|
.. |Build Status| image:: https://api.travis-ci.org/benvanwerkhoven/kernel_tuner.svg?branch=master
|
|
162
176
|
:target: https://travis-ci.org/benvanwerkhoven/kernel_tuner
|
|
@@ -182,3 +196,9 @@ Classifier: Topic :: Scientific/Engineering
|
|
|
182
196
|
Classifier: Topic :: Software Development
|
|
183
197
|
Classifier: Topic :: System :: Distributed Computing
|
|
184
198
|
Classifier: Development Status :: 4 - Beta
|
|
199
|
+
Provides-Extra: cuda_opencl
|
|
200
|
+
Provides-Extra: cuda
|
|
201
|
+
Provides-Extra: dev
|
|
202
|
+
Provides-Extra: tutorial
|
|
203
|
+
Provides-Extra: opencl
|
|
204
|
+
Provides-Extra: doc
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
Kernel Tuner
|
|
2
|
-
|
|
1
|
+
Kernel Tuner
|
|
2
|
+
============
|
|
3
3
|
|
|
4
4
|
|Build Status| |Codacy Badge| |Codacy Badge2| |PyPi Badge|
|
|
5
5
|
|
|
@@ -91,6 +91,23 @@ You can find many - more extensive - example codes, in the
|
|
|
91
91
|
and in the `Kernel Tuner
|
|
92
92
|
documentation pages <http://benvanwerkhoven.github.io/kernel_tuner/index.html>`__.
|
|
93
93
|
|
|
94
|
+
Search strategies for tuning
|
|
95
|
+
----------------------------
|
|
96
|
+
|
|
97
|
+
Kernel Tuner supports many optimization algorithms to accelerate the auto-tuning process. Currently
|
|
98
|
+
implemented search algorithms are: Brute Force (default), Nelder-Mead, Powell, CG, BFGS, L-BFGS-B, TNC,
|
|
99
|
+
COBYLA, SLSQP, Random Search, Basinhopping, Differential Evolution, a Genetic Algorithm, Particle Swarm
|
|
100
|
+
Optimization, the Firefly Algorithm, and Simulated Annealing.
|
|
101
|
+
|
|
102
|
+
.. image:: doc/gemm-amd-summary.png
|
|
103
|
+
:width: 100%
|
|
104
|
+
:align: center
|
|
105
|
+
|
|
106
|
+
Using a search strategy is easy, you only need to specify to ``tune_kernel`` which strategy and method
|
|
107
|
+
you would like to use, for example ``strategy="genetic_algorithm"`` or ``strategy="basinhopping",
|
|
108
|
+
method="Powell"``. For a full overview of the supported search strategies and methods please see the `user
|
|
109
|
+
api documentation <http://benvanwerkhoven.github.io/kernel_tuner/user-api.html>`__.
|
|
110
|
+
|
|
94
111
|
Tuning host and kernel code
|
|
95
112
|
---------------------------
|
|
96
113
|
|
|
@@ -105,12 +122,6 @@ and the
|
|
|
105
122
|
`documentation <http://benvanwerkhoven.github.io/kernel_tuner/hostcode.html>`__
|
|
106
123
|
for a detailed explanation of the kernel tuner Python script.
|
|
107
124
|
|
|
108
|
-
Search strategies for tuning
|
|
109
|
-
----------------------------
|
|
110
|
-
|
|
111
|
-
Kernel Tuner supports several strategies: brute_force (default), random_sample, minimize, basinhopping, and diff_evo (differential
|
|
112
|
-
evolution). Using different strategies is easy, you only need to specify to ``tune_kernel`` which strategy you would like to use, for example: ``strategy="basinhopping", method="TNC"``. For a full overview of the supported search strategies and methods please see the
|
|
113
|
-
`user api <http://benvanwerkhoven.github.io/kernel_tuner/user-api.html>`__.
|
|
114
125
|
|
|
115
126
|
Correctness verification
|
|
116
127
|
------------------------
|
|
@@ -132,23 +143,26 @@ Please see the `Contributions Guide <http://benvanwerkhoven.github.io/kernel_tun
|
|
|
132
143
|
|
|
133
144
|
Citation
|
|
134
145
|
--------
|
|
135
|
-
A scientific paper about
|
|
146
|
+
A scientific paper about Kernel Tuner has been accepted for publication, please cite
|
|
147
|
+
Kernel Tuner as follows:
|
|
136
148
|
|
|
137
149
|
.. code:: latex
|
|
138
150
|
|
|
139
|
-
@
|
|
140
|
-
author
|
|
141
|
-
title
|
|
142
|
-
|
|
151
|
+
@article{kerneltuner,
|
|
152
|
+
author = {Ben van Werkhoven},
|
|
153
|
+
title = {Kernel Tuner: A search-optimizing GPU code auto-tuner},
|
|
154
|
+
journal = {Future Generation Computer Systems},
|
|
155
|
+
year = {2019},
|
|
156
|
+
volume = {90},
|
|
157
|
+
pages = {347-358},
|
|
158
|
+
doi = {https://doi.org/10.1016/j.future.2018.08.004},
|
|
143
159
|
}
|
|
144
160
|
|
|
145
161
|
Related work
|
|
146
162
|
------------
|
|
147
163
|
|
|
148
164
|
You may also like `CLTune <https://github.com/CNugteren/CLTune>`__ by
|
|
149
|
-
Cedric Nugteren. CLTune is a C++ library for kernel tuning
|
|
150
|
-
various advanced features like machine learning to optimize the time
|
|
151
|
-
spent on tuning kernels.
|
|
165
|
+
Cedric Nugteren. CLTune is a C++ library for kernel tuning.
|
|
152
166
|
|
|
153
167
|
.. |Build Status| image:: https://api.travis-ci.org/benvanwerkhoven/kernel_tuner.svg?branch=master
|
|
154
168
|
:target: https://travis-ci.org/benvanwerkhoven/kernel_tuner
|
|
@@ -4,6 +4,7 @@ from collections import namedtuple
|
|
|
4
4
|
import subprocess
|
|
5
5
|
import platform
|
|
6
6
|
import errno
|
|
7
|
+
import re
|
|
7
8
|
import logging
|
|
8
9
|
import ctypes as C
|
|
9
10
|
import _ctypes
|
|
@@ -115,25 +116,35 @@ class CFunctions(object):
|
|
|
115
116
|
if self.lib != None:
|
|
116
117
|
self.cleanup_lib()
|
|
117
118
|
|
|
118
|
-
suffix = ".cc"
|
|
119
|
-
|
|
120
|
-
if not "extern \"C\"" in kernel_string:
|
|
121
|
-
kernel_string = "extern \"C\" {\n" + kernel_string + "\n}"
|
|
122
|
-
|
|
123
119
|
compiler_options = ["-fPIC"]
|
|
124
|
-
|
|
120
|
+
|
|
121
|
+
#detect openmp
|
|
122
|
+
if "#include <omp.h>" in kernel_string or "use omp_lib" in kernel_string:
|
|
125
123
|
logging.debug('set using_openmp to true')
|
|
126
124
|
self.using_openmp = True
|
|
127
|
-
|
|
125
|
+
if self.compiler == "pgfortran":
|
|
126
|
+
compiler_options.append("-mp")
|
|
127
|
+
else:
|
|
128
|
+
compiler_options.append("-fopenmp")
|
|
128
129
|
|
|
130
|
+
#detect whether to use nvcc as default instead of g++, may overrule an explicitly passed g++
|
|
129
131
|
if ("#include <cuda" in kernel_string) or ("__global__" in kernel_string):
|
|
130
|
-
if self.nvcc_available:
|
|
132
|
+
if self.compiler == "g++" and self.nvcc_available:
|
|
131
133
|
self.compiler = "nvcc"
|
|
132
134
|
|
|
135
|
+
#select right suffix based on compiler
|
|
136
|
+
suffix = ".cc"
|
|
137
|
+
if self.compiler in ["gfortran", "pgfortran", "ftn", "ifort"]:
|
|
138
|
+
suffix = ".F90"
|
|
133
139
|
if self.compiler == "nvcc":
|
|
134
140
|
suffix = suffix[:-1] + "u"
|
|
135
141
|
compiler_options = ["-Xcompiler=" + c for c in compiler_options]
|
|
136
142
|
|
|
143
|
+
if ".c" in suffix:
|
|
144
|
+
if not "extern \"C\"" in kernel_string:
|
|
145
|
+
kernel_string = "extern \"C\" {\n" + kernel_string + "\n}"
|
|
146
|
+
|
|
147
|
+
#copy user specified compiler options to current list
|
|
137
148
|
if self.compiler_options:
|
|
138
149
|
compiler_options += self.compiler_options
|
|
139
150
|
|
|
@@ -148,6 +159,17 @@ class CFunctions(object):
|
|
|
148
159
|
source_file = get_temp_filename(suffix=suffix)
|
|
149
160
|
filename = ".".join(source_file.split(".")[:-1])
|
|
150
161
|
|
|
162
|
+
#detect Fortran modules
|
|
163
|
+
match = re.search(r"\s*module\s+([a-zA-Z_]*)", kernel_string)
|
|
164
|
+
if match:
|
|
165
|
+
if self.compiler == "gfortran":
|
|
166
|
+
kernel_name = "__" + match.group(1) + "_MOD_" + kernel_name
|
|
167
|
+
elif self.compiler in ["ftn", "ifort"]:
|
|
168
|
+
kernel_name = match.group(1) + "_mp_" + kernel_name + "_"
|
|
169
|
+
elif self.compiler == "pgfortran":
|
|
170
|
+
kernel_name = match.group(1) + "_" + kernel_name + "_"
|
|
171
|
+
|
|
172
|
+
|
|
151
173
|
try:
|
|
152
174
|
write_file(source_file, kernel_string)
|
|
153
175
|
|
|
@@ -158,8 +180,8 @@ class CFunctions(object):
|
|
|
158
180
|
subprocess.check_call([self.compiler, "-c", source_file] + compiler_options + ["-o", filename + ".o"])
|
|
159
181
|
subprocess.check_call([self.compiler, filename + ".o"] + compiler_options + ["-shared", "-o", filename + lib_extension] + lib_args)
|
|
160
182
|
|
|
161
|
-
self.lib = numpy.ctypeslib.load_library(filename, '.')
|
|
162
183
|
|
|
184
|
+
self.lib = numpy.ctypeslib.load_library(filename, '.')
|
|
163
185
|
func = getattr(self.lib, kernel_name)
|
|
164
186
|
func.restype = C.c_float
|
|
165
187
|
|
|
@@ -47,11 +47,22 @@ class CudaFunctions(object):
|
|
|
47
47
|
#inspect device properties
|
|
48
48
|
devprops = {str(k): v for (k, v) in self.context.get_device().get_attributes().items()}
|
|
49
49
|
self.max_threads = devprops['MAX_THREADS_PER_BLOCK']
|
|
50
|
-
|
|
50
|
+
cc = str(devprops.get('COMPUTE_CAPABILITY_MAJOR', '0')) + str(devprops.get('COMPUTE_CAPABILITY_MINOR', '0'))
|
|
51
|
+
if cc == "00":
|
|
52
|
+
cc = self.context.get_device().compute_capability()
|
|
53
|
+
self.cc = str(cc[0])+str(cc[1])
|
|
51
54
|
self.iterations = iterations
|
|
52
55
|
self.current_module = None
|
|
53
56
|
self.compiler_options = compiler_options or []
|
|
54
57
|
|
|
58
|
+
#select PyCUDA source module
|
|
59
|
+
if int(self.cc) >= 35:
|
|
60
|
+
self.source_mod = DynamicSourceModule
|
|
61
|
+
else:
|
|
62
|
+
self.source_mod = SourceModule
|
|
63
|
+
if not self.source_mod:
|
|
64
|
+
raise ImportError("Error: pycuda not correctly installed, please ensure pycuda is installed on the same CUDA installation as you're using right now")
|
|
65
|
+
|
|
55
66
|
#collect environment information
|
|
56
67
|
env = dict()
|
|
57
68
|
env["device_name"] = self.context.get_device().name()
|
|
@@ -114,16 +125,10 @@ class CudaFunctions(object):
|
|
|
114
125
|
if self.compiler_options:
|
|
115
126
|
compiler_options += self.compiler_options
|
|
116
127
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
self.current_module = source_mod(kernel_string, options=compiler_options + ["-e", kernel_name],
|
|
123
|
-
arch=('compute_' + self.cc) if self.cc != "00" else None,
|
|
124
|
-
code=('sm_' + self.cc) if self.cc != "00" else None,
|
|
125
|
-
cache_dir=False, no_extern_c=no_extern_c)
|
|
126
|
-
|
|
128
|
+
self.current_module = self.source_mod(kernel_string, options=compiler_options + ["-e", kernel_name],
|
|
129
|
+
arch=('compute_' + self.cc) if self.cc != "00" else None,
|
|
130
|
+
code=('sm_' + self.cc) if self.cc != "00" else None,
|
|
131
|
+
cache_dir=False, no_extern_c=no_extern_c)
|
|
127
132
|
|
|
128
133
|
func = self.current_module.get_function(kernel_name)
|
|
129
134
|
return func
|
|
@@ -35,7 +35,7 @@ import numpy
|
|
|
35
35
|
import kernel_tuner.util as util
|
|
36
36
|
import kernel_tuner.core as core
|
|
37
37
|
|
|
38
|
-
from kernel_tuner.strategies import brute_force, random_sample, diff_evo, minimize, basinhopping
|
|
38
|
+
from kernel_tuner.strategies import brute_force, random_sample, diff_evo, minimize, basinhopping, genetic_algorithm, pso, simulated_annealing, firefly_algorithm
|
|
39
39
|
|
|
40
40
|
class Options(OrderedDict):
|
|
41
41
|
"""read-only class for passing options around"""
|
|
@@ -194,6 +194,10 @@ _tuning_options = Options([
|
|
|
194
194
|
* "random_sample", specify: *sample_fraction*,
|
|
195
195
|
* "minimize" or "basinhopping", specify: *method*,
|
|
196
196
|
* "diff_evo", specify: *method*.
|
|
197
|
+
* "genetic_algorithm"
|
|
198
|
+
* "pso"
|
|
199
|
+
* "firefly_algorithm"
|
|
200
|
+
* "simulated_annealing"
|
|
197
201
|
|
|
198
202
|
"brute_force" is the default and iterates over the entire search
|
|
199
203
|
space.
|
|
@@ -213,6 +217,17 @@ _tuning_options = Options([
|
|
|
213
217
|
"rand2exp", "randtobest1bin", "best2bin", "rand2bin", "rand1bin".
|
|
214
218
|
The default is "best1bin".
|
|
215
219
|
|
|
220
|
+
"genetic_algorithm" implements a simple Genetic Algorithm, default
|
|
221
|
+
setting uses a population size of 20 for 100 generations.
|
|
222
|
+
|
|
223
|
+
"pso" implements Particle Swarm Optimization, using the default
|
|
224
|
+
setting of 20 particles for 100 iterations.
|
|
225
|
+
|
|
226
|
+
"firefly_algorithm" implements the Firefly Algorithm, using 20
|
|
227
|
+
fireflies for 100 iterations.
|
|
228
|
+
|
|
229
|
+
"simulated_annealing" uses Simulated Annealing.
|
|
230
|
+
|
|
216
231
|
""", "")),
|
|
217
232
|
("method", ("""Specify a method for the strategy that searches through
|
|
218
233
|
the parameter space during tuning.
|
|
@@ -324,6 +339,11 @@ def tune_kernel(kernel_name, kernel_string, problem_size, arguments,
|
|
|
324
339
|
raise ValueError("It's not possible to use both sample_fraction in combination with other strategies. " \
|
|
325
340
|
'Please set strategy=None or strategy="random_sample", when using sample_fraction')
|
|
326
341
|
|
|
342
|
+
strategy_map = {"genetic_algorithm": genetic_algorithm,
|
|
343
|
+
"pso": pso,
|
|
344
|
+
"simulated_annealing": simulated_annealing,
|
|
345
|
+
"firefly_algorithm": firefly_algorithm}
|
|
346
|
+
|
|
327
347
|
if strategy in [None, 'sample_fraction', 'brute_force']:
|
|
328
348
|
if sample_fraction:
|
|
329
349
|
use_strategy = random_sample
|
|
@@ -346,6 +366,8 @@ def tune_kernel(kernel_name, kernel_string, problem_size, arguments,
|
|
|
346
366
|
if not method in ["best1bin", "best1exp", "rand1exp", "randtobest1exp", "best2exp",
|
|
347
367
|
"rand2exp", "randtobest1bin", "best2bin", "rand2bin", "rand1bin"]:
|
|
348
368
|
raise ValueError("method option not recognized")
|
|
369
|
+
elif strategy in strategy_map.keys():
|
|
370
|
+
use_strategy = strategy_map[strategy]
|
|
349
371
|
else:
|
|
350
372
|
raise ValueError("strategy option not recognized")
|
|
351
373
|
strategy = use_strategy
|
|
@@ -474,6 +496,9 @@ def run_kernel(kernel_name, kernel_string, problem_size, arguments,
|
|
|
474
496
|
results.append(numpy.zeros_like(arg))
|
|
475
497
|
dev.memcpy_dtoh(results[-1], gpu_args[i])
|
|
476
498
|
|
|
499
|
+
#trying to make run_kernel work nicely with the Nvidia Visual Profiler
|
|
500
|
+
del dev
|
|
501
|
+
|
|
477
502
|
return results
|
|
478
503
|
|
|
479
504
|
|
|
@@ -4,7 +4,7 @@ from __future__ import print_function
|
|
|
4
4
|
from scipy.optimize import differential_evolution
|
|
5
5
|
from kernel_tuner import util
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
from kernel_tuner.strategies.minimize import get_bounds, _cost_func
|
|
8
8
|
|
|
9
9
|
def tune(runner, kernel_options, device_options, tuning_options):
|
|
10
10
|
""" Find the best performing kernel configuration in the parameter space
|
|
@@ -31,40 +31,21 @@ def tune(runner, kernel_options, device_options, tuning_options):
|
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
33
|
results = []
|
|
34
|
+
cache = {}
|
|
34
35
|
|
|
36
|
+
tuning_options["scaling"] = False
|
|
35
37
|
#build a bounds array as needed for the optimizer
|
|
36
|
-
bounds =
|
|
38
|
+
bounds = get_bounds(tuning_options.tune_params)
|
|
39
|
+
|
|
40
|
+
args = (kernel_options, tuning_options, runner, results, cache)
|
|
37
41
|
|
|
38
42
|
#call the differential evolution optimizer
|
|
39
|
-
opt_result = differential_evolution(_cost_func, bounds,
|
|
40
|
-
|
|
43
|
+
opt_result = differential_evolution(_cost_func, bounds, args, maxiter=1,
|
|
44
|
+
polish=False, disp=tuning_options.verbose)
|
|
41
45
|
|
|
42
46
|
if tuning_options.verbose:
|
|
43
47
|
print(opt_result.message)
|
|
44
|
-
print('best config:', minimize.snap_to_nearest_config(opt_result.x, tuning_options.tune_params))
|
|
45
48
|
|
|
46
49
|
return results, runner.dev.get_environment()
|
|
47
50
|
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
def _cost_func(x, kernel_options, tuning_options, runner, results):
|
|
51
|
-
""" Cost function used by the differential evolution optimizer """
|
|
52
|
-
|
|
53
|
-
#snap values in x to nearest actual value for each parameter
|
|
54
|
-
params = minimize.snap_to_nearest_config(x, tuning_options.tune_params)
|
|
55
|
-
|
|
56
|
-
#check if this is a legal (non-restricted) parameter instance
|
|
57
|
-
if tuning_options.restrictions:
|
|
58
|
-
legal = util.check_restrictions(tuning_options.restrictions, params, tuning_options.tune_params.keys(), tuning_options.verbose)
|
|
59
|
-
if not legal:
|
|
60
|
-
return 1e20
|
|
61
|
-
|
|
62
|
-
#compile and benchmark this instance
|
|
63
|
-
res, _ = runner.run([params], kernel_options, tuning_options)
|
|
64
|
-
|
|
65
|
-
#append to tuning results
|
|
66
|
-
if len(res) > 0:
|
|
67
|
-
results.append(res[0])
|
|
68
|
-
return res[0]['time']
|
|
69
|
-
|
|
70
|
-
return 1e20
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
""" The strategy that uses the firefly algorithm for optimization"""
|
|
2
|
+
from __future__ import print_function
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from kernel_tuner.strategies.minimize import _cost_func, get_bounds_x0_eps
|
|
6
|
+
from kernel_tuner.strategies.pso import Particle
|
|
7
|
+
|
|
8
|
+
def tune(runner, kernel_options, device_options, tuning_options):
|
|
9
|
+
""" Find the best performing kernel configuration in the parameter space
|
|
10
|
+
|
|
11
|
+
:params runner: A runner from kernel_tuner.runners
|
|
12
|
+
:type runner: kernel_tuner.runner
|
|
13
|
+
|
|
14
|
+
:param kernel_options: A dictionary with all options for the kernel.
|
|
15
|
+
:type kernel_options: dict
|
|
16
|
+
|
|
17
|
+
:param device_options: A dictionary with all options for the device
|
|
18
|
+
on which the kernel should be tuned.
|
|
19
|
+
:type device_options: dict
|
|
20
|
+
|
|
21
|
+
:param tuning_options: A dictionary with all options regarding the tuning
|
|
22
|
+
process.
|
|
23
|
+
:type tuning_options: dict
|
|
24
|
+
|
|
25
|
+
:returns: A list of dictionaries for executed kernel configurations and their
|
|
26
|
+
execution times. And a dictionary that contains a information
|
|
27
|
+
about the hardware/software environment on which the tuning took place.
|
|
28
|
+
:rtype: list(dict()), dict()
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
results = []
|
|
33
|
+
cache = {}
|
|
34
|
+
|
|
35
|
+
#scale variables in x because PSO works with velocities to visit different configurations
|
|
36
|
+
tuning_options["scaling"] = True
|
|
37
|
+
|
|
38
|
+
#using this instead of get_bounds because scaling is used
|
|
39
|
+
bounds, _, _ = get_bounds_x0_eps(tuning_options)
|
|
40
|
+
|
|
41
|
+
args = (kernel_options, tuning_options, runner, results, cache)
|
|
42
|
+
|
|
43
|
+
num_particles = 20
|
|
44
|
+
maxiter = 100
|
|
45
|
+
|
|
46
|
+
#parameters needed by the Firefly Algorithm
|
|
47
|
+
B0 = 1.0
|
|
48
|
+
gamma = 1.0
|
|
49
|
+
alpha = 0.20
|
|
50
|
+
|
|
51
|
+
best_time_global = 1e20
|
|
52
|
+
best_position_global = []
|
|
53
|
+
|
|
54
|
+
# init particle swarm
|
|
55
|
+
swarm = []
|
|
56
|
+
for i in range(0, num_particles):
|
|
57
|
+
swarm.append(Firefly(bounds, args))
|
|
58
|
+
|
|
59
|
+
# compute initial intensities
|
|
60
|
+
for j in range(num_particles):
|
|
61
|
+
swarm[j].compute_intensity(_cost_func)
|
|
62
|
+
|
|
63
|
+
for c in range(maxiter):
|
|
64
|
+
if tuning_options.verbose:
|
|
65
|
+
print("start iteration ", c, "best time global", best_time_global)
|
|
66
|
+
|
|
67
|
+
# compare all to all and compute attractiveness
|
|
68
|
+
for i in range(num_particles):
|
|
69
|
+
for j in range(num_particles):
|
|
70
|
+
|
|
71
|
+
if swarm[i].intensity < swarm[j].intensity:
|
|
72
|
+
dist = swarm[i].distance_to(swarm[j])
|
|
73
|
+
beta = B0 * np.exp(-gamma * dist * dist)
|
|
74
|
+
|
|
75
|
+
swarm[i].move_towards(swarm[j], beta, alpha)
|
|
76
|
+
swarm[i].compute_intensity(_cost_func)
|
|
77
|
+
|
|
78
|
+
# update global best if needed, actually only used for printing
|
|
79
|
+
if swarm[i].time <= best_time_global:
|
|
80
|
+
best_position_global = swarm[i].position
|
|
81
|
+
best_time_global = swarm[i].time
|
|
82
|
+
|
|
83
|
+
swarm.sort(key=lambda x: x.time)
|
|
84
|
+
|
|
85
|
+
if tuning_options.verbose:
|
|
86
|
+
print('Final result:')
|
|
87
|
+
print(best_position_global)
|
|
88
|
+
print(best_time_global)
|
|
89
|
+
|
|
90
|
+
return results, runner.dev.get_environment()
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class Firefly(Particle):
|
|
94
|
+
"""Firefly object for use in the Firefly Algorithm"""
|
|
95
|
+
|
|
96
|
+
def __init__(self, bounds, args):
|
|
97
|
+
"""Create Firefly at random position within bounds"""
|
|
98
|
+
super().__init__(bounds, args)
|
|
99
|
+
self.bounds = bounds
|
|
100
|
+
self.intensity = 1 / self.time
|
|
101
|
+
|
|
102
|
+
def distance_to(self, other):
|
|
103
|
+
"""Return Euclidian distance between self and other Firefly"""
|
|
104
|
+
return np.linalg.norm(self.position-other.position)
|
|
105
|
+
|
|
106
|
+
def compute_intensity(self, _cost_func):
|
|
107
|
+
"""Evaluate cost function and compute intensity at this position"""
|
|
108
|
+
self.evaluate(_cost_func)
|
|
109
|
+
self.intensity = 1 / self.time
|
|
110
|
+
|
|
111
|
+
def move_towards(self, other, beta, alpha):
|
|
112
|
+
"""Move firefly towards another given beta and alpha values"""
|
|
113
|
+
self.position += beta * (other.position - self.position)
|
|
114
|
+
self.position += alpha * (np.random.uniform(-0.5, 0.5, len(self.position)))
|
|
115
|
+
self.position = np.minimum(self.position, [b[1] for b in self.bounds])
|
|
116
|
+
self.position = np.maximum(self.position, [b[0] for b in self.bounds])
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
""" A simple genetic algorithm for parameter search """
|
|
2
|
+
from __future__ import print_function
|
|
3
|
+
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
from kernel_tuner.strategies.minimize import _cost_func
|
|
7
|
+
|
|
8
|
+
def tune(runner, kernel_options, device_options, tuning_options):
|
|
9
|
+
""" Find the best performing kernel configuration in the parameter space
|
|
10
|
+
|
|
11
|
+
:params runner: A runner from kernel_tuner.runners
|
|
12
|
+
:type runner: kernel_tuner.runner
|
|
13
|
+
|
|
14
|
+
:param kernel_options: A dictionary with all options for the kernel.
|
|
15
|
+
:type kernel_options: kernel_tuner.interface.Options
|
|
16
|
+
|
|
17
|
+
:param device_options: A dictionary with all options for the device
|
|
18
|
+
on which the kernel should be tuned.
|
|
19
|
+
:type device_options: kernel_tuner.interface.Options
|
|
20
|
+
|
|
21
|
+
:param tuning_options: A dictionary with all options regarding the tuning
|
|
22
|
+
process.
|
|
23
|
+
:type tuning_options: kernel_tuner.interface.Options
|
|
24
|
+
|
|
25
|
+
:returns: A list of dictionaries for executed kernel configurations and their
|
|
26
|
+
execution times. And a dictionary that contains a information
|
|
27
|
+
about the hardware/software environment on which the tuning took place.
|
|
28
|
+
:rtype: list(dict()), dict()
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
dna_size = len(tuning_options.tune_params.keys())
|
|
33
|
+
pop_size = 20
|
|
34
|
+
generations = 100
|
|
35
|
+
tuning_options["scaling"] = False
|
|
36
|
+
|
|
37
|
+
tune_params = tuning_options.tune_params
|
|
38
|
+
|
|
39
|
+
population = random_population(dna_size, pop_size, tune_params)
|
|
40
|
+
|
|
41
|
+
best_time = 1e20
|
|
42
|
+
all_results = []
|
|
43
|
+
cache = {}
|
|
44
|
+
|
|
45
|
+
for generation in range(generations):
|
|
46
|
+
if tuning_options.verbose:
|
|
47
|
+
print("Generation %d, best_time %f" % (generation, best_time))
|
|
48
|
+
|
|
49
|
+
#determine fitness of population members
|
|
50
|
+
weighted_population = []
|
|
51
|
+
for dna in population:
|
|
52
|
+
time = _cost_func(dna, kernel_options, tuning_options, runner, all_results, cache)
|
|
53
|
+
weighted_population.append((dna, time))
|
|
54
|
+
population = []
|
|
55
|
+
|
|
56
|
+
#'best_time' is used only for printing
|
|
57
|
+
if tuning_options.verbose and all_results:
|
|
58
|
+
best_time = min(all_results, key=lambda x: x["time"])["time"]
|
|
59
|
+
|
|
60
|
+
#population is sorted such that better configs have higher chance of reproducing
|
|
61
|
+
weighted_population.sort(key=lambda x: x[1])
|
|
62
|
+
|
|
63
|
+
#crossover and mutate
|
|
64
|
+
for _ in range(pop_size//2):
|
|
65
|
+
ind1 = weighted_choice(weighted_population)
|
|
66
|
+
ind2 = weighted_choice(weighted_population)
|
|
67
|
+
|
|
68
|
+
ind1, ind2 = crossover(ind1, ind2)
|
|
69
|
+
|
|
70
|
+
population.append(mutate(ind1, dna_size, tune_params))
|
|
71
|
+
population.append(mutate(ind2, dna_size, tune_params))
|
|
72
|
+
|
|
73
|
+
return all_results, runner.dev.get_environment()
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def weighted_choice(population):
|
|
78
|
+
"""Randomly select, fitness determines probability of being selected"""
|
|
79
|
+
random_number = random.betavariate(1, 2.5) #increased probability of selecting members early in the list
|
|
80
|
+
#random_number = random.random()
|
|
81
|
+
ind = int(random_number*len(population))
|
|
82
|
+
ind = min(max(ind, 0), len(population)-1)
|
|
83
|
+
return population[ind][0]
|
|
84
|
+
|
|
85
|
+
def random_population(dna_size, pop_size, tune_params):
|
|
86
|
+
"""create a random population"""
|
|
87
|
+
population = []
|
|
88
|
+
for _ in range(pop_size):
|
|
89
|
+
dna = []
|
|
90
|
+
for i in range(dna_size):
|
|
91
|
+
dna.append(random_val(i, tune_params))
|
|
92
|
+
population.append(dna)
|
|
93
|
+
return population
|
|
94
|
+
|
|
95
|
+
def random_val(index, tune_params):
|
|
96
|
+
"""return a random value for a parameter"""
|
|
97
|
+
key = list(tune_params.keys())[index]
|
|
98
|
+
return random.choice(tune_params[key])
|
|
99
|
+
|
|
100
|
+
def mutate(dna, dna_size, tune_params):
|
|
101
|
+
"""Mutate DNA with 1/mutation_chance chance"""
|
|
102
|
+
dna_out = []
|
|
103
|
+
mutation_chance = 10
|
|
104
|
+
for i in range(dna_size):
|
|
105
|
+
if int(random.random()*mutation_chance) == 1:
|
|
106
|
+
dna_out.append(random_val(i, tune_params))
|
|
107
|
+
else:
|
|
108
|
+
dna_out.append(dna[i])
|
|
109
|
+
return dna_out
|
|
110
|
+
|
|
111
|
+
def crossover(dna1, dna2):
|
|
112
|
+
"""crossover dna1 and dna2 at a random index"""
|
|
113
|
+
pos = int(random.random()*len(dna1))
|
|
114
|
+
if random.random() < 0.5:
|
|
115
|
+
return (dna1[:pos]+dna2[pos:], dna2[:pos]+dna1[pos:])
|
|
116
|
+
else:
|
|
117
|
+
return (dna2[:pos]+dna1[pos:], dna1[:pos]+dna2[pos:])
|