Support numpy scalars in Trial.user_attrs

This commit is contained in:
Toshihiko Yanase
2023-11-22 11:48:22 +09:00
parent cd2159ea46
commit ecf5ab80f7
4 changed files with 56 additions and 7 deletions
@@ -2,12 +2,14 @@ from __future__ import annotations
import copy
import threading
from typing import Any
from typing import List
from typing import Optional
from typing import Set
from typing import Tuple
from typing import TYPE_CHECKING
import numpy as np
from optuna.distributions import BaseDistribution
from optuna.trial import FrozenTrial
from optuna.trial import TrialState
@@ -84,12 +86,11 @@ class _CachedExtraStudyProperty:
self._cursor = next_cursor
def _is_sortable_value(self, v: Any) -> bool:
return not isinstance(v, bool) and isinstance(v, (int, float, np.integer, np.floating))
def _update_user_attrs(self, trial: FrozenTrial) -> None:
# TODO(c-bata): Support numpy-specific number types.
current_user_attrs = {
k: not isinstance(v, bool) and isinstance(v, (int, float))
for k, v in trial.user_attrs.items()
}
current_user_attrs = {k: self._is_sortable_value(v) for k, v in trial.user_attrs.items()}
for attr_name, current_is_sortable in current_user_attrs.items():
is_sortable = self._union_user_attrs.get(attr_name)
if is_sortable is None:
+2
View File
@@ -104,6 +104,8 @@ def serialize_attrs(attrs: dict[str, Any]) -> list[Attribute]:
value = "<binary object>"
elif isinstance(v, str):
value = v
elif isinstance(v, (np.floating, np.integer)):
value = v.item()
else:
value = json.dumps(v)
value = value[:MAX_ATTR_LENGTH] if len(value) > MAX_ATTR_LENGTH else value
@@ -4,6 +4,7 @@ from typing import Any
from unittest import TestCase
import warnings
import numpy as np
import optuna
from optuna import create_trial
from optuna.distributions import BaseDistribution
@@ -254,11 +255,29 @@ class _CachedExtraStudyPropertyUserAttrs(TestCase):
def test_infer_sortable(self) -> None:
user_attrs_list: list[dict[str, Any]] = [
{"a": 1, "b": 1, "c": 1, "d": "a", "e": 1, "f": True},
{
"a": 1,
"b": 1,
"c": 1,
"d": "a",
"e": 1,
"f": True,
"g": np.float128(1.1),
"h": np.int64(2),
},
{"a": 2, "b": "a", "c": "a", "d": "a"},
{"a": 3, "b": None, "c": 3, "d": "a", "e": 3},
]
expected = {"a": True, "b": False, "c": False, "d": False, "e": True, "f": False}
expected = {
"a": True,
"b": False,
"c": False,
"d": False,
"e": True,
"f": False,
"g": True,
"h": True,
}
trials = []
for user_attrs in user_attrs_list:
+27
View File
@@ -2,6 +2,7 @@ from __future__ import annotations
import sys
import numpy as np
import optuna
from optuna_dashboard._serializer import serialize_attrs
from optuna_dashboard._serializer import serialize_study_detail
@@ -25,6 +26,32 @@ def test_serialize_dict() -> None:
assert len(serialized) <= 1
def test_serialize_numpy_integer() -> None:
serialized = serialize_attrs(
{
"int8": np.int8(1),
"int16": np.int16(1),
"int32": np.int32(1),
"int64": np.int64(1),
}
)
assert len(serialized) == 4
assert all([v["value"] == 1 for v in serialized])
def test_serialize_numpy_floating() -> None:
serialized = serialize_attrs(
{
"float16": np.float16(1.0),
"float32": np.float32(1.0),
"float64": np.float64(1.0),
"float128": np.float128(1.0),
}
)
assert len(serialized) == 4
assert all([v["value"] == 1.0 for v in serialized])
@pytest.mark.skipif(sys.version_info < (3, 8), reason="BoTorch dropped Python3.7 support")
def test_get_study_detail_is_preferential() -> None:
storage = optuna.storages.InMemoryStorage()