holobench 1.3.5__py3-none-any.whl → 1.23.0__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 +12 -0
- bencher/bench_cfg.py +29 -33
- bencher/bench_plot_server.py +5 -1
- bencher/bench_report.py +14 -14
- bencher/bench_runner.py +3 -2
- bencher/bencher.py +80 -53
- bencher/class_enum.py +52 -0
- bencher/job.py +6 -4
- bencher/optuna_conversions.py +4 -3
- bencher/utils.py +55 -4
- bencher/video_writer.py +48 -11
- holobench-1.23.0.data/data/share/bencher/package.xml +33 -0
- holobench-1.23.0.dist-info/LICENSE +21 -0
- {holobench-1.3.5.dist-info → holobench-1.23.0.dist-info}/METADATA +41 -31
- holobench-1.23.0.dist-info/RECORD +20 -0
- {holobench-1.3.5.dist-info → holobench-1.23.0.dist-info}/WHEEL +2 -1
- holobench-1.23.0.dist-info/top_level.txt +1 -0
- bencher/example/benchmark_data.py +0 -200
- bencher/example/example_all.py +0 -45
- bencher/example/example_categorical.py +0 -99
- bencher/example/example_custom_sweep.py +0 -59
- bencher/example/example_docs.py +0 -34
- bencher/example/example_float3D.py +0 -101
- bencher/example/example_float_cat.py +0 -98
- bencher/example/example_floats.py +0 -89
- bencher/example/example_floats2D.py +0 -93
- bencher/example/example_holosweep.py +0 -104
- bencher/example/example_holosweep_objects.py +0 -111
- bencher/example/example_holosweep_tap.py +0 -144
- bencher/example/example_image.py +0 -82
- bencher/example/example_levels.py +0 -181
- bencher/example/example_pareto.py +0 -53
- bencher/example/example_sample_cache.py +0 -85
- bencher/example/example_sample_cache_context.py +0 -116
- bencher/example/example_simple.py +0 -134
- bencher/example/example_simple_bool.py +0 -34
- bencher/example/example_simple_cat.py +0 -47
- bencher/example/example_simple_float.py +0 -38
- bencher/example/example_strings.py +0 -46
- bencher/example/example_time_event.py +0 -62
- bencher/example/example_video.py +0 -124
- bencher/example/example_workflow.py +0 -189
- bencher/example/experimental/example_bokeh_plotly.py +0 -38
- bencher/example/experimental/example_hover_ex.py +0 -45
- bencher/example/experimental/example_hvplot_explorer.py +0 -39
- bencher/example/experimental/example_interactive.py +0 -75
- bencher/example/experimental/example_streamnd.py +0 -49
- bencher/example/experimental/example_streams.py +0 -36
- bencher/example/experimental/example_template.py +0 -40
- bencher/example/experimental/example_updates.py +0 -84
- bencher/example/experimental/example_vector.py +0 -84
- bencher/example/meta/example_meta.py +0 -171
- bencher/example/meta/example_meta_cat.py +0 -25
- bencher/example/meta/example_meta_float.py +0 -23
- bencher/example/meta/example_meta_levels.py +0 -26
- bencher/example/optuna/example_optuna.py +0 -78
- bencher/example/shelved/example_float2D_scatter.py +0 -109
- bencher/example/shelved/example_float3D_cone.py +0 -96
- bencher/example/shelved/example_kwargs.py +0 -63
- bencher/plotting/__init__.py +0 -0
- bencher/plotting/plot_filter.py +0 -110
- bencher/plotting/plt_cnt_cfg.py +0 -74
- bencher/results/__init__.py +0 -0
- bencher/results/bench_result.py +0 -80
- bencher/results/bench_result_base.py +0 -405
- bencher/results/float_formatter.py +0 -44
- bencher/results/holoview_result.py +0 -592
- bencher/results/optuna_result.py +0 -354
- bencher/results/panel_result.py +0 -113
- bencher/results/plotly_result.py +0 -65
- bencher/variables/inputs.py +0 -193
- bencher/variables/parametrised_sweep.py +0 -206
- bencher/variables/results.py +0 -176
- bencher/variables/sweep_base.py +0 -167
- bencher/variables/time.py +0 -74
- holobench-1.3.5.dist-info/RECORD +0 -74
- /bencher/example/__init__.py → /holobench-1.23.0.data/data/share/ament_index/resource_index/packages/bencher +0 -0
@@ -1,111 +0,0 @@
|
|
1
|
-
# THIS IS NOT A WORKING EXAMPLE YET
|
2
|
-
|
3
|
-
# pylint: disable=duplicate-code,unused-argument
|
4
|
-
|
5
|
-
|
6
|
-
import bencher as bch
|
7
|
-
import math
|
8
|
-
import random
|
9
|
-
import numpy as np
|
10
|
-
import holoviews as hv
|
11
|
-
|
12
|
-
from strenum import StrEnum
|
13
|
-
from enum import auto
|
14
|
-
|
15
|
-
|
16
|
-
class Function(StrEnum):
|
17
|
-
fn_cos = auto()
|
18
|
-
fn_sin = auto()
|
19
|
-
fn_log = auto()
|
20
|
-
fn_arctan = auto()
|
21
|
-
|
22
|
-
def call(self, arg) -> float:
|
23
|
-
"""Calls the function defined by the name of the enum
|
24
|
-
|
25
|
-
Returns:
|
26
|
-
float: The result of calling the function defined by the enum
|
27
|
-
"""
|
28
|
-
return getattr(np, self.removeprefix("fn_"))(arg)
|
29
|
-
|
30
|
-
|
31
|
-
class FunctionInputs(bch.ParametrizedSweep):
|
32
|
-
phase = bch.FloatSweep(
|
33
|
-
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5
|
34
|
-
)
|
35
|
-
|
36
|
-
freq = bch.FloatSweep(default=1, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5)
|
37
|
-
|
38
|
-
theta = bch.FloatSweep(
|
39
|
-
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=10
|
40
|
-
)
|
41
|
-
|
42
|
-
compute_fn = bch.EnumSweep(Function)
|
43
|
-
|
44
|
-
|
45
|
-
class FunctionOutputs(bch.ParametrizedSweep):
|
46
|
-
fn_output = bch.ResultVar(units="v", doc="sin of theta with some noise")
|
47
|
-
|
48
|
-
out_sum = bch.ResultVar(units="v", doc="The sum")
|
49
|
-
|
50
|
-
hmap = bch.ResultHmap()
|
51
|
-
|
52
|
-
hmap2 = bch.ResultHmap()
|
53
|
-
|
54
|
-
|
55
|
-
def bench_fn(self, **kwargs) -> dict:
|
56
|
-
fin = FunctionInputs()
|
57
|
-
fin.update_params_from_kwargs(**kwargs)
|
58
|
-
|
59
|
-
output = FunctionOutputs()
|
60
|
-
|
61
|
-
output.fn_output = fin.compute_fn.call(fin.phase + fin.freq * fin.theta) + random.uniform(0, 0)
|
62
|
-
output.hmap = hv.Text(0, 0, f"{fin.phase}\n{fin.freq}\n {fin.theta}")
|
63
|
-
output.hmap2 = hv.Ellipse(0, 0, 1)
|
64
|
-
return output
|
65
|
-
|
66
|
-
|
67
|
-
def plot_holo(self, plot=True) -> hv.core.ViewableElement:
|
68
|
-
"""Plots a generic representation of the object that is not a basic hv datatype. In this case its an image of the values of the object, but it could be any representation of the object, e.g. a screenshot of the object state"""
|
69
|
-
if plot:
|
70
|
-
pt = hv.Text(0, 0, f"{self.phase}\n{self.freq}\n {self.theta}")
|
71
|
-
pt *= hv.Ellipse(0, 0, 1)
|
72
|
-
return pt
|
73
|
-
return None
|
74
|
-
|
75
|
-
|
76
|
-
def example_holosweep(
|
77
|
-
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
78
|
-
) -> bch.Bench:
|
79
|
-
# wv = PlotFunctions()
|
80
|
-
|
81
|
-
bench = bch.Bench(
|
82
|
-
"waves", bench_fn, worker_input_cfg=FunctionInputs, run_cfg=run_cfg, report=report
|
83
|
-
)
|
84
|
-
|
85
|
-
res = bench.plot_sweep(
|
86
|
-
"phase",
|
87
|
-
input_vars=[FunctionInputs.param.theta, FunctionInputs.param.freq],
|
88
|
-
result_vars=[
|
89
|
-
FunctionOutputs.param.fn_output,
|
90
|
-
FunctionOutputs.param.hmap,
|
91
|
-
FunctionOutputs.param.hmap2,
|
92
|
-
],
|
93
|
-
)
|
94
|
-
|
95
|
-
# bench.report.append(res.summarise_sweep())
|
96
|
-
# bench.report.append(res.to_optuna())
|
97
|
-
# bench.report.append(res.get_best_holomap())
|
98
|
-
# bench.report.append(res.to_curve(), "Slider view")
|
99
|
-
# bench.report.append(res.to_holomap().layout())
|
100
|
-
# print(res.to_holomap())
|
101
|
-
bench.report.append(res.to_holomap())
|
102
|
-
# bench.report.append(res.to_holomap())
|
103
|
-
|
104
|
-
return bench
|
105
|
-
|
106
|
-
|
107
|
-
if __name__ == "__main__":
|
108
|
-
bench_run = bch.BenchRunner("bench_runner_test", run_cfg=bch.BenchRunCfg())
|
109
|
-
|
110
|
-
bench_run.add_run(example_holosweep)
|
111
|
-
bench_run.run(level=4, show=True)
|
@@ -1,144 +0,0 @@
|
|
1
|
-
# THIS IS NOT A WORKING EXAMPLE YET
|
2
|
-
|
3
|
-
# pylint: disable=duplicate-code,unused-argument
|
4
|
-
|
5
|
-
|
6
|
-
import bencher as bch
|
7
|
-
import math
|
8
|
-
import random
|
9
|
-
import numpy as np
|
10
|
-
import holoviews as hv
|
11
|
-
|
12
|
-
from strenum import StrEnum
|
13
|
-
from enum import auto
|
14
|
-
|
15
|
-
|
16
|
-
class Function(StrEnum):
|
17
|
-
fn_cos = auto()
|
18
|
-
fn_sin = auto()
|
19
|
-
fn_log = auto()
|
20
|
-
fn_arctan = auto()
|
21
|
-
|
22
|
-
def call(self, arg) -> float:
|
23
|
-
"""Calls the function defined by the name of the enum
|
24
|
-
|
25
|
-
Returns:
|
26
|
-
float: The result of calling the function defined by the enum
|
27
|
-
"""
|
28
|
-
return getattr(np, self.removeprefix("fn_"))(arg)
|
29
|
-
|
30
|
-
|
31
|
-
class PlotFunctions(bch.ParametrizedSweep):
|
32
|
-
phase = bch.FloatSweep(
|
33
|
-
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5
|
34
|
-
)
|
35
|
-
|
36
|
-
freq = bch.FloatSweep(default=1, bounds=[0, math.pi], doc="Input angle", units="rad", samples=5)
|
37
|
-
|
38
|
-
theta = bch.FloatSweep(
|
39
|
-
default=0, bounds=[0, math.pi], doc="Input angle", units="rad", samples=10
|
40
|
-
)
|
41
|
-
|
42
|
-
compute_fn = bch.EnumSweep(Function)
|
43
|
-
|
44
|
-
fn_output = bch.ResultVar(units="v", doc="sin of theta with some noise")
|
45
|
-
|
46
|
-
out_sum = bch.ResultVar(units="v", doc="The sum")
|
47
|
-
|
48
|
-
hmap = bch.ResultHmap()
|
49
|
-
|
50
|
-
def __call__(self, plot=True, **kwargs) -> dict:
|
51
|
-
self.update_params_from_kwargs(**kwargs)
|
52
|
-
noise = 0.1
|
53
|
-
|
54
|
-
self.fn_output = self.compute_fn.call(self.phase + self.freq * self.theta) + random.uniform(
|
55
|
-
0, noise
|
56
|
-
)
|
57
|
-
self.hmap = self.plot_holo(plot)
|
58
|
-
|
59
|
-
return self.get_results_values_as_dict()
|
60
|
-
|
61
|
-
def plot_holo(self, plot=True) -> hv.core.ViewableElement:
|
62
|
-
"""Plots a generic representation of the object that is not a basic hv datatype. In this case its an image of the values of the object, but it could be any representation of the object, e.g. a screenshot of the object state"""
|
63
|
-
if plot:
|
64
|
-
pt = hv.Text(0, 0, f"phase:{self.phase}\nfreq:{self.freq}\ntheta:{self.theta}")
|
65
|
-
pt *= hv.Ellipse(0, 0, 1)
|
66
|
-
return pt
|
67
|
-
return None
|
68
|
-
|
69
|
-
def calc_vec(self, **kwargs) -> dict:
|
70
|
-
theta = self.param.theta.values()
|
71
|
-
kwargs.pop("theta", 0)
|
72
|
-
dat = [self.__call__(plot=False, theta=i, **kwargs)["fn_output"] for i in theta]
|
73
|
-
# print(dat)
|
74
|
-
self.out_sum = sum(dat)
|
75
|
-
self.hmap = hv.Curve((theta, dat), "theta", "voltage")
|
76
|
-
# pt = hv.Text(0, 0, f"{self.compute_fn}\n{self.phase}\n{self.freq}")
|
77
|
-
# pt *= hv.Ellipse(0, 0, 1)
|
78
|
-
return self.get_results_values_as_dict()
|
79
|
-
|
80
|
-
|
81
|
-
def example_holosweep_tap(
|
82
|
-
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
83
|
-
) -> bch.Bench:
|
84
|
-
wv = PlotFunctions()
|
85
|
-
|
86
|
-
run_cfg.use_optuna = True
|
87
|
-
run_cfg.auto_plot = False
|
88
|
-
bench = bch.Bench("waves", wv, run_cfg=run_cfg, report=report)
|
89
|
-
|
90
|
-
res = bench.plot_sweep(
|
91
|
-
"phase",
|
92
|
-
input_vars=[PlotFunctions.param.theta, PlotFunctions.param.freq],
|
93
|
-
result_vars=[PlotFunctions.param.fn_output, PlotFunctions.param.hmap],
|
94
|
-
run_cfg=run_cfg,
|
95
|
-
)
|
96
|
-
|
97
|
-
bench.report.append(res.describe_sweep())
|
98
|
-
bench.report.append(res.to_heatmap_tap(PlotFunctions.param.fn_output))
|
99
|
-
|
100
|
-
return bench
|
101
|
-
|
102
|
-
|
103
|
-
def example_holosweep_tap_slider(
|
104
|
-
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
105
|
-
) -> bch.Bench: # pragma: no cover
|
106
|
-
wv = PlotFunctions()
|
107
|
-
|
108
|
-
run_cfg.use_optuna = True
|
109
|
-
bench = bch.Bench("waves", wv, run_cfg=run_cfg, report=report)
|
110
|
-
|
111
|
-
res = bench.plot_sweep(
|
112
|
-
"phase",
|
113
|
-
input_vars=[PlotFunctions.param.theta, PlotFunctions.param.freq, PlotFunctions.param.phase],
|
114
|
-
result_vars=[PlotFunctions.param.fn_output],
|
115
|
-
run_cfg=run_cfg,
|
116
|
-
)
|
117
|
-
|
118
|
-
print(res.get_best_trial_params())
|
119
|
-
bench.report.append(res.get_best_holomap())
|
120
|
-
|
121
|
-
heatmap = res.to_heatmap().opts(tools=["hover", "tap"])
|
122
|
-
posxy = hv.streams.Tap(source=heatmap, x=0, y=0)
|
123
|
-
sld1 = wv.param.phase.as_slider(run_cfg.debug)
|
124
|
-
|
125
|
-
def tap_plot(x, y):
|
126
|
-
print(x, y)
|
127
|
-
selres = bch.get_nearest_coords(res.ds, theta=x, freq=y, phase=sld1.value, repeat=1)
|
128
|
-
return res.hmaps[bch.hmap_canonical_input(selres)]
|
129
|
-
|
130
|
-
tap_dmap = hv.DynamicMap(tap_plot, streams=[posxy])
|
131
|
-
|
132
|
-
bench.report.append_tab(heatmap + tap_dmap, "Interactive Heatmap")
|
133
|
-
bench.report.append(sld1)
|
134
|
-
|
135
|
-
bench.report.append_tab(res.to_curve(), "Slider view")
|
136
|
-
|
137
|
-
return bench
|
138
|
-
|
139
|
-
|
140
|
-
if __name__ == "__main__":
|
141
|
-
example_holosweep_tap(bch.BenchRunCfg()).report.show()
|
142
|
-
|
143
|
-
|
144
|
-
# todo https://discourse.holoviz.org/t/pointdraw-as-parameterized-class/3539
|
bencher/example/example_image.py
DELETED
@@ -1,82 +0,0 @@
|
|
1
|
-
import bencher as bch
|
2
|
-
import numpy as np
|
3
|
-
import math
|
4
|
-
import holoviews as hv
|
5
|
-
import matplotlib.pyplot as plt
|
6
|
-
|
7
|
-
|
8
|
-
def polygon_points(radius: float, sides: int):
|
9
|
-
points = []
|
10
|
-
for ang in np.linspace(0, math.pi * 2, sides + 1):
|
11
|
-
points.append(([math.sin(ang) * radius, math.cos(ang) * radius]))
|
12
|
-
return points
|
13
|
-
|
14
|
-
|
15
|
-
class BenchPolygons(bch.ParametrizedSweep):
|
16
|
-
sides = bch.IntSweep(default=3, bounds=(3, 5))
|
17
|
-
radius = bch.FloatSweep(default=1, bounds=(1, 2))
|
18
|
-
linewidth = bch.FloatSweep(default=1, bounds=(1, 10))
|
19
|
-
linestyle = bch.StringSweep(["solid", "dashed", "dotted"])
|
20
|
-
color = bch.StringSweep(["red", "green", "blue"])
|
21
|
-
polygon = bch.ResultImage()
|
22
|
-
hmap = bch.ResultHmap()
|
23
|
-
|
24
|
-
def __call__(self, **kwargs):
|
25
|
-
self.update_params_from_kwargs(**kwargs)
|
26
|
-
points = polygon_points(self.radius, self.sides)
|
27
|
-
self.hmap = hv.Curve(points)
|
28
|
-
self.polygon = self.points_to_polygon_png(points, bch.gen_image_path("polygon"))
|
29
|
-
return super().__call__()
|
30
|
-
|
31
|
-
def points_to_polygon_png(self, points: list[float], filename: str):
|
32
|
-
"""Draw a closed polygon and save to png"""
|
33
|
-
fig = plt.figure(frameon=False)
|
34
|
-
ax = plt.Axes(fig, [0.0, 0.0, 1.0, 1.0], frameon=False)
|
35
|
-
ax.set_axis_off()
|
36
|
-
ax.plot(
|
37
|
-
[p[0] for p in points],
|
38
|
-
[p[1] for p in points],
|
39
|
-
linewidth=self.linewidth,
|
40
|
-
linestyle=self.linestyle,
|
41
|
-
color=self.color,
|
42
|
-
)
|
43
|
-
ax.set_aspect("equal")
|
44
|
-
fig.add_axes(ax)
|
45
|
-
fig.savefig(filename, dpi=50)
|
46
|
-
return filename
|
47
|
-
|
48
|
-
|
49
|
-
def example_image(
|
50
|
-
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
51
|
-
) -> bch.Bench:
|
52
|
-
bench = bch.Bench("polygons", BenchPolygons(), run_cfg=run_cfg, report=report)
|
53
|
-
|
54
|
-
for s in [
|
55
|
-
[BenchPolygons.param.sides],
|
56
|
-
[BenchPolygons.param.sides, BenchPolygons.param.linewidth],
|
57
|
-
[BenchPolygons.param.sides, BenchPolygons.param.linewidth, BenchPolygons.param.linestyle],
|
58
|
-
[
|
59
|
-
BenchPolygons.param.sides,
|
60
|
-
BenchPolygons.param.linewidth,
|
61
|
-
BenchPolygons.param.linestyle,
|
62
|
-
BenchPolygons.param.color,
|
63
|
-
],
|
64
|
-
[
|
65
|
-
BenchPolygons.param.sides,
|
66
|
-
BenchPolygons.param.linewidth,
|
67
|
-
BenchPolygons.param.linestyle,
|
68
|
-
BenchPolygons.param.color,
|
69
|
-
BenchPolygons.param.radius,
|
70
|
-
],
|
71
|
-
]:
|
72
|
-
bench.plot_sweep(
|
73
|
-
f"Polygons Sweeping {len(s)} Parameters",
|
74
|
-
input_vars=s,
|
75
|
-
result_vars=[BenchPolygons.param.polygon],
|
76
|
-
)
|
77
|
-
|
78
|
-
return bench
|
79
|
-
|
80
|
-
|
81
|
-
if __name__ == "__main__":
|
82
|
-
example_image(bch.BenchRunCfg(level=2)).report.show()
|
@@ -1,181 +0,0 @@
|
|
1
|
-
import bencher as bch
|
2
|
-
from bencher.utils import int_to_col
|
3
|
-
|
4
|
-
import math
|
5
|
-
import holoviews as hv
|
6
|
-
from typing import Any, List
|
7
|
-
import panel as pn
|
8
|
-
from holoviews import opts
|
9
|
-
|
10
|
-
|
11
|
-
class LevelsExample(bch.ParametrizedSweep):
|
12
|
-
xval = bch.FloatSweep(bounds=[0, 3.14])
|
13
|
-
yval = bch.FloatSweep(bounds=[0, 3.14])
|
14
|
-
level = bch.IntSweep(default=1, bounds=[1, 6])
|
15
|
-
|
16
|
-
output = bch.ResultVar(units="v")
|
17
|
-
hmap = bch.ResultHmap()
|
18
|
-
|
19
|
-
def __call__(self, **kwargs: Any) -> Any:
|
20
|
-
self.update_params_from_kwargs(**kwargs)
|
21
|
-
self.output = math.sin(self.xval) + math.cos(self.yval)
|
22
|
-
self.hmap = hv.Points((self.xval, self.yval)).opts(
|
23
|
-
marker="o", size=110 - self.level * 20, color=int_to_col(self.level - 1)
|
24
|
-
)
|
25
|
-
|
26
|
-
return self.get_results_values_as_dict()
|
27
|
-
|
28
|
-
|
29
|
-
class RunWithLevel(bch.ParametrizedSweep):
|
30
|
-
level = bch.IntSweep(default=1, bounds=[1, 8])
|
31
|
-
dimensions = bch.IntSweep(default=1, bounds=[1, 2])
|
32
|
-
|
33
|
-
level_samples = bch.ResultVar()
|
34
|
-
|
35
|
-
def __call__(self, **kwargs) -> dict():
|
36
|
-
self.update_params_from_kwargs(**kwargs)
|
37
|
-
|
38
|
-
self.level_samples = int(
|
39
|
-
pow(
|
40
|
-
len(bch.FloatSweep(bounds=[0, 1]).with_level(self.level).values(False)),
|
41
|
-
self.dimensions,
|
42
|
-
)
|
43
|
-
)
|
44
|
-
return self.get_results_values_as_dict()
|
45
|
-
|
46
|
-
|
47
|
-
def run_with_dim(bench: bch.Bench, dims: List[bch.SweepBase]) -> List[bch.BenchResult]:
|
48
|
-
results = []
|
49
|
-
for level in range(1, 6):
|
50
|
-
print(level)
|
51
|
-
res = bench.plot_sweep(
|
52
|
-
f"Level:{level}",
|
53
|
-
input_vars=dims,
|
54
|
-
const_vars=LevelsExample.get_input_defaults(
|
55
|
-
[LevelsExample.param.level.with_const(level)]
|
56
|
-
),
|
57
|
-
result_vars=[LevelsExample.param.output, LevelsExample.param.hmap],
|
58
|
-
run_cfg=bch.BenchRunCfg(level=level, auto_plot=False),
|
59
|
-
)
|
60
|
-
|
61
|
-
results.append(res)
|
62
|
-
return results
|
63
|
-
|
64
|
-
|
65
|
-
def run_levels_1D(bench: bch.Bench) -> bch.Bench:
|
66
|
-
results = run_with_dim(bench, [LevelsExample.param.xval])
|
67
|
-
bench.report.append_title("Using Levels to define sample density")
|
68
|
-
|
69
|
-
bench1 = bch.Bench("levels", RunWithLevel(), run_cfg=bch.BenchRunCfg(auto_plot=False))
|
70
|
-
res1 = bench1.plot_sweep("Levels", input_vars=[RunWithLevel.param.level])
|
71
|
-
|
72
|
-
bench.report.append_markdown(
|
73
|
-
"Sample levels let you perform parameter sweeps without having to decide how many samples to take when defining the class. If you perform a sweep at level 2, then all the points are reused when sampling at level 3. The higher levels reuse the points from lower levels to avoid having to recompute potentially expensive samples. The other advantage is that it enables a workflow where you can quickly see the results of the sweep at a low resolution to sense check the code, and then run it at a high level to get the fidelity you want. When calling a sweep at a high level, you can publish the intermediate lower level results as the computiation continues so that you can track the progress of the computation and end the sweep early when you have sufficient resolution",
|
74
|
-
width=600,
|
75
|
-
)
|
76
|
-
row = pn.Row()
|
77
|
-
row.append(res1.to_table())
|
78
|
-
# row.append(res1.to_curve().opts(shared_axes=False))
|
79
|
-
row.append(res1.to_curve())
|
80
|
-
|
81
|
-
bench.report.append(row)
|
82
|
-
|
83
|
-
bench.report.append_markdown(
|
84
|
-
"Level 1 returns a single point at the lower bound of the parameter. Level 2 uses the uppper and lower bounds of the parameter. All subsequent levels are created by adding a sample between each previously calculated sample to ensure that all previous values can be reused while retaining an equal sample spacing. The following plots show the sample points as circles and the corresponding plot of a sin function sampled at that level.",
|
85
|
-
width=600,
|
86
|
-
)
|
87
|
-
|
88
|
-
combined_pts = hv.Overlay()
|
89
|
-
combined_curve = hv.Overlay()
|
90
|
-
for it, r in enumerate(results):
|
91
|
-
lvl = it + 1
|
92
|
-
row = pn.Row()
|
93
|
-
pts = r.to_holomap().overlay().opts(title=f"Sample Points for level: {lvl}", height=300)
|
94
|
-
ds = r.to_hv_dataset()
|
95
|
-
crv = r.to_curve_ds(ds.data).opts(shared_axes=False, height=300) * r.to_hv_dataset(
|
96
|
-
bch.ReduceType.NONE
|
97
|
-
).to(hv.Scatter).opts(
|
98
|
-
title=f"Function Values for level: {lvl}", size=5, height=300, shared_axes=False
|
99
|
-
)
|
100
|
-
|
101
|
-
combined_pts *= pts
|
102
|
-
combined_curve *= crv
|
103
|
-
row.append(pts)
|
104
|
-
row.append(crv)
|
105
|
-
bench.report.append_markdown(f"## {r.bench_cfg.title}")
|
106
|
-
bench.report.append(row)
|
107
|
-
|
108
|
-
bench.report.append_markdown(
|
109
|
-
"This plot overlays the previous plots into a single image. It shows how each level overlaps the previous level"
|
110
|
-
)
|
111
|
-
|
112
|
-
bench.report.append(pn.Row(combined_pts, combined_curve))
|
113
|
-
return bench
|
114
|
-
|
115
|
-
|
116
|
-
def run_levels_2D(bench: bch.Bench) -> bch.Bench:
|
117
|
-
results = run_with_dim(bench, [LevelsExample.param.xval, LevelsExample.param.yval])
|
118
|
-
bench.report.append_markdown("# Using Levels to define 2D sample density", "Levels 2D")
|
119
|
-
|
120
|
-
bench1 = bch.Bench("lol", RunWithLevel(), run_cfg=bch.BenchRunCfg(auto_plot=False))
|
121
|
-
res1 = bench1.plot_sweep(
|
122
|
-
"Levels",
|
123
|
-
input_vars=[RunWithLevel.param.level],
|
124
|
-
const_vars=[RunWithLevel.param.dimensions.with_const(2)],
|
125
|
-
)
|
126
|
-
row = pn.Row()
|
127
|
-
row.append(res1.to_table())
|
128
|
-
# row.append(res1.to_curve().opts(shared_axes=False))
|
129
|
-
row.append(res1.to_curve())
|
130
|
-
|
131
|
-
bench.report.append(row)
|
132
|
-
|
133
|
-
for it, r in enumerate(results):
|
134
|
-
lvl = it + 1
|
135
|
-
row = pn.Row()
|
136
|
-
bench.report.append_markdown(f"## {r.bench_cfg.title}")
|
137
|
-
row.append(
|
138
|
-
r.to_holomap()
|
139
|
-
.overlay()
|
140
|
-
.opts(title=f"Sample Points for level: {lvl}", shared_axes=False)
|
141
|
-
)
|
142
|
-
row.append(
|
143
|
-
r.to_heatmap_single(r.bench_cfg.result_vars[0], bch.ReduceType.NONE).opts(
|
144
|
-
title=f"Function Value Heatmap for level: {lvl}", shared_axes=False
|
145
|
-
)
|
146
|
-
)
|
147
|
-
bench.report.append(row)
|
148
|
-
|
149
|
-
bench.report.append_markdown(
|
150
|
-
"This plot overlays the previous plots into a single image. It shows how each level overlaps the previous level"
|
151
|
-
)
|
152
|
-
overlay = hv.Overlay()
|
153
|
-
for lvl, r in enumerate(results):
|
154
|
-
overlay *= (
|
155
|
-
r.to_holomap()
|
156
|
-
.overlay()
|
157
|
-
.opts(width=1000, height=1000, show_legend=False, shared_axes=False)
|
158
|
-
)
|
159
|
-
|
160
|
-
bench.report.append(overlay)
|
161
|
-
return bench
|
162
|
-
|
163
|
-
|
164
|
-
def run_levels(
|
165
|
-
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
166
|
-
) -> bch.Bench:
|
167
|
-
hv.extension("bokeh")
|
168
|
-
opts.defaults(
|
169
|
-
opts.Curve(show_legend=False),
|
170
|
-
opts.Points(show_legend=False),
|
171
|
-
)
|
172
|
-
|
173
|
-
bench = bch.Bench("Levels", LevelsExample(), run_cfg=run_cfg, report=report)
|
174
|
-
bench = run_levels_1D(bench)
|
175
|
-
bench = run_levels_2D(bench)
|
176
|
-
|
177
|
-
return bench
|
178
|
-
|
179
|
-
|
180
|
-
if __name__ == "__main__":
|
181
|
-
run_levels().report.show()
|
@@ -1,53 +0,0 @@
|
|
1
|
-
# pylint: disable=duplicate-code
|
2
|
-
|
3
|
-
import bencher as bch
|
4
|
-
|
5
|
-
# All the examples will be using the data structures and benchmark function defined in this file
|
6
|
-
from bencher.example.benchmark_data import ExampleBenchCfgIn, ExampleBenchCfgOut, bench_function
|
7
|
-
|
8
|
-
|
9
|
-
def example_pareto(
|
10
|
-
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(), report: bch.BenchReport = bch.BenchReport()
|
11
|
-
) -> bch.Bench:
|
12
|
-
"""Example of how to calculate the pareto front of a parameter sweep
|
13
|
-
|
14
|
-
Args:
|
15
|
-
run_cfg (BenchRunCfg): configuration of how to perform the param sweep
|
16
|
-
|
17
|
-
Returns:
|
18
|
-
Bench: results of the parameter sweep
|
19
|
-
"""
|
20
|
-
run_cfg.use_optuna = True
|
21
|
-
|
22
|
-
bench = bch.Bench(
|
23
|
-
"Multi-objective optimisation",
|
24
|
-
bench_function,
|
25
|
-
ExampleBenchCfgIn,
|
26
|
-
run_cfg=run_cfg,
|
27
|
-
report=report,
|
28
|
-
)
|
29
|
-
|
30
|
-
res = bench.plot_sweep(
|
31
|
-
title="Pareto Optimisation with Optuna",
|
32
|
-
description="This example shows how to plot the pareto front of the tradeoff between multiple criteria. When multiple result variable are defined, and use_optuna=True a pareto plot and the relative importance of each input variable on the output criteria is plotted. A summary of the points on the pareto front is printed as well. You can use the pareto plot to decide the how to trade off one objective for another. Pareto plots are suppored for 2D and 3D. If you have more than 3 result variables the first 3 are selected for the pareto plot. Plotting 4D surfaces is left as an exercise to the reader",
|
33
|
-
input_vars=[
|
34
|
-
ExampleBenchCfgIn.param.theta,
|
35
|
-
ExampleBenchCfgIn.param.offset,
|
36
|
-
],
|
37
|
-
result_vars=[ExampleBenchCfgOut.param.out_sin, ExampleBenchCfgOut.param.out_cos],
|
38
|
-
const_vars=ExampleBenchCfgIn.get_input_defaults(
|
39
|
-
[ExampleBenchCfgIn.param.noisy.with_const(True)]
|
40
|
-
),
|
41
|
-
post_description="""# Post Description
|
42
|
-
This is a slightly unusual way of doing pareto optimisation as we are not using a typical multi-objective optimisation algorithm [TODO, add example]. Instead we are performing a grid search and looking at the resulting pareto plot. The reason for doing a grid search instead of standard pareto optimisation is that we can produce more isolated plots of how an input affects an output which can help understanding of the parameter space. Future examples will show how to use grid search to bootstrap further optimisation with a multi objective optimiser""",
|
43
|
-
)
|
44
|
-
|
45
|
-
bench.report.append(res.to_optuna_plots())
|
46
|
-
return bench
|
47
|
-
|
48
|
-
|
49
|
-
if __name__ == "__main__":
|
50
|
-
run_cfg_ex = bch.BenchRunCfg()
|
51
|
-
run_cfg_ex.repeats = 2
|
52
|
-
run_cfg_ex.level = 2
|
53
|
-
example_pareto(run_cfg_ex).report.show()
|
@@ -1,85 +0,0 @@
|
|
1
|
-
import bencher as bch
|
2
|
-
|
3
|
-
|
4
|
-
class UnreliableClass(bch.ParametrizedSweep):
|
5
|
-
"""This class helps demonstrate benchmarking a function that sometimes crashes during sampling. By using BenchRunCfg.use_sample_cache you can store the results of every call to the benchmark function so data is not lost in the event of a crash. However, because cache invalidation is hard (https://martinfowler.com/bliki/TwoHardThings.html) you need to be mindful of how you could get bad results due to incorrect cache data. For example if you change your benchmark function and use the sample cache you will not get correct values; you will need to use BenchRunCfg.clear_sample_cache to purge any out of date results."""
|
6
|
-
|
7
|
-
input_val = bch.IntSweep(
|
8
|
-
default=0,
|
9
|
-
bounds=[0, 3],
|
10
|
-
doc="If check limit=True the crashy_fn will crash if this value is >1",
|
11
|
-
)
|
12
|
-
return_value = bch.ResultVar(
|
13
|
-
units="ul",
|
14
|
-
doc="This is a dummy result variable. In this example, it is the same as the value passed in.",
|
15
|
-
)
|
16
|
-
trigger_crash = bch.ResultVar(
|
17
|
-
units="True/False",
|
18
|
-
doc="if true crashy_fn will crash when input_val >1",
|
19
|
-
)
|
20
|
-
|
21
|
-
def crashy_fn(self, input_val: int = 0, **kwargs) -> float: # pylint: disable=unused-argument
|
22
|
-
if self.trigger_crash:
|
23
|
-
if input_val > 1:
|
24
|
-
raise RuntimeError("I crashed for no good reason ;P")
|
25
|
-
|
26
|
-
return {"return_value": input_val, "trigger_crash": self.trigger_crash}
|
27
|
-
|
28
|
-
|
29
|
-
def example_sample_cache(
|
30
|
-
run_cfg: bch.BenchRunCfg = bch.BenchRunCfg(),
|
31
|
-
report: bch.BenchReport = bch.BenchReport(),
|
32
|
-
trigger_crash: bool = False,
|
33
|
-
) -> bch.Bench:
|
34
|
-
"""This example shows how to use the use_sample_cache option to deal with unreliable functions and to continue benchmarking using previously calculated results even if the code crashed during the run
|
35
|
-
|
36
|
-
Args:
|
37
|
-
run_cfg (BenchRunCfg): configuration of how to perform the param sweep
|
38
|
-
trigger_crash: (bool): Turn on/off code to artificially trigger a crash
|
39
|
-
|
40
|
-
Returns:
|
41
|
-
Bench: results of the parameter sweep
|
42
|
-
"""
|
43
|
-
|
44
|
-
instance = UnreliableClass()
|
45
|
-
instance.trigger_crash = trigger_crash
|
46
|
-
|
47
|
-
bencher = bch.Bench("example_sample_cache", instance.crashy_fn, run_cfg=run_cfg, report=report)
|
48
|
-
|
49
|
-
bencher.plot_sweep(
|
50
|
-
title="Example Crashy Function with the sample_cache",
|
51
|
-
input_vars=[UnreliableClass.param.input_val],
|
52
|
-
result_vars=[UnreliableClass.param.return_value, UnreliableClass.param.trigger_crash],
|
53
|
-
description="""This example shows how to use the use_sample_cache option to deal with unreliable functions and to continue benchmarking using previously calculated results even if the code crashed during the run""",
|
54
|
-
run_cfg=run_cfg,
|
55
|
-
post_description="The input_val vs return value graph is a straight line as expected and there is no record of the fact the benchmark crashed halfway through. The second graph shows that for values >1 the trigger_crash value had to be 0 in order to proceed",
|
56
|
-
)
|
57
|
-
return bencher
|
58
|
-
|
59
|
-
|
60
|
-
if __name__ == "__main__":
|
61
|
-
ex_run_cfg = bch.BenchRunCfg()
|
62
|
-
ex_run_cfg.repeats = 1
|
63
|
-
ex_run_cfg.executor = bch.Executors.SCOOP
|
64
|
-
|
65
|
-
# this will store the result of of every call to crashy_fn
|
66
|
-
ex_run_cfg.use_sample_cache = True
|
67
|
-
ex_run_cfg.clear_sample_cache = True
|
68
|
-
|
69
|
-
try:
|
70
|
-
# this will crash after iteration 2 because we are checking the crash_threshold >1. We don't want to lose those (potentially expensive to calculate) datapoints so they are stored in the sample_cache
|
71
|
-
example_sample_cache(ex_run_cfg, trigger_crash=True)
|
72
|
-
except RuntimeError as e:
|
73
|
-
print(f"caught the exception {e}")
|
74
|
-
|
75
|
-
print(
|
76
|
-
"Running the same benchmark but without checking the limit. The benchmarking should load the previously calculated values and continue to finish calculating the values that were missed due to the crash"
|
77
|
-
)
|
78
|
-
ex_run_cfg.clear_sample_cache = False
|
79
|
-
example_sample_cache(ex_run_cfg, trigger_crash=False)
|
80
|
-
|
81
|
-
ex_run_cfg.repeats = 2
|
82
|
-
|
83
|
-
example_sample_cache(ex_run_cfg, trigger_crash=False).report.show()
|
84
|
-
|
85
|
-
# see the test_sample_cache for a more detailed explanation of the mechanisms of the cache
|