holobench 1.3.3__py3-none-any.whl → 1.3.5__py3-none-any.whl
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.
- bencher/__init__.py +6 -1
- bencher/bench_cfg.py +17 -5
- bencher/bencher.py +105 -14
- bencher/example/example_video.py +40 -14
- bencher/example/meta/example_meta.py +9 -8
- bencher/example/optuna/example_optuna.py +3 -3
- bencher/optuna_conversions.py +4 -7
- bencher/results/bench_result.py +7 -7
- bencher/results/bench_result_base.py +15 -5
- bencher/results/holoview_result.py +65 -8
- bencher/results/optuna_result.py +43 -13
- bencher/results/panel_result.py +12 -3
- bencher/utils.py +24 -0
- bencher/variables/inputs.py +1 -1
- bencher/variables/parametrised_sweep.py +1 -1
- bencher/variables/results.py +26 -1
- bencher/video_writer.py +16 -3
- {holobench-1.3.3.dist-info → holobench-1.3.5.dist-info}/METADATA +1 -2
- {holobench-1.3.3.dist-info → holobench-1.3.5.dist-info}/RECORD +20 -20
- {holobench-1.3.3.dist-info → holobench-1.3.5.dist-info}/WHEEL +0 -0
bencher/__init__.py
CHANGED
@@ -5,6 +5,8 @@ from .bench_plot_server import BenchPlotServer
|
|
5
5
|
from .variables.sweep_base import hash_sha1
|
6
6
|
from .variables.inputs import IntSweep, FloatSweep, StringSweep, EnumSweep, BoolSweep, SweepBase
|
7
7
|
from .variables.time import TimeSnapshot
|
8
|
+
|
9
|
+
from .variables.inputs import box
|
8
10
|
from .variables.results import (
|
9
11
|
ResultVar,
|
10
12
|
ResultVec,
|
@@ -14,9 +16,11 @@ from .variables.results import (
|
|
14
16
|
ResultString,
|
15
17
|
ResultContainer,
|
16
18
|
ResultReference,
|
19
|
+
ResultVolume,
|
17
20
|
OptDir,
|
18
21
|
curve,
|
19
22
|
)
|
23
|
+
|
20
24
|
from .plotting.plot_filter import VarRange, PlotFilter
|
21
25
|
from .utils import (
|
22
26
|
hmap_canonical_input,
|
@@ -25,6 +29,7 @@ from .utils import (
|
|
25
29
|
gen_path,
|
26
30
|
gen_image_path,
|
27
31
|
gen_video_path,
|
32
|
+
lerp,
|
28
33
|
)
|
29
34
|
from .variables.parametrised_sweep import ParametrizedSweep
|
30
35
|
from .caching import CachedParams
|
@@ -33,4 +38,4 @@ from .results.panel_result import PanelResult
|
|
33
38
|
from .results.holoview_result import ReduceType, HoloviewResult
|
34
39
|
from .bench_report import BenchReport
|
35
40
|
from .job import Executors
|
36
|
-
from .video_writer import VideoWriter
|
41
|
+
from .video_writer import VideoWriter, add_image
|
bencher/bench_cfg.py
CHANGED
@@ -164,6 +164,15 @@ class BenchRunCfg(BenchPlotSrvCfg):
|
|
164
164
|
doc="The function can be run serially or in parallel with different futures executors",
|
165
165
|
)
|
166
166
|
|
167
|
+
plot_size = param.Integer(default=None, doc="Sets the width and height of the plot")
|
168
|
+
plot_width = param.Integer(
|
169
|
+
default=None,
|
170
|
+
doc="Sets with width of the plots, this will ovverride the plot_size parameter",
|
171
|
+
)
|
172
|
+
plot_height = param.Integer(
|
173
|
+
default=None, doc="Sets the height of the plot, this will ovverride the plot_size parameter"
|
174
|
+
)
|
175
|
+
|
167
176
|
@staticmethod
|
168
177
|
def from_cmd_line() -> BenchRunCfg: # pragma: no cover
|
169
178
|
"""create a BenchRunCfg by parsing command line arguments
|
@@ -424,12 +433,15 @@ class BenchCfg(BenchRunCfg):
|
|
424
433
|
col.append(pn.pane.Markdown("## Results:"))
|
425
434
|
return col
|
426
435
|
|
427
|
-
def optuna_targets(self) -> List[str]:
|
428
|
-
|
436
|
+
def optuna_targets(self, as_var=False) -> List[str]:
|
437
|
+
targets = []
|
429
438
|
for rv in self.result_vars:
|
430
|
-
if rv.direction != OptDir.none:
|
431
|
-
|
432
|
-
|
439
|
+
if hasattr(rv, "direction") and rv.direction != OptDir.none:
|
440
|
+
if as_var:
|
441
|
+
targets.append(rv)
|
442
|
+
else:
|
443
|
+
targets.append(rv.name)
|
444
|
+
return targets
|
433
445
|
|
434
446
|
|
435
447
|
class DimsCfg:
|
bencher/bencher.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import logging
|
2
2
|
from datetime import datetime
|
3
|
-
from itertools import product
|
3
|
+
from itertools import product, combinations
|
4
|
+
|
4
5
|
from typing import Callable, List
|
5
6
|
from copy import deepcopy
|
6
7
|
import numpy as np
|
@@ -186,9 +187,72 @@ class Bench(BenchPlotServer):
|
|
186
187
|
logging.info(f"setting worker {worker}")
|
187
188
|
self.worker_input_cfg = worker_input_cfg
|
188
189
|
|
190
|
+
def sweep(
|
191
|
+
self,
|
192
|
+
input_vars: List[ParametrizedSweep] = None,
|
193
|
+
result_vars: List[ParametrizedSweep] = None,
|
194
|
+
const_vars: List[ParametrizedSweep] = None,
|
195
|
+
time_src: datetime = None,
|
196
|
+
description: str = None,
|
197
|
+
post_description: str = None,
|
198
|
+
pass_repeat: bool = False,
|
199
|
+
tag: str = "",
|
200
|
+
run_cfg: BenchRunCfg = None,
|
201
|
+
plot: bool = False,
|
202
|
+
) -> BenchResult:
|
203
|
+
title = "Sweeping " + " vs ".join([self.get_name(i) for i in input_vars])
|
204
|
+
return self.plot_sweep(
|
205
|
+
title,
|
206
|
+
input_vars=input_vars,
|
207
|
+
result_vars=result_vars,
|
208
|
+
const_vars=const_vars,
|
209
|
+
time_src=time_src,
|
210
|
+
description=description,
|
211
|
+
post_description=post_description,
|
212
|
+
pass_repeat=pass_repeat,
|
213
|
+
tag=tag,
|
214
|
+
run_cfg=run_cfg,
|
215
|
+
plot=plot,
|
216
|
+
)
|
217
|
+
|
218
|
+
def sweep_sequential(
|
219
|
+
self,
|
220
|
+
title="",
|
221
|
+
input_vars: List[ParametrizedSweep] = None,
|
222
|
+
result_vars: List[ParametrizedSweep] = None,
|
223
|
+
const_vars: List[ParametrizedSweep] = None,
|
224
|
+
optimise_var: ParametrizedSweep = None,
|
225
|
+
run_cfg: BenchRunCfg = None,
|
226
|
+
group_size: int = 1,
|
227
|
+
iterations: int = 1,
|
228
|
+
relationship_cb=None,
|
229
|
+
) -> List[BenchResult]:
|
230
|
+
results = []
|
231
|
+
if relationship_cb is None:
|
232
|
+
relationship_cb = combinations
|
233
|
+
for it in range(iterations):
|
234
|
+
for input_group in relationship_cb(input_vars, group_size):
|
235
|
+
title_gen = (
|
236
|
+
title + "Sweeping " + " vs ".join([self.get_name(i) for i in input_group])
|
237
|
+
)
|
238
|
+
if iterations > 1:
|
239
|
+
title_gen += f" iteration:{it}"
|
240
|
+
res = self.plot_sweep(
|
241
|
+
title=title_gen,
|
242
|
+
input_vars=list(input_group),
|
243
|
+
result_vars=result_vars,
|
244
|
+
const_vars=const_vars,
|
245
|
+
run_cfg=run_cfg,
|
246
|
+
plot=True,
|
247
|
+
)
|
248
|
+
if optimise_var is not None:
|
249
|
+
const_vars = res.get_optimal_inputs(optimise_var, True)
|
250
|
+
results.append(res)
|
251
|
+
return results
|
252
|
+
|
189
253
|
def plot_sweep(
|
190
254
|
self,
|
191
|
-
title: str,
|
255
|
+
title: str = None,
|
192
256
|
input_vars: List[ParametrizedSweep] = None,
|
193
257
|
result_vars: List[ParametrizedSweep] = None,
|
194
258
|
const_vars: List[ParametrizedSweep] = None,
|
@@ -248,6 +312,20 @@ class Bench(BenchPlotServer):
|
|
248
312
|
else:
|
249
313
|
const_vars = deepcopy(const_vars)
|
250
314
|
|
315
|
+
for i in range(len(input_vars)):
|
316
|
+
input_vars[i] = self.convert_vars_to_params(input_vars[i], "input")
|
317
|
+
for i in range(len(result_vars)):
|
318
|
+
result_vars[i] = self.convert_vars_to_params(result_vars[i], "result")
|
319
|
+
|
320
|
+
if isinstance(const_vars, dict):
|
321
|
+
const_vars = list(const_vars.items())
|
322
|
+
|
323
|
+
for i in range(len(const_vars)):
|
324
|
+
# consts come as tuple pairs
|
325
|
+
cv_list = list(const_vars[i])
|
326
|
+
cv_list[0] = self.convert_vars_to_params(cv_list[0], "const")
|
327
|
+
const_vars[i] = cv_list
|
328
|
+
|
251
329
|
if run_cfg is None:
|
252
330
|
if self.run_cfg is None:
|
253
331
|
run_cfg = BenchRunCfg()
|
@@ -261,11 +339,24 @@ class Bench(BenchPlotServer):
|
|
261
339
|
|
262
340
|
self.last_run_cfg = run_cfg
|
263
341
|
|
342
|
+
if title is None:
|
343
|
+
if len(input_vars) > 0:
|
344
|
+
title = "Sweeping " + " vs ".join([i.name for i in input_vars])
|
345
|
+
elif len(const_vars) > 0:
|
346
|
+
title = "Constant Value"
|
347
|
+
if len(const_vars) > 1:
|
348
|
+
title += "s"
|
349
|
+
title += ": " + ", ".join([f"{c[0].name}={c[1]}" for c in const_vars])
|
350
|
+
else:
|
351
|
+
raise RuntimeError("you must pass a title, or define inputs or consts")
|
352
|
+
|
264
353
|
if run_cfg.level > 0:
|
265
354
|
inputs = []
|
266
|
-
|
267
|
-
|
268
|
-
|
355
|
+
print(input_vars)
|
356
|
+
if len(input_vars) > 0:
|
357
|
+
for i in input_vars:
|
358
|
+
inputs.append(i.with_level(run_cfg.level))
|
359
|
+
input_vars = inputs
|
269
360
|
|
270
361
|
# if any of the inputs have been include as constants, remove those variables from the list of constants
|
271
362
|
with suppress(ValueError, AttributeError):
|
@@ -276,14 +367,6 @@ class Bench(BenchPlotServer):
|
|
276
367
|
const_vars.remove(c)
|
277
368
|
logging.info(f"removing {i.name} from constants")
|
278
369
|
|
279
|
-
for i in input_vars:
|
280
|
-
self.check_var_is_a_param(i, "input")
|
281
|
-
for i in result_vars:
|
282
|
-
self.check_var_is_a_param(i, "result")
|
283
|
-
for i in const_vars:
|
284
|
-
# consts come as tuple pairs
|
285
|
-
self.check_var_is_a_param(i[0], "const")
|
286
|
-
|
287
370
|
result_hmaps = []
|
288
371
|
result_vars_only = []
|
289
372
|
for i in result_vars:
|
@@ -368,7 +451,12 @@ class Bench(BenchPlotServer):
|
|
368
451
|
self.results.append(bench_res)
|
369
452
|
return bench_res
|
370
453
|
|
371
|
-
def
|
454
|
+
def get_name(self, var):
|
455
|
+
if isinstance(var, param.Parameter):
|
456
|
+
return var.name
|
457
|
+
return var
|
458
|
+
|
459
|
+
def convert_vars_to_params(self, variable: param.Parameter, var_type: str):
|
372
460
|
"""check that a variable is a subclass of param
|
373
461
|
|
374
462
|
Args:
|
@@ -378,10 +466,13 @@ class Bench(BenchPlotServer):
|
|
378
466
|
Raises:
|
379
467
|
TypeError: the input variable type is not a param.
|
380
468
|
"""
|
469
|
+
if isinstance(variable, str):
|
470
|
+
variable = self.worker_class_instance.param.objects(instance=False)[variable]
|
381
471
|
if not isinstance(variable, param.Parameter):
|
382
472
|
raise TypeError(
|
383
473
|
f"You need to use {var_type}_vars =[{self.worker_input_cfg}.param.your_variable], instead of {var_type}_vars =[{self.worker_input_cfg}.your_variable]"
|
384
474
|
)
|
475
|
+
return variable
|
385
476
|
|
386
477
|
def cache_results(self, bench_res: BenchResult, bench_cfg_hash: int) -> None:
|
387
478
|
with Cache("cachedir/benchmark_inputs", size_limit=self.cache_size) as c:
|
bencher/example/example_video.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import bencher as bch
|
2
2
|
import numpy as np
|
3
3
|
import matplotlib.pyplot as plt
|
4
|
-
|
4
|
+
import panel as pn
|
5
5
|
|
6
6
|
|
7
7
|
# code from https://ipython-books.github.io/124-simulating-a-partial-differential-equation-reaction-diffusion-systems-and-turing-patterns/
|
@@ -11,11 +11,12 @@ class TuringPattern(bch.ParametrizedSweep):
|
|
11
11
|
tau = bch.FloatSweep(default=0.1, bounds=(0.01, 0.5))
|
12
12
|
k = bch.FloatSweep(default=-0.005, bounds=(-0.01, 0.01))
|
13
13
|
|
14
|
-
size = bch.IntSweep(default=
|
14
|
+
size = bch.IntSweep(default=30, bounds=(30, 200), doc="size of the 2D grid")
|
15
15
|
time = bch.FloatSweep(default=20.0, bounds=(1, 100), doc="total time of simulation")
|
16
16
|
dt = bch.FloatSweep(default=0.001, doc="simulation time step")
|
17
17
|
|
18
18
|
video = bch.ResultVideo()
|
19
|
+
score = bch.ResultVar()
|
19
20
|
|
20
21
|
def laplacian(self, Z, dx):
|
21
22
|
Ztop = Z[0:-2, 1:-1]
|
@@ -57,20 +58,18 @@ class TuringPattern(bch.ParametrizedSweep):
|
|
57
58
|
fig, ax = plt.subplots(frameon=False, figsize=(2, 2))
|
58
59
|
fig.set_tight_layout(True)
|
59
60
|
ax.set_axis_off()
|
60
|
-
|
61
|
-
artists = []
|
62
|
-
|
61
|
+
vid_writer = bch.VideoWriter()
|
63
62
|
for i in range(n):
|
64
63
|
self.update(U, V, dx)
|
65
64
|
if i % 500 == 0:
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
self.
|
65
|
+
ax.imshow(U)
|
66
|
+
fig.canvas.draw()
|
67
|
+
rgb = np.array(fig.canvas.renderer.buffer_rgba())
|
68
|
+
vid_writer.append(rgb)
|
69
|
+
|
70
|
+
self.video = vid_writer.write()
|
71
|
+
|
72
|
+
self.score = self.alpha + self.beta
|
74
73
|
return super().__call__()
|
75
74
|
|
76
75
|
|
@@ -91,8 +90,35 @@ def example_video(
|
|
91
90
|
return bench
|
92
91
|
|
93
92
|
|
93
|
+
def example_video_tap(
|
94
|
+
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
95
|
+
) -> bch.Bench: # pragma: no cover
|
96
|
+
tp = TuringPattern()
|
97
|
+
|
98
|
+
run_cfg.use_sample_cache = False
|
99
|
+
# run_cfg.use_optuna = True
|
100
|
+
run_cfg.auto_plot = False
|
101
|
+
run_cfg.run_tag = "3"
|
102
|
+
bench = tp.to_bench(run_cfg=run_cfg, report=report)
|
103
|
+
|
104
|
+
res = bench.plot_sweep(
|
105
|
+
"phase",
|
106
|
+
input_vars=["alpha", "beta"],
|
107
|
+
# result_vars=["video","score"],
|
108
|
+
run_cfg=run_cfg,
|
109
|
+
)
|
110
|
+
|
111
|
+
bench.report.append(res.describe_sweep())
|
112
|
+
bench.report.append(
|
113
|
+
res.to_heatmap(tp.param.score, tap_var=tp.param.video, tap_container=pn.pane.Video)
|
114
|
+
)
|
115
|
+
|
116
|
+
return bench
|
117
|
+
|
118
|
+
|
94
119
|
if __name__ == "__main__":
|
95
120
|
run_cfg_ex = bch.BenchRunCfg()
|
96
121
|
run_cfg_ex.level = 2
|
97
122
|
|
98
|
-
example_video(run_cfg_ex).report.show()
|
123
|
+
# example_video(run_cfg_ex).report.show()
|
124
|
+
example_video_tap(run_cfg_ex).report.show()
|
@@ -100,20 +100,21 @@ class BenchMeta(bch.ParametrizedSweep):
|
|
100
100
|
run_cfg.level = self.level
|
101
101
|
run_cfg.repeats = self.sample_with_repeats
|
102
102
|
run_cfg.over_time = self.sample_over_time
|
103
|
+
run_cfg.plot_size = 500
|
103
104
|
|
104
105
|
bench = bch.Bench("benchable", BenchableObject(), run_cfg=run_cfg)
|
105
106
|
|
106
107
|
inputs_vars_float = [
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
"float1",
|
109
|
+
"float2",
|
110
|
+
"float3",
|
111
|
+
"sigma",
|
111
112
|
]
|
112
113
|
|
113
114
|
inputs_vars_cat = [
|
114
|
-
|
115
|
-
|
116
|
-
|
115
|
+
"noisy",
|
116
|
+
"noise_distribution",
|
117
|
+
"negate_output",
|
117
118
|
]
|
118
119
|
|
119
120
|
input_vars = (
|
@@ -131,7 +132,7 @@ class BenchMeta(bch.ParametrizedSweep):
|
|
131
132
|
)
|
132
133
|
|
133
134
|
self.plots = bch.ResultReference()
|
134
|
-
self.plots.obj = res.to_auto(
|
135
|
+
self.plots.obj = res.to_auto()
|
135
136
|
|
136
137
|
# self.plots.obj = res.to_heatmap_multi()
|
137
138
|
|
@@ -25,7 +25,7 @@ class ToyOptimisationProblem(bch.ParametrizedSweep):
|
|
25
25
|
bump_scale = bch.FloatSweep(default=1.5, bounds=[1, 10])
|
26
26
|
|
27
27
|
# RESULTS
|
28
|
-
output = bch.ResultVar(bch.OptDir.minimize)
|
28
|
+
output = bch.ResultVar("ul", bch.OptDir.minimize)
|
29
29
|
|
30
30
|
def rastrigin(self, **kwargs) -> dict:
|
31
31
|
"""A modified version of the rastrigin function which is very difficult to find the global optimum
|
@@ -58,7 +58,7 @@ def optuna_rastrigin(
|
|
58
58
|
# n_trials=30
|
59
59
|
# )
|
60
60
|
|
61
|
-
run_cfg.use_optuna = True
|
61
|
+
# run_cfg.use_optuna = True
|
62
62
|
res = bench.plot_sweep(
|
63
63
|
"Rastrigin",
|
64
64
|
input_vars=[explorer.param.input1, explorer.param.input2],
|
@@ -67,7 +67,7 @@ def optuna_rastrigin(
|
|
67
67
|
)
|
68
68
|
|
69
69
|
bench.report.append(res.to_optuna_plots())
|
70
|
-
bench.report.append(res.to_optuna_from_sweep(bench
|
70
|
+
bench.report.append(res.to_optuna_from_sweep(bench))
|
71
71
|
bench.report.append_markdown(
|
72
72
|
f"The optimal value should be input1:{-optimal_value},input2:{-optimal_value} with a value of 0"
|
73
73
|
)
|
bencher/optuna_conversions.py
CHANGED
@@ -14,7 +14,6 @@ from bencher.bench_cfg import BenchCfg
|
|
14
14
|
|
15
15
|
from bencher.variables.inputs import IntSweep, FloatSweep, StringSweep, EnumSweep, BoolSweep
|
16
16
|
from bencher.variables.time import TimeSnapshot, TimeEvent
|
17
|
-
from bencher.variables.results import OptDir
|
18
17
|
|
19
18
|
from bencher.variables.parametrised_sweep import ParametrizedSweep
|
20
19
|
|
@@ -33,9 +32,8 @@ def optuna_grid_search(bench_cfg: BenchCfg) -> optuna.Study:
|
|
33
32
|
for iv in bench_cfg.all_vars:
|
34
33
|
search_space[iv.name] = iv.values(bench_cfg.debug)
|
35
34
|
directions = []
|
36
|
-
for rv in bench_cfg.
|
37
|
-
|
38
|
-
directions.append(rv.direction)
|
35
|
+
for rv in bench_cfg.optuna_targets(True):
|
36
|
+
directions.append(rv.direction)
|
39
37
|
|
40
38
|
study = optuna.create_study(
|
41
39
|
sampler=optuna.samplers.GridSampler(search_space),
|
@@ -76,9 +74,8 @@ def summarise_trial(trial: optuna.trial, bench_cfg: BenchCfg) -> List[str]:
|
|
76
74
|
for k, v in trial.params.items():
|
77
75
|
output.append(f"{sep}{sep}{k}:{v}")
|
78
76
|
output.append(f"{sep}Results:")
|
79
|
-
for it, rv in enumerate(bench_cfg.
|
80
|
-
|
81
|
-
output.append(f"{sep}{sep}{rv.name}:{trial.values[it]}")
|
77
|
+
for it, rv in enumerate(bench_cfg.optuna_targets()):
|
78
|
+
output.append(f"{sep}{sep}{rv}:{trial.values[it]}")
|
82
79
|
return output
|
83
80
|
|
84
81
|
|
bencher/results/bench_result.py
CHANGED
@@ -7,10 +7,6 @@ from bencher.results.plotly_result import PlotlyResult
|
|
7
7
|
from bencher.results.holoview_result import HoloviewResult
|
8
8
|
from bencher.results.bench_result_base import EmptyContainer
|
9
9
|
|
10
|
-
# from bencher.results.heatmap_result import HeatMapResult
|
11
|
-
|
12
|
-
# from bencher.results.seaborn_result import SeabornResult
|
13
|
-
|
14
10
|
|
15
11
|
class BenchResult(PlotlyResult, HoloviewResult):
|
16
12
|
|
@@ -40,12 +36,18 @@ class BenchResult(PlotlyResult, HoloviewResult):
|
|
40
36
|
def to_auto(
|
41
37
|
self,
|
42
38
|
plot_list: List[callable] = None,
|
39
|
+
remove_plots: List[callable] = None,
|
43
40
|
**kwargs,
|
44
41
|
) -> List[pn.panel]:
|
45
42
|
self.plt_cnt_cfg.print_debug = False
|
46
43
|
|
47
44
|
if plot_list is None:
|
48
45
|
plot_list = BenchResult.default_plot_callbacks()
|
46
|
+
if remove_plots is not None:
|
47
|
+
for p in remove_plots:
|
48
|
+
plot_list.remove(p)
|
49
|
+
|
50
|
+
kwargs = self.set_plot_size(**kwargs)
|
49
51
|
|
50
52
|
row = EmptyContainer(pn.Row())
|
51
53
|
for plot_callback in plot_list:
|
@@ -61,9 +63,6 @@ class BenchResult(PlotlyResult, HoloviewResult):
|
|
61
63
|
)
|
62
64
|
return row.pane
|
63
65
|
|
64
|
-
def to_auto_da(self):
|
65
|
-
pass
|
66
|
-
|
67
66
|
def to_auto_plots(self, **kwargs) -> List[pn.panel]:
|
68
67
|
"""Given the dataset result of a benchmark run, automatically dedeuce how to plot the data based on the types of variables that were sampled
|
69
68
|
|
@@ -73,6 +72,7 @@ class BenchResult(PlotlyResult, HoloviewResult):
|
|
73
72
|
Returns:
|
74
73
|
pn.pane: A panel containing plot results
|
75
74
|
"""
|
75
|
+
|
76
76
|
plot_cols = pn.Column()
|
77
77
|
plot_cols.append(self.to_sweep_summary(name="Plots View"))
|
78
78
|
plot_cols.append(self.to_auto(**kwargs))
|
@@ -5,7 +5,7 @@ import xarray as xr
|
|
5
5
|
from param import Parameter
|
6
6
|
import holoviews as hv
|
7
7
|
from functools import partial
|
8
|
-
from bencher.utils import int_to_col, color_tuple_to_css
|
8
|
+
from bencher.utils import int_to_col, color_tuple_to_css, callable_name
|
9
9
|
|
10
10
|
from bencher.variables.parametrised_sweep import ParametrizedSweep
|
11
11
|
from bencher.variables.results import OptDir
|
@@ -141,16 +141,20 @@ class BenchResultBase(OptunaResult):
|
|
141
141
|
return indicies
|
142
142
|
|
143
143
|
def get_optimal_inputs(
|
144
|
-
self,
|
145
|
-
|
144
|
+
self,
|
145
|
+
result_var: ParametrizedSweep,
|
146
|
+
keep_existing_consts: bool = True,
|
147
|
+
as_dict: bool = False,
|
148
|
+
) -> Tuple[ParametrizedSweep, Any] | dict[ParametrizedSweep, Any]:
|
146
149
|
"""Get a list of tuples of optimal variable names and value pairs, that can be fed in as constant values to subsequent parameter sweeps
|
147
150
|
|
148
151
|
Args:
|
149
152
|
result_var (bch.ParametrizedSweep): Optimal values of this result variable
|
150
153
|
keep_existing_consts (bool): Include any const values that were defined as part of the parameter sweep
|
154
|
+
as_dict (bool): return value as a dictionary
|
151
155
|
|
152
156
|
Returns:
|
153
|
-
Tuple[bch.ParametrizedSweep, Any]: Tuples of variable name and optimal values
|
157
|
+
Tuple[bch.ParametrizedSweep, Any]|[ParametrizedSweep, Any]: Tuples of variable name and optimal values
|
154
158
|
"""
|
155
159
|
da = self.get_optimal_value_indices(result_var)
|
156
160
|
if keep_existing_consts:
|
@@ -169,6 +173,8 @@ class BenchResultBase(OptunaResult):
|
|
169
173
|
output.append((iv, max(da.coords[iv.name].values[()])))
|
170
174
|
|
171
175
|
logging.info(f"Maximum value of {iv.name}: {output[-1][1]}")
|
176
|
+
if as_dict:
|
177
|
+
return dict(output)
|
172
178
|
return output
|
173
179
|
|
174
180
|
def describe_sweep(self):
|
@@ -235,6 +241,8 @@ class BenchResultBase(OptunaResult):
|
|
235
241
|
if hv_dataset is None:
|
236
242
|
hv_dataset = self.to_hv_dataset()
|
237
243
|
row = EmptyContainer(pn.Row())
|
244
|
+
|
245
|
+
# kwargs= self.set_plot_size(**kwargs)
|
238
246
|
for rv in self.get_results_var_list(result_var):
|
239
247
|
if result_types is None or isinstance(rv, result_types):
|
240
248
|
row.append(
|
@@ -273,7 +281,7 @@ class BenchResultBase(OptunaResult):
|
|
273
281
|
repeats_range=repeats_range,
|
274
282
|
input_range=input_range,
|
275
283
|
)
|
276
|
-
matches_res = plot_filter.matches_result(self.plt_cnt_cfg, plot_callback
|
284
|
+
matches_res = plot_filter.matches_result(self.plt_cnt_cfg, callable_name(plot_callback))
|
277
285
|
if matches_res.overall:
|
278
286
|
return self.map_plot_panes(
|
279
287
|
plot_callback=plot_callback,
|
@@ -294,6 +302,8 @@ class BenchResultBase(OptunaResult):
|
|
294
302
|
**kwargs,
|
295
303
|
):
|
296
304
|
dims = len(hv_dataset.dimensions())
|
305
|
+
if target_dimension is None:
|
306
|
+
target_dimension = dims
|
297
307
|
return self._to_panes_da(
|
298
308
|
hv_dataset.data,
|
299
309
|
plot_callback=plot_callback,
|
@@ -8,7 +8,7 @@ from functools import partial
|
|
8
8
|
import hvplot.xarray # noqa pylint: disable=duplicate-code,unused-import
|
9
9
|
import xarray as xr
|
10
10
|
|
11
|
-
from bencher.utils import hmap_canonical_input, get_nearest_coords
|
11
|
+
from bencher.utils import hmap_canonical_input, get_nearest_coords, get_nearest_coords1D
|
12
12
|
from bencher.results.panel_result import PanelResult
|
13
13
|
from bencher.results.bench_result_base import ReduceType
|
14
14
|
|
@@ -173,13 +173,27 @@ class HoloviewResult(PanelResult):
|
|
173
173
|
return pt.opts(legend_position="right").overlay()
|
174
174
|
return pt.opts(legend_position="right")
|
175
175
|
|
176
|
-
def to_heatmap(
|
176
|
+
def to_heatmap(
|
177
|
+
self,
|
178
|
+
result_var: Parameter = None,
|
179
|
+
tap_var=None,
|
180
|
+
tap_container=None,
|
181
|
+
target_dimension=2,
|
182
|
+
**kwargs,
|
183
|
+
) -> Optional[pn.panel]:
|
184
|
+
if tap_var is None:
|
185
|
+
heatmap_cb = self.to_heatmap_ds
|
186
|
+
else:
|
187
|
+
heatmap_cb = partial(
|
188
|
+
self.to_heatmap_container_tap_ds, result_var_plot=tap_var, container=tap_container
|
189
|
+
)
|
190
|
+
|
177
191
|
return self.filter(
|
178
|
-
|
192
|
+
heatmap_cb,
|
179
193
|
float_range=VarRange(2, None),
|
180
194
|
cat_range=VarRange(0, None),
|
181
195
|
input_range=VarRange(1, None),
|
182
|
-
target_dimension=
|
196
|
+
target_dimension=target_dimension,
|
183
197
|
result_var=result_var,
|
184
198
|
result_types=(ResultVar),
|
185
199
|
**kwargs,
|
@@ -189,9 +203,6 @@ class HoloviewResult(PanelResult):
|
|
189
203
|
self, dataset: xr.Dataset, result_var: Parameter, **kwargs
|
190
204
|
) -> Optional[hv.HeatMap]:
|
191
205
|
if len(dataset.dims) >= 2:
|
192
|
-
# dims = [d for d in da.sizes]
|
193
|
-
# x = dims[0]
|
194
|
-
# y = dims[1]
|
195
206
|
x = self.plt_cnt_cfg.float_vars[0].name
|
196
207
|
y = self.plt_cnt_cfg.float_vars[1].name
|
197
208
|
C = result_var.name
|
@@ -200,6 +211,50 @@ class HoloviewResult(PanelResult):
|
|
200
211
|
return dataset.hvplot.heatmap(x=x, y=y, C=C, cmap="plasma", **time_args, **kwargs)
|
201
212
|
return None
|
202
213
|
|
214
|
+
def to_heatmap_container_tap_ds(
|
215
|
+
self,
|
216
|
+
dataset: xr.Dataset,
|
217
|
+
result_var: Parameter,
|
218
|
+
result_var_plot: Parameter,
|
219
|
+
container: pn.pane.panel = pn.pane.panel,
|
220
|
+
**kwargs,
|
221
|
+
) -> pn.Row:
|
222
|
+
htmap = self.to_heatmap_ds(dataset, result_var).opts(tools=["hover", "tap"], **kwargs)
|
223
|
+
htmap_posxy = hv.streams.Tap(source=htmap, x=0, y=0)
|
224
|
+
|
225
|
+
container_instance = container(**kwargs)
|
226
|
+
title = pn.pane.Markdown("Selected: None")
|
227
|
+
|
228
|
+
def tap_plot(x, y): # pragma: no cover
|
229
|
+
x_nearest = get_nearest_coords1D(
|
230
|
+
x, dataset.coords[self.bench_cfg.input_vars[0].name].data
|
231
|
+
)
|
232
|
+
y_nearest = get_nearest_coords1D(
|
233
|
+
y, dataset.coords[self.bench_cfg.input_vars[1].name].data
|
234
|
+
)
|
235
|
+
kdims = {}
|
236
|
+
kdims[self.bench_cfg.input_vars[0].name] = x_nearest
|
237
|
+
kdims[self.bench_cfg.input_vars[1].name] = y_nearest
|
238
|
+
|
239
|
+
if hasattr(htmap, "current_key"):
|
240
|
+
for d, k in zip(htmap.kdims, htmap.current_key):
|
241
|
+
kdims[d.name] = k
|
242
|
+
|
243
|
+
ds = dataset[result_var_plot.name]
|
244
|
+
val = ds.sel(**kdims)
|
245
|
+
item = self.zero_dim_da_to_val(val)
|
246
|
+
title.object = "Selected: " + ", ".join([f"{k}:{v}" for k, v in kdims.items()])
|
247
|
+
container_instance.object = item
|
248
|
+
if hasattr(container, "autoplay"): # container is a video, set to autoplay
|
249
|
+
container_instance.paused = False
|
250
|
+
container_instance.time = 0
|
251
|
+
container_instance.loop = True
|
252
|
+
container_instance.autoplay = True
|
253
|
+
|
254
|
+
htmap_posxy.add_subscriber(tap_plot)
|
255
|
+
bound_plot = pn.Column(title, container_instance)
|
256
|
+
return pn.Row(htmap, bound_plot)
|
257
|
+
|
203
258
|
def to_error_bar(self) -> hv.Bars:
|
204
259
|
return self.to_hv_dataset(ReduceType.REDUCE).to(hv.ErrorBars)
|
205
260
|
|
@@ -312,7 +367,9 @@ class HoloviewResult(PanelResult):
|
|
312
367
|
# return matches.to_panel()
|
313
368
|
|
314
369
|
def to_scatter_jitter(
|
315
|
-
self,
|
370
|
+
self,
|
371
|
+
result_var: Parameter = None,
|
372
|
+
**kwargs, # pylint: disable=unused-argument
|
316
373
|
) -> List[hv.Scatter]:
|
317
374
|
return self.overlay_plots(partial(self.to_scatter_jitter_single, **kwargs))
|
318
375
|
|
bencher/results/optuna_result.py
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
from __future__ import annotations
|
1
2
|
from typing import List
|
3
|
+
from copy import deepcopy
|
4
|
+
|
2
5
|
import numpy as np
|
3
6
|
import optuna
|
4
7
|
import panel as pn
|
@@ -15,7 +18,6 @@ from optuna.visualization import (
|
|
15
18
|
)
|
16
19
|
from bencher.utils import hmap_canonical_input
|
17
20
|
from bencher.variables.time import TimeSnapshot, TimeEvent
|
18
|
-
from bencher.variables.results import OptDir
|
19
21
|
from bencher.bench_cfg import BenchCfg
|
20
22
|
from bencher.plotting.plt_cnt_cfg import PltCntCfg
|
21
23
|
|
@@ -122,25 +124,34 @@ class OptunaResult:
|
|
122
124
|
|
123
125
|
return self.collect_optuna_plots()
|
124
126
|
|
125
|
-
def to_optuna_from_sweep(self,
|
126
|
-
optu = self.to_optuna_from_results(
|
127
|
+
def to_optuna_from_sweep(self, bench, n_trials=30):
|
128
|
+
optu = self.to_optuna_from_results(
|
129
|
+
bench.worker, n_trials=n_trials, extra_results=bench.results
|
130
|
+
)
|
127
131
|
return summarise_optuna_study(optu)
|
128
132
|
|
129
|
-
def to_optuna_from_results(
|
133
|
+
def to_optuna_from_results(
|
134
|
+
self,
|
135
|
+
worker,
|
136
|
+
n_trials=100,
|
137
|
+
extra_results: List[OptunaResult] = None,
|
138
|
+
sampler=optuna.samplers.TPESampler(),
|
139
|
+
):
|
130
140
|
directions = []
|
131
|
-
for rv in self.bench_cfg.
|
132
|
-
|
133
|
-
directions.append(rv.direction)
|
141
|
+
for rv in self.bench_cfg.optuna_targets(True):
|
142
|
+
directions.append(rv.direction)
|
134
143
|
|
135
144
|
study = optuna.create_study(
|
136
145
|
sampler=sampler, directions=directions, study_name=self.bench_cfg.title
|
137
146
|
)
|
138
147
|
|
139
148
|
# add already calculated results
|
140
|
-
if
|
141
|
-
|
149
|
+
results_list = extra_results if extra_results is not None else [self]
|
150
|
+
for res in results_list:
|
151
|
+
if len(res.ds.sizes) > 0:
|
152
|
+
study.add_trials(res.bench_results_to_optuna_trials(True))
|
142
153
|
|
143
|
-
def wrapped(trial):
|
154
|
+
def wrapped(trial) -> tuple:
|
144
155
|
kwargs = {}
|
145
156
|
for iv in self.bench_cfg.input_vars:
|
146
157
|
kwargs[iv.name] = sweep_var_to_suggest(iv, trial)
|
@@ -197,9 +208,8 @@ class OptunaResult:
|
|
197
208
|
else:
|
198
209
|
params[i.name] = row[1][i.name]
|
199
210
|
|
200
|
-
for r in self.bench_cfg.
|
201
|
-
|
202
|
-
values.append(row[1][r.name])
|
211
|
+
for r in self.bench_cfg.optuna_targets():
|
212
|
+
values.append(row[1][r])
|
203
213
|
|
204
214
|
trials.append(
|
205
215
|
optuna.trial.create_trial(
|
@@ -322,3 +332,23 @@ class OptunaResult:
|
|
322
332
|
# for it, rv in enumerate(bench_cfg.result_vars):
|
323
333
|
# bench_cfg.ds[rv.name].loc[t.params] = t.values[it]
|
324
334
|
# return bench_cfg
|
335
|
+
|
336
|
+
def deep(self) -> OptunaResult: # pragma: no cover
|
337
|
+
"""Return a deep copy of these results"""
|
338
|
+
return deepcopy(self)
|
339
|
+
|
340
|
+
def set_plot_size(self, **kwargs) -> dict:
|
341
|
+
if "width" not in kwargs:
|
342
|
+
if self.bench_cfg.plot_size is not None:
|
343
|
+
kwargs["width"] = self.bench_cfg.plot_size
|
344
|
+
# specific width overrrides general size
|
345
|
+
if self.bench_cfg.plot_width is not None:
|
346
|
+
kwargs["width"] = self.bench_cfg.plot_width
|
347
|
+
|
348
|
+
if "height" not in kwargs:
|
349
|
+
if self.bench_cfg.plot_size is not None:
|
350
|
+
kwargs["height"] = self.bench_cfg.plot_size
|
351
|
+
# specific height overrrides general size
|
352
|
+
if self.bench_cfg.plot_height is not None:
|
353
|
+
kwargs["height"] = self.bench_cfg.plot_height
|
354
|
+
return kwargs
|
bencher/results/panel_result.py
CHANGED
@@ -71,14 +71,18 @@ class PanelResult(BenchResultBase):
|
|
71
71
|
|
72
72
|
def zero_dim_da_to_val(self, da_ds: xr.DataArray | xr.Dataset) -> Any:
|
73
73
|
# todo this is really horrible, need to improve
|
74
|
+
dim = None
|
74
75
|
if isinstance(da_ds, xr.Dataset):
|
75
76
|
dim = list(da_ds.keys())[0]
|
76
77
|
da = da_ds[dim]
|
77
78
|
else:
|
78
79
|
da = da_ds
|
80
|
+
|
79
81
|
for k in da.coords.keys():
|
80
82
|
dim = k
|
81
83
|
break
|
84
|
+
if dim is None:
|
85
|
+
return da_ds.values.squeeze().item()
|
82
86
|
return da.expand_dims(dim).values[0]
|
83
87
|
|
84
88
|
def ds_to_container(
|
@@ -86,16 +90,21 @@ class PanelResult(BenchResultBase):
|
|
86
90
|
) -> Any:
|
87
91
|
val = self.zero_dim_da_to_val(dataset[result_var.name])
|
88
92
|
if isinstance(result_var, ResultReference):
|
89
|
-
|
93
|
+
ref = self.object_index[val]
|
94
|
+
val = ref.obj
|
95
|
+
if ref.container is not None:
|
96
|
+
return ref.container(val, **kwargs)
|
90
97
|
if container is not None:
|
91
98
|
return container(val, styles={"background": "white"}, **kwargs)
|
92
99
|
return val
|
93
100
|
|
94
101
|
def to_panes(
|
95
|
-
self, result_var: Parameter = None, target_dimension: int = 0, **kwargs
|
102
|
+
self, result_var: Parameter = None, target_dimension: int = 0, container=None, **kwargs
|
96
103
|
) -> Optional[pn.pane.panel]:
|
104
|
+
if container is None:
|
105
|
+
container = pn.pane.panel
|
97
106
|
return self.map_plot_panes(
|
98
|
-
partial(self.ds_to_container, container=
|
107
|
+
partial(self.ds_to_container, container=container),
|
99
108
|
hv_dataset=self.to_hv_dataset(ReduceType.SQUEEZE),
|
100
109
|
target_dimension=target_dimension,
|
101
110
|
result_var=result_var,
|
bencher/utils.py
CHANGED
@@ -7,6 +7,8 @@ import math
|
|
7
7
|
from colorsys import hsv_to_rgb
|
8
8
|
from pathlib import Path
|
9
9
|
from uuid import uuid4
|
10
|
+
from functools import partial
|
11
|
+
from typing import Callable, Any
|
10
12
|
|
11
13
|
|
12
14
|
def hmap_canonical_input(dic: dict) -> tuple:
|
@@ -55,6 +57,12 @@ def get_nearest_coords(dataset: xr.Dataset, collapse_list=False, **kwargs) -> di
|
|
55
57
|
return cd2
|
56
58
|
|
57
59
|
|
60
|
+
def get_nearest_coords1D(val: Any, coords) -> Any:
|
61
|
+
if isinstance(val, (int, float)):
|
62
|
+
return min(coords, key=lambda x_: abs(x_ - val))
|
63
|
+
return val
|
64
|
+
|
65
|
+
|
58
66
|
def hash_sha1(var: any) -> str:
|
59
67
|
"""A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
|
60
68
|
return hashlib.sha1(str(var).encode("ASCII")).hexdigest()
|
@@ -106,6 +114,13 @@ def int_to_col(int_val, sat=0.5, val=0.95, alpha=-1) -> tuple[float, float, floa
|
|
106
114
|
return rgb
|
107
115
|
|
108
116
|
|
117
|
+
def lerp(value, input_low: float, input_high: float, output_low: float, output_high: float):
|
118
|
+
input_low = float(input_low)
|
119
|
+
return output_low + ((float(value) - input_low) / (float(input_high) - input_low)) * (
|
120
|
+
float(output_high) - output_low
|
121
|
+
)
|
122
|
+
|
123
|
+
|
109
124
|
def color_tuple_to_css(color: tuple[float, float, float]) -> str:
|
110
125
|
return f"rgb{(color[0] * 255, color[1] * 255, color[2] * 255)}"
|
111
126
|
|
@@ -122,3 +137,12 @@ def gen_video_path(video_name: str, extension: str = ".webm") -> str:
|
|
122
137
|
|
123
138
|
def gen_image_path(image_name: str, filetype=".png") -> str:
|
124
139
|
return gen_path(image_name, "img", filetype)
|
140
|
+
|
141
|
+
|
142
|
+
def callable_name(any_callable: Callable[..., Any]) -> str:
|
143
|
+
if isinstance(any_callable, partial):
|
144
|
+
return any_callable.func.__name__
|
145
|
+
try:
|
146
|
+
return any_callable.__name__
|
147
|
+
except AttributeError:
|
148
|
+
return str(any_callable)
|
bencher/variables/inputs.py
CHANGED
@@ -72,7 +72,7 @@ class EnumSweep(SweepSelector):
|
|
72
72
|
__slots__ = shared_slots
|
73
73
|
|
74
74
|
def __init__(
|
75
|
-
self, enum_type: Enum | List[Enum], units="", samples=None, samples_debug=2, **params
|
75
|
+
self, enum_type: Enum | List[Enum], units=" ", samples=None, samples_debug=2, **params
|
76
76
|
):
|
77
77
|
# The enum can either be an Enum type or a list of enums
|
78
78
|
list_of_enums = isinstance(enum_type, list)
|
@@ -132,7 +132,7 @@ class ParametrizedSweep(Parameterized):
|
|
132
132
|
assert isinstance(override_defaults, list)
|
133
133
|
for p in override_defaults:
|
134
134
|
inp = filter(partial(ParametrizedSweep.filter_fn, p_name=p[0].name), inp)
|
135
|
-
return override_defaults + [
|
135
|
+
return override_defaults + [[i, i.default] for i in inp]
|
136
136
|
|
137
137
|
@classmethod
|
138
138
|
def get_results_only(cls) -> List[Parameter]:
|
bencher/variables/results.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from enum import auto
|
2
|
-
from typing import List
|
2
|
+
from typing import List, Callable, Any
|
3
3
|
|
4
|
+
import panel as pn
|
4
5
|
import param
|
5
6
|
from param import Number
|
6
7
|
from strenum import StrEnum
|
@@ -23,6 +24,7 @@ class ResultVar(Number):
|
|
23
24
|
|
24
25
|
def __init__(self, units="ul", direction: OptDir = OptDir.minimize, **params):
|
25
26
|
Number.__init__(self, **params)
|
27
|
+
assert isinstance(units, str)
|
26
28
|
self.units = units
|
27
29
|
self.default = 0 # json is terrible and does not support nan values
|
28
30
|
self.direction = direction
|
@@ -136,6 +138,29 @@ class ResultContainer(param.Parameter):
|
|
136
138
|
|
137
139
|
|
138
140
|
class ResultReference(param.Parameter):
|
141
|
+
"""Use this class to save arbitrary objects that are not picklable or native to panel. You can pass a container callback that takes the object and returns a panel pane to be displayed"""
|
142
|
+
|
143
|
+
__slots__ = ["units", "obj", "container"]
|
144
|
+
|
145
|
+
def __init__(
|
146
|
+
self,
|
147
|
+
obj: Any = None,
|
148
|
+
container: Callable[Any, pn.pane.panel] = None,
|
149
|
+
default: Any = None,
|
150
|
+
units: str = "container",
|
151
|
+
**params,
|
152
|
+
):
|
153
|
+
super().__init__(default=default, **params)
|
154
|
+
self.units = units
|
155
|
+
self.obj = obj
|
156
|
+
self.container = container
|
157
|
+
|
158
|
+
def hash_persistent(self) -> str:
|
159
|
+
"""A hash function that avoids the PYTHONHASHSEED 'feature' which returns a different hash value each time the program is run"""
|
160
|
+
return hash_sha1(self)
|
161
|
+
|
162
|
+
|
163
|
+
class ResultVolume(param.Parameter):
|
139
164
|
__slots__ = ["units", "obj"]
|
140
165
|
|
141
166
|
def __init__(self, obj=None, default=None, units="container", **params):
|
bencher/video_writer.py
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
from bencher import gen_video_path
|
1
|
+
from bencher import gen_video_path, gen_image_path
|
2
|
+
from PIL import Image
|
3
|
+
import numpy as np
|
2
4
|
|
3
5
|
|
4
6
|
class VideoWriter:
|
5
|
-
def __init__(self, filename: str) -> None:
|
7
|
+
def __init__(self, filename: str = "vid") -> None:
|
6
8
|
self.images = []
|
7
9
|
self.filename = gen_video_path(filename)
|
8
10
|
|
@@ -12,6 +14,17 @@ class VideoWriter:
|
|
12
14
|
def write(self, bitrate: int = 1500) -> str:
|
13
15
|
import moviepy.video.io.ImageSequenceClip
|
14
16
|
|
17
|
+
# todo
|
18
|
+
# if len(self.images[0.shape) == 2:
|
19
|
+
# for i in range(len(self.images)):
|
20
|
+
# self.images[i] = np.expand_dims(self.images[i], 2)
|
21
|
+
|
15
22
|
clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(self.images, fps=30)
|
16
|
-
clip.write_videofile(self.filename, bitrate=f"{bitrate}k")
|
23
|
+
clip.write_videofile(self.filename, bitrate=f"{bitrate}k", logger=None)
|
17
24
|
return self.filename
|
25
|
+
|
26
|
+
|
27
|
+
def add_image(np_array: np.ndarray, name: str = "img"):
|
28
|
+
filename = gen_image_path(name)
|
29
|
+
Image.fromarray(np_array).save(filename)
|
30
|
+
return filename
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: holobench
|
3
|
-
Version: 1.3.
|
3
|
+
Version: 1.3.5
|
4
4
|
Summary: A package for benchmarking the performance of arbitrary functions
|
5
5
|
Author-email: Austin Gregg-Smith <blooop@gmail.com>
|
6
6
|
Requires-Python: >=3.10
|
@@ -21,7 +21,6 @@ Requires-Dist: strenum>=0.4.0,<=0.4.15
|
|
21
21
|
Requires-Dist: scikit-learn>=1.2,<=1.3.2
|
22
22
|
Requires-Dist: str2bool>=1.1,<=1.1
|
23
23
|
Requires-Dist: scoop>=0.7.0,<=0.7.2.0
|
24
|
-
Requires-Dist: ffmpeg-downloader>=0.3.0,<=0.3.0
|
25
24
|
Requires-Dist: moviepy>=1.0.3,<=1.0.3
|
26
25
|
Requires-Dist: black>=23,<=23.12.1 ; extra == "test"
|
27
26
|
Requires-Dist: pylint>=2.16,<=3.0.3 ; extra == "test"
|
@@ -1,14 +1,14 @@
|
|
1
|
-
bencher/__init__.py,sha256=
|
2
|
-
bencher/bench_cfg.py,sha256=
|
1
|
+
bencher/__init__.py,sha256=lw9moEkY3rb3kQVS3_SM9L0LsOAXRSM1JUJ_mm16tMQ,1236
|
2
|
+
bencher/bench_cfg.py,sha256=g7gMQhzMEHBZzVfpBXhn5f0juCGLqK-nEBoSFKXAS2I,18743
|
3
3
|
bencher/bench_plot_server.py,sha256=HnW6XpmARweMCd-koqzu1lxuj0gA4_fP-72D3Yfy-0M,4087
|
4
4
|
bencher/bench_report.py,sha256=b9jLksrXzBhSmvI7KetO1i0hsHknE7qk4b4k0MGGtNw,10484
|
5
5
|
bencher/bench_runner.py,sha256=TLJGn-NO4BBBZMG8W5E6u7IPyij67Yk3S4B29ONClnk,6049
|
6
|
-
bencher/bencher.py,sha256=
|
6
|
+
bencher/bencher.py,sha256=jYOkqs5F6vIL9_KLygVgi0O_vj-xspBVlipduNMtt1Y,32012
|
7
7
|
bencher/caching.py,sha256=AusaNrzGGlj5m6zcwcqnTn55Mam2mQdF--oqelO806M,1627
|
8
8
|
bencher/job.py,sha256=Q2zpia95Ibukk8EeFq5IBbpo2PMRe7o5keelJCJlGnI,5927
|
9
|
-
bencher/optuna_conversions.py,sha256=
|
10
|
-
bencher/utils.py,sha256=
|
11
|
-
bencher/video_writer.py,sha256=
|
9
|
+
bencher/optuna_conversions.py,sha256=9nLVPAydSQ8PyJlyhzs__Em6_Rx8l8Ld94UNJZxy6cY,5303
|
10
|
+
bencher/utils.py,sha256=oKUtD3Uw76n82ZeyWRBleneYKrZuuNE8pb7Gswlhwjc,5034
|
11
|
+
bencher/video_writer.py,sha256=L_RVrHU4C6hj9BhbEPelgPgtGZeHH4PYYW4CHjGXgJ0,937
|
12
12
|
bencher/worker_job.py,sha256=FREi0yWQACFmH86R1j-LH72tALEFkKhLDmmoGQY9Jh4,1571
|
13
13
|
bencher/example/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
14
|
bencher/example/benchmark_data.py,sha256=D9yUg_KKtqqEkAiLceodDwsv6sh7xEFWZNp6P6Y3pj4,6989
|
@@ -34,7 +34,7 @@ bencher/example/example_simple_cat.py,sha256=YFccE84g37U2M3ByWYIcGNLXWdW_ktJbbZv
|
|
34
34
|
bencher/example/example_simple_float.py,sha256=X4vsH0F4fZAoO0EKB1xIzFMY0f0Wyk8LV2plPlSEsbI,1323
|
35
35
|
bencher/example/example_strings.py,sha256=BdsEZgLT9mOxLkBKNHz2XpPwwe4SzNTdjnY1WVlOmNM,1570
|
36
36
|
bencher/example/example_time_event.py,sha256=y1vpK7UDrObEu0Z1x3e4OQzvGCQ7pF5GZvpKLegMbYk,2158
|
37
|
-
bencher/example/example_video.py,sha256=
|
37
|
+
bencher/example/example_video.py,sha256=w2NtsDL-afZWGlScrrHxr9vdCrxTvyzqOUhIeDOHjvU,4079
|
38
38
|
bencher/example/example_workflow.py,sha256=00QnUuViMfX_PqzqkXmg1wPX6yAq7IS7mCL_RFKwrMM,6806
|
39
39
|
bencher/example/experimental/example_bokeh_plotly.py,sha256=3jUKh8eKIAlpklKnp8UopIHhUDw1A0_5CwjeyTzbi7o,846
|
40
40
|
bencher/example/experimental/example_hover_ex.py,sha256=qszw4FkIfqQkVviPSpmUoFOoi6PGotGbsc7Ojyx8EtU,1052
|
@@ -45,11 +45,11 @@ bencher/example/experimental/example_streams.py,sha256=rrTmcmxDlirGoyTbJ4LT4fBIA
|
|
45
45
|
bencher/example/experimental/example_template.py,sha256=XdIVS9RtLdE5GNnerWiZMXvP7n17lzuc_YTLqJTwb6Q,1172
|
46
46
|
bencher/example/experimental/example_updates.py,sha256=rF4UgWY-CW6ohNtOpQklTuwbwVRvEM5j6edZOiMkspQ,1835
|
47
47
|
bencher/example/experimental/example_vector.py,sha256=3o_1dA4dc2HL6uIEvDAcvLPVJB8jgkq1QZ3BQIL-LEo,3118
|
48
|
-
bencher/example/meta/example_meta.py,sha256=
|
48
|
+
bencher/example/meta/example_meta.py,sha256=P71Q-3G8B44DYaZQe5eFmFxUsjbViSat3DcUvgdSSuw,5605
|
49
49
|
bencher/example/meta/example_meta_cat.py,sha256=YKVUiZ7M1tFFYgUTVQZeOe-1bnmxOjLdWy3nmCoyEe0,693
|
50
50
|
bencher/example/meta/example_meta_float.py,sha256=f3OcORsRUt9Bnd1M1hOjmgxulxcalwdQHSQ0Psx1rY8,650
|
51
51
|
bencher/example/meta/example_meta_levels.py,sha256=O77D4gAGYf7uZo7-Kj2ZwyNmpnc4paoQXE_DQtKKWKo,1488
|
52
|
-
bencher/example/optuna/example_optuna.py,sha256
|
52
|
+
bencher/example/optuna/example_optuna.py,sha256=-RIuDrdPjfXz1c1hOAmWeJNdmGICiWnyJfAavRsiMuk,2370
|
53
53
|
bencher/example/shelved/example_float2D_scatter.py,sha256=z8ranMq8IcJ1yoVSFDncp3gw-yWG7X9lXLimXKpy5Ks,3372
|
54
54
|
bencher/example/shelved/example_float3D_cone.py,sha256=T3-IapccLYX3BM9sGDyOTLhZVEmzkeMsXzQMT5msnNQ,2966
|
55
55
|
bencher/example/shelved/example_kwargs.py,sha256=Bgxkd7qeHdySBE24amdP-VNFRRgK_enyzprlxBwY9Ko,2461
|
@@ -57,18 +57,18 @@ bencher/plotting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
57
57
|
bencher/plotting/plot_filter.py,sha256=Zff02hEcRffiqDEoXUHVZQJK5kW4HbMxe2GYCrxI8jg,4688
|
58
58
|
bencher/plotting/plt_cnt_cfg.py,sha256=BkiAsgHm35Mqb5OsjULGVK0Q6pGZ0WSsJxxwSOrbaQs,3124
|
59
59
|
bencher/results/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
60
|
-
bencher/results/bench_result.py,sha256=
|
61
|
-
bencher/results/bench_result_base.py,sha256
|
60
|
+
bencher/results/bench_result.py,sha256=NiJ8UIYrw5QBksltIHAOh-4CaIMYI8YA-cEcWgfwZ70,2838
|
61
|
+
bencher/results/bench_result_base.py,sha256=-c46om4Gulzxn3PPvQAsQF9qzT7rQLtX6hsO65f9N2A,15767
|
62
62
|
bencher/results/float_formatter.py,sha256=sX6HNCyaXdHDxC8ybVUHwCJ3qOKbPUkBOplVIHtKWjM,1746
|
63
|
-
bencher/results/holoview_result.py,sha256=
|
64
|
-
bencher/results/optuna_result.py,sha256=
|
65
|
-
bencher/results/panel_result.py,sha256=
|
63
|
+
bencher/results/holoview_result.py,sha256=nfXYTaGQkXwLqJ_gEB3TYJxHfKAQCN1E60D9Tfbkxos,22254
|
64
|
+
bencher/results/optuna_result.py,sha256=jtsWJGdCS0L98EzxTxXU_AyarCL5CkXRLOVuSvs048M,13437
|
65
|
+
bencher/results/panel_result.py,sha256=SpVHHdTdlNHh1pGcK3DYLw6BClDRJ_37TNTkicnErTU,3936
|
66
66
|
bencher/results/plotly_result.py,sha256=wkgfL38qJp6RviekXBYpNPeU4HCf0nbtKDAhu5QZhUg,2132
|
67
|
-
bencher/variables/inputs.py,sha256=
|
68
|
-
bencher/variables/parametrised_sweep.py,sha256=
|
69
|
-
bencher/variables/results.py,sha256=
|
67
|
+
bencher/variables/inputs.py,sha256=XtUko3qNYB1xk7fwM9teVGRU0MNCW673n2teGtoyFGU,6393
|
68
|
+
bencher/variables/parametrised_sweep.py,sha256=3ioxqm8xg9WYIH-eRFRhDSn_YphGD-269gZ_FaxuEv8,7029
|
69
|
+
bencher/variables/results.py,sha256=omENIr_Y3RxRG8sr4RQKD1Y_vTyMJUoA7P-fV1uSX5Y,6015
|
70
70
|
bencher/variables/sweep_base.py,sha256=I1LEeG1y5Jsw0a-Ik03t0tSzcfENht2GmBECJ3KNs28,6559
|
71
71
|
bencher/variables/time.py,sha256=Le7s8_oUYJD4wCqwQw-a_FRDpYQOi8CqMbGYsBF07jg,2860
|
72
|
-
holobench-1.3.
|
73
|
-
holobench-1.3.
|
74
|
-
holobench-1.3.
|
72
|
+
holobench-1.3.5.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
|
73
|
+
holobench-1.3.5.dist-info/METADATA,sha256=yzGpIvCdTY9riHJHhC9OGAKymmg0LbbQ7AwheTwBhXo,4946
|
74
|
+
holobench-1.3.5.dist-info/RECORD,,
|
File without changes
|