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.
Files changed (41) hide show
  1. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/PKG-INFO +38 -18
  2. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/README.rst +30 -16
  3. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/c.py +31 -9
  4. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/cuda.py +16 -11
  5. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/interface.py +26 -1
  6. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/basinhopping.py +0 -1
  7. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/diff_evo.py +8 -27
  8. kernel_tuner-0.2.0/kernel_tuner/strategies/firefly_algorithm.py +116 -0
  9. kernel_tuner-0.2.0/kernel_tuner/strategies/genetic_algorithm.py +117 -0
  10. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/minimize.py +2 -4
  11. kernel_tuner-0.2.0/kernel_tuner/strategies/pso.py +113 -0
  12. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/random_sample.py +6 -2
  13. kernel_tuner-0.2.0/kernel_tuner/strategies/simulated_annealing.py +117 -0
  14. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/util.py +26 -23
  15. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/PKG-INFO +38 -18
  16. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/SOURCES.txt +4 -0
  17. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/setup.py +1 -1
  18. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_cuda_mocked.py +19 -11
  19. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_interface.py +3 -3
  20. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_util_functions.py +1 -1
  21. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/LICENSE +0 -0
  22. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/MANIFEST.in +0 -0
  23. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/__init__.py +0 -0
  24. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/core.py +0 -0
  25. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/opencl.py +0 -0
  26. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/runners/__init__.py +0 -0
  27. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/runners/noodles.py +0 -0
  28. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/runners/sequential.py +0 -0
  29. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/__init__.py +0 -0
  30. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/strategies/brute_force.py +0 -0
  31. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner/wrappers.py +0 -0
  32. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/dependency_links.txt +0 -0
  33. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/requires.txt +0 -0
  34. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/kernel_tuner.egg-info/top_level.txt +0 -0
  35. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/setup.cfg +0 -0
  36. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_c_functions.py +0 -0
  37. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_cuda_functions.py +0 -0
  38. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_device_interface.py +0 -0
  39. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_minimize.py +0 -0
  40. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_opencl_functions.py +0 -0
  41. {kernel_tuner-0.1.9 → kernel_tuner-0.2.0}/test/test_runners.py +0 -0
@@ -1,13 +1,13 @@
1
- Metadata-Version: 1.1
1
+ Metadata-Version: 2.1
2
2
  Name: kernel_tuner
3
- Version: 0.1.9
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: A Search-Optimizing GPU Code Auto-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 the Kernel Tuner is in preparation, in the meantime please cite the Kernel Tuner as follows:
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
- @misc{vanwerkhoven2018kerneltuner,
148
- author = {Ben van Werkhoven},
149
- title = {Kernel Tuner: A Search-Optimizing GPU Code Auto-Tuner},
150
- year = {2018}
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 and supports
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: A Search-Optimizing GPU Code Auto-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 the Kernel Tuner is in preparation, in the meantime please cite the Kernel Tuner as follows:
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
- @misc{vanwerkhoven2018kerneltuner,
140
- author = {Ben van Werkhoven},
141
- title = {Kernel Tuner: A Search-Optimizing GPU Code Auto-Tuner},
142
- year = {2018}
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 and supports
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
- if "#include <omp.h>" in kernel_string:
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
- compiler_options.append("-fopenmp")
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
- self.cc = str(devprops.get('COMPUTE_CAPABILITY_MAJOR','0')) + str(devprops.get('COMPUTE_CAPABILITY_MINOR','0'))
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
- if int(self.cc) >= 35:
118
- source_mod = DynamicSourceModule
119
- else:
120
- source_mod = SourceModule
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
 
@@ -55,4 +55,3 @@ def tune(runner, kernel_options, device_options, tuning_options):
55
55
  print(opt_result.message)
56
56
 
57
57
  return results, runner.dev.get_environment()
58
-
@@ -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
- import kernel_tuner.strategies.minimize as minimize
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 = minimize.get_bounds(tuning_options.tune_params)
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, [kernel_options, tuning_options, runner, results],
40
- maxiter=1, polish=False, disp=tuning_options.verbose)
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:])