Bug fix: after clicking compare button, the dropdown button (for selecting different keys) is not shown (#4990)

This commit is contained in:
Lijiaoa 2022-08-04 15:27:16 +08:00 коммит произвёл GitHub
Родитель 60e1e01f62
Коммит 33cdb5b60c
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
16 изменённых файлов: 333 добавлений и 465 удалений

Просмотреть файл

@ -26,7 +26,7 @@ const OpenRow = (props): any => {
const trialId = props.trialId;
const trial = TRIALS.getTrial(trialId);
const logPathRow = trial.info.logPath || "This trial's log path is not available.";
const originParameters = trial.description.parameters;
const originParameters = trial.parameter;
const hasVisualHyperParams = RETIARIIPARAMETERS in originParameters;
const hideMessageInfo = (): void => {
@ -55,7 +55,7 @@ const OpenRow = (props): any => {
const copyParams = (trial: Trial): void => {
// get copy parameters
const params = JSON.stringify(reformatRetiariiParameter(trial.description.parameters as any), null, 4);
const params = JSON.stringify(reformatRetiariiParameter(trial.parameter as any), null, 4);
if (copy.default(params)) {
getCopyStatus('Successfully copy parameters to clipboard in form of python dict !', 'success');
} else {

Просмотреть файл

@ -48,6 +48,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
render(): React.ReactNode {
const { whichChart } = this.state;
const source = TRIALS.toArray();
const paraSource = TRIALS.succeededTrials();
const succeededTrialIds = TRIALS.succeededTrials().map(trial => trial.id);
return (
<AppContext.Consumer>
@ -74,12 +75,12 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
{/* <PivotItem tab={this.titleOfhyper} key="2"> */}
<PivotItem headerText='Hyper-parameter' itemIcon='Equalizer' key='Hyper-parameter'>
<Stack className='graph'>
<Para trials={source} searchSpace={EXPERIMENT.searchSpaceNew} />
<Para trials={paraSource} searchSpace={EXPERIMENT.searchSpaceNew} />
</Stack>
</PivotItem>
{/* <PivotItem tab={this.titleOfDuration} key="3"> */}
<PivotItem headerText='Duration' itemIcon='BarChartHorizontal' key='Duration'>
<Duration source={source} />
<Duration source={TRIALS.notWaittingTrials()} />
</PivotItem>
{/* <PivotItem tab={this.titleOfIntermediate} key="4"> */}
<PivotItem
@ -88,7 +89,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
key='Intermediate result'
>
{/* *why this graph has small footprint? */}
<Intermediate source={source} />
<Intermediate source={TRIALS.allTrialsIntermediateChart()} />
</PivotItem>
</Pivot>
</div>

Просмотреть файл

@ -138,16 +138,17 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
trial.sequenceId,
trial.acc === undefined ? 0 : this.formatAccuracy(trial.acc[userSelectAccuracyNumberKey]),
trial.id,
trial.description.parameters
trial.parameter
]);
} else {
data = trials.map(trial => [
trial.sequenceId,
this.formatAccuracy(trial.accuracy),
trial.id,
trial.description.parameters
trial.parameter
]);
}
return {
symbolSize: 6,
type: 'scatter',
@ -163,7 +164,7 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
best.sequenceId,
best.acc === undefined ? 0 : this.formatAccuracy(best.acc[userSelectAccuracyNumberKey]),
best.id,
best.description.parameters
best.parameter
]
];
for (let i = 1; i < trials.length; i++) {
@ -176,7 +177,7 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
trial.sequenceId,
trial.acc === undefined ? 0 : this.formatAccuracy(trial.acc[userSelectAccuracyNumberKey]),
best.id,
trial.description.parameters
trial.parameter
]);
best = trial;
} else {
@ -184,7 +185,7 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
trial.sequenceId,
best.acc === undefined ? 0 : this.formatAccuracy(best.acc[userSelectAccuracyNumberKey]),
best.id,
trial.description.parameters
trial.parameter
]);
}
}

Просмотреть файл

