Unverified Commit e1ae623f authored by SparkSnail's avatar SparkSnail Committed by GitHub
Browse files

Merge pull request #147 from Microsoft/master

merge master
parents f796c60b 63697ec5
...@@ -75,7 +75,7 @@ def _pack_parameter(parameter_id, params, customized=False, trial_job_id=None, p ...@@ -75,7 +75,7 @@ def _pack_parameter(parameter_id, params, customized=False, trial_job_id=None, p
class MultiPhaseMsgDispatcher(MsgDispatcherBase): class MultiPhaseMsgDispatcher(MsgDispatcherBase):
def __init__(self, tuner, assessor=None): def __init__(self, tuner, assessor=None):
super() super(MultiPhaseMsgDispatcher, self).__init__()
self.tuner = tuner self.tuner = tuner
self.assessor = assessor self.assessor = assessor
if assessor is None: if assessor is None:
......
...@@ -42,11 +42,10 @@ class CommandType(Enum): ...@@ -42,11 +42,10 @@ class CommandType(Enum):
NoMoreTrialJobs = b'NO' NoMoreTrialJobs = b'NO'
KillTrialJob = b'KI' KillTrialJob = b'KI'
_lock = threading.Lock()
try: try:
_in_file = open(3, 'rb') _in_file = open(3, 'rb')
_out_file = open(4, 'wb') _out_file = open(4, 'wb')
_lock = threading.Lock()
except OSError: except OSError:
_msg = 'IPC pipeline not exists, maybe you are importing tuner/assessor from trial code?' _msg = 'IPC pipeline not exists, maybe you are importing tuner/assessor from trial code?'
import logging import logging
...@@ -60,8 +59,7 @@ def send(command, data): ...@@ -60,8 +59,7 @@ def send(command, data):
""" """
global _lock global _lock
try: try:
if multi_thread_enabled(): _lock.acquire()
_lock.acquire()
data = data.encode('utf8') data = data.encode('utf8')
assert len(data) < 1000000, 'Command too long' assert len(data) < 1000000, 'Command too long'
msg = b'%b%06d%b' % (command.value, len(data), data) msg = b'%b%06d%b' % (command.value, len(data), data)
...@@ -69,8 +67,7 @@ def send(command, data): ...@@ -69,8 +67,7 @@ def send(command, data):
_out_file.write(msg) _out_file.write(msg)
_out_file.flush() _out_file.flush()
finally: finally:
if multi_thread_enabled(): _lock.release()
_lock.release()
def receive(): def receive():
......
...@@ -73,11 +73,12 @@ class AssessorTestCase(TestCase): ...@@ -73,11 +73,12 @@ class AssessorTestCase(TestCase):
assessor = NaiveAssessor() assessor = NaiveAssessor()
dispatcher = MsgDispatcher(None, assessor) dispatcher = MsgDispatcher(None, assessor)
try: nni.msg_dispatcher_base._worker_fast_exit_on_terminate = False
dispatcher.run()
except Exception as e: dispatcher.run()
self.assertIs(type(e), AssertionError) e = dispatcher.worker_exceptions[0]
self.assertEqual(e.args[0], 'Unsupported command: CommandType.NewTrialJob') self.assertIs(type(e), AssertionError)
self.assertEqual(e.args[0], 'Unsupported command: CommandType.NewTrialJob')
self.assertEqual(_trials, ['A', 'B', 'A']) self.assertEqual(_trials, ['A', 'B', 'A'])
self.assertEqual(_end_trials, [('A', False), ('B', True)]) self.assertEqual(_end_trials, [('A', False), ('B', True)])
...@@ -90,4 +91,4 @@ class AssessorTestCase(TestCase): ...@@ -90,4 +91,4 @@ class AssessorTestCase(TestCase):
if __name__ == '__main__': if __name__ == '__main__':
main() main()
\ No newline at end of file
...@@ -88,11 +88,12 @@ class TunerTestCase(TestCase): ...@@ -88,11 +88,12 @@ class TunerTestCase(TestCase):
tuner = NaiveTuner() tuner = NaiveTuner()
dispatcher = MsgDispatcher(tuner) dispatcher = MsgDispatcher(tuner)
try: nni.msg_dispatcher_base._worker_fast_exit_on_terminate = False
dispatcher.run()
except Exception as e: dispatcher.run()
self.assertIs(type(e), AssertionError) e = dispatcher.worker_exceptions[0]
self.assertEqual(e.args[0], 'Unsupported command: CommandType.KillTrialJob') self.assertIs(type(e), AssertionError)
self.assertEqual(e.args[0], 'Unsupported command: CommandType.KillTrialJob')
_reverse_io() # now we are receiving from Tuner's outgoing stream _reverse_io() # now we are receiving from Tuner's outgoing stream
self._assert_params(0, 2, [ ], None) self._assert_params(0, 2, [ ], None)
......
...@@ -2,10 +2,7 @@ import * as React from 'react'; ...@@ -2,10 +2,7 @@ import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import { Row, Col } from 'antd'; import { Row, Col } from 'antd';
import { MANAGER_IP } from '../static/const'; import { MANAGER_IP } from '../static/const';
import { import { Experiment, TableObj, Parameters, TrialNumber } from '../static/interface';
Experiment, TableObj,
Parameters, TrialNumber
} from '../static/interface';
import { getFinal } from '../static/function'; import { getFinal } from '../static/function';
import SuccessTable from './overview/SuccessTable'; import SuccessTable from './overview/SuccessTable';
import Title1 from './overview/Title1'; import Title1 from './overview/Title1';
...@@ -117,7 +114,9 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -117,7 +114,9 @@ class Overview extends React.Component<{}, OverviewState> {
clusterMetaData: clusterMetaData ? clusterMetaData : undefined clusterMetaData: clusterMetaData ? clusterMetaData : undefined
}); });
// search space format loguniform max and min // search space format loguniform max and min
const searchSpace = JSON.parse(sessionData.params.searchSpace); const temp = sessionData.params.searchSpace;
const searchSpace = temp !== undefined
? JSON.parse(temp) : {};
Object.keys(searchSpace).map(item => { Object.keys(searchSpace).map(item => {
const key = searchSpace[item]._type; const key = searchSpace[item]._type;
let value = searchSpace[item]._value; let value = searchSpace[item]._value;
......
...@@ -141,6 +141,7 @@ class SlideBar extends React.Component<{}, SliderState> { ...@@ -141,6 +141,7 @@ class SlideBar extends React.Component<{}, SliderState> {
} }
}); });
} }
getNNIversion = () => { getNNIversion = () => {
axios(`${MANAGER_IP}/version`, { axios(`${MANAGER_IP}/version`, {
method: 'GET' method: 'GET'
...@@ -233,7 +234,6 @@ class SlideBar extends React.Component<{}, SliderState> { ...@@ -233,7 +234,6 @@ class SlideBar extends React.Component<{}, SliderState> {
</a> </a>
<span className="version">Version: {version}</span> <span className="version">Version: {version}</span>
</Col> </Col>
</Row> </Row>
); );
} }
......
import * as React from 'react'; import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import { MANAGER_IP } from '../static/const'; import { MANAGER_IP } from '../static/const';
import { Row, Col, Tabs, Input, Select, Button } from 'antd'; import { Row, Col, Tabs, Input, Select, Button, Icon } from 'antd';
const Option = Select.Option; const Option = Select.Option;
import { TableObj, Parameters, DetailAccurPoint, TooltipForAccuracy } from '../static/interface'; import { TableObj, Parameters } from '../static/interface';
import { getFinalResult, getFinal } from '../static/function'; import { getFinal } from '../static/function';
import Accuracy from './overview/Accuracy'; import DefaultPoint from './trial-detail/DefaultMetricPoint';
import Duration from './trial-detail/Duration'; import Duration from './trial-detail/Duration';
import Title1 from './overview/Title1'; import Title1 from './overview/Title1';
import Para from './trial-detail/Para'; import Para from './trial-detail/Para';
import Intermediate from './trial-detail/Intermeidate';
import TableList from './trial-detail/TableList'; import TableList from './trial-detail/TableList';
const TabPane = Tabs.TabPane; const TabPane = Tabs.TabPane;
import '../static/style/trialsDetail.scss'; import '../static/style/trialsDetail.scss';
...@@ -22,6 +23,8 @@ interface TrialDetailState { ...@@ -22,6 +23,8 @@ interface TrialDetailState {
experimentStatus: string; experimentStatus: string;
entriesTable: number; entriesTable: number;
experimentPlatform: string; experimentPlatform: string;
searchSpace: string;
defaultMetric?: Array<number>;
} }
class TrialsDetail extends React.Component<{}, TrialDetailState> { class TrialsDetail extends React.Component<{}, TrialDetailState> {
...@@ -33,6 +36,26 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -33,6 +36,26 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
public tableList: TableList | null; public tableList: TableList | null;
private titleOfacc = (
<Title1 text="Default Metric" icon="3.png" />
);
private titleOfhyper = (
<Title1 text="Hyper Parameter" icon="1.png" />
);
private titleOfDuration = (
<Title1 text="Trial Duration" icon="2.png" />
);
private titleOfIntermediate = (
// <Title1 text="Intermediate Result" icon="intermediate.png" />
<div className="panelTitle">
<Icon type="line-chart" />
<span>Intermediate Result</span>
</div>
);
constructor(props: {}) { constructor(props: {}) {
super(props); super(props);
...@@ -44,103 +67,29 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -44,103 +67,29 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
experimentStatus: '', experimentStatus: '',
entriesTable: 20, entriesTable: 20,
isHasSearch: false, isHasSearch: false,
experimentPlatform: '' experimentPlatform: '',
searchSpace: '',
defaultMetric: [0, 1]
}; };
} }
// trial accuracy graph
drawPointGraph = () => {
axios(`${MANAGER_IP}/trial-jobs`, { getDetailSource = () => {
method: 'GET'
})
.then(res => {
if (res.status === 200 && this._isMounted) {
const accData = res.data;
const accSource: Array<DetailAccurPoint> = [];
Object.keys(accData).map(item => {
if (accData[item].status === 'SUCCEEDED' && accData[item].finalMetricData) {
let searchSpace: object = {};
const acc = getFinalResult(accData[item].finalMetricData);
if (accData[item].hyperParameters) {
searchSpace = JSON.parse(accData[item].hyperParameters).parameters;
}
accSource.push({
acc: acc,
index: accData[item].sequenceId,
searchSpace: JSON.stringify(searchSpace)
});
}
});
const resultList: Array<number | string>[] = [];
Object.keys(accSource).map(item => {
const items = accSource[item];
let temp: Array<number | string>;
temp = [items.index, items.acc, JSON.parse(items.searchSpace)];
resultList.push(temp);
});
const allAcuracy = {
tooltip: {
trigger: 'item',
enterable: true,
position: function (point: Array<number>, data: TooltipForAccuracy) {
if (data.data[0] < resultList.length / 2) {
return [point[0], 80];
} else {
return [point[0] - 300, 80];
}
},
formatter: function (data: TooltipForAccuracy) {
const result = '<div class="tooldetailAccuracy">' +
'<div>Trial No: ' + data.data[0] + '</div>' +
'<div>Default Metric: ' + data.data[1] + '</div>' +
'<div>Parameters: ' +
'<pre>' + JSON.stringify(data.data[2], null, 4) + '</pre>' +
'</div>' +
'</div>';
return result;
}
},
xAxis: {
name: 'Trial',
type: 'category',
},
yAxis: {
name: 'Default Metric',
type: 'value',
},
series: [{
symbolSize: 6,
type: 'scatter',
data: resultList
}]
};
this.setState({ accSource: allAcuracy }, () => {
if (resultList.length === 0) {
this.setState({
accNodata: 'No data'
});
} else {
this.setState({
accNodata: ''
});
}
});
}
});
}
drawTableList = () => {
this.isOffIntervals(); this.isOffIntervals();
axios.get(`${MANAGER_IP}/trial-jobs`) axios
.then(res => { .all([
axios.get(`${MANAGER_IP}/trial-jobs`),
axios.get(`${MANAGER_IP}/metric-data`)
])
.then(axios.spread((res, res1) => {
if (res.status === 200) { if (res.status === 200) {
const trialJobs = res.data; const trialJobs = res.data;
const metricSource = res1.data;
const trialTable: Array<TableObj> = []; const trialTable: Array<TableObj> = [];
Object.keys(trialJobs).map(item => { Object.keys(trialJobs).map(item => {
// only succeeded trials have finalMetricData // only succeeded trials have finalMetricData
let desc: Parameters = { let desc: Parameters = {
parameters: {} parameters: {},
intermediate: []
}; };
let duration = 0; let duration = 0;
const id = trialJobs[item].id !== undefined const id = trialJobs[item].id !== undefined
...@@ -171,7 +120,23 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -171,7 +120,23 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
if (trialJobs[item].logPath !== undefined) { if (trialJobs[item].logPath !== undefined) {
desc.logPath = trialJobs[item].logPath; desc.logPath = trialJobs[item].logPath;
} }
const acc = getFinal(trialJobs[item].finalMetricData); const acc = getFinal(trialJobs[item].finalMetricData);
// deal with intermediate result list
const mediate: Array<number> = [];
Object.keys(metricSource).map(key => {
const items = metricSource[key];
if (items.trialJobId === id) {
// succeed trial, last intermediate result is final result
// final result format may be object
if (typeof JSON.parse(items.data) === 'object') {
mediate.push(JSON.parse(items.data).default);
} else {
mediate.push(JSON.parse(items.data));
}
}
});
desc.intermediate = mediate;
trialTable.push({ trialTable.push({
key: trialTable.length, key: trialTable.length,
sequenceId: trialJobs[item].sequenceId, sequenceId: trialJobs[item].sequenceId,
...@@ -182,7 +147,33 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -182,7 +147,33 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
description: desc description: desc
}); });
}); });
// search part data // get acc max and min for hyper-parameters graph color bar max and min
const sortSource = JSON.parse(JSON.stringify(trialTable));
sortSource.sort((a: TableObj, b: TableObj) => {
if (a.acc !== undefined && b.acc !== undefined) {
return JSON.parse(a.acc.default) - JSON.parse(b.acc.default);
} else {
return NaN;
}
});
if (this._isMounted && sortSource !== undefined) {
const hyperMin = sortSource[0].acc !== undefined
?
sortSource[0].acc.default
:
'0';
const max = sortSource[sortSource.length - 1].acc;
let maxResult = '1';
if (max !== undefined) {
maxResult = max.default;
}
this.setState(() => ({
defaultMetric: [JSON.parse(hyperMin), JSON.parse(maxResult)]
}));
}
// update search data result
const { searchResultSource } = this.state; const { searchResultSource } = this.state;
if (searchResultSource.length !== 0) { if (searchResultSource.length !== 0) {
const temp: Array<number> = []; const temp: Array<number> = [];
...@@ -211,111 +202,29 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -211,111 +202,29 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
})); }));
} }
} }
}); }));
}
// update all data in table
drawAllTableList = () => {
this.isOffIntervals();
axios.get(`${MANAGER_IP}/trial-jobs`)
.then(res => {
if (res.status === 200) {
const trialJobs = res.data;
const trialTable: Array<TableObj> = [];
Object.keys(trialJobs).map(item => {
// only succeeded trials have finalMetricData
let desc: Parameters = {
parameters: {}
};
let duration = 0;
const id = trialJobs[item].id !== undefined
? trialJobs[item].id
: '';
const status = trialJobs[item].status !== undefined
? trialJobs[item].status
: '';
const begin = trialJobs[item].startTime;
const end = trialJobs[item].endTime;
if (begin) {
if (end) {
duration = (end - begin) / 1000;
} else {
duration = (new Date().getTime() - begin) / 1000;
}
}
if (trialJobs[item].hyperParameters !== undefined) {
const getPara = JSON.parse(trialJobs[item].hyperParameters[0]).parameters;
if (typeof getPara === 'string') {
desc.parameters = JSON.parse(getPara);
} else {
desc.parameters = getPara;
}
} else {
desc.parameters = { error: 'This trial\'s parameters are not available.' };
}
if (trialJobs[item].logPath !== undefined) {
desc.logPath = trialJobs[item].logPath;
}
const acc = getFinal(trialJobs[item].finalMetricData);
trialTable.push({
key: trialTable.length,
sequenceId: trialJobs[item].sequenceId,
id: id,
status: status,
duration: duration,
acc: acc,
description: desc
});
});
if (this._isMounted) {
this.setState(() => ({
tableListSource: trialTable,
searchResultSource: trialTable
}));
}
}
});
}
callback = (key: string) => {
switch (key) {
case '1':
window.clearInterval(Para.intervalIDPara);
window.clearInterval(Duration.intervalDuration);
this.drawPointGraph();
this.interAccuracy = window.setInterval(this.drawPointGraph, 10000);
break;
case '2':
this.isOffIntervals();
window.clearInterval(this.interAccuracy);
window.clearInterval(Duration.intervalDuration);
break;
case '3':
this.isOffIntervals();
window.clearInterval(this.interAccuracy);
window.clearInterval(Para.intervalIDPara);
break;
default:
}
} }
// search a trial by trial No. & trial id // search a trial by trial No. & trial id
searchTrial = (event: React.ChangeEvent<HTMLInputElement>) => { searchTrial = (event: React.ChangeEvent<HTMLInputElement>) => {
const targetValue = event.target.value; const targetValue = event.target.value;
if (targetValue === '' || targetValue === ' ') { if (targetValue === '' || targetValue === ' ') {
this.drawAllTableList(); const { tableListSource } = this.state;
this.interAllTableList = window.setInterval(this.drawAllTableList, 10000); if (this._isMounted) {
this.setState(() => ({
isHasSearch: false,
tableListSource: tableListSource,
}));
}
} else { } else {
window.clearInterval(this.interAllTableList);
const { tableListSource } = this.state; const { tableListSource } = this.state;
const searchResultList: Array<TableObj> = []; const searchResultList: Array<TableObj> = [];
Object.keys(tableListSource).map(key => { Object.keys(tableListSource).map(key => {
const item = tableListSource[key]; const item = tableListSource[key];
if (item.sequenceId.toString() === targetValue || item.id.includes(targetValue)) { if (item.sequenceId.toString() === targetValue
|| item.id.includes(targetValue)
|| item.status.includes(targetValue)
) {
searchResultList.push(item); searchResultList.push(item);
} }
}); });
...@@ -328,6 +237,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -328,6 +237,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
} }
} }
// close timer
isOffIntervals = () => { isOffIntervals = () => {
axios(`${MANAGER_IP}/check-status`, { axios(`${MANAGER_IP}/check-status`, {
method: 'GET' method: 'GET'
...@@ -338,11 +248,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -338,11 +248,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
case 'DONE': case 'DONE':
case 'ERROR': case 'ERROR':
case 'STOPPED': case 'STOPPED':
window.clearInterval(this.interAccuracy);
window.clearInterval(this.interTableList); window.clearInterval(this.interTableList);
window.clearInterval(Duration.intervalDuration);
window.clearInterval(Para.intervalIDPara);
window.clearInterval(this.interAllTableList);
break; break;
default: default:
} }
...@@ -362,7 +268,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -362,7 +268,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
this.setState(() => ({ entriesTable: 100 })); this.setState(() => ({ entriesTable: 100 }));
break; break;
case 'all': case 'all':
this.setState(() => ({ entriesTable: 100000 })); const { tableListSource } = this.state;
this.setState(() => ({ entriesTable: tableListSource.length }));
break; break;
default: default:
} }
...@@ -379,13 +286,14 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -379,13 +286,14 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
const trainingPlatform = res.data.params.trainingServicePlatform !== undefined const trainingPlatform = res.data.params.trainingServicePlatform !== undefined
? ?
res.data.params.trainingServicePlatform res.data.params.trainingServicePlatform
: :
''; '';
if (this._isMounted) { if (this._isMounted) {
this.setState({ this.setState({
experimentPlatform: trainingPlatform experimentPlatform: trainingPlatform,
searchSpace: res.data.params.searchSpace
}); });
} }
} }
...@@ -395,56 +303,55 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -395,56 +303,55 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
componentDidMount() { componentDidMount() {
this._isMounted = true; this._isMounted = true;
this.drawTableList(); this.getDetailSource();
this.drawPointGraph(); this.interTableList = window.setInterval(this.getDetailSource, 10000);
this.interTableList = window.setInterval(this.drawTableList, 10000);
this.interAccuracy = window.setInterval(this.drawPointGraph, 10000);
this.checkExperimentPlatform(); this.checkExperimentPlatform();
} }
componentWillUnmount() { componentWillUnmount() {
this._isMounted = false; this._isMounted = false;
window.clearInterval(this.interTableList); window.clearInterval(this.interTableList);
window.clearInterval(this.interAccuracy);
} }
render() { render() {
const { accSource, accNodata, tableListSource,
entriesTable, searchResultSource, isHasSearch, const {
experimentPlatform tableListSource, searchResultSource, isHasSearch,
entriesTable, experimentPlatform, searchSpace,
defaultMetric
} = this.state; } = this.state;
const titleOfacc = ( const source = isHasSearch ? searchResultSource : tableListSource;
<Title1 text="Default Metric" icon="3.png" />
);
const titleOfhyper = (
<Title1 text="Hyper Parameter" icon="1.png" />
);
const titleOfDuration = (
<Title1 text="Trial Duration" icon="2.png" />
);
return ( return (
<div> <div>
<div className="trial" id="tabsty"> <div className="trial" id="tabsty">
<Tabs onChange={this.callback} type="card"> <Tabs type="card">
<TabPane tab={titleOfacc} key="1"> <TabPane tab={this.titleOfacc} key="1">
<Row className="graph"> <Row className="graph">
<Accuracy <DefaultPoint
height={432} height={432}
accuracyData={accSource} showSource={source}
accNodata={accNodata} />
</Row>
</TabPane>
<TabPane tab={this.titleOfhyper} key="2">
<Row className="graph">
<Para
dataSource={source}
expSearchSpace={searchSpace}
defaultMetric={defaultMetric}
/> />
</Row> </Row>
</TabPane> </TabPane>
<TabPane tab={titleOfhyper} key="2"> <TabPane tab={this.titleOfDuration} key="3">
<Row className="graph"><Para /></Row> <Duration source={source} />
</TabPane> </TabPane>
<TabPane tab={titleOfDuration} key="3"> <TabPane tab={this.titleOfIntermediate} key="4">
<Duration /> <Intermediate source={source} />
</TabPane> </TabPane>
</Tabs> </Tabs>
</div> </div>
{/* trial table list */} {/* trial table list */}
<Title1 text="All Trials" icon="6.png" /> <Title1 text="Trial Jobs" icon="6.png" />
<Row className="allList"> <Row className="allList">
<Col span={12}> <Col span={12}>
<span>show</span> <span>show</span>
...@@ -472,12 +379,11 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -472,12 +379,11 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</Button> </Button>
</Col> </Col>
<Col span={12}> <Col span={12}>
{/* <span>Search:</span> */}
<Input <Input
type="text" type="text"
placeholder="search by Trial No. and id" placeholder="search by Id, Trial No. or Status"
onChange={this.searchTrial} onChange={this.searchTrial}
style={{ width: 200, marginLeft: 6 }} style={{ width: 230, marginLeft: 6 }}
/> />
</Col> </Col>
</Row> </Row>
...@@ -485,10 +391,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -485,10 +391,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
</Row> </Row>
<TableList <TableList
entries={entriesTable} entries={entriesTable}
tableSource={tableListSource} tableSource={source}
updateList={this.drawTableList} updateList={this.getDetailSource}
searchResult={searchResultSource}
isHasSearch={isHasSearch}
platform={experimentPlatform} platform={experimentPlatform}
ref={(tabList) => this.tableList = tabList} ref={(tabList) => this.tableList = tabList}
/> />
......
...@@ -2,7 +2,7 @@ import * as React from 'react'; ...@@ -2,7 +2,7 @@ import * as React from 'react';
interface Title1Props { interface Title1Props {
text: string; text: string;
icon: string; icon?: string;
bgcolor?: string; bgcolor?: string;
} }
......
import * as React from 'react';
import ReactEcharts from 'echarts-for-react';
import { TableObj, DetailAccurPoint, TooltipForAccuracy } from '../../static/interface';
require('echarts/lib/chart/scatter');
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
interface DefaultPointProps {
showSource: Array<TableObj>;
height: number;
}
interface DefaultPointState {
defaultSource: object;
accNodata: string;
}
class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState> {
public _isMounted = false;
constructor(props: DefaultPointProps) {
super(props);
this.state = {
defaultSource: {},
accNodata: 'No data'
};
}
defaultMetric = (showSource: Array<TableObj>) => {
const accSource: Array<DetailAccurPoint> = [];
Object.keys(showSource).map(item => {
const temp = showSource[item];
if (temp.status === 'SUCCEEDED' && temp.acc.default !== undefined) {
const searchSpace = temp.description.parameters;
accSource.push({
acc: temp.acc.default,
index: temp.sequenceId,
searchSpace: JSON.stringify(searchSpace)
});
}
});
const resultList: Array<number | string>[] = [];
Object.keys(accSource).map(item => {
const items = accSource[item];
let temp: Array<number | string>;
temp = [items.index, items.acc, JSON.parse(items.searchSpace)];
resultList.push(temp);
});
const allAcuracy = {
grid: {
left: '8%'
},
tooltip: {
trigger: 'item',
enterable: true,
position: function (point: Array<number>, data: TooltipForAccuracy) {
if (data.data[0] < resultList.length / 2) {
return [point[0], 80];
} else {
return [point[0] - 300, 80];
}
},
formatter: function (data: TooltipForAccuracy) {
const result = '<div class="tooldetailAccuracy">' +
'<div>Trial No: ' + data.data[0] + '</div>' +
'<div>Default Metric: ' + data.data[1] + '</div>' +
'<div>Parameters: ' +
'<pre>' + JSON.stringify(data.data[2], null, 4) + '</pre>' +
'</div>' +
'</div>';
return result;
}
},
xAxis: {
name: 'Trial',
type: 'category',
},
yAxis: {
name: 'Default Metric',
type: 'value',
},
series: [{
symbolSize: 6,
type: 'scatter',
data: resultList
}]
};
if (this._isMounted === true) {
this.setState({ defaultSource: allAcuracy }, () => {
if (resultList.length === 0) {
this.setState({
accNodata: 'No data'
});
} else {
this.setState({
accNodata: ''
});
}
});
}
}
// update parent component state
componentWillReceiveProps(nextProps: DefaultPointProps) {
const showSource = nextProps.showSource;
this.defaultMetric(showSource);
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
const { height } = this.props;
const { defaultSource, accNodata } = this.state;
return (
<div>
<ReactEcharts
option={defaultSource}
style={{
width: '100%',
height: height,
margin: '0 auto',
}}
theme="my_theme"
notMerge={true} // update now
/>
<div className="showMess">{accNodata}</div>
</div>
);
}
}
export default DefaultPoint;
\ No newline at end of file
import * as React from 'react'; import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../../static/const';
import ReactEcharts from 'echarts-for-react'; import ReactEcharts from 'echarts-for-react';
const echarts = require('echarts/lib/echarts'); import { TableObj } from 'src/static/interface';
require('echarts/lib/chart/bar'); require('echarts/lib/chart/bar');
require('echarts/lib/component/tooltip'); require('echarts/lib/component/tooltip');
require('echarts/lib/component/title'); require('echarts/lib/component/title');
echarts.registerTheme('my_theme', {
color: '#3c8dbc'
});
interface Runtrial { interface Runtrial {
trialId: Array<string>; trialId: Array<string>;
trialTime: Array<number>; trialTime: Array<number>;
} }
interface DurationProps {
source: Array<TableObj>;
}
interface DurationState { interface DurationState {
durationSource: {}; durationSource: {};
} }
class Duration extends React.Component<{}, DurationState> { class Duration extends React.Component<DurationProps, DurationState> {
static intervalDuration = 1;
public _isMounted = false; public _isMounted = false;
constructor(props: {}) { constructor(props: DurationProps) {
super(props);
super(props);
this.state = { this.state = {
durationSource: {} durationSource: {}
}; };
} }
getOption = (dataObj: Runtrial) => { getOption = (dataObj: Runtrial) => {
let xAxis = dataObj.trialTime; return {
let yAxis = dataObj.trialId;
let option = {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
axisPointer: { axisPointer: {
...@@ -50,6 +45,7 @@ class Duration extends React.Component<{}, DurationState> { ...@@ -50,6 +45,7 @@ class Duration extends React.Component<{}, DurationState> {
left: '1%', left: '1%',
right: '4%' right: '4%'
}, },
dataZoom: [{ dataZoom: [{
type: 'slider', type: 'slider',
name: 'trial', name: 'trial',
...@@ -69,65 +65,52 @@ class Duration extends React.Component<{}, DurationState> { ...@@ -69,65 +65,52 @@ class Duration extends React.Component<{}, DurationState> {
yAxis: { yAxis: {
name: 'Trial', name: 'Trial',
type: 'category', type: 'category',
data: yAxis data: dataObj.trialId
}, },
series: [{ series: [{
type: 'bar', type: 'bar',
data: xAxis data: dataObj.trialTime
}] }]
}; };
return option;
} }
drawRunGraph = () => { drawDurationGraph = (trialJobs: Array<TableObj>) => {
axios(`${MANAGER_IP}/trial-jobs`, { const trialId: Array<string> = [];
method: 'GET' const trialTime: Array<number> = [];
}) const trialRun: Array<Runtrial> = [];
.then(res => { Object.keys(trialJobs).map(item => {
if (res.status === 200) { const temp = trialJobs[item];
const trialJobs = res.data; if (temp.status !== 'WAITING') {
const trialId: Array<string> = []; trialId.push(temp.sequenceId);
const trialTime: Array<number> = []; trialTime.push(temp.duration);
const trialRun: Array<Runtrial> = []; }
Object.keys(trialJobs).map(item => { });
if (trialJobs[item].status !== 'WAITING') { trialRun.push({
let duration: number = 0; trialId: trialId,
const end = trialJobs[item].endTime; trialTime: trialTime
const start = trialJobs[item].startTime; });
if (start && end) { if (this._isMounted) {
duration = (end - start) / 1000; this.setState({
} else { durationSource: this.getOption(trialRun[0])
duration = (new Date().getTime() - start) / 1000;
}
trialId.push(trialJobs[item].sequenceId);
trialTime.push(duration);
}
});
trialRun.push({
trialId: trialId,
trialTime: trialTime
});
if (this._isMounted && res.status === 200) {
this.setState({
durationSource: this.getOption(trialRun[0])
});
}
}
}); });
}
} }
componentDidMount() { componentWillReceiveProps(nextProps: DurationProps) {
const trialJobs = nextProps.source;
this.drawDurationGraph(trialJobs);
}
componentDidMount() {
this._isMounted = true; this._isMounted = true;
this.drawRunGraph(); // init: user don't search
Duration.intervalDuration = window.setInterval(this.drawRunGraph, 10000); const {source} = this.props;
this.drawDurationGraph(source);
} }
componentWillUnmount() { componentWillUnmount() {
this._isMounted = false; this._isMounted = false;
window.clearInterval(Duration.intervalDuration);
} }
render() { render() {
...@@ -136,7 +119,7 @@ class Duration extends React.Component<{}, DurationState> { ...@@ -136,7 +119,7 @@ class Duration extends React.Component<{}, DurationState> {
<div> <div>
<ReactEcharts <ReactEcharts
option={durationSource} option={durationSource}
style={{ width: '100%', height: 412, margin: '0 auto' }} style={{ width: '95%', height: 412, margin: '0 auto' }}
theme="my_theme" theme="my_theme"
/> />
</div> </div>
......
import * as React from 'react';
import { Row, Col, Button, Switch } from 'antd';
import { TooltipForIntermediate, TableObj } from '../../static/interface';
import ReactEcharts from 'echarts-for-react';
require('echarts/lib/component/tooltip');
require('echarts/lib/component/title');
interface Intermedia {
name: string; // id
type: string;
data: Array<number | object>; // intermediate data
hyperPara: object; // each trial hyperpara value
}
interface IntermediateState {
interSource: object;
filterSource: Array<TableObj>;
eachIntermediateNum: number; // trial's intermediate number count
isLoadconfirmBtn: boolean;
isFilter: boolean;
}
interface IntermediateProps {
source: Array<TableObj>;
}
class Intermediate extends React.Component<IntermediateProps, IntermediateState> {
static intervalMediate = 1;
public _isMounted = false;
public pointInput: HTMLInputElement | null;
public minValInput: HTMLInputElement | null;
public maxValInput: HTMLInputElement | null;
constructor(props: IntermediateProps) {
super(props);
this.state = {
interSource: {},
filterSource: [],
eachIntermediateNum: 1,
isLoadconfirmBtn: false,
isFilter: false
};
}
initMediate = () => {
const option = {
grid: {
left: '5%',
top: 40,
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
},
yAxis: {
type: 'value',
name: 'Scape'
}
};
if (this._isMounted) {
this.setState(() => ({
interSource: option
}));
}
}
drawIntermediate = (source: Array<TableObj>) => {
if (source.length > 0) {
const trialIntermediate: Array<Intermedia> = [];
Object.keys(source).map(item => {
const temp = source[item];
trialIntermediate.push({
name: temp.id,
data: temp.description.intermediate,
type: 'line',
hyperPara: temp.description.parameters
});
});
// find max intermediate number
trialIntermediate.sort((a, b) => { return (b.data.length - a.data.length); });
const legend: Array<string> = [];
// max length
const length = trialIntermediate[0].data.length;
const xAxis: Array<number> = [];
Object.keys(trialIntermediate).map(item => {
const temp = trialIntermediate[item];
legend.push(temp.name);
});
for (let i = 1; i <= length; i++) {
xAxis.push(i);
}
const option = {
tooltip: {
trigger: 'item',
enterable: true,
position: function (point: Array<number>, data: TooltipForIntermediate) {
if (data.dataIndex < length / 2) {
return [point[0], 80];
} else {
return [point[0] - 300, 80];
}
},
formatter: function (data: TooltipForIntermediate) {
const trialId = data.seriesName;
let obj = {};
const temp = trialIntermediate.find(key => key.name === trialId);
if (temp !== undefined) {
obj = temp.hyperPara;
}
return '<div class="tooldetailAccuracy">' +
'<div>Trial Id: ' + trialId + '</div>' +
'<div>Intermediate: ' + data.data + '</div>' +
'<div>Parameters: ' +
'<pre>' + JSON.stringify(obj, null, 4) + '</pre>' +
'</div>' +
'</div>';
}
},
grid: {
left: '5%',
top: 40,
containLabel: true
},
xAxis: {
type: 'category',
name: 'Scape',
boundaryGap: false,
data: xAxis
},
yAxis: {
type: 'value',
name: 'Intermediate'
},
series: trialIntermediate
};
if (this._isMounted) {
this.setState(() => ({
interSource: option
}));
}
} else {
this.initMediate();
}
}
// confirm btn function [filter data]
filterLines = () => {
if (this._isMounted) {
const filterSource: Array<TableObj> = [];
this.setState({ isLoadconfirmBtn: true }, () => {
const { source } = this.props;
// get input value
const pointVal = this.pointInput !== null ? this.pointInput.value : '';
const minVal = this.minValInput !== null ? this.minValInput.value : '';
const maxVal = this.maxValInput !== null ? this.maxValInput.value : '';
// user not input message
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];
if (val >= min) {
filterSource.push(temp);
}
});
} else {
const max = JSON.parse(maxVal);
Object.keys(source).map(item => {
const temp = source[item];
const val = temp.description.intermediate[position - 1];
if (val >= min && val <= max) {
filterSource.push(temp);
}
});
}
if (this._isMounted) {
this.setState({ filterSource: filterSource });
}
this.drawIntermediate(filterSource);
}
this.setState({ isLoadconfirmBtn: false });
});
}
}
switchTurn = (checked: boolean) => {
if (this._isMounted) {
this.setState({ isFilter: checked });
}
if (checked === false) {
this.drawIntermediate(this.props.source);
}
}
componentDidMount() {
this._isMounted = true;
const { source } = this.props;
this.drawIntermediate(source);
}
componentWillReceiveProps(nextProps: IntermediateProps) {
const { isFilter, filterSource } = this.state;
if (isFilter === true) {
const pointVal = this.pointInput !== null ? this.pointInput.value : '';
const minVal = this.minValInput !== null ? this.minValInput.value : '';
if (pointVal === '' && minVal === '') {
this.drawIntermediate(nextProps.source);
} else {
this.drawIntermediate(filterSource);
}
} else {
this.drawIntermediate(nextProps.source);
}
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
const { interSource, isLoadconfirmBtn, isFilter } = this.state;
return (
<div>
{/* style in para.scss */}
<Row className="meline intermediate">
<Col span={8} />
<Col span={3} style={{ height: 34 }}>
{/* filter message */}
<span>filter</span>
<Switch
defaultChecked={false}
onChange={this.switchTurn}
/>
</Col>
{
isFilter
?
<div>
<Col span={3}>
<span>Scape</span>
<input
placeholder="point"
ref={input => this.pointInput = input}
className="strange"
/>
</Col>
<Col className="range" span={10}>
<span>Intermediate Result</span>
<input
placeholder="number"
ref={input => this.minValInput = input}
/>
<span className="heng">-</span>
<input
placeholder="number"
ref={input => this.maxValInput = input}
/>
<Button
type="primary"
className="changeBtu tableButton"
onClick={this.filterLines}
disabled={isLoadconfirmBtn}
>
Confirm
</Button>
</Col>
</div>
:
<Col />
}
</Row>
<Row>
<ReactEcharts
option={interSource}
style={{ width: '100%', height: 418, margin: '0 auto' }}
notMerge={true} // update now
/>
</Row>
</div>
);
}
}
export default Intermediate;
\ No newline at end of file
import * as React from 'react'; import * as React from 'react';
import axios from 'axios';
import { MANAGER_IP } from '../../static/const';
import ReactEcharts from 'echarts-for-react'; import ReactEcharts from 'echarts-for-react';
import { Row, Col, Select, Button, message } from 'antd'; import { Row, Col, Select, Button, message } from 'antd';
import { ParaObj, VisualMapValue, Dimobj } from '../../static/interface'; import { ParaObj, Dimobj, TableObj, SearchSpace } from '../../static/interface';
import { getFinalResult } from '../../static/function';
const Option = Select.Option; const Option = Select.Option;
require('echarts/lib/chart/parallel'); require('echarts/lib/chart/parallel');
require('echarts/lib/component/tooltip'); require('echarts/lib/component/tooltip');
...@@ -20,12 +17,14 @@ interface ParaState { ...@@ -20,12 +17,14 @@ interface ParaState {
swapAxisArr: Array<string>; swapAxisArr: Array<string>;
percent: number; percent: number;
paraNodata: string; paraNodata: string;
visualValue: VisualMapValue; barColorMax: number;
barColorMin: number;
} }
interface SearchSpace { interface ParaProps {
_value: Array<number | string>; dataSource: Array<TableObj>;
_type: string; expSearchSpace: string;
defaultMetric: Array<number> | undefined;
} }
message.config({ message.config({
...@@ -33,12 +32,18 @@ message.config({ ...@@ -33,12 +32,18 @@ message.config({
duration: 2, duration: 2,
}); });
class Para extends React.Component<{}, ParaState> { class Para extends React.Component<ParaProps, ParaState> {
static intervalIDPara = 4;
public _isMounted = false; public _isMounted = false;
constructor(props: {}) { private chartMulineStyle = {
width: '100%',
height: 392,
margin: '0 auto',
padding: '0 15 10 15'
};
constructor(props: ParaProps) {
super(props); super(props);
this.state = { this.state = {
option: {}, option: {},
...@@ -53,28 +58,37 @@ class Para extends React.Component<{}, ParaState> { ...@@ -53,28 +58,37 @@ class Para extends React.Component<{}, ParaState> {
swapAxisArr: [], swapAxisArr: [],
percent: 0, percent: 0,
paraNodata: '', paraNodata: '',
visualValue: { barColorMax: this.props.defaultMetric !== undefined
minAccuracy: 0, ?
maxAccuracy: 1 this.props.defaultMetric[1]
} :
1,
barColorMin: this.props.defaultMetric !== undefined
?
this.props.defaultMetric[0]
:
1
}; };
} }
componentDidMount() {
this._isMounted = true;
this.reInit();
}
getParallelAxis = getParallelAxis =
( (
dimName: Array<string>, searchRange: SearchSpace, dimName: Array<string>, searchRange: SearchSpace,
parallelAxis: Array<Dimobj>, accPara: Array<number>, accPara: Array<number>,
eachTrialParams: Array<string>, paraYdata: number[][] eachTrialParams: Array<string>, paraYdata: number[][]
) => { ) => {
if (this._isMounted) { if (this._isMounted) {
this.setState(() => ({ this.setState(() => ({
dimName: dimName, dimName: dimName
visualValue: {
minAccuracy: accPara.length !== 0 ? Math.min(...accPara) : 0,
maxAccuracy: accPara.length !== 0 ? Math.max(...accPara) : 1
}
})); }));
} }
const parallelAxis: Array<Dimobj> = [];
// search space range and specific value [only number] // search space range and specific value [only number]
for (let i = 0; i < dimName.length; i++) { for (let i = 0; i < dimName.length; i++) {
const searchKey = searchRange[dimName[i]]; const searchKey = searchRange[dimName[i]];
...@@ -107,7 +121,24 @@ class Para extends React.Component<{}, ParaState> { ...@@ -107,7 +121,24 @@ class Para extends React.Component<{}, ParaState> {
dim: i, dim: i,
name: dimName[i], name: dimName[i],
type: 'category', type: 'category',
data: data data: data,
boundaryGap: true,
axisLine: {
lineStyle: {
type: 'dotted', // axis type,solid,dashed,dotted
width: 1
}
},
axisTick: {
show: true,
interval: 0,
alignWithLabel: true,
},
axisLabel: {
show: true,
interval: 0,
// rotate: 30
},
}); });
break; break;
// support log distribute // support log distribute
...@@ -143,100 +174,70 @@ class Para extends React.Component<{}, ParaState> { ...@@ -143,100 +174,70 @@ class Para extends React.Component<{}, ParaState> {
} }
paraYdata.push(temp); paraYdata.push(temp);
}); });
// add acc
Object.keys(paraYdata).map(item => {
paraYdata[item].push(accPara[item]);
});
// according acc to sort ydata
if (paraYdata.length !== 0) {
const len = paraYdata[0].length - 1;
paraYdata.sort((a, b) => b[len] - a[len]);
}
const paraData = {
parallelAxis: parallelAxis,
data: paraYdata
};
const { percent, swapAxisArr } = this.state;
// need to cut down the data
if (percent !== 0) {
const linesNum = paraData.data.length;
const len = Math.floor(linesNum * percent);
paraData.data.length = len;
}
// need to swap the yAxis
if (swapAxisArr.length >= 2) {
this.swapGraph(paraData, swapAxisArr);
}
this.getOption(paraData);
} }
hyperParaPic = () => { hyperParaPic = (dataSource: Array<TableObj>, searchSpace: string) => {
axios const accPara: Array<number> = [];
.all([ // specific value array
axios.get(`${MANAGER_IP}/trial-jobs`), const eachTrialParams: Array<string> = [];
axios.get(`${MANAGER_IP}/experiment`) const paraYdata: number[][] = [];
]) // experiment interface search space obj
.then(axios.spread((res, res1) => { const searchRange = JSON.parse(searchSpace);
if (res.status === 200 && res1.status === 200) { const dimName = Object.keys(searchRange);
if (res.data.length !== 0) { // trial-jobs interface list
const accParaData = res.data; Object.keys(dataSource).map(item => {
const accPara: Array<number> = []; const temp = dataSource[item];
// specific value array if (temp.status === 'SUCCEEDED') {
const eachTrialParams: Array<string> = []; accPara.push(temp.acc.default);
const parallelAxis: Array<Dimobj> = []; eachTrialParams.push(temp.description.parameters);
const paraYdata: number[][] = []; }
// experiment interface search space obj });
const searchRange = JSON.parse(res1.data.params.searchSpace); this.getParallelAxis(dimName, searchRange, accPara, eachTrialParams, paraYdata);
const reallySearchKeys = Object.keys(searchRange);
// trial-jobs interface list
Object.keys(accParaData).map(item => {
if (accParaData[item].status === 'SUCCEEDED') {
const finalData = accParaData[item].finalMetricData;
if (finalData && accParaData[item].hyperParameters) {
const result = getFinalResult(finalData);
accPara.push(result);
// get dim and every line specific number
const temp = JSON.parse(accParaData[item].hyperParameters).parameters;
eachTrialParams.push(temp);
}
}
});
const dimName = reallySearchKeys;
this.getParallelAxis(dimName, searchRange, parallelAxis, accPara, eachTrialParams, paraYdata);
// add acc
Object.keys(paraYdata).map(item => {
paraYdata[item].push(accPara[item]);
});
// according acc to sort ydata
if (paraYdata.length !== 0) {
const len = paraYdata[0].length - 1;
paraYdata.sort((a, b) => b[len] - a[len]);
}
if (this._isMounted) {
this.setState(() => ({
paraBack: {
parallelAxis: parallelAxis,
data: paraYdata
}
}));
}
const { percent, swapAxisArr, paraBack } = this.state;
// need to cut down the data
if (percent !== 0) {
const linesNum = paraBack.data.length;
const len = Math.floor(linesNum * percent);
paraBack.data.length = len;
}
// need to swap the yAxis
if (swapAxisArr.length >= 2) {
this.swapGraph(paraBack, swapAxisArr);
}
this.getOption(paraBack);
}
}
}));
} }
// get percent value number // get percent value number
percentNum = (value: string) => { percentNum = (value: string) => {
window.clearInterval(Para.intervalIDPara);
let vals = parseFloat(value); let vals = parseFloat(value);
if (this._isMounted) { if (this._isMounted) {
this.setState(() => ({ this.setState({ percent: vals }, () => {
percent: vals this.reInit();
})); });
} }
this.hyperParaPic();
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
} }
// deal with response data into pic data // deal with response data into pic data
getOption = (dataObj: ParaObj) => { getOption = (dataObj: ParaObj) => {
const { visualValue } = this.state; const {barColorMax, barColorMin} = this.state;
let parallelAxis = dataObj.parallelAxis; let parallelAxis = dataObj.parallelAxis;
let paralleData = dataObj.data; let paralleData = dataObj.data;
const maxAccuracy = visualValue.maxAccuracy;
const minAccuracy = visualValue.minAccuracy;
let visualMapObj = {}; let visualMapObj = {};
if (maxAccuracy === minAccuracy) { if (barColorMax === barColorMin) {
visualMapObj = { visualMapObj = {
type: 'continuous', type: 'continuous',
precision: 3, precision: 3,
...@@ -247,10 +248,9 @@ class Para extends React.Component<{}, ParaState> { ...@@ -247,10 +248,9 @@ class Para extends React.Component<{}, ParaState> {
bottom: '20px', bottom: '20px',
type: 'continuous', type: 'continuous',
precision: 3, precision: 3,
min: visualValue.minAccuracy, min: barColorMin,
max: visualValue.maxAccuracy, max: barColorMax,
color: ['#CA0000', '#FFC400', '#90EE90'], color: ['#CA0000', '#FFC400', '#90EE90']
calculable: true
}; };
} }
let optionown = { let optionown = {
...@@ -317,11 +317,9 @@ class Para extends React.Component<{}, ParaState> { ...@@ -317,11 +317,9 @@ class Para extends React.Component<{}, ParaState> {
} }
} }
swapBtn = () => { reInit = () => {
const { dataSource, expSearchSpace } = this.props;
window.clearInterval(Para.intervalIDPara); this.hyperParaPic(dataSource, expSearchSpace);
this.hyperParaPic();
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
} }
sortDimY = (a: Dimobj, b: Dimobj) => { sortDimY = (a: Dimobj, b: Dimobj) => {
...@@ -330,79 +328,73 @@ class Para extends React.Component<{}, ParaState> { ...@@ -330,79 +328,73 @@ class Para extends React.Component<{}, ParaState> {
// deal with after swap data into pic // deal with after swap data into pic
swapGraph = (paraBack: ParaObj, swapAxisArr: string[]) => { swapGraph = (paraBack: ParaObj, swapAxisArr: string[]) => {
const paralDim = paraBack.parallelAxis;
if (swapAxisArr.length >= 2) { const paraData = paraBack.data;
const paralDim = paraBack.parallelAxis; let temp: number;
const paraData = paraBack.data; let dim1: number;
let temp: number; let dim2: number;
let dim1: number; let bool1: boolean = false;
let dim2: number; let bool2: boolean = false;
let bool1: boolean = false; let bool3: boolean = false;
let bool2: boolean = false; Object.keys(paralDim).map(item => {
let bool3: boolean = false; const paral = paralDim[item];
Object.keys(paralDim).map(item => { switch (paral.name) {
const paral = paralDim[item]; case swapAxisArr[0]:
switch (paral.name) { dim1 = paral.dim;
case swapAxisArr[0]: bool1 = true;
dim1 = paral.dim; break;
bool1 = true;
break; case swapAxisArr[1]:
dim2 = paral.dim;
case swapAxisArr[1]: bool2 = true;
dim2 = paral.dim; break;
bool2 = true;
break; default:
}
default: if (bool1 && bool2) {
} bool3 = true;
if (bool1 && bool2) { }
bool3 = true; });
// swap dim's number
Object.keys(paralDim).map(item => {
if (bool3) {
if (paralDim[item].name === swapAxisArr[0]) {
paralDim[item].dim = dim2;
} }
}); if (paralDim[item].name === swapAxisArr[1]) {
// swap dim's number paralDim[item].dim = dim1;
Object.keys(paralDim).map(item => {
if (bool3) {
if (paralDim[item].name === this.state.swapAxisArr[0]) {
paralDim[item].dim = dim2;
}
if (paralDim[item].name === this.state.swapAxisArr[1]) {
paralDim[item].dim = dim1;
}
} }
}); }
paralDim.sort(this.sortDimY); });
// swap data array paralDim.sort(this.sortDimY);
Object.keys(paraData).map(paraItem => { // swap data array
Object.keys(paraData).map(paraItem => {
temp = paraData[paraItem][dim1];
paraData[paraItem][dim1] = paraData[paraItem][dim2]; temp = paraData[paraItem][dim1];
paraData[paraItem][dim2] = temp; paraData[paraItem][dim1] = paraData[paraItem][dim2];
}); paraData[paraItem][dim2] = temp;
} });
} }
componentDidMount() { componentWillReceiveProps(nextProps: ParaProps) {
const dataSource = nextProps.dataSource;
const expSearchSpace = nextProps.expSearchSpace;
const metricMax = nextProps.defaultMetric !== undefined
?
nextProps.defaultMetric[1]
:
1;
this.setState({ barColorMax: metricMax });
this.hyperParaPic(dataSource, expSearchSpace);
this._isMounted = true;
// default draw all data pic
this.hyperParaPic();
Para.intervalIDPara = window.setInterval(this.hyperParaPic, 10000);
} }
componentWillUnmount() { componentWillUnmount() {
this._isMounted = false; this._isMounted = false;
window.clearInterval(Para.intervalIDPara);
} }
render() { render() {
const { option, paraNodata, dimName } = this.state; const { option, paraNodata, dimName } = this.state;
const chartMulineStyle = {
width: '100%',
height: 392,
margin: '0 auto',
padding: '0 15 10 15'
};
return ( return (
<Row className="parameter"> <Row className="parameter">
<Row> <Row>
...@@ -439,7 +431,7 @@ class Para extends React.Component<{}, ParaState> { ...@@ -439,7 +431,7 @@ class Para extends React.Component<{}, ParaState> {
<Button <Button
type="primary" type="primary"
className="changeBtu tableButton" className="changeBtu tableButton"
onClick={this.swapBtn} onClick={this.reInit}
> >
Confirm Confirm
</Button> </Button>
...@@ -449,8 +441,8 @@ class Para extends React.Component<{}, ParaState> { ...@@ -449,8 +441,8 @@ class Para extends React.Component<{}, ParaState> {
<Row className="searcHyper"> <Row className="searcHyper">
<ReactEcharts <ReactEcharts
option={option} option={option}
style={chartMulineStyle} style={this.chartMulineStyle}
// lazyUpdate={true} lazyUpdate={true}
notMerge={true} // update now notMerge={true} // update now
/> />
<div className="noneData">{paraNodata}</div> <div className="noneData">{paraNodata}</div>
......
...@@ -2,9 +2,8 @@ import * as React from 'react'; ...@@ -2,9 +2,8 @@ import * as React from 'react';
import axios from 'axios'; import axios from 'axios';
import ReactEcharts from 'echarts-for-react'; import ReactEcharts from 'echarts-for-react';
import { import {
Row, Input, Table, Button, Popconfirm, Modal, Checkbox Row, Table, Button, Popconfirm, Modal, Checkbox
} from 'antd'; } from 'antd';
const { TextArea } = Input;
const CheckboxGroup = Checkbox.Group; const CheckboxGroup = Checkbox.Group;
import { MANAGER_IP, DOWNLOAD_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/const'; import { MANAGER_IP, DOWNLOAD_IP, trialJobStatus, COLUMN, COLUMN_INDEX } from '../../static/const';
import { convertDuration, intermediateGraphOption, killJob } from '../../static/function'; import { convertDuration, intermediateGraphOption, killJob } from '../../static/function';
...@@ -29,9 +28,7 @@ echarts.registerTheme('my_theme', { ...@@ -29,9 +28,7 @@ echarts.registerTheme('my_theme', {
interface TableListProps { interface TableListProps {
entries: number; entries: number;
tableSource: Array<TableObj>; tableSource: Array<TableObj>;
searchResult: Array<TableObj>;
updateList: Function; updateList: Function;
isHasSearch: boolean;
platform: string; platform: string;
} }
...@@ -78,6 +75,7 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -78,6 +75,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
.then(res => { .then(res => {
if (res.status === 200) { if (res.status === 200) {
const intermediateArr: number[] = []; const intermediateArr: number[] = [];
// support intermediate result is dict
Object.keys(res.data).map(item => { Object.keys(res.data).map(item => {
const temp = JSON.parse(res.data[item].data); const temp = JSON.parse(res.data[item].data);
if (typeof temp === 'object') { if (typeof temp === 'object') {
...@@ -244,10 +242,8 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -244,10 +242,8 @@ class TableList extends React.Component<TableListProps, TableListState> {
render() { render() {
const { entries, tableSource, searchResult, isHasSearch, updateList } = this.props; const { entries, tableSource, updateList } = this.props;
const { intermediateOption, modalVisible, isShowColumn, columnSelected, const { intermediateOption, modalVisible, isShowColumn, columnSelected} = this.state;
logMessage, logModal
} = this.state;
let showTitle = COLUMN; let showTitle = COLUMN;
let bgColor = ''; let bgColor = '';
const trialJob: Array<TrialJob> = []; const trialJob: Array<TrialJob> = [];
...@@ -340,7 +336,10 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -340,7 +336,10 @@ class TableList extends React.Component<TableListProps, TableListState> {
); );
}, },
filters: trialJob, filters: trialJob,
onFilter: (value: string, record: TableObj) => record.status.indexOf(value) === 0, onFilter: (value: string, record: TableObj) => {
return record.status.indexOf(value) === 0;
},
// onFilter: (value: string, record: TableObj) => record.status.indexOf(value) === 0,
sorter: (a: TableObj, b: TableObj): number => a.status.localeCompare(b.status) sorter: (a: TableObj, b: TableObj): number => a.status.localeCompare(b.status)
}); });
break; break;
...@@ -453,7 +452,7 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -453,7 +452,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
<Table <Table
columns={showColumn} columns={showColumn}
expandedRowRender={this.openRow} expandedRowRender={this.openRow}
dataSource={isHasSearch ? searchResult : tableSource} dataSource={tableSource}
className="commonTableStyle" className="commonTableStyle"
pagination={{ pageSize: entries }} pagination={{ pageSize: entries }}
/> />
...@@ -475,24 +474,6 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -475,24 +474,6 @@ class TableList extends React.Component<TableListProps, TableListState> {
theme="my_theme" theme="my_theme"
/> />
</Modal> </Modal>
{/* trial log modal */}
<Modal
title="trial log"
visible={logModal}
onCancel={this.hideLogModal}
footer={null}
destroyOnClose={true}
width="80%"
>
<div id="trialLogContent" style={{ height: window.innerHeight * 0.6 }}>
<TextArea
value={logMessage}
disabled={true}
className="logcontent"
/>
</div>
</Modal>
</div> </div>
{/* Add Column Modal */} {/* Add Column Modal */}
<Modal <Modal
......
...@@ -10,6 +10,11 @@ interface TableObj { ...@@ -10,6 +10,11 @@ interface TableObj {
color?: string; color?: string;
} }
interface SearchSpace {
_value: Array<number | string>;
_type: string;
}
interface FinalType { interface FinalType {
default: string; default: string;
} }
...@@ -21,6 +26,7 @@ interface ErrorParameter { ...@@ -21,6 +26,7 @@ interface ErrorParameter {
interface Parameters { interface Parameters {
parameters: ErrorParameter; parameters: ErrorParameter;
logPath?: string; logPath?: string;
intermediate?: Array<number>;
} }
interface Experiment { interface Experiment {
...@@ -54,6 +60,12 @@ interface DetailAccurPoint { ...@@ -54,6 +60,12 @@ interface DetailAccurPoint {
searchSpace: string; searchSpace: string;
} }
interface TooltipForIntermediate {
data: string;
seriesName: string;
dataIndex: number;
}
interface TooltipForAccuracy { interface TooltipForAccuracy {
data: Array<number | object>; data: Array<number | object>;
} }
...@@ -80,6 +92,10 @@ interface Dimobj { ...@@ -80,6 +92,10 @@ interface Dimobj {
min?: number; min?: number;
type?: string; type?: string;
data?: string[]; data?: string[];
boundaryGap?: boolean;
axisTick?: object;
axisLabel?: object;
axisLine?: object;
} }
interface ParaObj { interface ParaObj {
...@@ -87,11 +103,6 @@ interface ParaObj { ...@@ -87,11 +103,6 @@ interface ParaObj {
parallelAxis: Array<Dimobj>; parallelAxis: Array<Dimobj>;
} }
interface VisualMapValue {
maxAccuracy: number;
minAccuracy: number;
}
interface FinalResult { interface FinalResult {
data: string; data: string;
} }
...@@ -100,5 +111,6 @@ export { ...@@ -100,5 +111,6 @@ export {
TableObj, Parameters, Experiment, TableObj, Parameters, Experiment,
AccurPoint, TrialNumber, TrialJob, AccurPoint, TrialNumber, TrialJob,
DetailAccurPoint, TooltipForAccuracy, DetailAccurPoint, TooltipForAccuracy,
ParaObj, VisualMapValue, Dimobj, FinalResult, FinalType ParaObj, Dimobj, FinalResult, FinalType,
TooltipForIntermediate, SearchSpace
}; };
...@@ -13,7 +13,6 @@ $titleBgcolor: #b3b3b3; ...@@ -13,7 +13,6 @@ $titleBgcolor: #b3b3b3;
height: 22px; height: 22px;
margin-top: -8px; margin-top: -8px;
padding-left: 14px; padding-left: 14px;
padding-right: 14px;
} }
span{ span{
...@@ -22,9 +21,22 @@ $titleBgcolor: #b3b3b3; ...@@ -22,9 +21,22 @@ $titleBgcolor: #b3b3b3;
font-family: 'Segoe'; font-family: 'Segoe';
color: #333; color: #333;
line-height: 38px; line-height: 38px;
margin-left: 14px;
}
i{
font-size: 24px;
margin-left: 14px;
color: #545454;
position: relative;
top: 2px;
} }
} }
/* antd icon margin intermediate result style*/
#tabsty .anticon{
margin-right: 0;
}
.top10bg{ .top10bg{
background-color: $titleBgcolor; background-color: $titleBgcolor;
......
.parameter{ .parameter{
height: 100%; height: 100%;
}
.meline{ .meline{
margin-top: 15px; margin-top: 15px;
span{ span{
font-size: 14px; font-size: 14px;
margin-right: 6px; margin-right: 6px;
}
} }
} }
.searcHyper{ .searcHyper{
...@@ -24,4 +23,23 @@ ...@@ -24,4 +23,23 @@
font-size: 13px; font-size: 13px;
color: #999; color: #999;
} }
} }
\ No newline at end of file
/* Intermediate Result Style */
.intermediate{
/* border: 1px solid blue; */
input{
width: 80px;
height: 32px;
padding-left: 8px;
}
.strange{
margin-top: 2px;
}
.range{
.heng{
margin-left: 6px;
margin-right: 6px;
}
}
}
...@@ -76,8 +76,8 @@ def run(dispatch_type): ...@@ -76,8 +76,8 @@ def run(dispatch_type):
dipsatcher_list = TUNER_LIST if dispatch_type == 'Tuner' else ASSESSOR_LIST dipsatcher_list = TUNER_LIST if dispatch_type == 'Tuner' else ASSESSOR_LIST
for dispatcher_name in dipsatcher_list: for dispatcher_name in dipsatcher_list:
try: try:
# sleep 5 seconds here, to make sure previous stopped exp has enough time to exit to avoid port conflict # Sleep here to make sure previous stopped exp has enough time to exit to avoid port conflict
time.sleep(5) time.sleep(6)
test_builtin_dispatcher(dispatch_type, dispatcher_name) test_builtin_dispatcher(dispatch_type, dispatcher_name)
print(GREEN + 'Test %s %s: TEST PASS' % (dispatcher_name, dispatch_type) + CLEAR) print(GREEN + 'Test %s %s: TEST PASS' % (dispatcher_name, dispatch_type) + CLEAR)
except Exception as error: except Exception as error:
......
...@@ -36,6 +36,7 @@ Optional('nniManagerIp'): str, ...@@ -36,6 +36,7 @@ Optional('nniManagerIp'): str,
Optional('logDir'): os.path.isdir, Optional('logDir'): os.path.isdir,
Optional('debug'): bool, Optional('debug'): bool,
Optional('logLevel'): Or('trace', 'debug', 'info', 'warning', 'error', 'fatal'), Optional('logLevel'): Or('trace', 'debug', 'info', 'warning', 'error', 'fatal'),
Optional('logCollection'): Or('http', 'none'),
'useAnnotation': bool, 'useAnnotation': bool,
Optional('advisor'): Or({ Optional('advisor'): Or({
'builtinAdvisorName': Or('Hyperband'), 'builtinAdvisorName': Or('Hyperband'),
...@@ -57,6 +58,7 @@ Optional('tuner'): Or({ ...@@ -57,6 +58,7 @@ Optional('tuner'): Or({
Optional('classArgs'): { Optional('classArgs'): {
'optimize_mode': Or('maximize', 'minimize') 'optimize_mode': Or('maximize', 'minimize')
}, },
Optional('includeIntermediateResults'): bool,
Optional('gpuNum'): And(int, lambda x: 0 <= x <= 99999), Optional('gpuNum'): And(int, lambda x: 0 <= x <= 99999),
},{ },{
'builtinTunerName': Or('BatchTuner', 'GridSearch'), 'builtinTunerName': Or('BatchTuner', 'GridSearch'),
......
...@@ -274,6 +274,8 @@ def set_experiment(experiment_config, mode, port, config_file_name): ...@@ -274,6 +274,8 @@ def set_experiment(experiment_config, mode, port, config_file_name):
#debug mode should disable version check #debug mode should disable version check
if experiment_config.get('debug') is not None: if experiment_config.get('debug') is not None:
request_data['versionCheck'] = not experiment_config.get('debug') request_data['versionCheck'] = not experiment_config.get('debug')
if experiment_config.get('logCollection'):
request_data['logCollection'] = experiment_config.get('logCollection')
request_data['clusterMetaData'] = [] request_data['clusterMetaData'] = []
if experiment_config['trainingServicePlatform'] == 'local': if experiment_config['trainingServicePlatform'] == 'local':
......
...@@ -25,6 +25,7 @@ import logging ...@@ -25,6 +25,7 @@ import logging
import logging.handlers import logging.handlers
import time import time
import threading import threading
import re
from datetime import datetime from datetime import datetime
from enum import Enum, unique from enum import Enum, unique
...@@ -81,7 +82,7 @@ class RemoteLogger(object): ...@@ -81,7 +82,7 @@ class RemoteLogger(object):
""" """
NNI remote logger NNI remote logger
""" """
def __init__(self, syslog_host, syslog_port, tag, std_output_type, log_level=logging.INFO): def __init__(self, syslog_host, syslog_port, tag, std_output_type, log_collection, log_level=logging.INFO):
''' '''
constructor constructor
''' '''
...@@ -94,12 +95,13 @@ class RemoteLogger(object): ...@@ -94,12 +95,13 @@ class RemoteLogger(object):
self.orig_stdout = sys.__stdout__ self.orig_stdout = sys.__stdout__
else: else:
self.orig_stdout = sys.__stderr__ self.orig_stdout = sys.__stderr__
self.log_collection = log_collection
def get_pipelog_reader(self): def get_pipelog_reader(self):
''' '''
Get pipe for remote logger Get pipe for remote logger
''' '''
return PipeLogReader(self.logger, logging.INFO) return PipeLogReader(self.logger, self.log_collection, logging.INFO)
def write(self, buf): def write(self, buf):
''' '''
...@@ -117,7 +119,7 @@ class PipeLogReader(threading.Thread): ...@@ -117,7 +119,7 @@ class PipeLogReader(threading.Thread):
""" """
The reader thread reads log data from pipe The reader thread reads log data from pipe
""" """
def __init__(self, logger, log_level=logging.INFO): def __init__(self, logger, log_collection, log_level=logging.INFO):
"""Setup the object with a logger and a loglevel """Setup the object with a logger and a loglevel
and start the thread and start the thread
""" """
...@@ -131,6 +133,8 @@ class PipeLogReader(threading.Thread): ...@@ -131,6 +133,8 @@ class PipeLogReader(threading.Thread):
self.orig_stdout = sys.__stdout__ self.orig_stdout = sys.__stdout__
self._is_read_completed = False self._is_read_completed = False
self.process_exit = False self.process_exit = False
self.log_collection = log_collection
self.log_pattern = re.compile(r'^NNISDK_MEb\'.*\'$')
def _populateQueue(stream, queue): def _populateQueue(stream, queue):
''' '''
...@@ -143,8 +147,6 @@ class PipeLogReader(threading.Thread): ...@@ -143,8 +147,6 @@ class PipeLogReader(threading.Thread):
line = self.queue.get(True, 5) line = self.queue.get(True, 5)
try: try:
self.logger.log(self.log_level, line.rstrip()) self.logger.log(self.log_level, line.rstrip())
self.orig_stdout.write(line.rstrip() + '\n')
self.orig_stdout.flush()
except Exception as e: except Exception as e:
pass pass
except Exception as e: except Exception as e:
...@@ -165,9 +167,17 @@ class PipeLogReader(threading.Thread): ...@@ -165,9 +167,17 @@ class PipeLogReader(threading.Thread):
def run(self): def run(self):
"""Run the thread, logging everything. """Run the thread, logging everything.
If the log_collection is 'none', the log content will not be enqueued
""" """
for line in iter(self.pipeReader.readline, ''): for line in iter(self.pipeReader.readline, ''):
self.orig_stdout.write(line.rstrip() + '\n')
self.orig_stdout.flush()
if self.log_collection == 'none':
# If not match metrics, do not put the line into queue
if not self.log_pattern.match(line):
continue
self.queue.put(line) self.queue.put(line)
self.pipeReader.close() self.pipeReader.close()
def close(self): def close(self):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment