Add API to set objective names

This commit is contained in:
c-bata
2023-01-04 19:38:44 +09:00
parent 879ce4cacf
commit 192b24eeb3
14 changed files with 71 additions and 12 deletions
+6 -2
View File
@@ -88,14 +88,18 @@ This function uses wsgiref module which is not intended for the production use.
This function exposes WSGI interface for people who want to run on the
production-class WSGI servers like Gunicorn or uWSGI.
**`save_study_note(study: Study, body: string) -> None`**
**`save_study_note(study: Study, body: str) -> None`**
Save the note (Markdown format) to the Study.
**`save_trial_note(trial: Trial, body: string) -> None`**
**`save_trial_note(trial: Trial, body: str) -> None`**
Save the note (Markdown format) to the Trial.
**`set_objective_names(study: Study, names: list[str]) -> None`**
Set the names of objectives.
</details>
## Using an official Docker image
+1
View File
@@ -1,5 +1,6 @@
from ._app import run_server # noqa
from ._app import wsgi # noqa
from ._named_objectives import set_objective_names # noqa
from ._note import save_study_note # noqa
from ._note import save_trial_note # noqa
+35
View File
@@ -0,0 +1,35 @@
from __future__ import annotations
from typing import Any
from typing import Optional
import optuna
SYSTEM_ATTR_NAME = "dashboard:objective_names"
def set_objective_names(study: optuna.Study, names: list[str]) -> None:
"""Set the names of objectives.
Example:
.. code-block:: python
import optuna
from optuna_dashboard import set_objective_names
study = optuna.create_study(directions=["minimize", "minimize"])
set_objective_names(study, ["val_loss", "flops"])
"""
storage = study._storage
study_id = study._study_id
directions = storage.get_study_directions(study_id)
if len(directions) != len(names):
raise ValueError("names must be the same length with the number of objectives.")
storage.set_study_system_attr(study_id, SYSTEM_ATTR_NAME, names)
def get_objective_names(system_attrs: dict[str, Any]) -> Optional[list[str]]:
return system_attrs.get(SYSTEM_ATTR_NAME)
+4
View File
@@ -11,6 +11,7 @@ from optuna.study import StudySummary
from optuna.trial import FrozenTrial
from . import _note as note
from ._named_objectives import get_objective_names
if TYPE_CHECKING:
@@ -99,6 +100,9 @@ def serialize_study_detail(
serialized["union_user_attrs"] = [{"key": a[0], "sortable": a[1]} for a in union_user_attrs]
serialized["has_intermediate_values"] = has_intermediate_values
serialized["note"] = note.get_note_from_system_attrs(system_attrs, None)
objective_names = get_objective_names(system_attrs)
if objective_names:
serialized["objective_names"] = objective_names
return serialized
+2
View File
@@ -49,6 +49,7 @@ interface StudyDetailResponse {
union_user_attrs: AttributeSpec[]
has_intermediate_values: boolean
note: Note
objective_names?: string[]
}
export const getStudyDetailAPI = (
@@ -80,6 +81,7 @@ export const getStudyDetailAPI = (
union_user_attrs: res.data.union_user_attrs,
has_intermediate_values: res.data.has_intermediate_values,
note: res.data.note,
objective_names: res.data.objective_names,
}
})
}
@@ -41,6 +41,7 @@ export const Contour: FC<{
const [xParam, setXParam] = useState("")
const [yParam, setYParam] = useState("")
const paramNames = study?.union_search_space.map((s) => s.name)
const objectiveNames: string[] = study?.objective_names || []
if (!xParam && paramNames && paramNames.length > 0) {
setXParam(paramNames[0])
@@ -85,7 +86,7 @@ export const Contour: FC<{
<Select value={objectiveId} onChange={handleObjectiveChange}>
{study.directions.map((d, i) => (
<MenuItem value={i} key={i}>
{i}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
+2 -1
View File
@@ -20,6 +20,7 @@ export const Edf: FC<{
}> = ({ study = null }) => {
const theme = useTheme()
const [objectiveId, setObjectiveId] = useState<number>(0)
const objectiveNames: string[] = study?.objective_names || []
const handleObjectiveChange = (event: SelectChangeEvent<number>) => {
setObjectiveId(event.target.value as number)
@@ -48,7 +49,7 @@ export const Edf: FC<{
<Select value={objectiveId} onChange={handleObjectiveChange}>
{study.directions.map((d, i) => (
<MenuItem value={i} key={i}>
{i}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
@@ -28,6 +28,7 @@ export const GraphHistory: FC<{
const [logScale, setLogScale] = useState<boolean>(false)
const [filterCompleteTrial, setFilterCompleteTrial] = useState<boolean>(false)
const [filterPrunedTrial, setFilterPrunedTrial] = useState<boolean>(false)
const objectiveNames: string[] = study?.objective_names || []
const handleObjectiveChange = (event: SelectChangeEvent<number>) => {
setObjectiveId(event.target.value as number)
@@ -92,7 +93,7 @@ export const GraphHistory: FC<{
<Select value={objectiveId} onChange={handleObjectiveChange}>
{study.directions.map((d, i) => (
<MenuItem value={i} key={i}>
{i}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
@@ -32,6 +32,7 @@ export const GraphHyperparameterImportanceBeta: FC<{
const numCompletedTrials =
study?.trials.filter((t) => t.state === "Complete").length || 0
const nObjectives = useStudyDirections(studyId)?.length
const objectiveNames: string[] = study?.objective_names || []
useEffect(() => {
action.updateParamImportance(studyId)
@@ -48,7 +49,11 @@ export const GraphHyperparameterImportanceBeta: FC<{
{Array.from({ length: nObjectives || 1 }, (_, i) => {
let title = `Importance for the Objective Value`
if (nObjectives != null && nObjectives > 1) {
title = `Importance for the Objective ${i}`
if (objectiveNames.length == nObjectives) {
title = `Importance for ${objectiveNames[i]} (Objective ${i})`
} else {
title = `Importance for the Objective ${i}`
}
}
return (
<Grid2 key={i} xs={6}>
@@ -20,6 +20,7 @@ export const GraphParallelCoordinate: FC<{
}> = ({ study = null }) => {
const theme = useTheme()
const [objectiveId, setObjectiveId] = useState<number>(0)
const objectiveNames: string[] = study?.objective_names || []
const handleObjectiveChange = (event: SelectChangeEvent<number>) => {
setObjectiveId(event.target.value as number)
@@ -49,7 +50,7 @@ export const GraphParallelCoordinate: FC<{
<Select value={objectiveId} onChange={handleObjectiveChange}>
{study.directions.map((d, i) => (
<MenuItem value={i} key={i}>
{i}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
@@ -21,6 +21,7 @@ export const GraphParetoFront: FC<{
const theme = useTheme()
const [objectiveXId, setObjectiveXId] = useState<number>(0)
const [objectiveYId, setObjectiveYId] = useState<number>(1)
const objectiveNames: string[] = study?.objective_names || []
const handleObjectiveXChange = (event: SelectChangeEvent<number>) => {
setObjectiveXId(event.target.value as number)
@@ -55,7 +56,7 @@ export const GraphParetoFront: FC<{
<Select value={objectiveXId} onChange={handleObjectiveXChange}>
{study.directions.map((d, i) => (
<MenuItem value={i} key={i}>
{i}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
@@ -65,7 +66,7 @@ export const GraphParetoFront: FC<{
<Select value={objectiveYId} onChange={handleObjectiveYChange}>
{study.directions.map((d, i) => (
<MenuItem value={i} key={i}>
{i}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
@@ -32,6 +32,7 @@ export const GraphSlice: FC<{
const distributions = new Map(
study?.union_search_space.map((s) => [s.name, s.distribution])
)
const objectiveNames: string[] = study?.objective_names || []
if (selected === null && paramNames && paramNames.length > 0) {
const distribution = distributions.get(paramNames[0]) || ""
setSelected(paramNames[0])
@@ -82,7 +83,7 @@ export const GraphSlice: FC<{
<Select value={objectiveId} onChange={handleObjectiveChange}>
{study.directions.map((d, i) => (
<MenuItem value={i} key={i}>
{i}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
@@ -93,7 +94,7 @@ export const GraphSlice: FC<{
<Select value={selected || ""} onChange={handleSelectedParam}>
{paramNames?.map((p, i) => (
<MenuItem value={p} key={i}>
{p}
{objectiveNames.length === study?.directions.length ? objectiveNames[i] : `${i}`}
</MenuItem>
))}
</Select>
@@ -8,6 +8,7 @@ export const TrialTable: FC<{
initialRowsPerPage?: number
}> = ({ studyDetail, initialRowsPerPage }) => {
const trials: Trial[] = studyDetail !== null ? studyDetail.trials : []
const objectiveNames: string[] = studyDetail?.objective_names || []
const columns: DataGridColumn<Trial>[] = [
{ field: "number", label: "Number", sortable: true, padding: "none" },
@@ -55,7 +56,7 @@ export const TrialTable: FC<{
const objectiveColumns: DataGridColumn<Trial>[] =
studyDetail.directions.map((s, objectiveId) => ({
field: "values",
label: `Objective ${objectiveId}`,
label: objectiveNames.length === studyDetail?.directions.length ? objectiveNames[objectiveId] : `Objective ${objectiveId}`,
sortable: true,
less: (firstEl, secondEl): number => {
const firstVal = firstEl.values?.[objectiveId]
+1
View File
@@ -106,6 +106,7 @@ declare interface StudyDetail {
union_user_attrs: AttributeSpec[]
has_intermediate_values: boolean
note: Note
objective_names?: string[]
}
declare interface StudyDetails {