Skip to content

Commit f68033d

Browse files
clemens-frickepre-commit-ci[bot]Copilot
authored
Version 0.2.3 (#57)
* ci(precommit): ruff update v0.11.12-> v0.12.2 updates: - [github.com/astral-sh/ruff-pre-commit: v0.11.12 → v0.12.2](astral-sh/ruff-pre-commit@v0.11.12...v0.12.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * Ft(geom)!: Apply random inital position for incremental approach (#49) * feat(geom)!: Add random start for incremental approach BREAKING CHANGE: Discrete values are not clipped anymore. If the step would exceed the range the step is not taken. It is therefore possible that the extreme values of the given ranges are not reachable. * test(random_init): Fixes the issues with the not working tests after inital commit. * Feat: Add util function for caching of results (pyspor) (#47) * feat(pyspor): Add util function for caching of results * Doc: add more documentation for the cache * docs(caching): Added docs that explain how to use the caching and added generate key function for easier use * chore: use new ruff dual call in pre-commit and add conventional commits (#50) * chore(pre-commit): update ruff call to new check and format calls and added conventional commits * style: adapt new format rules * fix(cli): version cli works again and help as well * chore: version bump * fix: harden against SQL injection -> suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * fix: improve input parameter checking -> suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * chore: format carfuffle * fix: Episode numbers in step-log were off, now fixed (#52) * fix: Episode numbers in step-log were off, now fixed * chore(version): version bumb for new release * fix(visu, step-log): Change episode selection in step log visualization (#55) * fix(visu, step-log): Change episode selection in step log visualization * Update version to 0.2.2.dev1 * Feat: episode log validation (#56) * feat(visu, episode-log): Added visualization of validation values, toggle to show them, moved slow imports in main function to function they are used in visualization speed-up * CI(pre-commit): changed the branch the prs are opened on * feat(visu, episode-log): Add boxplot to visualize validation distribution * feat(visu, episode-log): Boxplot width dependent on validation frequency * chore: Deleted soon * chore: Deleted * Feat(visu, episode-log): Changed validation value visualization to scatter based error bars * Chore(visu, episode-log): Clean up unused code * Chore: Bump version to 0.2.2.dev2 * [pre-commit.ci] pre-commit autoupdate (#54) * mini version (#53) * fix: Episode numbers in step-log were off, now fixed (#52) * chore(version): version bumb for new release * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/pre-commit/pre-commit-hooks: v5.0.0 → v6.0.0](pre-commit/pre-commit-hooks@v5.0.0...v6.0.0) - [github.com/astral-sh/ruff-pre-commit: v0.11.13 → v0.12.11](astral-sh/ruff-pre-commit@v0.11.13...v0.12.11) --------- Co-authored-by: clemens.fricke <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * Chore(ruff): fix format error * Fix index error (#58) --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Copilot <[email protected]>
1 parent 60ddde7 commit f68033d

File tree

4 files changed

+115
-10
lines changed

4 files changed

+115
-10
lines changed

.pre-commit-config.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# See https://pre-commit.com/hooks.html for more hooks
33
ci:
44
autofix_prs: false
5+
autoupdate_branch: 'develop'
56
autoupdate_schedule: monthly
67

78

@@ -12,7 +13,7 @@ default_language_version:
1213
python: python3.11
1314
repos:
1415
- repo: https://github.com/pre-commit/pre-commit-hooks
15-
rev: v5.0.0
16+
rev: v6.0.0
1617
hooks:
1718
- id: end-of-file-fixer
1819
- id: check-yaml
@@ -29,7 +30,7 @@ repos:
2930
- id: mixed-line-ending
3031
- id: trailing-whitespace
3132
- repo: https://github.com/astral-sh/ruff-pre-commit
32-
rev: v0.11.13
33+
rev: v0.12.11
3334
hooks:
3435
# Run the linter.
3536
- id: ruff-check

releso/__main__.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,8 @@
1515
import gymnasium
1616
import hjson
1717
import numpy as np
18-
import stable_baselines3
19-
import torch
2018

2119
from releso.__version__ import __version__
22-
from releso.base_parser import BaseParser
2320
from releso.util.module_import_raiser import ModuleImportRaiser
2421

2522
try:
@@ -126,6 +123,11 @@ def main(args) -> pathlib.Path:
126123
Raises:
127124
ValueError: Thrown if the json file could not be found.
128125
"""
126+
import stable_baselines3
127+
import torch
128+
129+
from releso.base_parser import BaseParser
130+
129131
###########################
130132
# #
131133
# Loading and parsing #
@@ -322,6 +324,12 @@ def entry():
322324
"timesteps will be included."
323325
),
324326
)
327+
parser_visualize_episodelog.add_argument(
328+
"-v",
329+
"--show-validation",
330+
action="store_true",
331+
help=("Whether to show validation results. Defaults to False."),
332+
)
325333
parser_visualize_steplog = sub_parser_visualize.add_parser(
326334
"step-log",
327335
parents=[visualize_shared_args],
@@ -417,6 +425,7 @@ def entry():
417425
args.window,
418426
window_size=figure_size,
419427
cut_off_point=args.cut_off_point,
428+
show_validation=args.show_validation,
420429
)
421430
export_figure(fig, args.export_path, "episode_log.html")
422431
# Visualize contents of step_log.jsonl

releso/__version__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
Current version.
44
"""
55

6-
__version__ = "0.2.2"
6+
__version__ = "0.2.3"

releso/util/visualization.py

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def plot_episode_log(
6868
window: int = 5,
6969
window_size: Union[tuple[int, int], Literal["auto"]] = "auto",
7070
cut_off_point: int = np.iinfo(int).max,
71+
show_validation: bool = False,
7172
) -> Figure:
7273
"""Plot one or multiple episodes to check out the training progress.
7374
@@ -109,13 +110,16 @@ def plot_episode_log(
109110
or container size. Defaults to "auto".
110111
cut_off_point (int, optional): Plot the episode only to a certain
111112
number of time steps. Defaults to max int.
113+
show_validation (bool, optional): Whether to show validation results.
114+
Defaults to False.
112115
113116
Returns:
114117
fig (plotly.graph_objects.Figure): Plotly figure object with the
115118
requested plots for further customization or export.
116119
"""
117120
end_episode = []
118121
df: list[pd.DataFrame] = []
122+
df_val: list[pd.DataFrame] = []
119123
# make a separate list for just the names of the experiments
120124
n_env: list[str] = list(result_folders.keys())
121125
# set of all episode end reasons
@@ -139,14 +143,45 @@ def plot_episode_log(
139143
temp_df["episode_reward"] / temp_df["steps_in_episode"]
140144
)
141145
unique_values.update(temp_df["episode_end_reason"].unique())
146+
147+
# Validation
148+
if (
149+
show_validation
150+
and (val_file := folder / "eval/log/evaluations.npz").exists()
151+
):
152+
val_data = np.load(val_file)
153+
data = dict()
154+
data["total_timesteps"] = val_data["timesteps"][
155+
val_data["timesteps"] <= cut_off_point
156+
]
157+
cut_off = len(data["total_timesteps"])
158+
data["val_reward_mean"] = val_data["results"][:cut_off].mean(
159+
axis=1
160+
)
161+
data["val_reward_min"] = val_data["results"][:cut_off].min(axis=1)
162+
data["val_reward_max"] = val_data["results"][:cut_off].max(axis=1)
163+
data["val_length_mean"] = val_data["ep_lengths"][:cut_off].mean(
164+
axis=1
165+
)
166+
data["val_length_min"] = val_data["ep_lengths"][:cut_off].min(
167+
axis=1
168+
)
169+
data["val_length_max"] = val_data["ep_lengths"][:cut_off].max(
170+
axis=1
171+
)
172+
173+
temp_val = pd.DataFrame(data, index=data["total_timesteps"])
174+
else:
175+
temp_val = None
176+
df_val.append(temp_val)
142177
df.append(temp_df)
143178

144179
fig = make_subplots(
145180
rows=6, cols=1, shared_xaxes=True, vertical_spacing=0.01
146181
)
147182
# plot each experiment into each sub plot, the idx is used to determine the
148183
# episode end and the episode name
149-
for idx, dataframe in enumerate(df):
184+
for idx, (dataframe, val_dataframe) in enumerate(zip(df, df_val)):
150185
# first subplot
151186
fig.add_trace(
152187
go.Scatter(
@@ -166,6 +201,30 @@ def plot_episode_log(
166201
row=1,
167202
col=1,
168203
)
204+
if val_dataframe is not None:
205+
fig.add_trace(
206+
go.Scatter(
207+
x=val_dataframe["total_timesteps"],
208+
y=val_dataframe["val_reward_mean"],
209+
legendgroup=f"{n_env[idx]}",
210+
name=f"Validation {n_env[idx]}",
211+
# line_color=plotly_colors[idx],
212+
mode="markers",
213+
showlegend=True,
214+
opacity=0.2,
215+
error_y=dict(
216+
type="data",
217+
symmetric=False,
218+
array=val_dataframe["val_reward_max"]
219+
- val_dataframe["val_reward_mean"],
220+
arrayminus=val_dataframe["val_reward_mean"]
221+
- val_dataframe["val_reward_min"],
222+
),
223+
marker=dict(color=plotly_colors[idx], size=8),
224+
),
225+
row=1,
226+
col=1,
227+
)
169228
# second subplot
170229
fig.add_trace(
171230
go.Scatter(
@@ -183,6 +242,30 @@ def plot_episode_log(
183242
row=2,
184243
col=1,
185244
)
245+
246+
if val_dataframe is not None:
247+
fig.add_trace(
248+
go.Scatter(
249+
x=val_dataframe["total_timesteps"],
250+
y=val_dataframe["val_length_mean"],
251+
legendgroup=f"{n_env[idx]}",
252+
name=f"Validation {n_env[idx]}",
253+
mode="markers",
254+
showlegend=False,
255+
opacity=0.2,
256+
error_y=dict(
257+
type="data",
258+
symmetric=False,
259+
array=val_dataframe["val_length_max"]
260+
- val_dataframe["val_length_mean"],
261+
arrayminus=val_dataframe["val_length_mean"]
262+
- val_dataframe["val_length_min"],
263+
),
264+
marker=dict(color=plotly_colors[idx], size=8),
265+
),
266+
row=2,
267+
col=1,
268+
)
186269
# third subplot
187270
fig.add_trace(
188271
go.Scatter(
@@ -488,7 +571,10 @@ def plot_step_log(
488571
df = pd.concat(
489572
[df_raw["episodes"], df_raw["reward"], objectives, design_vars], axis=1
490573
)
491-
574+
if df.empty:
575+
raise ValueError(
576+
f"The provided step log file {step_log_file} is empty or does not follow the current format."
577+
)
492578
# Filter only the selected episodes
493579
max_idx = df["episodes"].max()
494580
if episode_end is None or episode_end > max_idx:
@@ -497,8 +583,17 @@ def plot_step_log(
497583
# filter does not directly filter for episode number but filters the whole
498584
# list of episodes, which can have missing episodes, due to episodes
499585
# generated outside the environment id chosen.
500-
selected_episodes = df["episodes"].unique()[
501-
episode_start : (episode_end + 1) : episode_step
586+
try:
587+
idx_start = df[df["episodes"] >= episode_start].index[0]
588+
idx_end = df[df["episodes"] <= episode_end].index[-1]
589+
except IndexError as err:
590+
raise IndexError(
591+
f"Could not find any episode in the range {episode_start} to {episode_end}. "
592+
f"The available episodes range from {df['episodes'].unique().min()} "
593+
f"to {df['episodes'].unique().max()}"
594+
) from err
595+
selected_episodes = df.iloc[idx_start : idx_end + 1]["episodes"].unique()[
596+
::episode_step
502597
]
503598
df = df[df["episodes"].isin(selected_episodes)]
504599

0 commit comments

Comments
 (0)