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 @@
# ==================================================================================================
import inspect
import math
import random
from .common import env_args
from .env_vars import trial_env_vars
from . import trial
......@@ -44,7 +42,7 @@ __all__ = [
# pylint: disable=unused-argument
if env_args.platform is None:
if trial_env_vars.NNI_PLATFORM is None:
def choice(*options, name=None):
return random.choice(options)
......
......@@ -21,7 +21,7 @@
import json_tricks
from .common import env_args
from .env_vars import trial_env_vars
from . import platform
......@@ -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'
metric = json_tricks.dumps({
'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',
'sequence': _intermediate_seq,
'value': 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'
metric = json_tricks.dumps({
'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',
'sequence': 0, # TODO: may be unnecessary
'value': metric
......
......@@ -98,6 +98,12 @@ class Tuner(Recoverable):
checkpoin_path = self.get_checkpoint_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):
pass
......
......@@ -18,8 +18,14 @@
# 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'):
"""
Extract scalar reward from trial result.
Raises
------
RuntimeError
......@@ -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)):
reward = value[scalar_key]
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__))
return reward
\ No newline at end of file
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
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 {
accNodata: string;
trialNumber: TrialNumber;
isTop10: boolean;
titleMaxbgcolor: string;
titleMaxbgcolor?: string;
titleMinbgcolor?: string;
// trial stdout is content(false) or link(true)
isLogCollection: boolean;
isMultiPhase: boolean;
}
class Overview extends React.Component<{}, OverviewState> {
......@@ -80,8 +81,8 @@ class Overview extends React.Component<{}, OverviewState> {
totalCurrentTrial: 0
},
isTop10: true,
titleMaxbgcolor: '#999',
isLogCollection: false
isLogCollection: false,
isMultiPhase: false
};
}
......@@ -94,39 +95,67 @@ class Overview extends React.Component<{}, OverviewState> {
if (res.status === 200) {
let sessionData = res.data;
let trialPro = [];
const trainingPlatform = sessionData.params.trainingServicePlatform;
const tempara = sessionData.params;
const trainingPlatform = tempara.trainingServicePlatform;
// assessor clusterMeteData
const clusterMetaData = sessionData.params.clusterMetaData;
const clusterMetaData = tempara.clusterMetaData;
const endTimenum = sessionData.endTime;
const assessor = sessionData.params.assessor;
const advisor = sessionData.params.advisor;
const assessor = tempara.assessor;
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
const logCollection = res.data.params.logCollection;
const logCollection = tempara.logCollection;
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') {
expLogCollection = true;
}
trialPro.push({
id: sessionData.id,
author: sessionData.params.authorName,
author: tempara.authorName,
revision: sessionData.revision,
experName: sessionData.params.experimentName,
runConcurren: sessionData.params.trialConcurrency,
experName: tempara.experimentName,
runConcurren: tempara.trialConcurrency,
logDir: sessionData.logDir ? sessionData.logDir : 'undefined',
maxDuration: sessionData.params.maxExecDuration,
maxDuration: tempara.maxExecDuration,
execDuration: sessionData.execDuration,
MaxTrialNum: sessionData.params.maxTrialNum,
MaxTrialNum: tempara.maxTrialNum,
startTime: sessionData.startTime,
endTime: endTimenum ? endTimenum : undefined,
trainingServicePlatform: trainingPlatform,
tuner: sessionData.params.tuner,
tuner: tempara.tuner,
assessor: assessor ? assessor : undefined,
advisor: advisor ? advisor : undefined,
clusterMetaData: clusterMetaData ? clusterMetaData : undefined,
logCollection: logCollection
});
// search space format loguniform max and min
const temp = sessionData.params.searchSpace;
const temp = tempara.searchSpace;
const searchSpace = temp !== undefined
? JSON.parse(temp) : {};
Object.keys(searchSpace).map(item => {
......@@ -148,7 +177,8 @@ class Overview extends React.Component<{}, OverviewState> {
experimentAPI: res.data,
trialProfile: trialPro[0],
searchSpace: searchSpace,
isLogCollection: expLogCollection
isLogCollection: expLogCollection,
isMultiPhase: isMultiy
});
}
}
......@@ -229,8 +259,10 @@ class Overview extends React.Component<{}, OverviewState> {
const duration = (tableData[item].endTime - tableData[item].startTime) / 1000;
const acc = getFinal(tableData[item].finalMetricData);
// if hyperparameters is undefine, show error message, else, show parameters value
if (tableData[item].hyperParameters) {
const parameters = JSON.parse(tableData[item].hyperParameters[0]).parameters;
const tempara = tableData[item].hyperParameters;
if (tempara !== undefined) {
const tempLength = tempara.length;
const parameters = JSON.parse(tempara[tempLength - 1]).parameters;
if (typeof parameters === 'string') {
desJobDetail.parameters = JSON.parse(parameters);
} else {
......@@ -315,8 +347,9 @@ class Overview extends React.Component<{}, OverviewState> {
indexarr.push(items.sequenceId);
});
const accOption = {
// support max show 0.0000000
grid: {
left: 40,
left: 67,
right: 40
},
tooltip: {
......@@ -396,7 +429,7 @@ class Overview extends React.Component<{}, OverviewState> {
const {
trialProfile, searchSpace, tableData, accuracyData,
accNodata, status, errorStr, trialNumber, bestAccuracy,
accNodata, status, errorStr, trialNumber, bestAccuracy, isMultiPhase,
titleMaxbgcolor, titleMinbgcolor, isLogCollection, experimentAPI
} = this.state;
......@@ -470,6 +503,7 @@ class Overview extends React.Component<{}, OverviewState> {
<Col span={16} id="succeTable">
<SuccessTable
tableSource={tableData}
multiphase={isMultiPhase}
logCollection={isLogCollection}
trainingPlatform={trialProfile.trainingServicePlatform}
/>
......
......@@ -25,7 +25,7 @@ interface TrialDetailState {
experimentLogCollection: boolean;
entriesTable: number;
searchSpace: string;
defaultMetric?: Array<number>;
isMultiPhase: boolean;
}
class TrialsDetail extends React.Component<{}, TrialDetailState> {
......@@ -70,7 +70,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
entriesTable: 20,
isHasSearch: false,
searchSpace: '',
defaultMetric: [0, 1]
isMultiPhase: false
};
}
......@@ -87,7 +87,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
const metricSource = res1.data;
const trialTable: Array<TableObj> = [];
Object.keys(trialJobs).map(item => {
// only succeeded trials have finalMetricData
let desc: Parameters = {
parameters: {},
intermediate: []
......@@ -108,8 +107,9 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
duration = (new Date().getTime() - begin) / 1000;
}
}
if (trialJobs[item].hyperParameters !== undefined) {
const getPara = JSON.parse(trialJobs[item].hyperParameters[0]).parameters;
const tempHyper = trialJobs[item].hyperParameters;
if (tempHyper !== undefined) {
const getPara = JSON.parse(tempHyper[tempHyper.length - 1]).parameters;
if (typeof getPara === 'string') {
desc.parameters = JSON.parse(getPara);
} else {
......@@ -148,32 +148,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
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
const { searchResultSource } = this.state;
if (searchResultSource.length !== 0) {
......@@ -295,6 +269,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
// default logCollection is true
const logCollection = res.data.params.logCollection;
let expLogCollection: boolean = false;
const isMultiy: boolean = res.data.params.multiPhase !== undefined
? res.data.params.multiPhase : false;
if (logCollection !== undefined && logCollection !== 'none') {
expLogCollection = true;
}
......@@ -302,7 +278,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
this.setState({
experimentPlatform: trainingPlatform,
searchSpace: res.data.params.searchSpace,
experimentLogCollection: expLogCollection
experimentLogCollection: expLogCollection,
isMultiPhase: isMultiy
});
}
}
......@@ -325,9 +302,8 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
render() {
const {
tableListSource, searchResultSource, isHasSearch,
entriesTable, experimentPlatform, searchSpace,
defaultMetric, experimentLogCollection
tableListSource, searchResultSource, isHasSearch, isMultiPhase,
entriesTable, experimentPlatform, searchSpace, experimentLogCollection
} = this.state;
const source = isHasSearch ? searchResultSource : tableListSource;
return (
......@@ -347,7 +323,6 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
<Para
dataSource={source}
expSearchSpace={searchSpace}
defaultMetric={defaultMetric}
/>
</Row>
</TabPane>
......@@ -401,6 +376,7 @@ class TrialsDetail extends React.Component<{}, TrialDetailState> {
<TableList
entries={entriesTable}
tableSource={source}
isMultiPhase={isMultiPhase}
platform={experimentPlatform}
updateList={this.getDetailSource}
logCollection={experimentLogCollection}
......
......@@ -161,13 +161,14 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
const bar2Percent = (bar2 / trialProfile.MaxTrialNum) * 100;
const percent = (trialProfile.execDuration / trialProfile.maxDuration) * 100;
const runDuration = convertTime(trialProfile.execDuration);
const temp = trialProfile.maxDuration - trialProfile.execDuration;
let remaining;
if (status === 'DONE') {
let errorContent;
if (temp < 0) {
remaining = '0';
} else {
remaining = convertTime(trialProfile.maxDuration - trialProfile.execDuration);
remaining = convertTime(temp);
}
let errorContent;
if (errors !== '') {
errorContent = (
<div className="errors">
......@@ -225,33 +226,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
<Col span={6}>
<Row className="basic colorOfbasic">
<p>Remaining</p>
<div>{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>
<div className="time">{remaining}</div>
</Row>
</Col>
<Col span={12}>
......@@ -282,6 +257,33 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
</Row>
</Col>
</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>
);
}
......
......@@ -11,6 +11,7 @@ interface SuccessTableProps {
tableSource: Array<TableObj>;
trainingPlatform: string;
logCollection: boolean;
multiphase: boolean;
}
class SuccessTable extends React.Component<SuccessTableProps, {}> {
......@@ -23,12 +24,13 @@ class SuccessTable extends React.Component<SuccessTableProps, {}> {
}
openRow = (record: TableObj) => {
const { trainingPlatform, logCollection } = this.props;
const { trainingPlatform, logCollection, multiphase } = this.props;
return (
<OpenRow
trainingPlatform={trainingPlatform}
record={record}
logCollection={logCollection}
multiphase={multiphase}
/>
);
}
......
......@@ -4,6 +4,8 @@ import PaiTrialLog from '../public-child/PaiTrialLog';
import TrialLog from '../public-child/TrialLog';
import { TableObj } from '../../static/interface';
import { Row, Tabs, Button, message } from 'antd';
import { MANAGER_IP } from '../../static/const';
import '../../static/style/overview.scss';
import JSONTree from 'react-json-tree';
const TabPane = Tabs.TabPane;
......@@ -11,6 +13,7 @@ interface OpenRowProps {
trainingPlatform: string;
record: TableObj;
logCollection: boolean;
multiphase: boolean;
}
interface OpenRowState {
......@@ -46,7 +49,7 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
}
render() {
const { trainingPlatform, record, logCollection } = this.props;
const { trainingPlatform, record, logCollection, multiphase } = this.props;
const { idList } = this.state;
let isClick = false;
let isHasParameters = true;
......@@ -54,9 +57,8 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
if (record.description.parameters.error) {
isHasParameters = false;
}
const openRowDataSource = {
parameters: record.description.parameters
};
const openRowDataSource = record.description.parameters;
const trialink: string = `${MANAGER_IP}/trial-jobs/${record.id}`;
const logPathRow = record.description.logPath !== undefined
?
record.description.logPath
......@@ -66,6 +68,19 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
<Row className="openRowContent hyperpar">
<Tabs tabPosition="left" className="card">
<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
?
......@@ -74,13 +89,13 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
{
isClick
?
<pre>{JSON.stringify(openRowDataSource.parameters, null, 4)}</pre>
<pre>{JSON.stringify(openRowDataSource, null, 4)}</pre>
:
<JSONTree
hideRoot={true}
shouldExpandNode={() => true} // default expandNode
getItemString={() => (<span />)} // remove the {} items
data={openRowDataSource.parameters}
data={openRowDataSource}
/>
}
</Row>
......
......@@ -17,14 +17,13 @@ interface ParaState {
swapAxisArr: Array<string>;
percent: number;
paraNodata: string;
barColorMax: number;
barColorMin: number;
max: number; // graph color bar limit
min: number;
}
interface ParaProps {
dataSource: Array<TableObj>;
expSearchSpace: string;
defaultMetric: Array<number> | undefined;
}
message.config({
......@@ -58,16 +57,8 @@ class Para extends React.Component<ParaProps, ParaState> {
swapAxisArr: [],
percent: 0,
paraNodata: '',
barColorMax: this.props.defaultMetric !== undefined
?
this.props.defaultMetric[1]
:
1,
barColorMin: this.props.defaultMetric !== undefined
?
this.props.defaultMetric[0]
:
1
min: 0,
max: 1
};
}
......@@ -107,7 +98,7 @@ class Para extends React.Component<ParaProps, ParaState> {
parallelAxis.push({
dim: i,
name: dimName[i],
max: searchKey._value[0],
max: searchKey._value[0] - 1,
min: 0
});
break;
......@@ -217,7 +208,11 @@ class Para extends React.Component<ParaProps, ParaState> {
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
......@@ -233,11 +228,11 @@ class Para extends React.Component<ParaProps, ParaState> {
// deal with response data into pic data
getOption = (dataObj: ParaObj) => {
const {barColorMax, barColorMin} = this.state;
const { max, min } = this.state;
let parallelAxis = dataObj.parallelAxis;
let paralleData = dataObj.data;
let visualMapObj = {};
if (barColorMax === barColorMin) {
if (max === min) {
visualMapObj = {
type: 'continuous',
precision: 3,
......@@ -248,8 +243,8 @@ class Para extends React.Component<ParaProps, ParaState> {
bottom: '20px',
type: 'continuous',
precision: 3,
min: barColorMin,
max: barColorMax,
min: min,
max: max,
color: ['#CA0000', '#FFC400', '#90EE90']
};
}
......@@ -379,12 +374,6 @@ class Para extends React.Component<ParaProps, ParaState> {
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);
}
......
......@@ -32,6 +32,7 @@ interface TableListProps {
updateList: Function;
platform: string;
logCollection: boolean;
isMultiPhase: boolean;
}
interface TableListState {
......@@ -175,12 +176,13 @@ class TableList extends React.Component<TableListProps, TableListState> {
}
openRow = (record: TableObj) => {
const { platform, logCollection } = this.props;
const { platform, logCollection, isMultiPhase } = this.props;
return (
<OpenRow
trainingPlatform={platform}
record={record}
logCollection={logCollection}
multiphase={isMultiPhase}
/>
);
}
......@@ -386,16 +388,23 @@ class TableList extends React.Component<TableListProps, TableListState> {
key: item,
width: 150,
render: (text: string, record: TableObj) => {
return (
<div>
{
record.acc
?
record.acc[item]
:
'--'
const temp = record.acc;
let decimals = 0;
let other = '';
if (temp !== undefined) {
if (temp[item].toString().indexOf('.') !== -1) {
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) => {
// get final result value
// draw Accuracy point graph
const getFinalResult = (final: FinalResult) => {
const getFinalResult = (final: Array<FinalResult>) => {
let acc;
let showDefault = 0;
if (final) {
acc = JSON.parse(final[0].data);
acc = JSON.parse(final[final.length - 1].data);
if (typeof (acc) === 'object') {
if (acc.default) {
showDefault = acc.default;
......@@ -53,10 +53,10 @@ const getFinalResult = (final: FinalResult) => {
};
// get final result value // acc obj
const getFinal = (final: FinalResult) => {
const getFinal = (final: Array<FinalResult>) => {
let showDefault: FinalType;
if (final) {
showDefault = JSON.parse(final[0].data);
showDefault = JSON.parse(final[final.length - 1].data);
if (typeof showDefault === 'number') {
showDefault = { default: showDefault };
}
......
......@@ -49,3 +49,7 @@
}
}
.link{
margin-bottom: 10px;
}
......@@ -61,6 +61,11 @@
div{
color: #0573bc;
}
.time{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
}
.mess{
......
......@@ -18,6 +18,8 @@
# 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.
import sys
import glob
import argparse
from utils import get_yml_content, dump_yml_content
......@@ -69,6 +71,19 @@ def update_training_service_config(args):
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__':
parser = argparse.ArgumentParser()
parser.add_argument("--ts", type=str, choices=['pai', 'kubeflow', 'remote'], default='pai')
......@@ -96,3 +111,4 @@ if __name__ == '__main__':
args = parser.parse_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
import collections
import json
import os
import sys
import subprocess
import requests
import yaml
import ruamel.yaml as yaml
EXPERIMENT_DONE_SIGNAL = '"Experiment done"'
......@@ -55,7 +56,7 @@ def remove_files(file_list):
def get_yml_content(file_path):
'''Load yaml file content'''
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):
'''Dump yaml file content'''
......@@ -65,7 +66,7 @@ def dump_yml_content(file_path, content):
def setup_experiment(installed=True):
'''setup the experiment if nni is 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')
cmd_path = os.path.abspath('../tools')
pypath = os.environ.get('PYTHONPATH')
......@@ -79,7 +80,7 @@ def fetch_nni_log_path(experiment_url):
'''get nni's log path from nni's experiment url'''
experiment_profile = requests.get(experiment_url)
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')
return nnimanager_log_path
......@@ -87,7 +88,10 @@ def fetch_nni_log_path(experiment_url):
def is_experiment_done(nnimanager_log_path):
'''check if the experiment is done successfully'''
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)
return completed_process.returncode == 0
......@@ -112,7 +116,10 @@ def print_stderr(trial_jobs_url):
for trial_job in trial_jobs:
if trial_job['status'] == 'FAILED':
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):
unit = max_exec_duration[-1]
......
......@@ -20,6 +20,7 @@
import os
import sys
import shutil
from . import code_generator
......@@ -28,6 +29,9 @@ from . import search_space_generator
__all__ = ['generate_search_space', 'expand_annotations']
slash = '/'
if sys.platform == "win32":
slash = '\\'
def generate_search_space(code_dir):
"""Generate search space from Python source code.
......@@ -35,8 +39,8 @@ def generate_search_space(code_dir):
code_dir: directory path of source files (str)
"""
search_space = {}
if code_dir.endswith('/'):
if code_dir.endswith(slash):
code_dir = code_dir[:-1]
for subdir, _, files in os.walk(code_dir):
......@@ -44,9 +48,9 @@ def generate_search_space(code_dir):
if subdir == code_dir:
package = ''
else:
assert subdir.startswith(code_dir + '/'), subdir
assert subdir.startswith(code_dir + slash), subdir
prefix_len = len(code_dir) + 1
package = subdir[prefix_len:].replace('/', '.') + '.'
package = subdir[prefix_len:].replace(slash, '.') + '.'
for file_name in files:
if file_name.endswith('.py'):
......@@ -76,9 +80,10 @@ def expand_annotations(src_dir, dst_dir):
src_dir: directory path of user code (str)
dst_dir: directory to place generated files (str)
"""
if src_dir[-1] == '/':
if src_dir[-1] == slash:
src_dir = src_dir[:-1]
if dst_dir[-1] == '/':
if dst_dir[-1] == slash:
dst_dir = dst_dir[:-1]
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