@ -1,18 +1,19 @@
import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
import { TableObj, EventMap } from '@static/interface';
import { filterDuration, convertDuration } from '@static/function';
import { EventMap } from '@static/interface';
import { Trial } from '@model/trial';
import { convertDuration } from '@static/function';
import 'echarts/lib/chart/bar';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';
interface Runtrial {
trialId: string[];
trialId: number[];
trialTime: number[];
}
interface DurationProps {
source: Array<TableObj>;
source: Trial[];
}
interface DurationState {
@ -31,12 +32,10 @@ class Duration extends React.Component<DurationProps, DurationState> {
};
}
initDuration = (source: Array<TableObj>): any => {
initDuration = (source: Trial[]): any => {
const trialId: number[] = [];
const trialTime: number[] = [];
const trialJobs = source.filter(filterDuration);
trialJobs.forEach(item => {
source.forEach(item => {
trialId.push(item.sequenceId);
trialTime.push(item.duration);
});
@ -146,17 +145,16 @@ class Duration extends React.Component<DurationProps, DurationState> {
};
};
drawDurationGraph = (source: Array<TableObj>): void => {
drawDurationGraph = (source: Trial[]): void => {
// why this function run two times when props changed?
const trialId: string[] = [];
const trialId: number[] = [];
const trialTime: number[] = [];
const trialRun: Runtrial[] = [];
const trialJobs = source.filter(filterDuration);
Object.keys(trialJobs).map(item => {
const temp = trialJobs[item];
trialId.push(temp.sequenceId);
trialTime.push(temp.duration);
source.forEach(item => {
trialId.push(item.sequenceId);
trialTime.push(item.duration);
});
trialRun.push({
trialId: trialId,
trialTime: trialTime

Просмотреть файл

@ -1,6 +1,6 @@
import * as React from 'react';
import { Stack, PrimaryButton, Toggle, IStackTokens } from '@fluentui/react';
import { TooltipForIntermediate, TableObj, Intermedia, EventMap } from '@static/interface';
import { TooltipForIntermediate, EventMap, allTrialsIntermediateChart } from '@static/interface';
import { reformatRetiariiParameter } from '@static/function';
import ReactEcharts from 'echarts-for-react';
import 'echarts/lib/component/tooltip';
@ -11,20 +11,19 @@ const stackTokens: IStackTokens = {
};
interface IntermediateState {
detailSource: Array<TableObj>;
detailSource: allTrialsIntermediateChart[];
interSource: object;
filterSource: Array<TableObj>;
filterSource: allTrialsIntermediateChart[];
eachIntermediateNum: number; // trial's intermediate number count
isLoadconfirmBtn: boolean;
isFilter?: boolean | undefined;
length: number;
clickCounts: number; // user filter intermediate click confirm btn's counts
startMediaY: number;
endMediaY: number;
}
interface IntermediateProps {
source: Array<TableObj>;
source: allTrialsIntermediateChart[];
}
class Intermediate extends React.Component<IntermediateProps, IntermediateState> {
@ -43,43 +42,24 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
isLoadconfirmBtn: false,
isFilter: false,
length: 100000,
clickCounts: 0,
startMediaY: 0,
endMediaY: 100
};
}
drawIntermediate = (source: Array<TableObj>): void => {
drawIntermediate = (source: allTrialsIntermediateChart[]): void => {
if (source.length > 0) {
this.setState({
length: source.length,
detailSource: source
});
const { startMediaY, endMediaY } = this.state;
const trialIntermediate: Array<Intermedia> = [];
Object.keys(source).map(item => {
const temp = source[item];
trialIntermediate.push({
name: temp.id,
trialNum: temp.sequenceId,
data: temp.description.intermediate,
type: 'line',
hyperPara: temp.description.parameters
});
});
// find max intermediate number
trialIntermediate.sort((a, b) => {
const xAxis: number[] = [];
// find having most intermediate number
source.sort((a, b) => {
return b.data.length - a.data.length;
});
const legend: string[] = [];
// max length
const length = trialIntermediate[0].data.length;
const xAxis: number[] = [];
Object.keys(trialIntermediate).map(item => {
const temp = trialIntermediate[item];
legend.push(temp.name);
});
for (let i = 1; i <= length; i++) {
for (let i = 1; i <= source[0].data.length; i++) {
xAxis.push(i);
}
const option = {
@ -89,20 +69,21 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
confine: true,
formatter: function (data: TooltipForIntermediate): React.ReactNode {
const trialId = data.seriesName;
let parameters = {};
let trialNum = 0;
const temp = trialIntermediate.find(key => key.name === trialId);
if (temp !== undefined) {
parameters = temp.hyperPara;
trialNum = temp.trialNum;
// parameter and trialNo need to have the init value otherwise maybe cause page broke down
let parameter = {};
let trialNo = 0;
const renderTrial = source.find(key => key.name === trialId);
if (renderTrial !== undefined) {
parameter = renderTrial.parameter;
trialNo = renderTrial.sequenceId;
}
return `
<div class="tooldetailAccuracy">
<div>Trial No.: ${trialNum}</div>
<div>Trial No.: ${trialNo}</div>
<div>Trial ID: ${trialId}</div>
<div>Intermediate: ${data.data}</div>
<div>Parameters: <pre>${JSON.stringify(
reformatRetiariiParameter(parameters),
reformatRetiariiParameter(parameter),
null,
4
)}</pre>
@ -137,7 +118,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
end: endMediaY
}
],
series: trialIntermediate
series: source
};
this.setState({
interSource: option
@ -164,7 +145,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
// confirm btn function [filter data]
filterLines = (): void => {
const filterSource: Array<TableObj> = [];
const filterSource: allTrialsIntermediateChart[] = [];
this.setState({ isLoadconfirmBtn: true }, () => {
const { source } = this.props;
// get input value
@ -175,32 +156,29 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
if (pointVal === '' || minVal === '') {
alert('Please input filter message');
} else {
// user not input max value
const position = JSON.parse(pointVal);
const min = JSON.parse(minVal);
if (maxVal === '') {
Object.keys(source).map(item => {
const temp = source[item];
const val = temp.description.intermediate[position - 1];
// user not input max value
for (const item of source) {
const val = item.data[position - 1];
if (val >= min) {
filterSource.push(temp);
filterSource.push(item);
}
});
}
} else {
const max = JSON.parse(maxVal);
Object.keys(source).map(item => {
const temp = source[item];
const val = temp.description.intermediate[position - 1];
for (const item of source) {
const val = item.data[position - 1];
if (val >= min && val <= max) {
filterSource.push(temp);
filterSource.push(item);
}
});
}
}
this.setState({ filterSource: filterSource });
this.drawIntermediate(filterSource);
}
const counts = this.state.clickCounts + 1;
this.setState({ isLoadconfirmBtn: false, clickCounts: counts });
this.setState({ isLoadconfirmBtn: false });
});
};

Просмотреть файл

@ -3,9 +3,9 @@ import * as d3 from 'd3';
import { Dropdown, IDropdownOption, Stack, DefaultButton } from '@fluentui/react';
import ParCoords from 'parcoord-es';
import { SearchSpace } from '@model/searchspace';
import { filterByStatus } from '@static/function';
import { EXPERIMENT, TRIALS } from '@static/datamodel';
import { TableObj, SingleAxis, MultipleAxes } from '@static/interface';
import { SingleAxis, MultipleAxes } from '@static/interface';
import { Trial } from '@model/trial';
import ChangeColumnComponent from '../ChangeColumnComponent';
import { optimizeModeValue } from './optimizeMode';
@ -25,7 +25,7 @@ interface ParaState {
}
interface ParaProps {
trials: Array<TableObj>;
trials: Trial[];
searchSpace: SearchSpace;
}
@ -304,9 +304,8 @@ class Para extends React.Component<ParaProps, ParaState> {
private getTrialsAsObjectList(inferredSearchSpace: MultipleAxes, inferredMetricSpace: MultipleAxes): {}[] {
const { trials } = this.props;
const succeededTrials = trials.filter(filterByStatus);
return succeededTrials.map(s => {
return trials.map(s => {
const entries = Array.from(s.parameters(inferredSearchSpace).entries());
entries.push(...Array.from(s.metrics(inferredMetricSpace).entries()));
const ret = {};

Просмотреть файл

@ -13,22 +13,15 @@ import {
import { Trial } from '@model/trial';
import { TOOLTIP_BACKGROUND_COLOR } from '@static/const';
import { EXPERIMENT, TRIALS } from '@static/datamodel';
import {
convertDuration,
formatTimestamp,
copyAndSort,
parametersType,
_inferColumnTitle,
getIntermediateAllKeys
} from '@static/function';
import { TableObj, SortInfo, SearchItems } from '@static/interface';
import { convertDuration, formatTimestamp, copyAndSort, parametersType, _inferColumnTitle } from '@static/function';
import { SortInfo, SearchItems } from '@static/interface';
import { blocked, copy, LineChart, tableListIcon } from '@components/fluent/Icon';
import Customize from './tableFunction/CustomizedTrial';
import TensorboardUI from './tableFunction/tensorboard/TensorboardUI';
import Search from './tableFunction/search/Search';
import ExpandableDetails from '@components/common/ExpandableDetails/ExpandableIndex';
import ChangeColumnComponent from '../ChangeColumnComponent';
import Compare from './tableFunction/Compare';
import Compare from './tableFunction/CompareIndex';
import KillJobIndex from './tableFunction/killJob/KillJobIndex';
import { getTrialsBySearchFilters } from './tableFunction/search/searchFunction';
import PaginationTable from '@components/common/PaginationTable';
@ -43,7 +36,7 @@ type SearchOptionType = 'id' | 'trialnum' | 'status' | 'parameters';
const defaultDisplayedColumns = ['sequenceId', 'id', 'duration', 'status', 'latestAccuracy'];
interface TableListProps {
tableSource: TableObj[];
tableSource: Trial[];
}
interface TableListState {
@ -55,12 +48,11 @@ interface TableListState {
selectedRowIds: string[];
customizeColumnsDialogVisible: boolean;
compareDialogVisible: boolean;
intermediateDialogTrial: TableObj | undefined;
intermediateDialogTrial: Trial[] | undefined;
copiedTrialId: string | undefined;
sortInfo: SortInfo;
searchItems: Array<SearchItems>;
relation: Map<string, string>;
intermediateKeyList: string[];
}
class TableList extends React.Component<TableListProps, TableListState> {
@ -86,8 +78,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
copiedTrialId: undefined,
sortInfo: { field: '', isDescend: true },
searchItems: [],
relation: parametersType(),
intermediateKeyList: []
relation: parametersType()
};
this._expandedTrialIds = new Set<string>();
@ -113,8 +104,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
selectedRowIds,
intermediateDialogTrial,
copiedTrialId,
searchItems,
intermediateKeyList
searchItems
} = this.state;
return (
@ -145,10 +135,23 @@ class TableList extends React.Component<TableListProps, TableListState> {
text='Compare'
className='allList-compare'
onClick={(): void => {
this.setState({ compareDialogVisible: true });
this.setState({
compareDialogVisible: true
});
}}
disabled={selectedRowIds.length === 0}
/>
{/* compare model: trial intermediates graph; table: id,no,status,default dict value */}
{compareDialogVisible && (
<Compare
title='Compare trials'
trials={this.props.tableSource.filter(trial => selectedRowIds.includes(trial.id))}
onHideDialog={(): void => {
this.setState({ compareDialogVisible: false });
}}
changeSelectTrialIds={this.changeSelectTrialIds}
/>
)}
<TensorboardUI
selectedRowIds={selectedRowIds}
changeSelectTrialIds={this.changeSelectTrialIds}
@ -172,23 +175,10 @@ class TableList extends React.Component<TableListProps, TableListState> {
}}
/>
)}
{compareDialogVisible && (
<Compare
title='Compare trials'
showDetails={true}
trials={this.props.tableSource.filter(trial => selectedRowIds.includes(trial.id))}
onHideDialog={(): void => {
this.setState({ compareDialogVisible: false });
}}
changeSelectTrialIds={this.changeSelectTrialIds}
/>
)}
{intermediateDialogTrial !== undefined && (
<Compare
title='Intermediate results'
showDetails={false}
trials={[intermediateDialogTrial]}
intermediateKeyList={intermediateKeyList}
trials={intermediateDialogTrial}
onHideDialog={(): void => {
this.setState({ intermediateDialogTrial: undefined });
}}
@ -236,32 +226,21 @@ class TableList extends React.Component<TableListProps, TableListState> {
);
}
private _trialsToTableItems(trials: TableObj[]): any[] {
private _trialsToTableItems(trials: Trial[]): any[] {
// TODO: use search space and metrics space from TRIALS will cause update issues.
const searchSpace = TRIALS.inferredSearchSpace(EXPERIMENT.searchSpaceNew);
const metricSpace = TRIALS.inferredMetricSpace();
const { selectedRowIds } = this.state;
const items = trials.map(trial => {
const ret = {
sequenceId: trial.sequenceId,
id: trial.id,
_checked: selectedRowIds.includes(trial.id) ? true : false,
startTime: (trial as Trial).info.startTime, // FIXME: why do we need info here?
endTime: (trial as Trial).info.endTime,
duration: trial.duration,
status: trial.status,
message: (trial as Trial).info.message || '--',
intermediateCount: trial.intermediates.length,
_expandDetails: this._expandedTrialIds.has(trial.id) // hidden field names should start with `_`
};
const ret = trial.tableRecord;
ret['_checked'] = selectedRowIds.includes(trial.id) ? true : false;
ret['_expandDetails'] = this._expandedTrialIds.has(trial.id); // hidden field names should start with `_`
for (const [k, v] of trial.parameters(searchSpace)) {
ret[`space/${k.baseName}`] = v;
}
for (const [k, v] of trial.metrics(metricSpace)) {
ret[`metric/${k.baseName}`] = v;
}
ret['latestAccuracy'] = (trial as Trial).latestAccuracy;
ret['_formattedLatestAccuracy'] = (trial as Trial).formatLatestAccuracy();
return ret;
});
@ -397,9 +376,6 @@ class TableList extends React.Component<TableListProps, TableListState> {
...(k === 'status' && {
// color status
onRender: (record): React.ReactNode => (
// kill 成功之后,重新拉取的数据如果有 endtime 字段会马上render出user_cancel
// 的状态反之没有这个字段table依然是部分刷新只刷新duration不会
// 刷新 status
<span className={`${record.status} commonStyle`}>{record.status}</span>
)
}),
@ -461,7 +437,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
}
}}
>
<div className='ellipsis'>{record._formattedLatestAccuracy}</div>
<div className='ellipsis'>{record.formattedLatestAccuracy}</div>
</TooltipHost>
)
}),
@ -545,11 +521,9 @@ class TableList extends React.Component<TableListProps, TableListState> {
title='Intermediate'
onClick={(): void => {
const { tableSource } = this.props;
const trial = tableSource.find(trial => trial.id === record.id) as TableObj;
const intermediateKeyListResult = getIntermediateAllKeys(trial);
const trial = tableSource.find(trial => trial.id === record.id) as Trial;
this.setState({
intermediateDialogTrial: trial,
intermediateKeyList: intermediateKeyListResult
intermediateDialogTrial: [trial]
});
}}
>

Просмотреть файл

@ -1,11 +1,12 @@
import * as React from 'react';
import React, { useState, useEffect } from 'react';
import { renderToString } from 'react-dom/server';
import { Stack, Modal, IconButton, IDragOptions, ContextualMenu, Dropdown, IDropdownOption } from '@fluentui/react';
import ReactEcharts from 'echarts-for-react';
import { TooltipForIntermediate, TableObj, SingleAxis } from '@static/interface';
import { contentStyles, iconButtonStyles } from '@components/fluent/ModalTheme';
import { convertDuration, parseMetrics } from '@static/function';
import { EXPERIMENT, TRIALS } from '@static/datamodel';
import { Trial } from '@model/trial';
import { TooltipForIntermediate, SingleAxis } from '@static/interface';
import { contentStyles, iconButtonStyles } from '@components/fluent/ModalTheme';
import { convertDuration, parseMetrics, getIntermediateAllKeys } from '@static/function';
import '@style/experiment/trialdetail/compare.scss';
/***
@ -26,7 +27,7 @@ const dragOptions: IDragOptions = {
// TODO: this should be refactored to the common modules
// copied from trial.ts
function _parseIntermediates(trial: TableObj, key: string): number[] {
function _parseIntermediates(trial: Trial, key: string): number[] {
const intermediates: number[] = [];
for (const metric of trial.intermediates) {
if (metric === undefined) {
@ -53,30 +54,46 @@ interface Item {
}
interface CompareProps {
trials: TableObj[];
trials: Trial[];
title: string;
showDetails: boolean;
intermediateKeyList?: string[];
onHideDialog: () => void;
changeSelectTrialIds?: () => void;
}
interface CompareState {
intermediateKey: string; // default, dict other keys
}
function CompareIndex(props: CompareProps): any {
const { trials, title } = props;
const atrial = trials.find(item => item.intermediates.length > 0);
const intermediateAllKeysList = getIntermediateAllKeys(atrial === undefined ? trials[0] : atrial);
const [intermediateKey, setIntermediateKey] = useState(
intermediateAllKeysList.length > 0 ? intermediateAllKeysList[0] : 'default'
);
const runningTrial = trials.find(item => item.status === 'RUNNING');
const runningTrialIntermediateListLength = runningTrial !== undefined ? runningTrial.intermediates.length : -1;
class Compare extends React.Component<CompareProps, CompareState> {
constructor(props: CompareProps) {
super(props);
this.state = {
// intermediate result maybe don't have the 'default' key...
intermediateKey:
this.props.intermediateKeyList !== undefined ? this.props.intermediateKeyList[0] : 'default'
function itemsList(): Item[] {
const inferredSearchSpace = TRIALS.inferredSearchSpace(EXPERIMENT.searchSpaceNew);
const flatten = (m: Map<SingleAxis, any>): Map<string, any> => {
return new Map(Array.from(m).map(([key, value]) => [key.baseName, value]));
};
return trials.map(trial => ({
id: trial.id,
sequenceId: trial.sequenceId,
duration: convertDuration(trial.duration),
parameters: flatten(trial.parameters(inferredSearchSpace)),
metrics: flatten(trial.metrics(TRIALS.inferredMetricSpace())),
intermediates: _parseIntermediates(trial, intermediateKey)
}));
}
private _generateTooltipSummary = (row: Item, value: string): string =>
const [items, setItems] = useState(itemsList());
// react componentDidMount & componentDidUpdate
useEffect(() => {
setItems(itemsList());
}, [intermediateKey, runningTrialIntermediateListLength]); // update condition
// page related function
const _generateTooltipSummary = (row: Item, value: string): string =>
renderToString(
<div className='tooldetailAccuracy'>
<div>Trial No.: {row.sequenceId}</div>
@ -85,7 +102,7 @@ class Compare extends React.Component<CompareProps, CompareState> {
</div>
);
private _intermediates(items: Item[]): React.ReactNode {
function _intermediates(items: Item[]): React.ReactNode {
// Precondition: make sure `items` is not empty
const xAxisMax = Math.max(...items.map(item => item.intermediates.length));
const xAxis = Array(xAxisMax)
@ -104,7 +121,7 @@ class Compare extends React.Component<CompareProps, CompareState> {
confine: true,
formatter: (data: TooltipForIntermediate): string => {
const item = items.find(k => k.id === data.seriesName) as Item;
return this._generateTooltipSummary(item, data.data);
return _generateTooltipSummary(item, data.data);
}
},
grid: {
@ -141,7 +158,7 @@ class Compare extends React.Component<CompareProps, CompareState> {
);
}
private _renderRow(
function _renderRow(
key: string,
rowName: string,
className: string,
@ -160,7 +177,7 @@ class Compare extends React.Component<CompareProps, CompareState> {
);
}
private _overlapKeys(s: Map<string, any>[]): string[] {
function _overlapKeys(s: Map<string, any>[]): string[] {
// Calculate the overlapped keys for multiple
const intersection: string[] = [];
for (const i of s[0].keys()) {
@ -179,7 +196,7 @@ class Compare extends React.Component<CompareProps, CompareState> {
}
// render table column ---
private _columns(items: Item[]): React.ReactNode {
function _columns(items: Item[]): React.ReactNode {
// Precondition: make sure `items` is not empty
const width = _getWebUIWidth();
let scrollClass: string = '';
@ -190,23 +207,21 @@ class Compare extends React.Component<CompareProps, CompareState> {
} else {
scrollClass = items.length > 2 ? 'flex' : '';
}
const parameterKeys = this._overlapKeys(items.map(item => item.parameters));
const metricKeys = this._overlapKeys(items.map(item => item.metrics));
const parameterKeys = _overlapKeys(items.map(item => item.parameters));
const metricKeys = _overlapKeys(items.map(item => item.metrics));
return (
<table className={`compare-modal-table ${scrollClass} fontColor333`}>
<tbody>
{this._renderRow('id', 'ID', 'value idList', items, item => item.id)}
{this._renderRow('trialnum', 'Trial No.', 'value', items, item => item.sequenceId.toString())}
{this._renderRow('duration', 'Duration', 'value', items, item => item.duration)}
{_renderRow('id', 'ID', 'value idList', items, item => item.id)}
{_renderRow('trialnum', 'Trial No.', 'value', items, item => item.sequenceId.toString())}
{_renderRow('duration', 'Duration', 'value', items, item => item.duration)}
{parameterKeys.map(k =>
this._renderRow(`space_${k}`, k, 'value', items, item => item.parameters.get(k))
_renderRow(`space_${k}`, k, 'value', items, item => item.parameters.get(k))
)}
{metricKeys !== undefined
? metricKeys.map(k =>
this._renderRow(`metrics_${k}`, `Metric: ${k}`, 'value', items, item =>
item.metrics.get(k)
)
_renderRow(`metrics_${k}`, `Metric: ${k}`, 'value', items, item => item.metrics.get(k))
)
: null}
</tbody>
@ -214,80 +229,62 @@ class Compare extends React.Component<CompareProps, CompareState> {
);
}
private closeCompareModal = (): void => {
const { showDetails, changeSelectTrialIds, onHideDialog } = this.props;
if (showDetails === true) {
const closeCompareModal = (): void => {
const { title, changeSelectTrialIds, onHideDialog } = props;
if (title === 'Compare trials') {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
changeSelectTrialIds!();
}
onHideDialog();
};
private selectOtherKeys = (_event: React.FormEvent<HTMLDivElement>, item?: IDropdownOption): void => {
const selectOtherKeys = (_event: React.FormEvent<HTMLDivElement>, item?: IDropdownOption): void => {
if (item !== undefined) {
this.setState(() => ({ intermediateKey: item.text }));
setIntermediateKey(item.text);
}
};
render(): React.ReactNode {
const { trials, title, showDetails, intermediateKeyList } = this.props;
const { intermediateKey } = this.state;
const intermediateAllKeysList: string[] = intermediateKeyList !== undefined ? intermediateKeyList : [];
const flatten = (m: Map<SingleAxis, any>): Map<string, any> => {
return new Map(Array.from(m).map(([key, value]) => [key.baseName, value]));
};
const inferredSearchSpace = TRIALS.inferredSearchSpace(EXPERIMENT.searchSpaceNew);
const items: Item[] = trials.map(trial => ({
id: trial.id,
sequenceId: trial.sequenceId,
duration: convertDuration(trial.duration),
parameters: flatten(trial.parameters(inferredSearchSpace)),
metrics: flatten(trial.metrics(TRIALS.inferredMetricSpace())),
intermediates: _parseIntermediates(trial, intermediateKey)
}));
return (
<Modal
isOpen={true}
containerClassName={contentStyles.container}
className='compare-modal'
allowTouchBodyScroll={true}
dragOptions={dragOptions}
onDismiss={this.closeCompareModal}
>
<div>
<div className={contentStyles.header}>
<span>{title}</span>
<IconButton
styles={iconButtonStyles}
iconProps={{ iconName: 'Cancel' }}
ariaLabel='Close popup modal'
onClick={this.closeCompareModal}
/>
</div>
{intermediateAllKeysList.length > 1 ||
(intermediateAllKeysList.length === 1 && intermediateAllKeysList !== ['default']) ? (
<Stack horizontalAlign='end' className='selectKeys'>
<Dropdown
className='select'
selectedKey={intermediateKey}
options={intermediateAllKeysList.map((key, item) => ({
key: key,
text: intermediateAllKeysList[item]
}))}
onChange={this.selectOtherKeys}
/>
</Stack>
) : null}
<Stack className='compare-modal-intermediate'>
{this._intermediates(items)}
<Stack className='compare-yAxis fontColor333'># Intermediate result</Stack>
</Stack>
{showDetails && <Stack>{this._columns(items)}</Stack>}
return (
<Modal
isOpen={true}
containerClassName={contentStyles.container}
className='compare-modal'
allowTouchBodyScroll={true}
dragOptions={dragOptions}
onDismiss={closeCompareModal}
>
<div>
<div className={contentStyles.header}>
<span>{title}</span>
<IconButton
styles={iconButtonStyles}
iconProps={{ iconName: 'Cancel' }}
ariaLabel='Close popup modal'
onClick={closeCompareModal}
/>
</div>
</Modal>
);
}
{intermediateAllKeysList.length > 1 ||
(intermediateAllKeysList.length === 1 && intermediateAllKeysList !== ['default']) ? (
<Stack horizontalAlign='end' className='selectKeys'>
<Dropdown
className='select'
selectedKey={intermediateKey}
options={intermediateAllKeysList.map((key, item) => ({
key: key,
text: intermediateAllKeysList[item]
}))}
onChange={selectOtherKeys}
/>
</Stack>
) : null}
<Stack className='compare-modal-intermediate'>
{_intermediates(items)}
<Stack className='compare-yAxis fontColor333'># Intermediate result</Stack>
</Stack>
{title === 'Compare trials' && <Stack>{_columns(items)}</Stack>}
</div>
</Modal>
);
}
export default Compare;
export default CompareIndex;

Просмотреть файл

@ -154,7 +154,7 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
componentDidMount(): void {
const { copyTrialId } = this.props;
if (copyTrialId !== undefined && TRIALS.getTrial(copyTrialId) !== undefined) {
const originCopyTrialPara = TRIALS.getTrial(copyTrialId).description.parameters;
const originCopyTrialPara = TRIALS.getTrial(copyTrialId).parameter;
this.setState(() => ({ copyTrialParameter: originCopyTrialPara }));
}
}
@ -163,7 +163,7 @@ class Customize extends React.Component<CustomizeProps, CustomizeState> {
if (this.props.copyTrialId !== prevProps.copyTrialId) {
const { copyTrialId } = this.props;
if (copyTrialId !== undefined && TRIALS.getTrial(copyTrialId) !== undefined) {
const originCopyTrialPara = TRIALS.getTrial(copyTrialId).description.parameters;
const originCopyTrialPara = TRIALS.getTrial(copyTrialId).parameter;
this.setState(() => ({ copyTrialParameter: originCopyTrialPara }));
}
}

Просмотреть файл

@ -14,7 +14,7 @@ const METRIC_GROUP_UPDATE_SIZE = 20;
const prefix = getPrefix();
const RESTAPI = '/api/v1/nni';
const MANAGER_IP = prefix === undefined ? RESTAPI : `${prefix}${RESTAPI}`;
const DOWNLOAD_IP = `${prefix}/logs`;
const DOWNLOAD_IP = prefix === undefined ? '/logs' : `${prefix}/logs`;
const WEBUIDOC = 'https://nni.readthedocs.io/en/latest/experiment/webui.html';

Просмотреть файл

@ -3,7 +3,7 @@ import axios from 'axios';
import { IContextualMenuProps } from '@fluentui/react';
import { RETIARIIPARAMETERS } from './const';
import { EXPERIMENT } from './datamodel';
import { MetricDataRecord, FinalType, TableObj, Tensorboard } from './interface';
import { MetricDataRecord, FinalType, Tensorboard } from './interface';
function getPrefix(): string | undefined {
const pathName = window.location.pathname;
@ -188,15 +188,6 @@ const intermediateGraphOption = (intermediateArr: number[], id: string): any =>
};
};
const filterByStatus = (item: TableObj): boolean => {
return item.status === 'SUCCEEDED';
};
// a waittiong trial may havn't start time
const filterDuration = (item: TableObj): boolean => {
return item.status !== 'WAITING';
};
const downFile = (content: string, fileName: string): void => {
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
@ -376,8 +367,8 @@ function _inferColumnTitle(columnKey: string): string {
const getIntermediateAllKeys = (intermediateDialogTrial: any): string[] => {
let intermediateAllKeysList: string[] = [];
if (intermediateDialogTrial!.intermediateMetrics !== undefined && intermediateDialogTrial!.intermediateMetrics[0]) {
const parsedMetric = parseMetrics(intermediateDialogTrial!.intermediateMetrics[0].data);
if (intermediateDialogTrial!.intermediates !== undefined && intermediateDialogTrial!.intermediates[0]) {
const parsedMetric = parseMetrics(intermediateDialogTrial!.intermediates[0].data);
if (parsedMetric !== undefined && typeof parsedMetric === 'object') {
const allIntermediateKeys: string[] = [];
// just add type=number keys
@ -407,8 +398,6 @@ export {
getFinal,
downFile,
intermediateGraphOption,
filterByStatus,
filterDuration,
formatAccuracy,
formatTimestamp,
expformatTimestamp,

Просмотреть файл

@ -26,23 +26,6 @@ interface MultipleAxes {
axes: Map<string, SingleAxis>;
}
// draw accuracy graph data export interface
interface TableObj {
key: number;
sequenceId: number;
id: string;
duration: number;
status: string;
acc?: FinalType; // draw accuracy graph
description: Parameters;
color?: string;
startTime?: number;
endTime?: number;
intermediates: (MetricDataRecord | undefined)[];
parameters(axes: MultipleAxes): Map<SingleAxis, any>;
metrics(axes: MultipleAxes): Map<SingleAxis, any>;
}
interface TableRecord {
key: string;
sequenceId: number;
@ -53,7 +36,6 @@ interface TableRecord {
status: string;
message: string;
intermediateCount: number;
accuracy?: number | any;
latestAccuracy: number | undefined;
formattedLatestAccuracy: string; // format (LATEST/FINAL),
}
@ -67,17 +49,6 @@ interface FinalType {
default: string;
}
interface ErrorParameter {
error?: string;
}
interface Parameters {
parameters: ErrorParameter;
logPath?: string;
intermediate: number[];
multiProgress?: number;
}
// trial accuracy
interface AccurPoint {
acc: number;
@ -120,14 +91,6 @@ interface ParaObj {
parallelAxis: Array<Dimobj>;
}
interface Intermedia {
name: string; // id
type: string;
data: Array<number | object>; // intermediate data
hyperPara: object; // each trial hyperpara value
trialNum: number;
}
interface MetricDataRecord {
timestamp: number;
trialJobId: string;
@ -223,20 +186,25 @@ interface SearchItems {
isChoice: boolean; // for parameters: type = choice and status also as choice type
}
interface allTrialsIntermediateChart {
name: string;
// id: string;
sequenceId: number;
data: number[];
parameter: object;
type: string;
}
export {
TableObj,
TableRecord,
SearchSpace,
FinalType,
ErrorParameter,
Parameters,
AccurPoint,
DetailAccurPoint,
TooltipForIntermediate,
TooltipForAccuracy,
Dimobj,
ParaObj,
Intermedia,
MetricDataRecord,
TrialJobInfo,
ExperimentProfile,
@ -248,5 +216,6 @@ export {
SortInfo,
AllExperimentList,
Tensorboard,
SearchItems
SearchItems,
allTrialsIntermediateChart
};

Просмотреть файл

@ -51,7 +51,6 @@ class Experiment {
private profileField?: ExperimentProfile;
private metadataField?: ExperimentMetadata = undefined;
private statusField?: NNIManagerStatus = undefined;
private isNestedExperiment: boolean = false;
private isexperimentError: boolean = false;
private experimentErrorMessage: string = '';
private isStatusError: boolean = false;

Просмотреть файл

@ -1,4 +1,5 @@
import { SingleAxis, MultipleAxes, TableObj } from '../interface';
import { SingleAxis, MultipleAxes } from '../interface';
import { Trial } from './trial';
import { SUPPORTED_SEARCH_SPACE_TYPE } from '../const';
import { formatComplexTypeValue } from '../function';
@ -111,7 +112,7 @@ export class SearchSpace implements MultipleAxes {
});
}
static inferFromTrials(searchSpace: SearchSpace, trials: TableObj[]): SearchSpace {
static inferFromTrials(searchSpace: SearchSpace, trials: Trial[]): SearchSpace {
const newSearchSpace = new SearchSpace(searchSpace.baseName, searchSpace.fullName, undefined);
for (const [k, v] of searchSpace.axes) {
newSearchSpace.axes.set(k, v);
@ -153,7 +154,7 @@ export class MetricSpace implements MultipleAxes {
baseName = '';
fullName = '';
constructor(trials: TableObj[]) {
constructor(trials: Trial[]) {
const columns = new Map<string, any[]>();
for (const trial of trials) {
if (trial.acc === undefined) {

Просмотреть файл

@ -1,14 +1,4 @@
import * as JSON5 from 'json5';
import {
MetricDataRecord,
TrialJobInfo,
TableObj,
TableRecord,
Parameters,
FinalType,
MultipleAxes,
SingleAxis
} from '../interface';
import { MetricDataRecord, TrialJobInfo, TableRecord, FinalType, MultipleAxes, SingleAxis } from '../interface';
import {
getFinal,
formatAccuracy,
@ -59,12 +49,11 @@ function inferTrialParameters(
return [parameters, unexpectedEntries];
}
class Trial implements TableObj {
class Trial {
private metricsInitialized: boolean = false;
private infoField: TrialJobInfo | undefined;
public accuracy: number | undefined; // trial default metric val: number value or undefined
public intermediates: (MetricDataRecord | undefined)[] = [];
public final: MetricDataRecord | undefined;
private finalAcc: number | undefined;
constructor(info?: TrialJobInfo, metrics?: MetricDataRecord[]) {
this.infoField = info;
@ -78,7 +67,7 @@ class Trial implements TableObj {
return undefined;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return this.finalAcc! - otherTrial.finalAcc!;
return this.accuracy! - otherTrial.accuracy!;
}
get info(): TrialJobInfo {
@ -86,25 +75,58 @@ class Trial implements TableObj {
return this.infoField!;
}
get intermediateMetrics(): MetricDataRecord[] {
const ret: MetricDataRecord[] = [];
for (let i = 0; i < this.intermediates.length; i++) {
if (this.intermediates[i]) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
ret.push(this.intermediates[i]!);
} else {
break;
}
}
return ret;
get sequenceId(): number {
return this.info.sequenceId;
}
get accuracy(): number | undefined {
return this.finalAcc;
get id(): string {
return this.info.trialJobId;
}
get duration(): number {
const endTime = this.info.endTime || new Date().getTime();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return (endTime - this.info.startTime!) / 1000;
}
get status(): string {
return this.info.status;
}
get parameter(): object {
return JSON.parse(this.info.hyperParameters![0]).parameters;
}
// return dict final result: {default: xxx...}
get acc(): FinalType | undefined {
if (this.info === undefined) {
return undefined;
}
return getFinal(this.info.finalMetricData);
}
public parameters(axes: MultipleAxes): Map<SingleAxis, any> {
const ret = new Map<SingleAxis, any>(Array.from(axes.axes.values()).map(k => [k, null]));
if (this.info === undefined || this.info.hyperParameters === undefined) {
throw ret;
} else {
let params = JSON.parse(this.info.hyperParameters[0]).parameters;
if (typeof params === 'string') {
params = JSON.parse(params);
}
const [updated, unexpectedEntries] = inferTrialParameters(params, axes);
if (unexpectedEntries.size) {
throw unexpectedEntries;
}
for (const [k, v] of updated) {
ret.set(k, v);
}
return ret;
}
}
get sortable(): boolean {
return this.metricsInitialized && this.finalAcc !== undefined && isFinite(this.finalAcc);
return this.metricsInitialized && this.accuracy !== undefined && isFinite(this.accuracy);
}
get latestAccuracy(): number | undefined {
@ -131,66 +153,6 @@ class Trial implements TableObj {
return undefined;
}
}
/* table obj start */
get tableRecord(): TableRecord {
const endTime = this.info.endTime || new Date().getTime();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const duration = (endTime - this.info.startTime!) / 1000;
let accuracy;
if (this.acc !== undefined && this.acc.default !== undefined) {
if (typeof this.acc.default === 'number') {
accuracy = JSON5.parse(this.acc.default);
} else {
accuracy = this.acc.default;
}
}
return {
key: this.info.trialJobId,
sequenceId: this.info.sequenceId,
id: this.info.trialJobId,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
startTime: this.info.startTime!,
endTime: this.info.endTime,
duration,
status: this.info.status,
message: this.info.message || '--',
intermediateCount: this.intermediates.length,
accuracy: accuracy,
latestAccuracy: this.latestAccuracy,
formattedLatestAccuracy: this.formatLatestAccuracy()
};
}
get key(): number {
return this.info.sequenceId;
}
get sequenceId(): number {
return this.info.sequenceId;
}
get id(): string {
return this.info.trialJobId;
}
get duration(): number {
const endTime = this.info.endTime || new Date().getTime();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return (endTime - this.info.startTime!) / 1000;
}
get status(): string {
return this.info.status;
}
get acc(): FinalType | undefined {
if (this.info === undefined) {
return undefined;
}
return getFinal(this.info.finalMetricData);
}
get accuracyNumberTypeDictKeys(): string[] {
let accuracyTypeList: string[] = [];
@ -208,59 +170,27 @@ class Trial implements TableObj {
return accuracyTypeList;
}
get description(): Parameters {
const ret: Parameters = {
parameters: {},
intermediate: [],
multiProgress: 1
/* table obj start */
get tableRecord(): TableRecord {
const endTime = this.info.endTime || new Date().getTime();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const duration = (endTime - this.info.startTime!) / 1000;
return {
key: this.info.trialJobId,
sequenceId: this.info.sequenceId,
id: this.info.trialJobId,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
startTime: this.info.startTime!,
endTime: this.info.endTime,
duration,
status: this.info.status,
message: this.info.message ?? '--',
intermediateCount: this.intermediates.length,
latestAccuracy: this.latestAccuracy,
formattedLatestAccuracy: this.formatLatestAccuracy()
};
const tempHyper = this.info.hyperParameters;
if (tempHyper !== undefined) {
const getPara = JSON.parse(tempHyper[tempHyper.length - 1]).parameters;
ret.multiProgress = tempHyper.length;
if (typeof getPara === 'string') {
ret.parameters = JSON.parse(getPara);
} else {
ret.parameters = getPara;
}
} else {
ret.parameters = { error: "This trial's parameters are not available." };
}
if (this.info.logPath !== undefined) {
ret.logPath = this.info.logPath;
}
const mediate: number[] = [];
for (const items of this.intermediateMetrics) {
if (typeof parseMetrics(items.data) === 'object') {
mediate.push(parseMetrics(items.data).default);
} else {
mediate.push(parseMetrics(items.data));
}
}
ret.intermediate = mediate;
return ret;
}
public parameters(axes: MultipleAxes): Map<SingleAxis, any> {
const ret = new Map<SingleAxis, any>(Array.from(axes.axes.values()).map(k => [k, null]));
if (this.info === undefined || this.info.hyperParameters === undefined) {
throw ret;
} else {
const tempHyper = this.info.hyperParameters;
let params = JSON.parse(tempHyper[tempHyper.length - 1]).parameters;
if (typeof params === 'string') {
params = JSON.parse(params);
}
const [updated, unexpectedEntries] = inferTrialParameters(params, axes);
if (unexpectedEntries.size) {
throw unexpectedEntries;
}
for (const [k, v] of updated) {
ret.set(k, v);
}
return ret;
}
}
public metrics(space: MultipleAxes): Map<SingleAxis, any> {
@ -270,8 +200,7 @@ class Trial implements TableObj {
if (this.acc === undefined) {
return ret;
}
const acc = typeof this.acc === 'number' ? { default: this.acc } : this.acc;
Object.entries(acc).forEach(item => {
Object.entries(this.acc).forEach(item => {
const [k, v] = item;
const column = space.axes.get(k);
@ -287,14 +216,6 @@ class Trial implements TableObj {
return ret;
}
public finalKeys(): string[] {
if (this.acc !== undefined) {
return Object.keys(this.acc);
} else {
return [];
}
}
/* table obj end */
public initialized(): boolean {
@ -304,7 +225,7 @@ class Trial implements TableObj {
public updateMetrics(metrics: MetricDataRecord[]): boolean {
// parameter `metrics` must contain all known metrics of this trial
this.metricsInitialized = true;
const prevMetricCnt = this.intermediates.length + (this.final ? 1 : 0);
const prevMetricCnt = this.intermediates.length + (this.accuracy ? 1 : 0);
if (metrics.length <= prevMetricCnt) {
return false;
}
@ -312,8 +233,7 @@ class Trial implements TableObj {
if (metric.type === 'PERIODICAL') {
this.intermediates[metric.sequence] = metric;
} else {
this.final = metric;
this.finalAcc = metricAccuracy(metric);
this.accuracy = metricAccuracy(metric);
}
}
return true;
@ -328,9 +248,8 @@ class Trial implements TableObj {
updated = updated || !this.intermediates[metric.sequence];
this.intermediates[metric.sequence] = metric;
} else {
updated = updated || !this.final;
this.final = metric;
this.finalAcc = metricAccuracy(metric);
updated = updated || !this.accuracy;
this.accuracy = metricAccuracy(metric);
}
}
return updated;
@ -340,13 +259,20 @@ class Trial implements TableObj {
const same = this.infoField && this.infoField.status === trialJobInfo.status;
this.infoField = trialJobInfo;
if (trialJobInfo.finalMetricData) {
this.final = trialJobInfo.finalMetricData[trialJobInfo.finalMetricData.length - 1];
this.finalAcc = metricAccuracy(this.final);
this.accuracy = metricAccuracy(trialJobInfo.finalMetricData[0]);
}
return !same;
}
private renderNumber(val: any): string {
/**
*
* @param val trial latest accuracy
* @returns 0.9(FINAL) or 0.9(LATEST)
* NaN or Infinity
* string object such as: '{tensor: {data}}'
*
*/
private formatLatestAccuracyToString(val: any): string {
if (typeof val === 'number') {
if (isNaNorInfinity(val)) {
return `${val}`; // show 'NaN' or 'Infinity'
@ -363,19 +289,27 @@ class Trial implements TableObj {
}
}
public formatLatestAccuracy(): string {
// TODO: this should be private
/**
*
* @param val trial latest accuracy
* @returns 0.9(FINAL) or 0.9(LATEST)
* NaN or Infinity
* string object such as: '{tensor: {data}}'
* +1 describe type undefined: --
*
*/
private formatLatestAccuracy(): string {
if (this.status === 'SUCCEEDED') {
return this.accuracy === undefined ? '--' : this.renderNumber(this.accuracy);
return this.accuracy === undefined ? '--' : this.formatLatestAccuracyToString(this.accuracy);
} else {
if (this.accuracy !== undefined) {
return this.renderNumber(this.accuracy);
return this.formatLatestAccuracyToString(this.accuracy);
} else if (this.intermediates.length === 0) {
return '--';
} else {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const latest = this.intermediates[this.intermediates.length - 1]!;
return this.renderNumber(metricAccuracy(latest));
return this.formatLatestAccuracyToString(metricAccuracy(latest));
}
}
}

Просмотреть файл

@ -2,7 +2,8 @@ import { MANAGER_IP, METRIC_GROUP_UPDATE_THRESHOLD, METRIC_GROUP_UPDATE_SIZE } f
import { MetricDataRecord, TableRecord, TrialJobInfo, MultipleAxes } from '../interface';
import { Trial } from './trial';
import { SearchSpace, MetricSpace } from './searchspace';
import { requestAxios } from '../function';
import { requestAxios, parseMetrics } from '../function';
import { allTrialsIntermediateChart } from '../interface';
function groupMetricsByTrial(metrics: MetricDataRecord[]): Map<string, MetricDataRecord[]> {
const ret = new Map<string, MetricDataRecord[]>();
@ -86,10 +87,37 @@ class TrialManager {
return this.filter(trial => trial.status === 'SUCCEEDED');
}
public notWaittingTrials(): Trial[] {
return this.filter(trial => trial.status !== 'WAITING');
}
public allTrialsIntermediateChart(): allTrialsIntermediateChart[] {
const ret: allTrialsIntermediateChart[] = [];
for (const trial of this.trials.values()) {
const mediate: number[] = [];
for (const items of trial.intermediates) {
if (typeof parseMetrics(items!.data) === 'object') {
mediate.push(parseMetrics(items!.data).default);
} else {
mediate.push(parseMetrics(items!.data));
}
}
ret.push({
name: trial.id,
sequenceId: trial.sequenceId,
data: mediate,
parameter: trial.parameter,
type: 'line'
});
}
return ret;
}
public finalKeys(): string[] {
const succeedTrialsList = this.filter(trial => trial.status === 'SUCCEEDED');
if (succeedTrialsList !== undefined && succeedTrialsList[0] !== undefined) {
return succeedTrialsList[0].finalKeys();
return succeedTrialsList[0].acc !== undefined ? Object.keys(succeedTrialsList[0].acc) : [];
} else {
return ['default'];
}