Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 1.2.1 #161

Merged
merged 31 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
11eea1c
added parent directory to run display
KrissiHub May 12, 2024
2ae1a82
Increase plot font sizes
sarah-segel May 17, 2024
62d0dde
Merge development and solve conflicts
sarah-segel May 17, 2024
de52a58
Undo objective change in example log
sarah-segel May 17, 2024
76b5997
Merge pull request #146 from automl/138-run-names-in-logs-are-not-dis…
sarah-segel May 31, 2024
d5fb127
Fix linkcheck
sarah-segel Jun 3, 2024
15d249a
Fix linkcheck
sarah-segel Jun 3, 2024
324122f
Resolve merge conflict
sarah-segel Jun 6, 2024
568499f
Merge pull request #147 from automl/enhancement/increase-plot-fontsize
sarah-segel Jun 6, 2024
104f1f8
Fix test for random forest surrogate
helegraf Jun 7, 2024
9d3b002
Fix recorder examples: Seed is no longer optional in the recorder.
helegraf Jun 13, 2024
a87efac
Handle zero variance in all trees for fanova
sarah-segel Jun 14, 2024
1affa80
Handle zero variance in all trees for lpi
sarah-segel Jun 14, 2024
2bba758
Use variance based (normalized) importance for LPI
sarah-segel Jun 14, 2024
ecbd7ce
Edit changelog
sarah-segel Jun 14, 2024
ce0526c
Edit changelog
sarah-segel Jun 14, 2024
8db6cd1
Edit changelog
sarah-segel Jun 14, 2024
4ed490c
Merge pull request #151 from automl/bug/record_examples
sarah-segel Jun 14, 2024
119bb7f
Merge pull request #153 from automl/fix/importances-when-single-budge…
sarah-segel Jun 17, 2024
9fcf52a
Fix numpy version
sarah-segel Jun 18, 2024
46f490e
Merge pull request #156 from automl/bug/fix-numpy-version
sarah-segel Jun 18, 2024
e3196c9
Better cost-over-time hoover text
sarah-segel Jun 20, 2024
c6019a5
Better cost-over-time hoover text
sarah-segel Jun 20, 2024
09b2e2b
Merge pull request #158 from automl/bug/fix-cost-over-time-hoover-text
sarah-segel Jun 20, 2024
67f4437
Show best value for each objective in Overview
sarah-segel Jun 20, 2024
3e9e82d
Use chosen objective to get the incumbent for LPI
sarah-segel Jun 20, 2024
cecf5b1
Remove duplicate objective name in overview
sarah-segel Jun 21, 2024
2e0dfa8
Add total runtime in overview
sarah-segel Jun 21, 2024
257648a
Merge pull request #160 from automl/fix/remove-objective-merging-from…
sarah-segel Jun 21, 2024
13eaa0d
Rename runtime in overview for groups
sarah-segel Jun 21, 2024
f880994
Update version and correct typo
sarah-segel Jun 21, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# Version 1.2.1

## Quality of Life
- Runs now get displayed with their parent directory for better distinguishability.
- Increase plot font sizes.
- Add a simple loading bar functionality for longer runs.

## General
- Seed is now required in the Recorder.

