From a76e0e4f4af3384df3da52d8d0a81398bd9d4b8a Mon Sep 17 00:00:00 2001 From: c-bata Date: Tue, 12 Jan 2021 19:23:23 +0900 Subject: [PATCH] Support Optuna v2.4.0 --- optuna_dashboard/app.py | 6 ++- optuna_dashboard/serializer.py | 8 +-- optuna_dashboard/static/apiClient.ts | 16 +++--- .../static/components/GraphHistory.tsx | 24 ++++++--- .../components/GraphParallelCoordinate.tsx | 8 +-- .../static/components/StudyDetail.tsx | 49 ++++++++++++------- .../static/components/StudyList.tsx | 11 +++-- optuna_dashboard/static/types/index.d.ts | 6 +-- 8 files changed, 80 insertions(+), 48 deletions(-) diff --git a/optuna_dashboard/app.py b/optuna_dashboard/app.py index 7e388caf..811bb248 100644 --- a/optuna_dashboard/app.py +++ b/optuna_dashboard/app.py @@ -140,10 +140,12 @@ def create_app(storage_or_url: Union[str, BaseStorage]) -> Bottle: except DuplicatedStudyError: response.status = 400 # Bad request return {"reason": f"'{study_name}' is already exists"} + + # TODO(c-bata): Support multi-objective study. if direction.lower() == "maximize": - storage.set_study_direction(study_id, StudyDirection.MAXIMIZE) + storage.set_study_directions(study_id, [StudyDirection.MAXIMIZE]) else: - storage.set_study_direction(study_id, StudyDirection.MINIMIZE) + storage.set_study_directions(study_id, [StudyDirection.MINIMIZE]) summary = get_study_summary(storage, study_id) if summary is None: diff --git a/optuna_dashboard/serializer.py b/optuna_dashboard/serializer.py index 5002180a..76eef2f4 100644 --- a/optuna_dashboard/serializer.py +++ b/optuna_dashboard/serializer.py @@ -49,7 +49,7 @@ def serialize_study_summary(summary: StudySummary) -> Dict[str, Any]: serialized = { "study_id": summary._study_id, "study_name": summary.study_name, - "direction": summary.direction.name.lower(), + "directions": [d.name.lower() for d in summary.directions], "user_attrs": serialize_attrs(summary.user_attrs), "system_attrs": serialize_attrs(summary.system_attrs), } @@ -70,7 +70,7 @@ def serialize_study_detail( ) -> Dict[str, Any]: serialized: Dict[str, Any] = { "name": summary.study_name, - "direction": summary.direction.name.lower(), + "directions": [d.name.lower() for d in summary.directions], } if summary.datetime_start is not None: serialized["datetime_start"] = summary.datetime_start.isoformat() @@ -98,8 +98,8 @@ def serialize_frozen_trial(study_id: int, trial: FrozenTrial) -> Dict[str, Any]: "system_attrs": serialize_attrs(trial.system_attrs), } - if trial.value is not None: - serialized["value"] = trial.value + if trial.values is not None: + serialized["values"] = trial.values if trial.datetime_start is not None: serialized["datetime_start"] = trial.datetime_start.isoformat() diff --git a/optuna_dashboard/static/apiClient.ts b/optuna_dashboard/static/apiClient.ts index 3e5b5f74..e8867420 100644 --- a/optuna_dashboard/static/apiClient.ts +++ b/optuna_dashboard/static/apiClient.ts @@ -7,7 +7,7 @@ interface TrialResponse { study_id: number number: number state: TrialState - value?: number + values?: number[] intermediate_values: TrialIntermediateValue[] datetime_start: string datetime_complete?: string @@ -22,7 +22,7 @@ const convertTrialResponse = (res: TrialResponse): Trial => { study_id: res.study_id, number: res.number, state: res.state, - value: res.value, + values: res.values, intermediate_values: res.intermediate_values, datetime_start: new Date(res.datetime_start), datetime_complete: res.datetime_complete @@ -37,7 +37,7 @@ const convertTrialResponse = (res: TrialResponse): Trial => { interface StudyDetailResponse { name: string datetime_start: string - direction: StudyDirection + directions: StudyDirection[] best_trial?: TrialResponse trials: TrialResponse[] } @@ -54,7 +54,7 @@ export const getStudyDetailAPI = (studyId: number): Promise => { return { name: res.data.name, datetime_start: new Date(res.data.datetime_start), - direction: res.data.direction, + directions: res.data.directions, best_trial: res.data.best_trial ? convertTrialResponse(res.data.best_trial) : undefined, @@ -67,7 +67,7 @@ interface StudySummariesResponse { study_summaries: { study_id: number study_name: string - direction: StudyDirection + directions: StudyDirection[] best_trial?: { trial_id: number study_id: number @@ -99,7 +99,7 @@ export const getStudySummariesAPI = (): Promise => { return { study_id: study.study_id, study_name: study.study_name, - direction: study.direction, + directions: study.directions, best_trial: best_trial, user_attrs: study.user_attrs, system_attrs: study.system_attrs, @@ -116,7 +116,7 @@ interface CreateNewStudyResponse { study_summary: { study_id: number study_name: string - direction: StudyDirection + directions: StudyDirection[] best_trial?: { trial_id: number study_id: number @@ -150,7 +150,7 @@ export const createNewStudyAPI = ( return { study_id: study_summary.study_id, study_name: study_summary.study_name, - direction: study_summary.direction, + directions: study_summary.directions, // best_trial: undefined, user_attrs: study_summary.user_attrs, system_attrs: study_summary.system_attrs, diff --git a/optuna_dashboard/static/components/GraphHistory.tsx b/optuna_dashboard/static/components/GraphHistory.tsx index c1d72d73..34fb0270 100644 --- a/optuna_dashboard/static/components/GraphHistory.tsx +++ b/optuna_dashboard/static/components/GraphHistory.tsx @@ -44,6 +44,7 @@ export const GraphHistory: FC<{ if (study !== null) { plotHistory( study, + 0, // TODO(c-bata): Support multi-objective studies. xAxis, logScale, filterCompleteTrial, @@ -121,6 +122,7 @@ export const GraphHistory: FC<{ const plotHistory = ( study: StudyDetail, + objectiveId: number, xAxis: string, logScale: boolean, filterCompleteTrial: boolean, @@ -163,13 +165,19 @@ const plotHistory = ( let currentBest: number | null = null filteredTrials.forEach((item) => { if (currentBest === null) { - currentBest = item.value! + currentBest = item.values![objectiveId] trialsForLinePlot.push(item) - } else if (study.direction === "maximize" && item.value! > currentBest) { - currentBest = item.value! + } else if ( + study.directions[objectiveId] === "maximize" && + item.values![objectiveId] > currentBest + ) { + currentBest = item.values![objectiveId] trialsForLinePlot.push(item) - } else if (study.direction === "minimize" && item.value! < currentBest) { - currentBest = item.value! + } else if ( + study.directions[objectiveId] === "minimize" && + item.values![objectiveId] < currentBest + ) { + currentBest = item.values![objectiveId] trialsForLinePlot.push(item) } }) @@ -184,13 +192,15 @@ const plotHistory = ( let xForLinePlot = trialsForLinePlot.map(getAxisX) xForLinePlot.push(getAxisX(filteredTrials[filteredTrials.length - 1])) - let yForLinePlot = trialsForLinePlot.map((t: Trial): number => t.value!) + let yForLinePlot = trialsForLinePlot.map( + (t: Trial): number => t.values![objectiveId] + ) yForLinePlot.push(yForLinePlot[yForLinePlot.length - 1]) const plotData: Partial[] = [ { x: filteredTrials.map(getAxisX), - y: filteredTrials.map((t: Trial): number => t.value!), + y: filteredTrials.map((t: Trial): number => t.values![objectiveId]), mode: "markers", type: "scatter", }, diff --git a/optuna_dashboard/static/components/GraphParallelCoordinate.tsx b/optuna_dashboard/static/components/GraphParallelCoordinate.tsx index 7af367d7..d9e81466 100644 --- a/optuna_dashboard/static/components/GraphParallelCoordinate.tsx +++ b/optuna_dashboard/static/components/GraphParallelCoordinate.tsx @@ -7,12 +7,12 @@ export const GraphParallelCoordinate: FC<{ trials: Trial[] }> = ({ trials = [] }) => { useEffect(() => { - plotCoordinate(trials) + plotCoordinate(trials, 0) // TODO(c-bata): Support multi-objective studies. }, [trials]) return
} -const plotCoordinate = (trials: Trial[]) => { +const plotCoordinate = (trials: Trial[], objectiveId: number) => { if (document.getElementById(plotDomId) === null) { return } @@ -47,7 +47,9 @@ const plotCoordinate = (trials: Trial[]) => { return } - const objectiveValues: number[] = filteredTrials.map((t) => t.value!) + const objectiveValues: number[] = filteredTrials.map( + (t) => t.values![objectiveId] + ) let dimensions = [ { label: "Objective value", diff --git a/optuna_dashboard/static/components/StudyDetail.tsx b/optuna_dashboard/static/components/StudyDetail.tsx index 2ec18205..0d53c169 100644 --- a/optuna_dashboard/static/components/StudyDetail.tsx +++ b/optuna_dashboard/static/components/StudyDetail.tsx @@ -42,6 +42,10 @@ interface ParamTypes { studyId: string } +const isSingleObjectiveStudy = (studyDetail: StudyDetail): boolean => { + return studyDetail.directions.length === 1 +} + export const useStudyDetail = ( action: Action, studyId: number @@ -93,27 +97,31 @@ export const StudyDetail: FC<{}> = () => { {title} - - - - - - - + {studyDetail !== null && isSingleObjectiveStudy(studyDetail) ? ( +
- + - - - - - - - - - + + + + + + + + + + + + + + + + +
+ ) : null} @@ -134,7 +142,12 @@ const TrialTable: FC<{ trials: Trial[] }> = ({ trials = [] }) => { padding: "none", toCellValue: (i) => trials[i].state.toString(), }, - { field: "value", label: "Value", sortable: true }, + { + field: "values", + label: "Value", + sortable: true, + toCellValue: (i) => trials[i].values?.join() || null, + }, { field: "params", label: "Params", diff --git a/optuna_dashboard/static/components/StudyList.tsx b/optuna_dashboard/static/components/StudyList.tsx index 1bc76149..1c2497dc 100644 --- a/optuna_dashboard/static/components/StudyList.tsx +++ b/optuna_dashboard/static/components/StudyList.tsx @@ -76,16 +76,21 @@ export const StudyList: FC<{}> = () => { ), }, { - field: "direction", + field: "directions", label: "Direction", sortable: false, - toCellValue: (i) => studies[i].direction.toString(), + toCellValue: (i) => studies[i].directions.join(), }, { field: "best_trial", label: "Best value", sortable: false, - toCellValue: (i) => studies[i].best_trial?.value || null, + toCellValue: (i) => { + if (studies[i].directions.length !== 1) { + return "-" // Multi-objective study does not hold best_trial attribute. + } + return studies[i].best_trial?.values?.[0] || null + }, }, { field: "study_name", diff --git a/optuna_dashboard/static/types/index.d.ts b/optuna_dashboard/static/types/index.d.ts index 84bf55e0..a534a02f 100644 --- a/optuna_dashboard/static/types/index.d.ts +++ b/optuna_dashboard/static/types/index.d.ts @@ -30,7 +30,7 @@ declare interface Trial { study_id: number number: number state: TrialState - value?: number + values?: number[] intermediate_values: TrialIntermediateValue[] datetime_start: Date datetime_complete?: Date @@ -42,7 +42,7 @@ declare interface Trial { declare interface StudySummary { study_id: number study_name: string - direction: StudyDirection + directions: StudyDirection[] best_trial?: Trial user_attrs: Attribute[] system_attrs: Attribute[] @@ -51,7 +51,7 @@ declare interface StudySummary { declare interface StudyDetail { name: string - direction: StudyDirection + directions: StudyDirection[] datetime_start: Date best_trial?: Trial trials: Trial[]