add history of optimal values and incorporate into each ranking
This commit is contained in:
parent
3353b27884
commit
05343dad24
3 changed files with 82 additions and 28 deletions
|
@ -269,21 +269,28 @@ if __name__ == "__main__":
|
||||||
new_results = {}
|
new_results = {}
|
||||||
for obj_name, obj_res in results.items():
|
for obj_name, obj_res in results.items():
|
||||||
new_res = {}
|
new_res = {}
|
||||||
for fopt, opt_name in sorted(obj_res):
|
for fopt, opt_name, extra in sorted(obj_res):
|
||||||
new_res.setdefault(opt_name, []).append(fopt)
|
l = new_res.setdefault(opt_name, [[], []])
|
||||||
for opt_name, fopts in new_res.items():
|
l[0].append(fopt)
|
||||||
|
l[1].append(extra)
|
||||||
|
slices = {}
|
||||||
|
for opt_name, res in new_res.items():
|
||||||
# in the event that an odd number of results needs to be trimmed,
|
# in the event that an odd number of results needs to be trimmed,
|
||||||
# prefer trimming from the bottom (i.e. worse solutions get removed first).
|
# prefer trimming from the bottom (i.e. worse solutions get removed first).
|
||||||
|
fopts, extras = res
|
||||||
down = (len(fopts) - multiple) // 2
|
down = (len(fopts) - multiple) // 2
|
||||||
up = len(fopts) - (len(fopts) - multiple + 1) // 2
|
up = len(fopts) - (len(fopts) - multiple + 1) // 2
|
||||||
# print("asdf", len(fopts), down, up)
|
slices[opt_name] = slice(down, up)
|
||||||
new_res[opt_name] = fopts[down:up]
|
for opt_name, res in new_res.items():
|
||||||
for opt_name, fopts in new_res.items():
|
fopts, extras = res
|
||||||
|
s = slices[opt_name]
|
||||||
|
fopts, extras = fopts[s], extras[s]
|
||||||
if not no_summary:
|
if not no_summary:
|
||||||
assert len(fopts) == multiple, (len(fopts), multiple)
|
assert len(fopts) == multiple, (len(fopts), multiple)
|
||||||
if len(fopts) == multiple:
|
if len(fopts) == multiple:
|
||||||
for fopt in fopts:
|
for fopt, extra in zip(fopts, extras):
|
||||||
new_results.setdefault(obj_name, []).append((fopt, opt_name))
|
result = (fopt, opt_name, extra)
|
||||||
|
new_results.setdefault(obj_name, []).append(result)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
reset = "\033[m"
|
reset = "\033[m"
|
||||||
|
@ -354,8 +361,8 @@ if __name__ == "__main__":
|
||||||
run = 1
|
run = 1
|
||||||
while (cache := wrapped.cached(run)) is not None:
|
while (cache := wrapped.cached(run)) is not None:
|
||||||
run += 1
|
run += 1
|
||||||
fopt, xopt = cache
|
fopt, xopt, history = cache
|
||||||
results.setdefault(obj_name, []).append((fopt, opt_name))
|
results.setdefault(obj_name, []).append((fopt, opt_name, history))
|
||||||
|
|
||||||
note = (lambda s: None) if quieter else m36
|
note = (lambda s: None) if quieter else m36
|
||||||
|
|
||||||
|
@ -377,7 +384,8 @@ if __name__ == "__main__":
|
||||||
)
|
)
|
||||||
_ = optimizer(wrapped, n_trials=n_trials, n_dim=n_dim, with_count=False)
|
_ = optimizer(wrapped, n_trials=n_trials, n_dim=n_dim, with_count=False)
|
||||||
fopt, xopt = wrapped.finish()
|
fopt, xopt = wrapped.finish()
|
||||||
results.setdefault(obj_name, []).append((fopt, opt_name))
|
result = (fopt, opt_name, wrapped.history)
|
||||||
|
results.setdefault(obj_name, []).append(result)
|
||||||
once = True
|
once = True
|
||||||
run += 1
|
run += 1
|
||||||
|
|
||||||
|
@ -391,7 +399,7 @@ if __name__ == "__main__":
|
||||||
print()
|
print()
|
||||||
m1(f"{obj_name}:")
|
m1(f"{obj_name}:")
|
||||||
all_res = {}
|
all_res = {}
|
||||||
for fopt, opt_name in obj_res:
|
for fopt, opt_name, extra in obj_res:
|
||||||
all_res.setdefault(fopt, []).append(opt_name)
|
all_res.setdefault(fopt, []).append(opt_name)
|
||||||
all_opt_names.add(opt_name)
|
all_opt_names.add(opt_name)
|
||||||
scores.setdefault(opt_name, 0.0)
|
scores.setdefault(opt_name, 0.0)
|
||||||
|
|
29
utils.py
29
utils.py
|
@ -173,6 +173,16 @@ class AcquireForWriting:
|
||||||
|
|
||||||
|
|
||||||
def perform_another_experimental_scoring_method(results):
|
def perform_another_experimental_scoring_method(results):
|
||||||
|
if len(results) and len(something := next(iter(results.values()))[0]) == 3:
|
||||||
|
history_length = len(something[2])
|
||||||
|
each = {}
|
||||||
|
for i in range(history_length):
|
||||||
|
# for k, v in results.items(): for vi in v: assert len(vi) == 3, vi
|
||||||
|
l = {k: [(res[2][i], res[1]) for res in v] for k, v in results.items()}
|
||||||
|
for k, v in perform_another_experimental_scoring_method(l).items():
|
||||||
|
each.setdefault(k, []).append(v)
|
||||||
|
return {k: sum(v) / len(v) for k, v in each.items()}
|
||||||
|
|
||||||
new_results = {}
|
new_results = {}
|
||||||
all_opt_names = set()
|
all_opt_names = set()
|
||||||
for obj_name, obj_res in results.items():
|
for obj_name, obj_res in results.items():
|
||||||
|
@ -203,7 +213,7 @@ def perform_another_experimental_scoring_method(results):
|
||||||
|
|
||||||
scores = {k: 0.0 for k in all_opt_names}
|
scores = {k: 0.0 for k in all_opt_names}
|
||||||
for opt_name, (rank, count) in best_ranks_and_counts.items():
|
for opt_name, (rank, count) in best_ranks_and_counts.items():
|
||||||
points = 2**(1 - rank)
|
points = 2 ** (1 - rank)
|
||||||
count = min(count, limited_by_floating_point_precision)
|
count = min(count, limited_by_floating_point_precision)
|
||||||
scores[opt_name] = score = sum(points / 2**i for i in range(count))
|
scores[opt_name] = score = sum(points / 2**i for i in range(count))
|
||||||
|
|
||||||
|
@ -211,17 +221,18 @@ def perform_another_experimental_scoring_method(results):
|
||||||
|
|
||||||
|
|
||||||
def needs_rerun(key, value):
|
def needs_rerun(key, value):
|
||||||
|
if value["duration"] < 0.0 or "history" not in value:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if value["timestamp"] < 1683295630.0: # bugged history field
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not value["history"]: # not sure what happened here
|
||||||
|
return True
|
||||||
|
|
||||||
n_dim = len(value["xopt"])
|
n_dim = len(value["xopt"])
|
||||||
ng = []
|
ng = []
|
||||||
|
|
||||||
if value["duration"] > -1683000000.0:
|
|
||||||
if n_dim == 3:
|
|
||||||
ng += "go_ackley01 go_alpine01 go_deflectedcorrugatedspring go_exponential go_griewank go_infinity go_mishra11 go_multimodal go_pinter go_qing go_rastrigin go_salomon go_schwefel01 go_schwefel20 go_schwefel21 go_schwefel22 go_sineenvelope go_sodp go_trigonometric02 go_wavy go_weierstrass go_xinsheyang01 go_xinsheyang02 go_xinsheyang03 go_yaoliu04 go_yaoliu09 go_zerosum".split()
|
|
||||||
ng += "go_amgm go_brown go_cigar go_deb01 go_deb03 go_deceptive go_needleeye go_penalty01 go_schwefel04 go_schwefel26 go_sphere go_stretchedv go_styblinskitang go_zacharov".split()
|
|
||||||
if n_dim == 4:
|
|
||||||
ng += "go_ackley01 go_alpine01 go_cigar go_exponential go_griewank go_infinity go_pinter go_qing go_schwefel01 go_schwefel02 go_schwefel20 go_schwefel21 go_schwefel22 go_sineenvelope go_sphere go_step2 go_step go_stretchedv go_trigonometric02 go_weierstrass go_whitley go_xinsheyang01 go_xinsheyang02 go_yaoliu04 go_yaoliu09 go_zerosum".split()
|
|
||||||
ng += "go_amgm go_brown go_colville go_deb03 go_penalty01 go_penalty02 go_powell go_rosenbrock go_schwefel04 go_shekel05 go_shekel07 go_shekel10 go_shubert03 go_shubert04 go_styblinskitang go_vincent".split()
|
|
||||||
|
|
||||||
kd = decode_key(key)
|
kd = decode_key(key)
|
||||||
assert kd is not None, key
|
assert kd is not None, key
|
||||||
if kd.obj in ng:
|
if kd.obj in ng:
|
||||||
|
|
49
utils_np.py
49
utils_np.py
|
@ -1,4 +1,5 @@
|
||||||
# i've separated numpy-dependent methods from the rest of the utils.
|
# i've separated numpy-dependent methods from the rest of the utils.
|
||||||
|
from time import time
|
||||||
from utils import AcquireForWriting, merge_summaries, feps, m33, m34, m93
|
from utils import AcquireForWriting, merge_summaries, feps, m33, m34, m93
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
@ -60,7 +61,14 @@ def do_bounding(x, method="clip"):
|
||||||
|
|
||||||
|
|
||||||
class OWrap:
|
class OWrap:
|
||||||
def __init__(self, objective, n_trials, frugal_percent=1.0, greedy_percent=2.0):
|
def __init__(
|
||||||
|
self,
|
||||||
|
objective,
|
||||||
|
n_trials,
|
||||||
|
frugal_percent=1.0,
|
||||||
|
greedy_percent=2.0,
|
||||||
|
history_frequency=10,
|
||||||
|
):
|
||||||
self.feval_count = 0
|
self.feval_count = 0
|
||||||
self.best_so_far = None
|
self.best_so_far = None
|
||||||
self.warning = None
|
self.warning = None
|
||||||
|
@ -69,6 +77,8 @@ class OWrap:
|
||||||
self.__name__ = objective.__name__ # for evolopy
|
self.__name__ = objective.__name__ # for evolopy
|
||||||
self.frugal_percent = float(frugal_percent)
|
self.frugal_percent = float(frugal_percent)
|
||||||
self.greedy_percent = float(greedy_percent)
|
self.greedy_percent = float(greedy_percent)
|
||||||
|
self.history_frequency = history_frequency
|
||||||
|
self.history = []
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return (
|
return (
|
||||||
|
@ -106,6 +116,10 @@ class OWrap:
|
||||||
if self.best_so_far is None or fx < self.best_so_far[0]:
|
if self.best_so_far is None or fx < self.best_so_far[0]:
|
||||||
self.best_so_far = (fx, x)
|
self.best_so_far = (fx, x)
|
||||||
|
|
||||||
|
if self.history_frequency > 0:
|
||||||
|
if self.feval_count % self.history_frequency == 0:
|
||||||
|
self.history.append(self.best_so_far[0])
|
||||||
|
|
||||||
return float(fx)
|
return float(fx)
|
||||||
|
|
||||||
def finish(self, optimizer_name):
|
def finish(self, optimizer_name):
|
||||||
|
@ -137,6 +151,7 @@ class COWrap:
|
||||||
self.n_dim = n_dim
|
self.n_dim = n_dim
|
||||||
self.kwargs = kwargs
|
self.kwargs = kwargs
|
||||||
self._dirty = False
|
self._dirty = False
|
||||||
|
self._history = None
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
@ -157,6 +172,8 @@ class COWrap:
|
||||||
|
|
||||||
def __call__(self, x, *args, **kwargs):
|
def __call__(self, x, *args, **kwargs):
|
||||||
assert not self._ran, "please run .finish() before continuing!"
|
assert not self._ran, "please run .finish() before continuing!"
|
||||||
|
if not self._dirty:
|
||||||
|
self.start_time = time()
|
||||||
result = self.ow.__call__(x, *args, **kwargs)
|
result = self.ow.__call__(x, *args, **kwargs)
|
||||||
self._dirty = True
|
self._dirty = True
|
||||||
return result
|
return result
|
||||||
|
@ -176,6 +193,12 @@ class COWrap:
|
||||||
opt_name = self.optimizer.__name__
|
opt_name = self.optimizer.__name__
|
||||||
return f"COWrap_d{self.n_dim:02}_n{self.n_trials:03}_{opt_name}"
|
return f"COWrap_d{self.n_dim:02}_n{self.n_trials:03}_{opt_name}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def history(self):
|
||||||
|
assert not self._dirty
|
||||||
|
assert self._history
|
||||||
|
return self._history
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cache_key(self):
|
def cache_key(self):
|
||||||
opt_name = self.optimizer.__name__
|
opt_name = self.optimizer.__name__
|
||||||
|
@ -237,15 +260,16 @@ class COWrap:
|
||||||
return None
|
return None
|
||||||
assert "fopt" in summary, summary
|
assert "fopt" in summary, summary
|
||||||
assert "xopt" in summary, summary
|
assert "xopt" in summary, summary
|
||||||
assert "duration" in summary, summary
|
assert "timestamp" in summary, summary
|
||||||
|
assert "history" in summary, summary
|
||||||
fopt = float(summary["fopt"])
|
fopt = float(summary["fopt"])
|
||||||
xopt = np.array(summary["xopt"], np.float64)
|
xopt = np.array(summary["xopt"], np.float64)
|
||||||
duration = float(summary["duration"])
|
history = [fval for fval in summary["history"]]
|
||||||
return fopt, xopt
|
assert history, "history cannot be empty" # this should get filtered now
|
||||||
|
return fopt, xopt, history
|
||||||
|
|
||||||
def finish(self, opt_name=None):
|
def finish(self, opt_name=None):
|
||||||
from json import dumps
|
from json import dumps
|
||||||
from time import time
|
|
||||||
|
|
||||||
assert self._dirty
|
assert self._dirty
|
||||||
self._ran = True
|
self._ran = True
|
||||||
|
@ -255,12 +279,23 @@ class COWrap:
|
||||||
assert self.ow.best_so_far is not None
|
assert self.ow.best_so_far is not None
|
||||||
# fopt, xopt = self.ow.best_so_far
|
# fopt, xopt = self.ow.best_so_far
|
||||||
fopt, xopt = self.ow.finish(self.optimizer.__name__)
|
fopt, xopt = self.ow.finish(self.optimizer.__name__)
|
||||||
|
|
||||||
|
expected_length = self.n_trials // self.ow.history_frequency
|
||||||
|
history = [float(fval) for fval in self.ow.history]
|
||||||
|
history += [fopt] * (expected_length - len(history))
|
||||||
|
|
||||||
|
finish_time = time()
|
||||||
summary = dict(
|
summary = dict(
|
||||||
fopt=float(fopt),
|
fopt=float(fopt),
|
||||||
xopt=[float(x) for x in xopt],
|
xopt=[float(x) for x in xopt],
|
||||||
# duration=float(-1), # old, bad for uniqueness
|
# timestamp=float(-1), # old, bad for uniqueness
|
||||||
duration=float(-time()),
|
timestamp=finish_time,
|
||||||
|
# optional: (for now?)
|
||||||
|
history=history,
|
||||||
|
duration=finish_time - self.start_time,
|
||||||
)
|
)
|
||||||
|
self._history = summary["history"]
|
||||||
|
assert self._history, "why"
|
||||||
|
|
||||||
with AcquireForWriting(self.cache_file) as fp:
|
with AcquireForWriting(self.cache_file) as fp:
|
||||||
self._cached_summaries = None # force reload
|
self._cached_summaries = None # force reload
|
||||||
|
|
Loading…
Reference in a new issue