## Bug-Fixes
- Use normalized LPI importance via variance instead of importance over mean (#152)
- Return nan as importance values if variance is 0. for a hyperparameter / budget (#152)

## Plugins
- Show a run's hoover-text for the actual budget of a trial in Cost over Time with Combined budget (#154).
- Use highest budget as default budget for Cost over Time instead of Combined.
- Show best value / config for each objective instead of merged objective in Overview (#159).
- Use chosen objective instead of merged objective to get the incumbent for the calculation of LPI importance (#159).
- Add total runtime in overview (#155).

# Version 1.2

## Plugins
Expand Down
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# are usually completed in github actions.

SHELL := /bin/bash
VERSION := 1.2
VERSION := 1.2.1

NAME := DeepCAVE
PACKAGE_NAME := deepcave
Expand Down Expand Up @@ -48,10 +48,10 @@ install:
install-dev:
$(PIP) install -e ".[dev]"
pre-commit install

install-examples:
$(PIP) install -e ".[examples]"

check-black:
$(BLACK) ${SOURCE_DIR} --check || :
$(BLACK) ${EXAMPLES_DIR} --check || :
Expand Down Expand Up @@ -123,7 +123,7 @@ publish: clean build
$(PYTHON) -m twine upload --repository testpypi ${DIST}/*
@echo
@echo "Test with the following:"
@echo "* Create a new virtual environment to install the uplaoded distribution into"
@echo "* Create a new virtual environment to install the uploaded distribution into"
@echo "* Run the following:"
@echo "--- pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ ${PACKAGE_NAME}==${VERSION}"
@echo
Expand Down
2 changes: 1 addition & 1 deletion deepcave/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"Source Code": "https://github.com/automl/deepcave",
}
copyright = f"Copyright {datetime.date.today().strftime('%Y')}, {author}"
version = "1.2"
version = "1.2.1"

_exec_file = sys.argv[0]
_exec_files = ["server.py", "worker.py", "sphinx-build"]
Expand Down
1 change: 1 addition & 0 deletions deepcave/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Config:
FIGURE_MARGIN = dict(t=30, b=0, l=0, r=0)
FIGURE_HEIGHT = "40vh"
FIGURE_DOWNLOAD_SCALE = 4.0
FIGURE_FONT_SIZE = 20

# Redis settings
REDIS_PORT: int = 6379
Expand Down
11 changes: 10 additions & 1 deletion deepcave/evaluators/fanova.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from deepcave.evaluators.epm.fanova_forest import FanovaForest
from deepcave.runs import AbstractRun
from deepcave.runs.objective import Objective
from deepcave.utils.logs import get_logger


class fANOVA:
Expand Down Expand Up @@ -50,6 +51,7 @@ def __init__(self, run: AbstractRun):
self.cs = run.configspace
self.hps = self.cs.get_hyperparameters()
self.hp_names = self.cs.get_hyperparameter_names()
self.logger = get_logger(self.__class__.__name__)

def calculate(
self,
Expand Down Expand Up @@ -152,7 +154,14 @@ def get_importances(
)

if len(non_zero_idx[0]) == 0:
raise RuntimeError("Encountered zero total variance in all trees.")
self.logger.warning("Encountered zero total variance in all trees.")
importances[sub_hp_ids] = (
np.nan,
np.nan,
np.nan,
np.nan,
)
continue

fractions_total = np.array(
[
Expand Down
13 changes: 8 additions & 5 deletions deepcave/evaluators/lpi.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ def calculate(

# Set variables
self.continous_neighbors = continous_neighbors
self.incumbent, _ = self.run.get_incumbent(budget=budget)
self.incumbent, _ = self.run.get_incumbent(budget=budget, objectives=objectives)
self.default = self.cs.get_default_configuration()
self.incumbent_array = self.incumbent.get_array()

Expand Down Expand Up @@ -220,7 +220,10 @@ def calculate(

# Normalize
overall_var_per_tree = {
p: [t / sum_var_per_tree[idx] for idx, t in enumerate(trees)]
p: [
t / sum_var_per_tree[idx] if sum_var_per_tree[idx] != 0.0 else np.nan
for idx, t in enumerate(trees)
]
for p, trees in overall_var_per_tree.items()
}
self.variances = overall_var_per_tree
Expand Down Expand Up @@ -254,11 +257,11 @@ def get_importances(self, hp_names: List[str]) -> Dict[str, Tuple[float, float]]
std = 0

if hp_name in self.importances:
mean = self.importances[hp_name][0]
mean = np.mean(self.variances[hp_name])
std = np.var(self.variances[hp_name])

# Use this to quantify importance via variance
# mean = np.mean(overall_var_per_tree[hp_name])
# Use this to quantify importance via importance over mean value (not normalized to 1)
# mean = self.importances[hp_name][0]

# Sometimes there is an ugly effect if default is better than
# incumbent.
Expand Down
6 changes: 5 additions & 1 deletion deepcave/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1145,8 +1145,12 @@ def load_run_inputs(
for run in runs:
if check_run_compatibility(run):
try:
run_path = run.path
if run_path is not None:
run_name = run_path.parent.name + "/" + run.name

values.append(run.id)
labels.append(run.name)
labels.append(run_name)
disabled.append(False)
except Exception:
pass
Expand Down
1 change: 1 addition & 0 deletions deepcave/plugins/budget/budget_correlation.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ def load_outputs(run, _, outputs) -> List[Any]: # type: ignore
yaxis=dict(title="Correlation"),
margin=config.FIGURE_MARGIN,
legend=dict(title="Budgets"),
font=dict(size=config.FIGURE_FONT_SIZE),
)

figure = go.Figure(data=traces, layout=layout)
Expand Down
6 changes: 6 additions & 0 deletions deepcave/plugins/hyperparameter/importances.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@
from deepcave.runs import AbstractRun
from deepcave.utils.cast import optional_int
from deepcave.utils.layout import get_checklist_options, get_select_options, help_button
from deepcave.utils.logs import get_logger
from deepcave.utils.styled_plot import plt
from deepcave.utils.styled_plotty import get_color, save_image

logger = get_logger(__name__)


class Importances(StaticPlugin):
"""
Expand Down Expand Up @@ -337,6 +340,8 @@ def process(run: AbstractRun, inputs: Dict[str, Any]) -> Dict[str, Any]:
evaluator.calculate(objective, budget, n_trees=n_trees, seed=0)

importances = evaluator.get_importances(hp_names)
if any(np.isnan(val) for value in importances.values() for val in value):
logger.warning(f"Nan encountered in importance values for budget {budget}.")
data[budget_id] = importances

return data # type: ignore
Expand Down Expand Up @@ -458,6 +463,7 @@ def load_outputs(run, inputs, outputs) -> go.Figure: # type: ignore
legend={"title": "Budget"},
margin=config.FIGURE_MARGIN,
xaxis=dict(tickangle=-45),
font=dict(size=config.FIGURE_FONT_SIZE),
)
save_image(figure, "importances.pdf")

Expand Down
9 changes: 8 additions & 1 deletion deepcave/plugins/hyperparameter/pdp.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ def get_output_layout(register: Callable) -> dcc.Graph:

@staticmethod
def get_pdp_figure( # type: ignore
run, inputs, outputs, show_confidence, show_ice, title=None
run, inputs, outputs, show_confidence, show_ice, title=None, fontsize=None
) -> go.Figure:
"""
Create a figure of the Partial Dependency Plot (PDP).
Expand All @@ -393,6 +393,8 @@ def get_pdp_figure( # type: ignore
Whether to show ice curves in the plot.
title
Title of the plot.
fontsize
Fontsize of the plot.

Returns
-------
Expand Down Expand Up @@ -471,6 +473,9 @@ def get_pdp_figure( # type: ignore
]

tickvals, ticktext = get_hyperparameter_ticks(hp1)
# Allow to pass a fontsize (necessary when leveraging PDP in Symbolic Explanation)
if fontsize is None:
fontsize = config.FIGURE_FONT_SIZE
layout = go.Layout(
{
"xaxis": {
Expand All @@ -482,6 +487,7 @@ def get_pdp_figure( # type: ignore
"title": objective_name,
},
"title": title,
"font": dict(size=fontsize),
}
)
else:
Expand Down Expand Up @@ -509,6 +515,7 @@ def get_pdp_figure( # type: ignore
yaxis=dict(tickvals=y_tickvals, ticktext=y_ticktext, title=hp2_name),
margin=config.FIGURE_MARGIN,
title=title,
font=dict(size=fontsize),
)
)

Expand Down
10 changes: 9 additions & 1 deletion deepcave/plugins/hyperparameter/symbolic_explanations.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,7 @@ def load_outputs(run, inputs, outputs) -> List[go.Figure]: # type: ignore
"title": objective_name,
},
"title": expr,
"font": dict(size=config.FIGURE_FONT_SIZE - 4),
}
)
else:
Expand All @@ -602,6 +603,7 @@ def load_outputs(run, inputs, outputs) -> List[go.Figure]: # type: ignore
yaxis=dict(tickvals=y_tickvals, ticktext=y_ticktext, title=hp2_name),
margin=config.FIGURE_MARGIN,
title=expr,
font=dict(size=config.FIGURE_FONT_SIZE - 4),
)
)

Expand All @@ -614,7 +616,13 @@ def load_outputs(run, inputs, outputs) -> List[go.Figure]: # type: ignore
pdp_title = "Partial Dependency for comparison:"

figure2 = PartialDependencies.get_pdp_figure(
run, inputs, outputs, show_confidence=False, show_ice=False, title=pdp_title
run,
inputs,
outputs,
show_confidence=False,
show_ice=False,
title=pdp_title,
fontsize=config.FIGURE_FONT_SIZE - 4,
)

return [figure1, figure2]
10 changes: 8 additions & 2 deletions deepcave/plugins/objective/configuration_cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,10 @@ def load_outputs(run, inputs, outputs) -> go.Figure: # type: ignore

if len(data) == 3:
trace = go.Scatter3d(x=x, y=y, z=z, **scatter_kwargs)
layout = go.Layout({"scene": {**layout_kwargs}})
layout = go.Layout(
{"scene": {**layout_kwargs}},
font=dict(size=config.FIGURE_FONT_SIZE),
)
else:
if len(data) == 1:
y = [0 for _ in x]
Expand All @@ -425,7 +428,10 @@ def load_outputs(run, inputs, outputs) -> go.Figure: # type: ignore
trace = go.Scatter(x=x, y=y, **scatter_kwargs)
else:
trace = go.Scatter(x=[], y=[])
layout = go.Layout(**layout_kwargs)
layout = go.Layout(
**layout_kwargs,
font=dict(size=config.FIGURE_FONT_SIZE),
)

figure = go.Figure(data=trace, layout=layout)
figure.update_layout(dict(margin=config.FIGURE_MARGIN))
Expand Down
14 changes: 9 additions & 5 deletions deepcave/plugins/objective/cost_over_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,9 @@ def load_inputs(self) -> Dict[str, Any]:
},
"budget_id": {
"options": self.budget_options,
"value": self.budget_options[-1]["value"],
"value": self.budget_options[0]["value"]
if len(self.budget_options) == 1
else self.budget_options[-2]["value"],
},
"xaxis": {
"options": [
Expand Down Expand Up @@ -344,8 +346,7 @@ def load_outputs(runs, inputs, outputs) -> go.Figure: # type: ignore
continue

objective = run.get_objective(inputs["objective_id"])
budget = run.get_budget(inputs["budget_id"])
config_ids = outputs[run.id]["config_ids"]
ids = outputs[run.id]["ids"]
x = outputs[run.id]["times"]
if inputs["xaxis"] == "trials":
x = outputs[run.id]["ids"]
Expand All @@ -360,9 +361,11 @@ def load_outputs(runs, inputs, outputs) -> go.Figure: # type: ignore
hoverinfo = "skip"
symbol = None
mode = "lines"
if len(config_ids) > 0:
if len(run.history) > 0:
hovertext = [
get_hovertext_from_config(run, config_id, budget) for config_id in config_ids
get_hovertext_from_config(run, trial.config_id, trial.budget)
for id, trial in enumerate(run.history)
if id in ids
]
hoverinfo = "text"
symbol = "circle"
Expand Down Expand Up @@ -423,6 +426,7 @@ def load_outputs(runs, inputs, outputs) -> go.Figure: # type: ignore
xaxis=dict(title=xaxis_label, type=type),
yaxis=dict(title=objective.name),
margin=config.FIGURE_MARGIN,
font=dict(size=config.FIGURE_FONT_SIZE),
)

figure = go.Figure(data=traces, layout=layout)
Expand Down
5 changes: 4 additions & 1 deletion deepcave/plugins/objective/parallel_coordinates.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,10 @@ def load_outputs(run, inputs, outputs) -> go.Figure: # type: ignore
dimensions=list([d for d in data.values()]),
labelangle=45,
),
layout=dict(margin=dict(t=150, b=50, l=100, r=0)),
layout=dict(
margin=dict(t=150, b=50, l=100, r=0),
font=dict(size=config.FIGURE_FONT_SIZE),
),
)
save_image(figure, "parallel_coordinates.pdf")

Expand Down
6 changes: 3 additions & 3 deletions deepcave/plugins/objective/pareto_front.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ def load_outputs(runs, inputs, outputs) -> go.Figure: # type: ignore
x_std += [points_std[point_idx][0]]
y_std += [points_std[point_idx][1]]

color = get_color(idx, alpha=0.1)
color = get_color(idx, alpha=0.5)
color_pareto = get_color(idx)

if show_all:
Expand Down Expand Up @@ -524,6 +524,7 @@ def load_outputs(runs, inputs, outputs) -> go.Figure: # type: ignore
xaxis=dict(title=objective_1.name),
yaxis=dict(title=objective_2.name),
margin=config.FIGURE_MARGIN,
font=dict(size=config.FIGURE_FONT_SIZE),
)
else:
layout = None
Expand Down Expand Up @@ -605,12 +606,11 @@ def load_mpl_outputs(runs, inputs, outputs): # type: ignore
x += [points[point_idx][0]]
y += [points[point_idx][1]]

# , alpha=0.1)
color = plt.get_color(idx) # type: ignore
color_pareto = plt.get_color(idx) # type: ignore

if show_all:
plt.scatter(x, y, color=color, marker="o", alpha=0.1, s=3)
plt.scatter(x, y, color=color, marker="o", s=3)

# Check if hv or vh is needed
objective_1 = run.get_objective(inputs["objective_id_1"])
Expand Down
8 changes: 6 additions & 2 deletions deepcave/plugins/summary/configurations.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,10 @@ def _get_objective_figure(
}
)

objective_layout = go.Layout(**layout_kwargs)
objective_layout = go.Layout(
**layout_kwargs,
font=dict(size=config.FIGURE_FONT_SIZE),
)
objective_figure = go.Figure(data=objective_data, layout=objective_layout)
save_image(objective_figure, "configure.pdf")

Expand Down Expand Up @@ -480,7 +483,8 @@ def _get_configspace_figure(
margin=dict(
t=150,
b=50,
)
),
font=dict(size=config.FIGURE_FONT_SIZE),
),
)

Expand Down
Loading