"docs/source/api/vscode:/vscode.git/clone" did not exist on "4a38166afeea498e8d333d40264e778ac5b16d81"
Unverified Commit 0663218b authored by SparkSnail's avatar SparkSnail Committed by GitHub
Browse files

Merge pull request #163 from Microsoft/master

merge master
parents 6c9360a5 cf983800
...@@ -19,11 +19,9 @@ ...@@ -19,11 +19,9 @@
# ================================================================================================== # ==================================================================================================
import inspect
import math
import random import random
from .common import env_args from .env_vars import trial_env_vars
from . import trial from . import trial
...@@ -44,7 +42,7 @@ __all__ = [ ...@@ -44,7 +42,7 @@ __all__ = [
# pylint: disable=unused-argument # pylint: disable=unused-argument
if env_args.platform is None: if trial_env_vars.NNI_PLATFORM is None:
def choice(*options, name=None): def choice(*options, name=None):
return random.choice(options) return random.choice(options)
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
import json_tricks import json_tricks
from .common import env_args from .env_vars import trial_env_vars
from . import platform from . import platform
...@@ -65,7 +65,7 @@ def report_intermediate_result(metric): ...@@ -65,7 +65,7 @@ def report_intermediate_result(metric):
assert _params is not None, 'nni.get_next_parameter() needs to be called before report_intermediate_result' assert _params is not None, 'nni.get_next_parameter() needs to be called before report_intermediate_result'
metric = json_tricks.dumps({ metric = json_tricks.dumps({
'parameter_id': _params['parameter_id'], 'parameter_id': _params['parameter_id'],
'trial_job_id': env_args.trial_job_id, 'trial_job_id': trial_env_vars.NNI_TRIAL_JOB_ID,
'type': 'PERIODICAL', 'type': 'PERIODICAL',
'sequence': _intermediate_seq, 'sequence': _intermediate_seq,
'value': metric 'value': metric
...@@ -81,7 +81,7 @@ def report_final_result(metric): ...@@ -81,7 +81,7 @@ def report_final_result(metric):
assert _params is not None, 'nni.get_next_parameter() needs to be called before report_final_result' assert _params is not None, 'nni.get_next_parameter() needs to be called before report_final_result'
metric = json_tricks.dumps({ metric = json_tricks.dumps({
'parameter_id': _params['parameter_id'], 'parameter_id': _params['parameter_id'],
'trial_job_id': env_args.trial_job_id, 'trial_job_id': trial_env_vars.NNI_TRIAL_JOB_ID,
'type': 'FINAL', 'type': 'FINAL',
'sequence': 0, # TODO: may be unnecessary 'sequence': 0, # TODO: may be unnecessary
'value': metric 'value': metric
......
...@@ -98,6 +98,12 @@ class Tuner(Recoverable): ...@@ -98,6 +98,12 @@ class Tuner(Recoverable):
checkpoin_path = self.get_checkpoint_path() checkpoin_path = self.get_checkpoint_path()
_logger.info('Save checkpoint ignored by tuner, checkpoint path: %s' % checkpoin_path) _logger.info('Save checkpoint ignored by tuner, checkpoint path: %s' % checkpoin_path)
def import_data(self, data):
"""Import additional data for tuning
data: a list of dictionarys, each of which has at least two keys, 'parameter' and 'value'
"""
pass
def _on_exit(self): def _on_exit(self):
pass pass
......
...@@ -18,8 +18,14 @@ ...@@ -18,8 +18,14 @@
# OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# ================================================================================================== # ==================================================================================================
import os
from .common import init_logger
from .env_vars import dispatcher_env_vars
def extract_scalar_reward(value, scalar_key='default'): def extract_scalar_reward(value, scalar_key='default'):
""" """
Extract scalar reward from trial result.
Raises Raises
------ ------
RuntimeError RuntimeError
...@@ -31,5 +37,23 @@ def extract_scalar_reward(value, scalar_key='default'): ...@@ -31,5 +37,23 @@ def extract_scalar_reward(value, scalar_key='default'):
elif isinstance(value, dict) and scalar_key in value and isinstance(value[scalar_key], (float, int)): elif isinstance(value, dict) and scalar_key in value and isinstance(value[scalar_key], (float, int)):
reward = value[scalar_key] reward = value[scalar_key]
else: else:
raise RuntimeError('Incorrect final result: the final result for %s should be float/int, or a dict which has a key named "default" whose value is float/int.' % str(self.__class__)) raise RuntimeError('Incorrect final result: the final result should be float/int, or a dict which has a key named "default" whose value is float/int.')
return reward return reward
\ No newline at end of file
def convert_dict2tuple(value):
"""
convert dict type to tuple to solve unhashable problem.
"""
if isinstance(value, dict):
for _keys in value:
value[_keys] = convert_dict2tuple(value[_keys])
return tuple(sorted(value.items()))
else:
return value
def init_dispatcher_logger():
""" Initialize dispatcher logging configuration"""
logger_file_path = 'dispatcher.log'
if dispatcher_env_vars.NNI_LOG_DIRECTORY is not None:
logger_file_path = os.path.join(dispatcher_env_vars.NNI_LOG_DIRECTORY, logger_file_path)
init_logger(logger_file_path, dispatcher_env_vars.NNI_LOG_LEVEL)
...@@ -32,10 +32,11 @@ interface OverviewState { ...@@ -32,10 +32,11 @@ interface OverviewState {
accNodata: string; accNodata: string;
trialNumber: TrialNumber; trialNumber: TrialNumber;
isTop10: boolean; isTop10: boolean;
titleMaxbgcolor: string; titleMaxbgcolor?: string;
titleMinbgcolor?: string; titleMinbgcolor?: string;
// trial stdout is content(false) or link(true) // trial stdout is content(false) or link(true)
isLogCollection: boolean; isLogCollection: boolean;
isMultiPhase: boolean;
} }
class Overview extends React.Component<{}, OverviewState> { class Overview extends React.Component<{}, OverviewState> {
...@@ -80,8 +81,8 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -80,8 +81,8 @@ class Overview extends React.Component<{}, OverviewState> {
totalCurrentTrial: 0 totalCurrentTrial: 0
}, },
isTop10: true, isTop10: true,
titleMaxbgcolor: '#999', isLogCollection: false,
isLogCollection: false isMultiPhase: false
}; };
} }
...@@ -94,39 +95,67 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -94,39 +95,67 @@ class Overview extends React.Component<{}, OverviewState> {
if (res.status === 200) { if (res.status === 200) {
let sessionData = res.data; let sessionData = res.data;
let trialPro = []; let trialPro = [];
const trainingPlatform = sessionData.params.trainingServicePlatform; const tempara = sessionData.params;
const trainingPlatform = tempara.trainingServicePlatform;
// assessor clusterMeteData // assessor clusterMeteData
const clusterMetaData = sessionData.params.clusterMetaData; const clusterMetaData = tempara.clusterMetaData;
const endTimenum = sessionData.endTime; const endTimenum = sessionData.endTime;
const assessor = sessionData.params.assessor; const assessor = tempara.assessor;
const advisor = sessionData.params.advisor; const advisor = tempara.advisor;
let optimizeMode = 'other';
if (tempara.tuner !== undefined) {
if (tempara.tuner.classArgs !== undefined) {
if (tempara.tuner.classArgs.optimize_mode !== undefined) {
optimizeMode = tempara.tuner.classArgs.optimize_mode;
}
}
}
// default logCollection is true // default logCollection is true
const logCollection = res.data.params.logCollection; const logCollection = tempara.logCollection;
let expLogCollection: boolean = false; let expLogCollection: boolean = false;
const isMultiy: boolean = tempara.multiPhase !== undefined
? tempara.multiPhase : false;
if (optimizeMode !== undefined) {
if (optimizeMode === 'minimize') {
if (this._isMounted) {
this.setState({
isTop10: false,
titleMinbgcolor: '#999'
});
}
} else {
if (this._isMounted) {
this.setState({
isTop10: true,
titleMaxbgcolor: '#999'
});
}
}
}
if (logCollection !== undefined && logCollection !== 'none') { if (logCollection !== undefined && logCollection !== 'none') {
expLogCollection = true; expLogCollection = true;
} }
trialPro.push({ trialPro.push({
id: sessionData.id, id: sessionData.id,
author: sessionData.params.authorName, author: tempara.authorName,
revision: sessionData.revision, revision: sessionData.revision,
experName: sessionData.params.experimentName, experName: tempara.experimentName,
runConcurren: sessionData.params.trialConcurrency, runConcurren: tempara.trialConcurrency,
logDir: sessionData.logDir ? sessionData.logDir : 'undefined', logDir: sessionData.logDir ? sessionData.logDir : 'undefined',
maxDuration: sessionData.params.maxExecDuration, maxDuration: tempara.maxExecDuration,
execDuration: sessionData.execDuration, execDuration: sessionData.execDuration,
MaxTrialNum: sessionData.params.maxTrialNum, MaxTrialNum: tempara.maxTrialNum,
startTime: sessionData.startTime, startTime: sessionData.startTime,
endTime: endTimenum ? endTimenum : undefined, endTime: endTimenum ? endTimenum : undefined,
trainingServicePlatform: trainingPlatform, trainingServicePlatform: trainingPlatform,
tuner: sessionData.params.tuner, tuner: tempara.tuner,
assessor: assessor ? assessor : undefined, assessor: assessor ? assessor : undefined,
advisor: advisor ? advisor : undefined, advisor: advisor ? advisor : undefined,
clusterMetaData: clusterMetaData ? clusterMetaData : undefined, clusterMetaData: clusterMetaData ? clusterMetaData : undefined,
logCollection: logCollection logCollection: logCollection
}); });
// search space format loguniform max and min // search space format loguniform max and min
const temp = sessionData.params.searchSpace; const temp = tempara.searchSpace;
const searchSpace = temp !== undefined const searchSpace = temp !== undefined
? JSON.parse(temp) : {}; ? JSON.parse(temp) : {};
Object.keys(searchSpace).map(item => { Object.keys(searchSpace).map(item => {
...@@ -148,7 +177,8 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -148,7 +177,8 @@ class Overview extends React.Component<{}, OverviewState> {
experimentAPI: res.data, experimentAPI: res.data,
trialProfile: trialPro[0], trialProfile: trialPro[0],
searchSpace: searchSpace, searchSpace: searchSpace,
isLogCollection: expLogCollection isLogCollection: expLogCollection,
isMultiPhase: isMultiy
}); });
} }
} }
...@@ -229,8 +259,10 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -229,8 +259,10 @@ class Overview extends React.Component<{}, OverviewState> {
const duration = (tableData[item].endTime - tableData[item].startTime) / 1000; const duration = (tableData[item].endTime - tableData[item].startTime) / 1000;
const acc = getFinal(tableData[item].finalMetricData); const acc = getFinal(tableData[item].finalMetricData);
// if hyperparameters is undefine, show error message, else, show parameters value // if hyperparameters is undefine, show error message, else, show parameters value
if (tableData[item].hyperParameters) { const tempara = tableData[item].hyperParameters;
const parameters = JSON.parse(tableData[item].hyperParameters[0]).parameters; if (tempara !== undefined) {
const tempLength = tempara.length;
const parameters = JSON.parse(tempara[tempLength - 1]).parameters;
if (typeof parameters === 'string') { if (typeof parameters === 'string') {
desJobDetail.parameters = JSON.parse(parameters); desJobDetail.parameters = JSON.parse(parameters);
} else { } else {
...@@ -315,8 +347,9 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -315,8 +347,9 @@ class Overview extends React.Component<{}, OverviewState> {
indexarr.push(items.sequenceId); indexarr.push(items.sequenceId);
}); });
const accOption = { const accOption = {
// support max show 0.0000000
grid: { grid: {
left: 40, left: 67,
right: 40 right: 40
}, },
tooltip: { tooltip: {
...@@ -396,7 +429,7 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -396,7 +429,7 @@ class Overview extends React.Component<{}, OverviewState> {
const { const {
trialProfile, searchSpace, tableData, accuracyData, trialProfile, searchSpace, tableData, accuracyData,
accNodata, status, errorStr, trialNumber, bestAccuracy, accNodata, status, errorStr, trialNumber, bestAccuracy, isMultiPhase,
titleMaxbgcolor, titleMinbgcolor, isLogCollection, experimentAPI titleMaxbgcolor, titleMinbgcolor, isLogCollection, experimentAPI
} = this.state; } = this.state;
...@@ -470,6 +503,7 @@ class Overview extends React.Component<{}, OverviewState> { ...@@ -470,6 +503,7 @@ class Overview extends React.Component<{}, OverviewState> {
<Col span={16} id="succeTable"> <Col span={16} id="succeTable">
<SuccessTable <SuccessTable
tableSource={tableData} tableSource={tableData}
multiphase={isMultiPhase}
logCollection={isLogCollection} logCollection={isLogCollection}
trainingPlatform={trialProfile.trainingServicePlatform} trainingPlatform={trialProfile.trainingServicePlatform}
/> />
......
...@@ -25,7 +25,7 @@ interface TrialDetailState { ...@@ -25,7 +25,7 @@ interface TrialDetailState {
experimentLogCollection: boolean; experimentLogCollection: boolean;
entriesTable: number; entriesTable: number;
searchSpace: string; searchSpace: string;
defaultMetric?: Array<number>; isMultiPhase: boolean;
} }
class TrialsDetail extends React.Component<{}, TrialDetailState> { class TrialsDetail extends React.Component<{}, TrialDetailState> {
...@@ -70,7 +70,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -70,7 +70,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
entriesTable: 20, entriesTable: 20,
isHasSearch: false, isHasSearch: false,
searchSpace: '', searchSpace: '',
defaultMetric: [0, 1] isMultiPhase: false
}; };
} }
...@@ -87,7 +87,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -87,7 +87,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
const metricSource = res1.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
let desc: Parameters = { let desc: Parameters = {
parameters: {}, parameters: {},
intermediate: [] intermediate: []
...@@ -108,8 +107,9 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -108,8 +107,9 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
duration = (new Date().getTime() - begin) / 1000; duration = (new Date().getTime() - begin) / 1000;
} }
} }
if (trialJobs[item].hyperParameters !== undefined) { const tempHyper = trialJobs[item].hyperParameters;
const getPara = JSON.parse(trialJobs[item].hyperParameters[0]).parameters; if (tempHyper !== undefined) {
const getPara = JSON.parse(tempHyper[tempHyper.length - 1]).parameters;
if (typeof getPara === 'string') { if (typeof getPara === 'string') {
desc.parameters = JSON.parse(getPara); desc.parameters = JSON.parse(getPara);
} else { } else {
...@@ -148,32 +148,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -148,32 +148,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
description: desc description: desc
}); });
}); });
// 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 // update search data result
const { searchResultSource } = this.state; const { searchResultSource } = this.state;
if (searchResultSource.length !== 0) { if (searchResultSource.length !== 0) {
...@@ -295,6 +269,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -295,6 +269,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
// default logCollection is true // default logCollection is true
const logCollection = res.data.params.logCollection; const logCollection = res.data.params.logCollection;
let expLogCollection: boolean = false; let expLogCollection: boolean = false;
const isMultiy: boolean = res.data.params.multiPhase !== undefined
? res.data.params.multiPhase : false;
if (logCollection !== undefined && logCollection !== 'none') { if (logCollection !== undefined && logCollection !== 'none') {
expLogCollection = true; expLogCollection = true;
} }
...@@ -302,7 +278,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -302,7 +278,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
this.setState({ this.setState({
experimentPlatform: trainingPlatform, experimentPlatform: trainingPlatform,
searchSpace: res.data.params.searchSpace, searchSpace: res.data.params.searchSpace,
experimentLogCollection: expLogCollection experimentLogCollection: expLogCollection,
isMultiPhase: isMultiy
}); });
} }
} }
...@@ -325,9 +302,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -325,9 +302,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
render() { render() {
const { const {
tableListSource, searchResultSource, isHasSearch, tableListSource, searchResultSource, isHasSearch, isMultiPhase,
entriesTable, experimentPlatform, searchSpace, entriesTable, experimentPlatform, searchSpace, experimentLogCollection
defaultMetric, experimentLogCollection
} = this.state; } = this.state;
const source = isHasSearch ? searchResultSource : tableListSource; const source = isHasSearch ? searchResultSource : tableListSource;
return ( return (
...@@ -347,7 +323,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -347,7 +323,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
<Para <Para
dataSource={source} dataSource={source}
expSearchSpace={searchSpace} expSearchSpace={searchSpace}
defaultMetric={defaultMetric}
/> />
</Row> </Row>
</TabPane> </TabPane>
...@@ -401,6 +376,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> { ...@@ -401,6 +376,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
<TableList <TableList
entries={entriesTable} entries={entriesTable}
tableSource={source} tableSource={source}
isMultiPhase={isMultiPhase}
platform={experimentPlatform} platform={experimentPlatform}
updateList={this.getDetailSource} updateList={this.getDetailSource}
logCollection={experimentLogCollection} logCollection={experimentLogCollection}
......
...@@ -161,13 +161,14 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -161,13 +161,14 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
const bar2Percent = (bar2 / trialProfile.MaxTrialNum) * 100; const bar2Percent = (bar2 / trialProfile.MaxTrialNum) * 100;
const percent = (trialProfile.execDuration / trialProfile.maxDuration) * 100; const percent = (trialProfile.execDuration / trialProfile.maxDuration) * 100;
const runDuration = convertTime(trialProfile.execDuration); const runDuration = convertTime(trialProfile.execDuration);
const temp = trialProfile.maxDuration - trialProfile.execDuration;
let remaining; let remaining;
if (status === 'DONE') { let errorContent;
if (temp < 0) {
remaining = '0'; remaining = '0';
} else { } else {
remaining = convertTime(trialProfile.maxDuration - trialProfile.execDuration); remaining = convertTime(temp);
} }
let errorContent;
if (errors !== '') { if (errors !== '') {
errorContent = ( errorContent = (
<div className="errors"> <div className="errors">
...@@ -225,33 +226,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -225,33 +226,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
<Col span={6}> <Col span={6}>
<Row className="basic colorOfbasic"> <Row className="basic colorOfbasic">
<p>Remaining</p> <p>Remaining</p>
<div>{remaining}</div> <div className="time">{remaining}</div>
</Row>
</Col>
<Col span={6}>
<Row className="basic colorOfbasic">
<p>Running</p>
<div>{trialNumber.runTrial}</div>
</Row>
</Col>
<Col span={6}>
<Row className="basic colorOfbasic">
<p>Succeeded</p>
<div>{trialNumber.succTrial}</div>
</Row>
</Col>
</Row>
<Row className="mess">
<Col span={6}>
<Row className="basic">
<p>Stopped</p>
<div>{trialNumber.stopTrial}</div>
</Row>
</Col>
<Col span={6}>
<Row className="basic">
<p>Failed</p>
<div>{trialNumber.failTrial}</div>
</Row> </Row>
</Col> </Col>
<Col span={12}> <Col span={12}>
...@@ -282,6 +257,33 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -282,6 +257,33 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
</Row> </Row>
</Col> </Col>
</Row> </Row>
<Row className="mess">
<Col span={6}>
<Row className="basic colorOfbasic">
<p>Running</p>
<div>{trialNumber.runTrial}</div>
</Row>
</Col>
<Col span={6}>
<Row className="basic colorOfbasic">
<p>Succeeded</p>
<div>{trialNumber.succTrial}</div>
</Row>
</Col>
<Col span={6}>
<Row className="basic">
<p>Stopped</p>
<div>{trialNumber.stopTrial}</div>
</Row>
</Col>
<Col span={6}>
<Row className="basic">
<p>Failed</p>
<div>{trialNumber.failTrial}</div>
</Row>
</Col>
</Row>
</Row> </Row>
); );
} }
......
...@@ -11,6 +11,7 @@ interface SuccessTableProps { ...@@ -11,6 +11,7 @@ interface SuccessTableProps {
tableSource: Array<TableObj>; tableSource: Array<TableObj>;
trainingPlatform: string; trainingPlatform: string;
logCollection: boolean; logCollection: boolean;
multiphase: boolean;
} }
class SuccessTable extends React.Component<SuccessTableProps, {}> { class SuccessTable extends React.Component<SuccessTableProps, {}> {
...@@ -23,12 +24,13 @@ class SuccessTable extends React.Component<SuccessTableProps, {}> { ...@@ -23,12 +24,13 @@ class SuccessTable extends React.Component<SuccessTableProps, {}> {
} }
openRow = (record: TableObj) => { openRow = (record: TableObj) => {
const { trainingPlatform, logCollection } = this.props; const { trainingPlatform, logCollection, multiphase } = this.props;
return ( return (
<OpenRow <OpenRow
trainingPlatform={trainingPlatform} trainingPlatform={trainingPlatform}
record={record} record={record}
logCollection={logCollection} logCollection={logCollection}
multiphase={multiphase}
/> />
); );
} }
......
...@@ -4,6 +4,8 @@ import PaiTrialLog from '../public-child/PaiTrialLog'; ...@@ -4,6 +4,8 @@ import PaiTrialLog from '../public-child/PaiTrialLog';
import TrialLog from '../public-child/TrialLog'; import TrialLog from '../public-child/TrialLog';
import { TableObj } from '../../static/interface'; import { TableObj } from '../../static/interface';
import { Row, Tabs, Button, message } from 'antd'; import { Row, Tabs, Button, message } from 'antd';
import { MANAGER_IP } from '../../static/const';
import '../../static/style/overview.scss';
import JSONTree from 'react-json-tree'; import JSONTree from 'react-json-tree';
const TabPane = Tabs.TabPane; const TabPane = Tabs.TabPane;
...@@ -11,6 +13,7 @@ interface OpenRowProps { ...@@ -11,6 +13,7 @@ interface OpenRowProps {
trainingPlatform: string; trainingPlatform: string;
record: TableObj; record: TableObj;
logCollection: boolean; logCollection: boolean;
multiphase: boolean;
} }
interface OpenRowState { interface OpenRowState {
...@@ -46,7 +49,7 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> { ...@@ -46,7 +49,7 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
} }
render() { render() {
const { trainingPlatform, record, logCollection } = this.props; const { trainingPlatform, record, logCollection, multiphase } = this.props;
const { idList } = this.state; const { idList } = this.state;
let isClick = false; let isClick = false;
let isHasParameters = true; let isHasParameters = true;
...@@ -54,9 +57,8 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> { ...@@ -54,9 +57,8 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
if (record.description.parameters.error) { if (record.description.parameters.error) {
isHasParameters = false; isHasParameters = false;
} }
const openRowDataSource = { const openRowDataSource = record.description.parameters;
parameters: record.description.parameters const trialink: string = `${MANAGER_IP}/trial-jobs/${record.id}`;
};
const logPathRow = record.description.logPath !== undefined const logPathRow = record.description.logPath !== undefined
? ?
record.description.logPath record.description.logPath
...@@ -66,6 +68,19 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> { ...@@ -66,6 +68,19 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
<Row className="openRowContent hyperpar"> <Row className="openRowContent hyperpar">
<Tabs tabPosition="left" className="card"> <Tabs tabPosition="left" className="card">
<TabPane tab="Parameters" key="1"> <TabPane tab="Parameters" key="1">
{
multiphase
?
<Row className="link">
Trails for multiphase experiment will return a set of parameters,
we are listing the latest parameter in webportal.
<br />
For the entire parameter set, please refer to the following "
<a href={trialink} target="_blank">{trialink}</a>".
</Row>
:
<div />
}
{ {
isHasParameters isHasParameters
? ?
...@@ -74,13 +89,13 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> { ...@@ -74,13 +89,13 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
{ {
isClick isClick
? ?
<pre>{JSON.stringify(openRowDataSource.parameters, null, 4)}</pre> <pre>{JSON.stringify(openRowDataSource, null, 4)}</pre>
: :
<JSONTree <JSONTree
hideRoot={true} hideRoot={true}
shouldExpandNode={() => true} // default expandNode shouldExpandNode={() => true} // default expandNode
getItemString={() => (<span />)} // remove the {} items getItemString={() => (<span />)} // remove the {} items
data={openRowDataSource.parameters} data={openRowDataSource}
/> />
} }
</Row> </Row>
......
...@@ -17,14 +17,13 @@ interface ParaState { ...@@ -17,14 +17,13 @@ interface ParaState {
swapAxisArr: Array<string>; swapAxisArr: Array<string>;
percent: number; percent: number;
paraNodata: string; paraNodata: string;
barColorMax: number; max: number; // graph color bar limit
barColorMin: number; min: number;
} }
interface ParaProps { interface ParaProps {
dataSource: Array<TableObj>; dataSource: Array<TableObj>;
expSearchSpace: string; expSearchSpace: string;
defaultMetric: Array<number> | undefined;
} }
message.config({ message.config({
...@@ -58,16 +57,8 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -58,16 +57,8 @@ class Para extends React.Component<ParaProps, ParaState> {
swapAxisArr: [], swapAxisArr: [],
percent: 0, percent: 0,
paraNodata: '', paraNodata: '',
barColorMax: this.props.defaultMetric !== undefined min: 0,
? max: 1
this.props.defaultMetric[1]
:
1,
barColorMin: this.props.defaultMetric !== undefined
?
this.props.defaultMetric[0]
:
1
}; };
} }
...@@ -107,7 +98,7 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -107,7 +98,7 @@ class Para extends React.Component<ParaProps, ParaState> {
parallelAxis.push({ parallelAxis.push({
dim: i, dim: i,
name: dimName[i], name: dimName[i],
max: searchKey._value[0], max: searchKey._value[0] - 1,
min: 0 min: 0
}); });
break; break;
...@@ -217,7 +208,11 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -217,7 +208,11 @@ class Para extends React.Component<ParaProps, ParaState> {
eachTrialParams.push(temp.description.parameters); eachTrialParams.push(temp.description.parameters);
} }
}); });
this.getParallelAxis(dimName, searchRange, accPara, eachTrialParams, paraYdata); if (this._isMounted) {
this.setState({ max: Math.max(...accPara), min: Math.min(...accPara) }, () => {
this.getParallelAxis(dimName, searchRange, accPara, eachTrialParams, paraYdata);
});
}
} }
// get percent value number // get percent value number
...@@ -233,11 +228,11 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -233,11 +228,11 @@ class Para extends React.Component<ParaProps, ParaState> {
// deal with response data into pic data // deal with response data into pic data
getOption = (dataObj: ParaObj) => { getOption = (dataObj: ParaObj) => {
const {barColorMax, barColorMin} = this.state; const { max, min } = this.state;
let parallelAxis = dataObj.parallelAxis; let parallelAxis = dataObj.parallelAxis;
let paralleData = dataObj.data; let paralleData = dataObj.data;
let visualMapObj = {}; let visualMapObj = {};
if (barColorMax === barColorMin) { if (max === min) {
visualMapObj = { visualMapObj = {
type: 'continuous', type: 'continuous',
precision: 3, precision: 3,
...@@ -248,8 +243,8 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -248,8 +243,8 @@ class Para extends React.Component<ParaProps, ParaState> {
bottom: '20px', bottom: '20px',
type: 'continuous', type: 'continuous',
precision: 3, precision: 3,
min: barColorMin, min: min,
max: barColorMax, max: max,
color: ['#CA0000', '#FFC400', '#90EE90'] color: ['#CA0000', '#FFC400', '#90EE90']
}; };
} }
...@@ -379,12 +374,6 @@ class Para extends React.Component<ParaProps, ParaState> { ...@@ -379,12 +374,6 @@ class Para extends React.Component<ParaProps, ParaState> {
componentWillReceiveProps(nextProps: ParaProps) { componentWillReceiveProps(nextProps: ParaProps) {
const dataSource = nextProps.dataSource; const dataSource = nextProps.dataSource;
const expSearchSpace = nextProps.expSearchSpace; const expSearchSpace = nextProps.expSearchSpace;
const metricMax = nextProps.defaultMetric !== undefined
?
nextProps.defaultMetric[1]
:
1;
this.setState({ barColorMax: metricMax });
this.hyperParaPic(dataSource, expSearchSpace); this.hyperParaPic(dataSource, expSearchSpace);
} }
......
...@@ -32,6 +32,7 @@ interface TableListProps { ...@@ -32,6 +32,7 @@ interface TableListProps {
updateList: Function; updateList: Function;
platform: string; platform: string;
logCollection: boolean; logCollection: boolean;
isMultiPhase: boolean;
} }
interface TableListState { interface TableListState {
...@@ -175,12 +176,13 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -175,12 +176,13 @@ class TableList extends React.Component<TableListProps, TableListState> {
} }
openRow = (record: TableObj) => { openRow = (record: TableObj) => {
const { platform, logCollection } = this.props; const { platform, logCollection, isMultiPhase } = this.props;
return ( return (
<OpenRow <OpenRow
trainingPlatform={platform} trainingPlatform={platform}
record={record} record={record}
logCollection={logCollection} logCollection={logCollection}
multiphase={isMultiPhase}
/> />
); );
} }
...@@ -386,16 +388,23 @@ class TableList extends React.Component<TableListProps, TableListState> { ...@@ -386,16 +388,23 @@ class TableList extends React.Component<TableListProps, TableListState> {
key: item, key: item,
width: 150, width: 150,
render: (text: string, record: TableObj) => { render: (text: string, record: TableObj) => {
return ( const temp = record.acc;
<div> let decimals = 0;
{ let other = '';
record.acc if (temp !== undefined) {
? if (temp[item].toString().indexOf('.') !== -1) {
record.acc[item] decimals = temp[item].toString().length - temp[item].toString().indexOf('.') - 1;
: if (decimals > 6) {
'--' other = `${temp[item].toFixed(6)}`;
} else {
other = temp[item].toString();
} }
</div> }
} else {
other = '--';
}
return (
<div>{other}</div>
); );
} }
}); });
......
...@@ -34,11 +34,11 @@ const convertDuration = (num: number) => { ...@@ -34,11 +34,11 @@ const convertDuration = (num: number) => {
// get final result value // get final result value
// draw Accuracy point graph // draw Accuracy point graph
const getFinalResult = (final: FinalResult) => { const getFinalResult = (final: Array<FinalResult>) => {
let acc; let acc;
let showDefault = 0; let showDefault = 0;
if (final) { if (final) {
acc = JSON.parse(final[0].data); acc = JSON.parse(final[final.length - 1].data);
if (typeof (acc) === 'object') { if (typeof (acc) === 'object') {
if (acc.default) { if (acc.default) {
showDefault = acc.default; showDefault = acc.default;
...@@ -53,10 +53,10 @@ const getFinalResult = (final: FinalResult) => { ...@@ -53,10 +53,10 @@ const getFinalResult = (final: FinalResult) => {
}; };
// get final result value // acc obj // get final result value // acc obj
const getFinal = (final: FinalResult) => { const getFinal = (final: Array<FinalResult>) => {
let showDefault: FinalType; let showDefault: FinalType;
if (final) { if (final) {
showDefault = JSON.parse(final[0].data); showDefault = JSON.parse(final[final.length - 1].data);
if (typeof showDefault === 'number') { if (typeof showDefault === 'number') {
showDefault = { default: showDefault }; showDefault = { default: showDefault };
} }
......
...@@ -49,3 +49,7 @@ ...@@ -49,3 +49,7 @@
} }
} }
.link{
margin-bottom: 10px;
}
...@@ -61,6 +61,11 @@ ...@@ -61,6 +61,11 @@
div{ div{
color: #0573bc; color: #0573bc;
} }
.time{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
} }
.mess{ .mess{
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import sys
import glob
import argparse import argparse
from utils import get_yml_content, dump_yml_content from utils import get_yml_content, dump_yml_content
...@@ -69,6 +71,19 @@ def update_training_service_config(args): ...@@ -69,6 +71,19 @@ def update_training_service_config(args):
dump_yml_content(TRAINING_SERVICE_FILE, config) dump_yml_content(TRAINING_SERVICE_FILE, config)
def convert_command():
'''convert command by platform'''
if sys.platform != 'win32':
return None
config_files = glob.glob('./**/*.yml') + glob.glob('./**/**/*.yml')
for config_file in config_files:
print('processing {}'.format(config_file))
yml_content = get_yml_content(config_file)
if yml_content.get('trial'):
if yml_content['trial'].get('command'):
yml_content['trial']['command'] = yml_content['trial']['command'].replace('python3', 'python')
dump_yml_content(config_file, yml_content)
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument("--ts", type=str, choices=['pai', 'kubeflow', 'remote'], default='pai') parser.add_argument("--ts", type=str, choices=['pai', 'kubeflow', 'remote'], default='pai')
...@@ -96,3 +111,4 @@ if __name__ == '__main__': ...@@ -96,3 +111,4 @@ if __name__ == '__main__':
args = parser.parse_args() args = parser.parse_args()
update_training_service_config(args) update_training_service_config(args)
convert_command()
jobs:
- job: 'Test'
steps:
- script: |
powershell.exe -file install.ps1
displayName: 'Install nni toolkit via source code'
- script: |
python -m pip install scikit-learn==0.20.0 --user
python -m pip install keras==2.1.6 --user
python -m pip install https://download.pytorch.org/whl/cu90/torch-0.4.1-cp36-cp36m-win_amd64.whl --user
python -m pip install torchvision --user
python -m pip install tensorflow-gpu==1.11.0 --user
displayName: 'Install dependencies for integration tests'
- script: |
cd test
python generate_ts_config.py
displayName: 'generate config files'
- script: |
cd test
python config_test.py --ts local --local_gpu --exclude smac,bohb
displayName: 'Examples and advanced features tests on local machine'
- script: |
cd test
powershell.exe -file unittest.ps1
displayName: 'unit test'
- script: |
cd test
python naive_test.py
displayName: 'Naive test'
- script: |
cd test
python tuner_test.py
displayName: 'Built-in tuners / assessors tests'
- script: |
cd test
python metrics_test.py
displayName: 'Trial job metrics test'
$CWD = $PWD
# -------------For python unittest-------------
## ------Run annotation test------
echo ""
echo "===========================Testing: nni_annotation==========================="
cd $CWD/../tools/
python -m unittest -v nni_annotation/test_annotation.py
## Export certain environment variables for unittest code to work
$env:NNI_TRIAL_JOB_ID="test_trial_job_id"
$env:NNI_PLATFORM="unittest"
## ------Run sdk test------
echo ""
echo "===========================Testing: nni_sdk==========================="
cd $CWD/../src/sdk/pynni/
python -m unittest discover -v tests
# -------------For typescript unittest-------------
cd $CWD/../src/nni_manager
echo ""
echo "===========================Testing: nni_manager==========================="
npm run test
...@@ -22,9 +22,10 @@ import contextlib ...@@ -22,9 +22,10 @@ import contextlib
import collections import collections
import json import json
import os import os
import sys
import subprocess import subprocess
import requests import requests
import yaml import ruamel.yaml as yaml
EXPERIMENT_DONE_SIGNAL = '"Experiment done"' EXPERIMENT_DONE_SIGNAL = '"Experiment done"'
...@@ -55,7 +56,7 @@ def remove_files(file_list): ...@@ -55,7 +56,7 @@ def remove_files(file_list):
def get_yml_content(file_path): def get_yml_content(file_path):
'''Load yaml file content''' '''Load yaml file content'''
with open(file_path, 'r') as file: with open(file_path, 'r') as file:
return yaml.load(file) return yaml.load(file, Loader=yaml.Loader)
def dump_yml_content(file_path, content): def dump_yml_content(file_path, content):
'''Dump yaml file content''' '''Dump yaml file content'''
...@@ -65,7 +66,7 @@ def dump_yml_content(file_path, content): ...@@ -65,7 +66,7 @@ def dump_yml_content(file_path, content):
def setup_experiment(installed=True): def setup_experiment(installed=True):
'''setup the experiment if nni is not installed''' '''setup the experiment if nni is not installed'''
if not installed: if not installed:
os.environ['PATH'] = os.environ['PATH'] + ':' + os.environ['PWD'] os.environ['PATH'] = os.environ['PATH'] + ':' + os.getcwd()
sdk_path = os.path.abspath('../src/sdk/pynni') sdk_path = os.path.abspath('../src/sdk/pynni')
cmd_path = os.path.abspath('../tools') cmd_path = os.path.abspath('../tools')
pypath = os.environ.get('PYTHONPATH') pypath = os.environ.get('PYTHONPATH')
...@@ -79,7 +80,7 @@ def fetch_nni_log_path(experiment_url): ...@@ -79,7 +80,7 @@ def fetch_nni_log_path(experiment_url):
'''get nni's log path from nni's experiment url''' '''get nni's log path from nni's experiment url'''
experiment_profile = requests.get(experiment_url) experiment_profile = requests.get(experiment_url)
experiment_id = json.loads(experiment_profile.text)['id'] experiment_id = json.loads(experiment_profile.text)['id']
experiment_path = os.path.join(os.environ['HOME'], 'nni/experiments', experiment_id) experiment_path = os.path.join(os.path.expanduser('~'), 'nni', 'experiments', experiment_id)
nnimanager_log_path = os.path.join(experiment_path, 'log', 'nnimanager.log') nnimanager_log_path = os.path.join(experiment_path, 'log', 'nnimanager.log')
return nnimanager_log_path return nnimanager_log_path
...@@ -87,7 +88,10 @@ def fetch_nni_log_path(experiment_url): ...@@ -87,7 +88,10 @@ def fetch_nni_log_path(experiment_url):
def is_experiment_done(nnimanager_log_path): def is_experiment_done(nnimanager_log_path):
'''check if the experiment is done successfully''' '''check if the experiment is done successfully'''
assert os.path.exists(nnimanager_log_path), 'Experiment starts failed' assert os.path.exists(nnimanager_log_path), 'Experiment starts failed'
cmds = ['cat', nnimanager_log_path, '|', 'grep', EXPERIMENT_DONE_SIGNAL] if sys.platform == "win32":
cmds = ['type', nnimanager_log_path, '|', 'find', EXPERIMENT_DONE_SIGNAL]
else:
cmds = ['cat', nnimanager_log_path, '|', 'grep', EXPERIMENT_DONE_SIGNAL]
completed_process = subprocess.run(' '.join(cmds), shell=True) completed_process = subprocess.run(' '.join(cmds), shell=True)
return completed_process.returncode == 0 return completed_process.returncode == 0
...@@ -112,7 +116,10 @@ def print_stderr(trial_jobs_url): ...@@ -112,7 +116,10 @@ def print_stderr(trial_jobs_url):
for trial_job in trial_jobs: for trial_job in trial_jobs:
if trial_job['status'] == 'FAILED': if trial_job['status'] == 'FAILED':
stderr_path = trial_job['stderrPath'].split(':')[-1] stderr_path = trial_job['stderrPath'].split(':')[-1]
subprocess.run(['cat', stderr_path]) if sys.platform == "win32":
subprocess.run(['type', stderr_path], shell=True)
else:
subprocess.run(['cat', stderr_path])
def parse_max_duration_time(max_exec_duration): def parse_max_duration_time(max_exec_duration):
unit = max_exec_duration[-1] unit = max_exec_duration[-1]
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
import os import os
import sys
import shutil import shutil
from . import code_generator from . import code_generator
...@@ -28,6 +29,9 @@ from . import search_space_generator ...@@ -28,6 +29,9 @@ from . import search_space_generator
__all__ = ['generate_search_space', 'expand_annotations'] __all__ = ['generate_search_space', 'expand_annotations']
slash = '/'
if sys.platform == "win32":
slash = '\\'
def generate_search_space(code_dir): def generate_search_space(code_dir):
"""Generate search space from Python source code. """Generate search space from Python source code.
...@@ -35,8 +39,8 @@ def generate_search_space(code_dir): ...@@ -35,8 +39,8 @@ def generate_search_space(code_dir):
code_dir: directory path of source files (str) code_dir: directory path of source files (str)
""" """
search_space = {} search_space = {}
if code_dir.endswith('/'): if code_dir.endswith(slash):
code_dir = code_dir[:-1] code_dir = code_dir[:-1]
for subdir, _, files in os.walk(code_dir): for subdir, _, files in os.walk(code_dir):
...@@ -44,9 +48,9 @@ def generate_search_space(code_dir): ...@@ -44,9 +48,9 @@ def generate_search_space(code_dir):
if subdir == code_dir: if subdir == code_dir:
package = '' package = ''
else: else:
assert subdir.startswith(code_dir + '/'), subdir assert subdir.startswith(code_dir + slash), subdir
prefix_len = len(code_dir) + 1 prefix_len = len(code_dir) + 1
package = subdir[prefix_len:].replace('/', '.') + '.' package = subdir[prefix_len:].replace(slash, '.') + '.'
for file_name in files: for file_name in files:
if file_name.endswith('.py'): if file_name.endswith('.py'):
...@@ -76,9 +80,10 @@ def expand_annotations(src_dir, dst_dir): ...@@ -76,9 +80,10 @@ def expand_annotations(src_dir, dst_dir):
src_dir: directory path of user code (str) src_dir: directory path of user code (str)
dst_dir: directory to place generated files (str) dst_dir: directory to place generated files (str)
""" """
if src_dir[-1] == '/': if src_dir[-1] == slash:
src_dir = src_dir[:-1] src_dir = src_dir[:-1]
if dst_dir[-1] == '/':
if dst_dir[-1] == slash:
dst_dir = dst_dir[:-1] dst_dir = dst_dir[:-1]
annotated = False annotated = False
......
from subprocess import call, check_output
import sys
import os
import signal
import psutil
from .common_utils import print_error, print_normal, print_warning
def check_output_command(file_path, head=None, tail=None):
'''call check_output command to read content from a file'''
if os.path.exists(file_path):
if sys.platform == 'win32':
cmds = ['powershell.exe', 'type', file_path]
if head:
cmds += ['|', 'select', '-first', str(head)]
elif tail:
cmds += ['|', 'select', '-last', str(tail)]
return check_output(cmds, shell=True).decode('utf-8')
else:
cmds = ['cat', file_path]
if head:
cmds = ['head', '-' + str(head), file_path]
elif tail:
cmds = ['tail', '-' + str(tail), file_path]
return check_output(cmds, shell=False).decode('utf-8')
else:
print_error('{0} does not exist!'.format(file_path))
exit(1)
def kill_command(pid):
'''kill command'''
if sys.platform == 'win32':
process = psutil.Process(pid=pid)
process.send_signal(signal.CTRL_BREAK_EVENT)
else:
cmds = ['kill', str(pid)]
call(cmds)
def install_package_command(package_name):
'''install python package from pip'''
#TODO refactor python logic
if sys.platform == "win32":
cmds = 'python -m pip install --user {0}'.format(package_name)
else:
cmds = 'python3 -m pip install --user {0}'.format(package_name)
call(cmds, shell=True)
def install_requirements_command(requirements_path):
'''install requirements.txt'''
cmds = 'cd ' + requirements_path + ' && {0} -m pip install --user -r requirements.txt'
#TODO refactor python logic
if sys.platform == "win32":
cmds = cmds.format('python')
else:
cmds = cmds.format('python3')
call(cmds, shell=True)
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