Replace StudySummary to ForzenStudy

This commit is contained in:
keisuke-umezawa
2024-02-18 14:49:27 +09:00
parent 09f61ce23c
commit 1c9dbbb7bc
4 changed files with 57 additions and 88 deletions
+17 -17
View File
@@ -40,11 +40,11 @@ from ._preferential_history import remove_history
from ._preferential_history import report_history
from ._preferential_history import restore_history
from ._rdb_migration import register_rdb_migration_route
from ._serializer import serialize_frozen_study
from ._serializer import serialize_study_detail
from ._serializer import serialize_study_summary
from ._storage import create_new_study
from ._storage import get_study_summaries
from ._storage import get_study_summary
from ._storage import get_studies
from ._storage import get_study
from ._storage import get_trials
from ._storage_url import get_storage
from .artifact._backend import delete_all_artifacts
@@ -102,8 +102,8 @@ def create_app(
@app.get("/api/studies")
@json_api_view
def list_study_summaries() -> dict[str, Any]:
summaries = get_study_summaries(storage)
serialized = [serialize_study_summary(summary) for summary in summaries]
studies = get_studies(storage)
serialized = [serialize_frozen_study(s) for s in studies]
return {
"study_summaries": serialized,
}
@@ -131,12 +131,12 @@ def create_app(
response.status = 400 # Bad request
return {"reason": f"'{study_name}' already exists"}
summary = get_study_summary(storage, study_id)
if summary is None:
study = get_study(storage, study_id)
if study is None:
response.status = 500 # Internal server error
return {"reason": "Failed to create study"}
response.status = 201 # Created
return {"study_summary": serialize_study_summary(summary)}
return {"study_summary": serialize_frozen_study(study)}
@app.post("/api/studies/<study_id:int>/rename")
@json_api_view
@@ -167,14 +167,14 @@ def create_app(
response.status = 500
storage.delete_study(dst_study._study_id)
return {"reason": str(e)}
new_study_summary = get_study_summary(storage, dst_study._study_id)
if new_study_summary is None:
new_study = get_study(storage, dst_study._study_id)
if new_study is None:
response.status = 500
return {"reason": "Failed to load the new study"}
storage.delete_study(src_study._study_id)
response.status = 201
return serialize_study_summary(new_study_summary)
return serialize_frozen_study(new_study)
@app.delete("/api/studies/<study_id:int>")
@json_api_view
@@ -201,24 +201,24 @@ def create_app(
return {"reason": "`after` should be larger or equal 0."}
except KeyError:
after = 0
summary = get_study_summary(storage, study_id)
if summary is None:
study = get_study(storage, study_id)
if study is None:
response.status = 404 # Not found
return {"reason": f"study_id={study_id} is not found"}
trials = get_trials(storage, study_id)
system_attrs = getattr(summary, "system_attrs", {})
system_attrs = getattr(study, "system_attrs", {})
is_preferential = system_attrs.get(_SYSTEM_ATTR_PREFERENTIAL_STUDY, False)
# TODO(c-bata): Cache best_trials
if is_preferential:
best_trials = get_best_preferential_trials(study_id, storage)
elif len(summary.directions) == 1:
elif len(study.directions) == 1:
if len([t for t in trials if t.state == TrialState.COMPLETE]) == 0:
best_trials = []
else:
best_trials = [storage.get_best_trial(study_id)]
else:
best_trials = get_pareto_front_trials(trials=trials, directions=summary.directions)
best_trials = get_pareto_front_trials(trials=trials, directions=study.directions)
(
# TODO: intersection_search_space and union_search_space look more clear since now we
# have union_user_attrs.
@@ -232,7 +232,7 @@ def create_app(
skipped_trial_ids = get_skipped_trial_ids(system_attrs)
skipped_trial_numbers = [t.number for t in trials if t._trial_id in skipped_trial_ids]
return serialize_study_detail(
summary,
study,
best_trials,
trials[after:],
intersection,
+14 -19
View File
@@ -12,7 +12,7 @@ from optuna.distributions import BaseDistribution
from optuna.distributions import CategoricalDistribution
from optuna.distributions import FloatDistribution
from optuna.distributions import IntDistribution
from optuna.study import StudySummary
from optuna.study._frozen import FrozenStudy
from optuna.trial import FrozenTrial
from . import _note as note
@@ -116,25 +116,22 @@ def serialize_attrs(attrs: dict[str, Any]) -> list[Attribute]:
return serialized
def serialize_study_summary(summary: StudySummary) -> dict[str, Any]:
def serialize_frozen_study(study: FrozenStudy) -> dict[str, Any]:
serialized = {
"study_id": summary._study_id,
"study_name": summary.study_name,
"directions": [d.name.lower() for d in summary.directions],
"user_attrs": serialize_attrs(summary.user_attrs),
"is_preferential": getattr(summary, "_system_attrs", {}).get(
"study_id": study._study_id,
"study_name": study.study_name,
"directions": [d.name.lower() for d in study.directions],
"user_attrs": serialize_attrs(study.user_attrs),
"is_preferential": getattr(study, "_system_attrs", {}).get(
_SYSTEM_ATTR_PREFERENTIAL_STUDY, False
),
}
if summary.datetime_start is not None:
serialized["datetime_start"] = summary.datetime_start.isoformat()
return serialized
def serialize_study_detail(
summary: StudySummary,
study: FrozenStudy,
best_trials: list[FrozenTrial],
trials: list[FrozenTrial],
intersection: list[tuple[str, BaseDistribution]],
@@ -145,20 +142,18 @@ def serialize_study_detail(
skipped_trial_numbers: list[int],
) -> dict[str, Any]:
serialized: dict[str, Any] = {
"name": summary.study_name,
"directions": [d.name.lower() for d in summary.directions],
"user_attrs": serialize_attrs(summary.user_attrs),
"name": study.study_name,
"directions": [d.name.lower() for d in study.directions],
"user_attrs": serialize_attrs(study.user_attrs),
}
system_attrs = getattr(summary, "system_attrs", {})
system_attrs = getattr(study, "system_attrs", {})
serialized["artifacts"] = list_study_artifacts(system_attrs)
if summary.datetime_start is not None:
serialized["datetime_start"] = summary.datetime_start.isoformat()
serialized["trials"] = [
serialize_frozen_trial(summary._study_id, trial, system_attrs) for trial in trials
serialize_frozen_trial(study._study_id, trial, system_attrs) for trial in trials
]
serialized["best_trials"] = [
serialize_frozen_trial(summary._study_id, trial, system_attrs) for trial in best_trials
serialize_frozen_trial(study._study_id, trial, system_attrs) for trial in best_trials
]
serialized["intersection_search_space"] = serialize_search_space(intersection)
serialized["union_search_space"] = serialize_search_space(union)
+8 -28
View File
@@ -3,19 +3,14 @@ from __future__ import annotations
from datetime import datetime
from datetime import timedelta
import threading
import typing
from optuna.storages import BaseStorage
from optuna.storages import RDBStorage
from optuna.study import StudyDirection
from optuna.study import StudySummary
from optuna.study._frozen import FrozenStudy
from optuna.trial import FrozenTrial
if typing.TYPE_CHECKING:
from optuna.study._frozen import FrozenStudy
# In-memory trials cache
trials_cache_lock = threading.Lock()
trials_cache: dict[int, list[FrozenTrial]] = {}
@@ -49,19 +44,19 @@ def get_trials(storage: BaseStorage, study_id: int) -> list[FrozenTrial]:
return trials
def get_study_summaries(storage: BaseStorage) -> list[StudySummary]:
def get_studies(storage: BaseStorage) -> list[FrozenStudy]:
frozen_studies = storage.get_all_studies()
if isinstance(storage, RDBStorage):
frozen_studies = sorted(frozen_studies, key=lambda s: s._study_id)
return [_frozen_study_to_study_summary(s) for s in frozen_studies]
return frozen_studies
def get_study_summary(storage: BaseStorage, study_id: int) -> StudySummary | None:
summaries = get_study_summaries(storage)
for summary in summaries:
if summary._study_id != study_id:
def get_study(storage: BaseStorage, study_id: int) -> FrozenStudy:
studies = get_studies(storage)
for s in studies:
if s._study_id != study_id:
continue
return summary
return s
return None
@@ -70,18 +65,3 @@ def create_new_study(
) -> int:
study_id = storage.create_new_study(directions, study_name=study_name)
return study_id
def _frozen_study_to_study_summary(frozen_study: "FrozenStudy") -> StudySummary:
is_single = len(frozen_study.directions) == 1
return StudySummary(
study_name=frozen_study.study_name,
study_id=frozen_study._study_id,
direction=frozen_study.direction if is_single else None,
directions=frozen_study.directions if not is_single else None,
user_attrs=frozen_study.user_attrs,
system_attrs=frozen_study.system_attrs,
best_trial=None,
n_trials=-1, # This field isn't used by Dashboard.
datetime_start=None,
)
+18 -24
View File
@@ -5,9 +5,9 @@ import sys
import numpy as np
import optuna
from optuna_dashboard._serializer import serialize_attrs
from optuna_dashboard._serializer import serialize_frozen_study
from optuna_dashboard._serializer import serialize_study_detail
from optuna_dashboard._serializer import serialize_study_summary
from optuna_dashboard._storage import get_study_summaries
from optuna_dashboard._storage import get_studies
from optuna_dashboard.preferential import create_study
from packaging import version
import pytest
@@ -60,26 +60,20 @@ def test_serialize_numpy_floating() -> None:
def test_get_study_detail_is_preferential() -> None:
storage = optuna.storages.InMemoryStorage()
study = create_study(n_generate=4, storage=storage)
study_summaries = get_study_summaries(storage)
assert len(study_summaries) == 1
studies = get_studies(storage)
assert len(studies) == 1
study_summary = study_summaries[0]
study_detail = serialize_study_detail(
study_summary, [], study.trials, [], [], [], False, {}, []
)
study_detail = serialize_study_detail(studies[0], [], study.trials, [], [], [], False, {}, [])
assert study_detail["is_preferential"]
def test_get_study_detail_is_not_preferential() -> None:
storage = optuna.storages.InMemoryStorage()
study = optuna.create_study(storage=storage)
study_summaries = get_study_summaries(storage)
assert len(study_summaries) == 1
studies = get_studies(storage)
assert len(studies) == 1
study_summary = study_summaries[0]
study_detail = serialize_study_detail(
study_summary, [], study.trials, [], [], [], False, {}, []
)
study_detail = serialize_study_detail(studies[0], [], study.trials, [], [], [], False, {}, [])
assert not study_detail["is_preferential"]
@@ -87,20 +81,20 @@ def test_get_study_detail_is_not_preferential() -> None:
@pytest.mark.skipif(
version.parse(optuna.__version__) < version.parse("3.2.0"), reason="Needs optuna.search_space"
)
def test_get_study_summary_is_preferential() -> None:
def test_get_study_is_preferential() -> None:
storage = optuna.storages.InMemoryStorage()
create_study(n_generate=4, storage=storage)
study_summaries = get_study_summaries(storage)
assert len(study_summaries) == 1
studies = get_studies(storage)
assert len(studies) == 1
study_summary = serialize_study_summary(study_summaries[0])
assert study_summary["is_preferential"]
serialized = serialize_frozen_study(studies[0])
assert serialized["is_preferential"]
def test_get_study_summary_is_not_preferential() -> None:
def test_get_study_is_not_preferential() -> None:
storage = optuna.storages.InMemoryStorage()
optuna.create_study(storage=storage)
study_summaries = get_study_summaries(storage)
assert len(study_summaries) == 1
study_summary = serialize_study_summary(study_summaries[0])
assert not study_summary["is_preferential"]
studies = get_studies(storage)
assert len(studies) == 1
serialized = serialize_frozen_study(studies[0])
assert not serialized["is_preferential"]