Unverified Commit f322548f authored by chicm-ms's avatar chicm-ms Committed by GitHub
Browse files

Merge pull request #30 from microsoft/master

pull code
parents cb361b34 797f0e2c
...@@ -17,11 +17,13 @@ ...@@ -17,11 +17,13 @@
NNI (Neural Network Intelligence) is a toolkit to help users run automated machine learning (AutoML) experiments. NNI (Neural Network Intelligence) is a toolkit to help users run automated machine learning (AutoML) experiments.
The tool dispatches and runs trial jobs generated by tuning algorithms to search the best neural architecture and/or hyper-parameters in different environments like local machine, remote servers and cloud. The tool dispatches and runs trial jobs generated by tuning algorithms to search the best neural architecture and/or hyper-parameters in different environments like local machine, remote servers and cloud.
### **NNI [v0.9](https://github.com/Microsoft/nni/releases) has been released! &nbsp;<a href="#nni-released-reminder"><img width="48" src="docs/img/release_icon.png"></a>** ### **NNI [v0.9](https://github.com/Microsoft/nni/releases) has been released! &nbsp;<a href="#nni-released-reminder"><img width="48" src="docs/img/release_icon.png"></a>**
<p align="center"> <p align="center">
<a href="#nni-has-been-released"><img src="docs/img/overview.svg" /></a> <a href="#nni-has-been-released"><img src="docs/img/overview.svg" /></a>
</p> </p>
<div>
<table> <table>
<tbody> <tbody>
<tr align="center" valign="bottom"> <tr align="center" valign="bottom">
...@@ -56,27 +58,27 @@ The tool dispatches and runs trial jobs generated by tuning algorithms to search ...@@ -56,27 +58,27 @@ The tool dispatches and runs trial jobs generated by tuning algorithms to search
<a href="docs/en_US/Tuner/BuiltinTuner.md">Tuner</a> <a href="docs/en_US/Tuner/BuiltinTuner.md">Tuner</a>
<br /> <br />
<ul> <ul>
<b style="margin-left:-20px"><font size=4 color=#800000>General Tuner</font></b> <b style="margin-left:-20px">General Tuner</b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Random"><font size=2.9>Random Search</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#Random">Random Search</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Evolution"><font size=2.9>Naïve Evolution</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#Evolution">Naïve Evolution</a></li>
<b><font size=4 color=#800000 style="margin-left:-20px">Tuner for HPO</font></b> <b style="margin-left:-20px">Tuner for HPO</b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#TPE"><font size=2.9>TPE</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#TPE">TPE</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Anneal"><font size=2.9>Anneal</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#Anneal">Anneal</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#SMAC"><font size=2.9>SMAC</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#SMAC">SMAC</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Batch"><font size=2.9>Batch</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#Batch">Batch</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#GridSearch"><font size=2.9>Grid Search</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#GridSearch">Grid Search</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#Hyperband"><font size=2.9>Hyperband</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#Hyperband">Hyperband</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#MetisTuner"><font size=2.9>Metis Tuner</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#MetisTuner">Metis Tuner</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#BOHB"><font size=2.9>BOHB</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#BOHB">BOHB</a></li>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#GPTuner"><font size=2.9>GP Tuner</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#GPTuner">GP Tuner</a></li>
<b style="margin-left:-20px"><font size=4 color=#800000 style="margin-left:-20px">Tuner for NAS</font></b> <b style="margin-left:-20px">Tuner for NAS</b>
<li><a href="docs/en_US/Tuner/BuiltinTuner.md#NetworkMorphism"><font size=2.9>Network Morphism</font></a></li> <li><a href="docs/en_US/Tuner/BuiltinTuner.md#NetworkMorphism">Network Morphism</a></li>
<li><a href="examples/tuners/enas_nni/README.md"><font size=2.9>ENAS</font></a></li> <li><a href="examples/tuners/enas_nni/README.md">ENAS</a></li>
</ul> </ul>
<a href="docs/en_US/Assessor/BuiltinAssessor.md">Assessor</a> <a href="docs/en_US/Assessor/BuiltinAssessor.md">Assessor</a>
<ul> <ul>
<li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Medianstop"><font size=2.9>Median Stop</font></a></li> <li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Medianstop">Median Stop</a></li>
<li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Curvefitting"><font size=2.9>Curve Fitting</font></a></li> <li><a href="docs/en_US/Assessor/BuiltinAssessor.md#Curvefitting">Curve Fitting</a></li>
</ul> </ul>
</td> </td>
<td> <td>
...@@ -91,52 +93,10 @@ The tool dispatches and runs trial jobs generated by tuning algorithms to search ...@@ -91,52 +93,10 @@ The tool dispatches and runs trial jobs generated by tuning algorithms to search
</ul> </ul>
</td> </td>
</tr> </tr>
<tr align="center" valign="bottom">
<td style="border-top:#FF0000 solid 0px;">
<b>References</b>
<img src="docs/img/bar.png"/>
</td>
<td style="border-top:#FF0000 solid 0px;">
<b>References</b>
<img src="docs/img/bar.png"/>
</td>
<td style="border-top:#FF0000 solid 0px;">
<b>References</b>
<img src="docs/img/bar.png"/>
</td>
</tr>
<tr valign="top">
<td style="border-top:#FF0000 solid 0px;">
<ul>
<li><a href="docs/en_US/sdk_reference.rst">Python API</a></li>
<li><a href="docs/en_US/Tutorial/AnnotationSpec.md">NNI Annotation</a></li>
<li><a href="docs/en_US/TrialExample/Trials.md#nni-python-annotation">Annotation tutorial</a></li>
</ul>
</td>
<td style="border-top:#FF0000 solid 0px;">
<ul>
<li><a href="docs/en_US/tuners.rst">Try different tuners</a></li>
<li><a href="docs/en_US/assessors.rst">Try different assessors</a></li>
<li><a href="docs/en_US/Tuner/CustomizeTuner.md">Implement a customized tuner</a></li>
<li><a href="docs/en_US/Tuner/CustomizeAdvisor.md">Implement a customized advisor</a></li>
<li><a href="docs/en_US/Assessor/CustomizeAssessor.md">Implement a customized assessor </a></li>
<li><a href="docs/en_US/CommunitySharings/HpoComparision.md">HPO Comparison</a></li>
<li><a href="docs/en_US/CommunitySharings/NasComparision.md">NAS Comparison</a></li>
<li><a href="docs/en_US/CommunitySharings/RecommendersSvd.md">Automatically tuning SVD on NNI</a></li>
</ul>
</td>
<td style="border-top:#FF0000 solid 0px;">
<ul>
<li><a href="docs/en_US/TrainingService/HowToImplementTrainingService.md">Implement TrainingService in NNI</a></li>
<li><a href="docs/en_US/TrainingService/LocalMode.md">Run an experiment on local</a></li>
<li><a href="docs/en_US/TrainingService/KubeflowMode.md">Run an experiment on Kubeflow</a></li>
<li><a href="docs/en_US/TrainingService/PaiMode.md">Run an experiment on OpenPAI?</a></li>
<li><a href="docs/en_US/TrainingService/RemoteMachineMode.md">Run an experiment on multiple machines?</a></li>
</ul>
</td>
</tbody> </tbody>
</table> </table>
</div>
## **Who should consider using NNI** ## **Who should consider using NNI**
...@@ -291,17 +251,18 @@ Maybe you want to read: ...@@ -291,17 +251,18 @@ Maybe you want to read:
* [Config an experiment](docs/en_US/Tutorial/ExperimentConfig.md) * [Config an experiment](docs/en_US/Tutorial/ExperimentConfig.md)
* [How to use annotation](docs/en_US/TrialExample/Trials.md#nni-python-annotation) * [How to use annotation](docs/en_US/TrialExample/Trials.md#nni-python-annotation)
## **Tutorials** ## **Tutorials**
* [Run an experiment on OpenPAI?](docs/en_US/PaiMode.md) * [Run an experiment on OpenPAI](docs/en_US/TrainingService/PaiMode.md)
* [Run an experiment on Kubeflow?](docs/en_US/KubeflowMode.md) * [Run an experiment on Kubeflow](docs/en_US/TrainingService/KubeflowMode.md)
* [Run an experiment on local (with multiple GPUs)?](docs/en_US/LocalMode.md) * [Run an experiment on local (with multiple GPUs)](docs/en_US/TrainingService/LocalMode.md)
* [Run an experiment on multiple machines?](docs/en_US/RemoteMachineMode.md) * [Run an experiment on multiple machines](docs/en_US/TrainingService/RemoteMachineMode.md)
* [Try different tuners](docs/en_US/tuners.rst) * [Try different tuners](docs/en_US/Tuner/BuiltinTuner.md)
* [Try different assessors](docs/en_US/assessors.rst) * [Try different assessors](docs/en_US/Assessor/BuiltinAssessor.md)
* [Implement a customized tuner](docs/en_US/Tuner/CustomizeTuner.md) * [Implement a customized tuner](docs/en_US/Tuner/CustomizeTuner.md)
* [Implement a customized assessor](docs/en_US/CustomizeAssessor.md) * [Implement a customized assessor](docs/en_US/Assessor/CustomizeAssessor.md)
* [Use Genetic Algorithm to find good model architectures for Reading Comprehension task](examples/trials/ga_squad/README.md) * [Use Genetic Algorithm to find good model architectures for Reading Comprehension task](docs/en_US/TrialExample/SquadEvolutionExamples.md)
## **Contribute** ## **Contribute**
This project welcomes contributions and there are many ways in which you can participate in the project, for example: This project welcomes contributions and there are many ways in which you can participate in the project, for example:
......
configspace @ f389e1d0
Subproject commit f389e1d0a72564f7f1fd4d86039e5f393a45a058
This file is placed here by pip to indicate the source was put
here by pip.
Once this package is successfully installed this source code will be
deleted (unless you remove this file).
ConfigSpace==0.4.7 ConfigSpace==0.4.7
statsmodels==0.9.0 statsmodels==0.10.0
\ No newline at end of file \ No newline at end of file
.nni{ .nni{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #212121; color: #212121;
font-size: 14px; font-size: 14px;
background: #f2f2f2; background: #f2f2f2;
......
import * as React from 'react';
import axios from 'axios';
import { downFile } from '../../static/function';
import { Drawer, Tabs, Row, Col, Button } from 'antd';
import { MANAGER_IP, DRAWEROPTION } from '../../static/const';
import MonacoEditor from 'react-monaco-editor';
const { TabPane } = Tabs;
import '../../static/style/logDrawer.scss';
interface ExpDrawerProps {
isVisble: boolean;
closeExpDrawer: () => void;
}
interface ExpDrawerState {
experiment: string;
}
class ExperimentDrawer extends React.Component<ExpDrawerProps, ExpDrawerState> {
public _isCompareMount: boolean;
constructor(props: ExpDrawerProps) {
super(props);
this.state = {
experiment: ''
};
}
getExperimentContent = () => {
axios
.all([
axios.get(`${MANAGER_IP}/experiment`),
axios.get(`${MANAGER_IP}/trial-jobs`),
axios.get(`${MANAGER_IP}/metric-data`)
])
.then(axios.spread((res, res1, res2) => {
if (res.status === 200 && res1.status === 200 && res2.status === 200) {
if (res.data.params.searchSpace) {
res.data.params.searchSpace = JSON.parse(res.data.params.searchSpace);
}
let trialMessagesArr = res1.data;
const interResultList = res2.data;
Object.keys(trialMessagesArr).map(item => {
// transform hyperparameters as object to show elegantly
trialMessagesArr[item].hyperParameters = JSON.parse(trialMessagesArr[item].hyperParameters);
const trialId = trialMessagesArr[item].id;
// add intermediate result message
trialMessagesArr[item].intermediate = [];
Object.keys(interResultList).map(key => {
const interId = interResultList[key].trialJobId;
if (trialId === interId) {
trialMessagesArr[item].intermediate.push(interResultList[key]);
}
});
});
const result = {
experimentParameters: res.data,
trialMessage: trialMessagesArr
};
if (this._isCompareMount === true) {
this.setState(() => ({ experiment: JSON.stringify(result, null, 4) }));
}
}
}));
}
downExperimentParameters = () => {
const { experiment } = this.state;
downFile(experiment, 'experiment.json');
}
componentDidMount() {
this._isCompareMount = true;
this.getExperimentContent();
}
componentWillReceiveProps(nextProps: ExpDrawerProps) {
const { isVisble } = nextProps;
if (isVisble === true) {
this.getExperimentContent();
}
}
componentWillUnmount() {
this._isCompareMount = false;
}
render() {
const { isVisble, closeExpDrawer } = this.props;
const { experiment } = this.state;
const heights: number = window.innerHeight - 48;
return (
<Row className="logDrawer">
<Drawer
// title="Log Message"
placement="right"
closable={false}
destroyOnClose={true}
onClose={closeExpDrawer}
visible={isVisble}
width="54%"
height={heights}
>
<div className="card-container log-tab-body" style={{ height: heights }}>
<Tabs type="card">
<TabPane tab="Experiment Parameters" key="Experiment">
<div className="just-for-log">
<MonacoEditor
width="100%"
height={heights * 0.9}
language="json"
value={experiment}
options={DRAWEROPTION}
/>
</div>
<Row className="buttons">
<Col span={12}>
<Button
type="primary"
onClick={this.downExperimentParameters}
>
Download
</Button>
</Col>
<Col span={12} className="close">
<Button
type="default"
onClick={closeExpDrawer}
>
Close
</Button>
</Col>
</Row>
</TabPane>
</Tabs>
</div>
</Drawer>
</Row>
);
}
}
export default ExperimentDrawer;
import * as React from 'react';
import axios from 'axios';
import { Drawer, Tabs, Row, Col, Button, Icon } from 'antd';
import { DOWNLOAD_IP } from '../../static/const';
import { downFile } from '../../static/function';
const { TabPane } = Tabs;
import MonacoHTML from '../public-child/MonacoEditor';
import '../../static/style/logDrawer.scss';
interface LogDrawerProps {
isVisble: boolean;
closeDrawer: () => void;
activeTab?: string;
}
interface LogDrawerState {
nniManagerLogStr: string;
dispatcherLogStr: string;
isLoading: boolean;
isLoadispatcher: boolean;
}
class LogDrawer extends React.Component<LogDrawerProps, LogDrawerState> {
public _isLogDrawer: boolean;
constructor(props: LogDrawerProps) {
super(props);
this.state = {
nniManagerLogStr: 'nnimanager',
dispatcherLogStr: 'dispatcher',
isLoading: false,
isLoadispatcher: false
};
}
getNNImanagerLogmessage = () => {
if (this._isLogDrawer === true) {
this.setState({ isLoading: true }, () => {
axios(`${DOWNLOAD_IP}/nnimanager.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
setTimeout(() => { this.setNNImanager(res.data); }, 300);
}
});
});
}
}
setDispatcher = (value: string) => {
if (this._isLogDrawer === true) {
this.setState(() => ({ isLoadispatcher: false, dispatcherLogStr: value }));
}
}
setNNImanager = (val: string) => {
if (this._isLogDrawer === true) {
this.setState(() => ({ isLoading: false, nniManagerLogStr: val }));
}
}
getdispatcherLogmessage = () => {
if (this._isLogDrawer === true) {
this.setState({ isLoadispatcher: true }, () => {
axios(`${DOWNLOAD_IP}/dispatcher.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
setTimeout(() => { this.setDispatcher(res.data); }, 300);
}
});
});
}
}
downloadNNImanager = () => {
const { nniManagerLogStr } = this.state;
downFile(nniManagerLogStr, 'nnimanager.log');
}
downloadDispatcher = () => {
const { dispatcherLogStr } = this.state;
downFile(dispatcherLogStr, 'dispatcher.log');
}
dispatcherHTML = () => {
return (
<div>
<span>Dispatcher Log</span>
<span className="refresh" onClick={this.getdispatcherLogmessage}>
<Icon type="sync" />
</span>
</div>
);
}
nnimanagerHTML = () => {
return (
<div>
<span>NNImanager Log</span>
<span className="refresh" onClick={this.getNNImanagerLogmessage}><Icon type="sync" /></span>
</div>
);
}
componentDidMount() {
this._isLogDrawer = true;
this.getNNImanagerLogmessage();
this.getdispatcherLogmessage();
}
componentWillReceiveProps(nextProps: LogDrawerProps) {
const { isVisble, activeTab } = nextProps;
if (isVisble === true) {
if (activeTab === 'nnimanager') {
this.getNNImanagerLogmessage();
}
if (activeTab === 'dispatcher') {
this.getdispatcherLogmessage();
}
}
}
componentWillUnmount() {
this._isLogDrawer = false;
}
render() {
const { isVisble, closeDrawer, activeTab } = this.props;
const { nniManagerLogStr, dispatcherLogStr, isLoadispatcher, isLoading } = this.state;
const heights: number = window.innerHeight - 48; // padding top and bottom
return (
<Row>
<Drawer
placement="right"
closable={false}
destroyOnClose={true}
onClose={closeDrawer}
visible={isVisble}
width="76%"
height={heights}
// className="logDrawer"
>
<div className="card-container log-tab-body" style={{ height: heights }}>
<Tabs type="card" defaultActiveKey={activeTab}>
{/* <Tabs type="card" onTabClick={this.selectwhichLog} defaultActiveKey={activeTab}> */}
{/* <TabPane tab="Dispatcher Log" key="dispatcher"> */}
<TabPane tab={this.dispatcherHTML()} key="dispatcher">
<div>
<MonacoHTML content={dispatcherLogStr} loading={isLoadispatcher} />
</div>
<Row className="buttons">
<Col span={12}>
<Button
type="primary"
onClick={this.downloadDispatcher}
>
Download
</Button>
</Col>
<Col span={12} className="close">
<Button
type="default"
onClick={closeDrawer}
>
Close
</Button>
</Col>
</Row>
</TabPane>
<TabPane tab={this.nnimanagerHTML()} key="nnimanager">
{/* <TabPane tab="NNImanager Log" key="nnimanager"> */}
<div>
<MonacoHTML content={nniManagerLogStr} loading={isLoading} />
</div>
<Row className="buttons">
<Col span={12} className="download">
<Button
type="primary"
onClick={this.downloadNNImanager}
>
Download
</Button>
</Col>
<Col span={12} className="close">
<Button
type="default"
onClick={closeDrawer}
>
Close
</Button>
</Col>
</Row>
</TabPane>
</Tabs>
</div>
</Drawer>
</Row>
);
}
}
export default LogDrawer;
...@@ -3,10 +3,11 @@ import { Link } from 'react-router'; ...@@ -3,10 +3,11 @@ import { Link } from 'react-router';
import axios from 'axios'; import axios from 'axios';
import { MANAGER_IP } from '../static/const'; import { MANAGER_IP } from '../static/const';
import MediaQuery from 'react-responsive'; import MediaQuery from 'react-responsive';
import { DOWNLOAD_IP } from '../static/const';
import { Row, Col, Menu, Dropdown, Icon, Select, Button } from 'antd'; import { Row, Col, Menu, Dropdown, Icon, Select, Button } from 'antd';
const { SubMenu } = Menu; const { SubMenu } = Menu;
const { Option } = Select; const { Option } = Select;
import LogDrawer from './Modal/LogDrawer';
import ExperimentDrawer from './Modal/ExperimentDrawer';
import '../static/style/slideBar.scss'; import '../static/style/slideBar.scss';
import '../static/style/button.scss'; import '../static/style/button.scss';
...@@ -15,6 +16,9 @@ interface SliderState { ...@@ -15,6 +16,9 @@ interface SliderState {
menuVisible: boolean; menuVisible: boolean;
navBarVisible: boolean; navBarVisible: boolean;
isdisabledFresh: boolean; isdisabledFresh: boolean;
isvisibleLogDrawer: boolean;
isvisibleExperimentDrawer: boolean;
activeKey: string;
} }
interface SliderProps { interface SliderProps {
...@@ -38,124 +42,13 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -38,124 +42,13 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
version: '', version: '',
menuVisible: false, menuVisible: false,
navBarVisible: false, navBarVisible: false,
isdisabledFresh: false isdisabledFresh: false,
isvisibleLogDrawer: false, // download button (nnimanager·dispatcher) click -> drawer
isvisibleExperimentDrawer: false,
activeKey: 'dispatcher'
}; };
} }
downExperimentContent = () => {
axios
.all([
axios.get(`${MANAGER_IP}/experiment`),
axios.get(`${MANAGER_IP}/trial-jobs`),
axios.get(`${MANAGER_IP}/metric-data`)
])
.then(axios.spread((res, res1, res2) => {
if (res.status === 200 && res1.status === 200 && res2.status === 200) {
if (res.data.params.searchSpace) {
res.data.params.searchSpace = JSON.parse(res.data.params.searchSpace);
}
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
let trialMessagesArr = res1.data;
const interResultList = res2.data;
Object.keys(trialMessagesArr).map(item => {
// transform hyperparameters as object to show elegantly
trialMessagesArr[item].hyperParameters = JSON.parse(trialMessagesArr[item].hyperParameters);
const trialId = trialMessagesArr[item].id;
// add intermediate result message
trialMessagesArr[item].intermediate = [];
Object.keys(interResultList).map(key => {
const interId = interResultList[key].trialJobId;
if (trialId === interId) {
trialMessagesArr[item].intermediate.push(interResultList[key]);
}
});
});
const result = {
experimentParameters: res.data,
trialMessage: trialMessagesArr
};
const aTag = document.createElement('a');
const file = new Blob([JSON.stringify(result, null, 4)], { type: 'application/json' });
aTag.download = 'experiment.json';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'experiment.json';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
}));
}
downnnimanagerLog = () => {
axios(`${DOWNLOAD_IP}/nnimanager.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const nniLogfile = res.data;
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([nniLogfile], { type: 'application/json' });
aTag.download = 'nnimanagerLog.log';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'nnimanagerLog.log';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
});
}
downDispatcherlog = () => {
axios(`${DOWNLOAD_IP}/dispatcher.log`, {
method: 'GET'
})
.then(res => {
if (res.status === 200) {
const dispatchLogfile = res.data;
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([dispatchLogfile], { type: 'application/json' });
aTag.download = 'dispatcherLog.log';
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = 'dispatcherLog.log';
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
}
});
}
getNNIversion = () => { getNNIversion = () => {
axios(`${MANAGER_IP}/version`, { axios(`${MANAGER_IP}/version`, {
method: 'GET' method: 'GET'
...@@ -170,17 +63,23 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -170,17 +63,23 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
handleMenuClick = (e: EventPer) => { handleMenuClick = (e: EventPer) => {
if (this._isMounted) { this.setState({ menuVisible: false }); } if (this._isMounted) { this.setState({ menuVisible: false }); }
switch (e.key) { switch (e.key) {
// download experiment related content // to see & download experiment parameters
case '1': case '1':
this.downExperimentContent(); if (this._isMounted === true) {
this.setState(() => ({ isvisibleExperimentDrawer: true }));
}
break; break;
// download nnimanager log file // to see & download nnimanager log
case '2': case '2':
this.downnnimanagerLog(); if (this._isMounted === true) {
this.setState(() => ({ activeKey: 'nnimanager', isvisibleLogDrawer: true }));
}
break; break;
// download dispatcher log file // to see & download dispatcher log
case '3': case '3':
this.downDispatcherlog(); if (this._isMounted === true) {
this.setState(() => ({ isvisibleLogDrawer: true, activeKey: 'dispatcher' }));
}
break; break;
case 'close': case 'close':
case '10': case '10':
...@@ -285,6 +184,20 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -285,6 +184,20 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
} }
} }
// close log drawer (nnimanager.dispatcher)
closeLogDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isvisibleLogDrawer: false, activeKey: '' }));
}
}
// close download experiment parameters drawer
closeExpDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isvisibleExperimentDrawer: false }));
}
}
componentDidMount() { componentDidMount() {
this._isMounted = true; this._isMounted = true;
this.getNNIversion(); this.getNNIversion();
...@@ -295,9 +208,10 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -295,9 +208,10 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
} }
render() { render() {
const { version, menuVisible } = this.state; const { version, menuVisible, isvisibleLogDrawer, activeKey, isvisibleExperimentDrawer } = this.state;
const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`; const feed = `https://github.com/Microsoft/nni/issues/new?labels=${version}`;
return ( return (
<Row>
<Row> <Row>
<Col span={18}> <Col span={18}>
<MediaQuery query="(min-width: 1299px)"> <MediaQuery query="(min-width: 1299px)">
...@@ -369,6 +283,17 @@ class SlideBar extends React.Component<SliderProps, SliderState> { ...@@ -369,6 +283,17 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
</Col> </Col>
<Col span={3}> {this.select()} </Col> <Col span={3}> {this.select()} </Col>
</Row> </Row>
{/* the drawer for dispatcher & nnimanager log message */}
<LogDrawer
isVisble={isvisibleLogDrawer}
closeDrawer={this.closeLogDrawer}
activeTab={activeKey}
/>
<ExperimentDrawer
isVisble={isvisibleExperimentDrawer}
closeExpDrawer={this.closeExpDrawer}
/>
</Row>
); );
} }
} }
......
...@@ -7,6 +7,7 @@ import { MANAGER_IP, CONTROLTYPE } from '../../static/const'; ...@@ -7,6 +7,7 @@ import { MANAGER_IP, CONTROLTYPE } from '../../static/const';
import { Experiment, TrialNumber } from '../../static/interface'; import { Experiment, TrialNumber } from '../../static/interface';
import { convertTime } from '../../static/function'; import { convertTime } from '../../static/function';
import ProgressBar from './ProgressItem'; import ProgressBar from './ProgressItem';
import LogDrawer from '../Modal/LogDrawer';
import '../../static/style/progress.scss'; import '../../static/style/progress.scss';
import '../../static/style/probar.scss'; import '../../static/style/probar.scss';
...@@ -24,6 +25,7 @@ interface ProgressState { ...@@ -24,6 +25,7 @@ interface ProgressState {
isEnable: boolean; isEnable: boolean;
userInputVal: string; // get user input userInputVal: string; // get user input
cancelSty: string; cancelSty: string;
isShowLogDrawer: boolean;
} }
class Progressed extends React.Component<ProgressProps, ProgressState> { class Progressed extends React.Component<ProgressProps, ProgressState> {
...@@ -36,7 +38,8 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -36,7 +38,8 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
btnName: 'Edit', btnName: 'Edit',
isEnable: true, isEnable: true,
userInputVal: this.props.trialProfile.runConcurren.toString(), userInputVal: this.props.trialProfile.runConcurren.toString(),
cancelSty: 'none' cancelSty: 'none',
isShowLogDrawer: false
}; };
} }
...@@ -139,6 +142,18 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -139,6 +142,18 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
} }
} }
isShowDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isShowLogDrawer: true }));
}
}
closeDrawer = () => {
if (this._isMounted === true) {
this.setState(() => ({ isShowLogDrawer: false }));
}
}
componentWillReceiveProps() { componentWillReceiveProps() {
const { trialProfile } = this.props; const { trialProfile } = this.props;
if (this.conInput !== null) { if (this.conInput !== null) {
...@@ -156,7 +171,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -156,7 +171,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
render() { render() {
const { trialProfile, trialNumber, bestAccuracy, status, errors } = this.props; const { trialProfile, trialNumber, bestAccuracy, status, errors } = this.props;
const { isEnable, btnName, cancelSty } = this.state; const { isEnable, btnName, cancelSty, isShowLogDrawer } = this.state;
const bar2 = trialNumber.totalCurrentTrial - trialNumber.waitTrial - trialNumber.unknowTrial; const bar2 = trialNumber.totalCurrentTrial - trialNumber.waitTrial - trialNumber.unknowTrial;
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;
...@@ -173,6 +188,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -173,6 +188,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
errorContent = ( errorContent = (
<div className="errors"> <div className="errors">
{errors} {errors}
<div><a href="#" onClick={this.isShowDrawer}>Learn about</a></div>
</div> </div>
); );
} }
...@@ -282,8 +298,13 @@ class Progressed extends React.Component<ProgressProps, ProgressState> { ...@@ -282,8 +298,13 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
<div>{trialNumber.failTrial}</div> <div>{trialNumber.failTrial}</div>
</Row> </Row>
</Col> </Col>
</Row> </Row>
{/* learn about click -> default active key is dispatcher. */}
<LogDrawer
isVisble={isShowLogDrawer}
closeDrawer={this.closeDrawer}
activeTab="dispatcher"
/>
</Row> </Row>
); );
} }
......
import * as React from 'react';
import { Spin } from 'antd';
import { DRAWEROPTION } from '../../static/const';
import MonacoEditor from 'react-monaco-editor';
interface MonacoEditorProps {
content: string;
loading: boolean;
}
class MonacoHTML extends React.Component<MonacoEditorProps, {}> {
public _isMonacoMount: boolean;
constructor(props: MonacoEditorProps) {
super(props);
}
componentDidMount() {
this._isMonacoMount = true;
}
componentWillUnmount() {
this._isMonacoMount = false;
}
render() {
const { content, loading } = this.props;
const heights: number = window.innerHeight - 48;
return (
<div className="just-for-log">
<Spin
// tip="Loading..."
style={{ width: '100%', height: heights * 0.9 }}
spinning={loading}
>
<MonacoEditor
width="100%"
height={heights * 0.9}
language="json"
value={content}
options={DRAWEROPTION}
/>
</Spin>
</div>
);
}
}
export default MonacoHTML;
...@@ -19,6 +19,11 @@ const MONACO = { ...@@ -19,6 +19,11 @@ const MONACO = {
readOnly: true, readOnly: true,
automaticLayout: true automaticLayout: true
}; };
const DRAWEROPTION = {
minimap: { enabled: false },
readOnly: true,
automaticLayout: true
};
const COLUMN_INDEX = [ const COLUMN_INDEX = [
{ {
name: 'Trial No.', name: 'Trial No.',
...@@ -52,5 +57,5 @@ const COLUMN_INDEX = [ ...@@ -52,5 +57,5 @@ const COLUMN_INDEX = [
const COLUMN = ['Trial No.', 'ID', 'Duration', 'Status', 'Default', 'Operation', 'Intermediate result']; const COLUMN = ['Trial No.', 'ID', 'Duration', 'Status', 'Default', 'Operation', 'Intermediate result'];
export { export {
MANAGER_IP, DOWNLOAD_IP, trialJobStatus, MANAGER_IP, DOWNLOAD_IP, trialJobStatus,
CONTROLTYPE, MONACO, COLUMN, COLUMN_INDEX CONTROLTYPE, MONACO, COLUMN, COLUMN_INDEX, DRAWEROPTION
}; };
...@@ -138,7 +138,29 @@ const filterDuration = (item: TableObj) => { ...@@ -138,7 +138,29 @@ const filterDuration = (item: TableObj) => {
return item.status !== 'WAITING'; return item.status !== 'WAITING';
}; };
const downFile = (content: string, fileName: string) => {
const aTag = document.createElement('a');
const isEdge = navigator.userAgent.indexOf('Edge') !== -1 ? true : false;
const file = new Blob([content], { type: 'application/json' });
aTag.download = fileName;
aTag.href = URL.createObjectURL(file);
aTag.click();
if (!isEdge) {
URL.revokeObjectURL(aTag.href);
}
if (navigator.userAgent.indexOf('Firefox') > -1) {
const downTag = document.createElement('a');
downTag.addEventListener('click', function () {
downTag.download = fileName;
downTag.href = URL.createObjectURL(file);
});
let eventMouse = document.createEvent('MouseEvents');
eventMouse.initEvent('click', false, false);
downTag.dispatchEvent(eventMouse);
}
};
export { export {
convertTime, convertDuration, getFinalResult, getFinal, convertTime, convertDuration, getFinalResult, getFinal, downFile,
intermediateGraphOption, killJob, filterByStatus, filterDuration intermediateGraphOption, killJob, filterByStatus, filterDuration
}; };
$btnBgcolor: #0071bc; $btnBgcolor: #0071bc;
Button.tableButton{ Button.tableButton{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: $btnBgcolor; background: $btnBgcolor;
border-color: $btnBgcolor; border-color: $btnBgcolor;
height: 26px; height: 26px;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
.column{ .column{
max-width: 124px; max-width: 124px;
padding-left: 18px; padding-left: 18px;
font-weight: 700; font-weight: 600;
} }
.value{ .value{
max-width: 152px; max-width: 152px;
...@@ -20,6 +20,6 @@ ...@@ -20,6 +20,6 @@
text-align: left; text-align: left;
} }
.idList{ .idList{
font-weight: 700; font-weight: 600;
} }
} }
...@@ -55,7 +55,7 @@ div.addtitle{ ...@@ -55,7 +55,7 @@ div.addtitle{
font-size: 20px; font-size: 20px;
} }
.line{ .line{
font-weight: bold; font-weight: 600;
color: rgb(60,141,188); color: rgb(60,141,188);
padding-right: 20px; padding-right: 20px;
} }
......
.card-container > .ant-tabs-card > .ant-tabs-content {
margin-top: -16px;
}
.card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane {
background: #fff;
padding: 16px;
}
.card-container > .ant-tabs-card > .ant-tabs-bar {
border-color: #fff;
}
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab {
border-color: transparent;
background: transparent;
}
.card-container > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active {
border-color: #fff;
background: #fff;
}
.logContainer{
height: 100%;
}
.buttons{
margin-top: 15px;
.close{
text-align: right;
}
}
/*
.logDrawer{
width: 100%;
.ant-drawer-body{
box-sizing: border-box;
-webkit-box-sizing: border-box;
}
}
*/
.ant-drawer-body{
background: #333;
}
.card-container > .ant-tabs-card > .ant-tabs-bar{
border: none;
}
.card-container > .ant-tabs-card > .ant-tabs-content > .ant-tabs-tabpane{
background-color: #333;
}
.close{
Button, Button:active, Button:hover{
background-color: #212121;
color: #fff;
border: none;
}
}
.download{
Button, Button:active, Button:hover{
background-color: #2772be;
color: #fff;
border: none;
}
}
.log-tab-body > .ant-tabs-card > .ant-tabs-bar .ant-tabs-tab-active{
background-color: #1e1e1e;
color: #fff;
border: none;
}
.log-tab-body .ant-tabs-nav .ant-tabs-tab:hover, .log-tab-body .ant-tabs-nav .ant-tabs-tab{
color: #fff;
border: none;
}
.ant-tabs.ant-tabs-card>.ant-tabs-bar .ant-tabs-tab{
border: none;
}
.log-tab-body{
.refresh{
margin-left: 10px;
display: none;
}
.ant-tabs-tab-active{
.refresh{
transition: 0.3s;
display: inline-block;
}
.refresh:hover{
transform: scale(1.2);
}
}
}
.just-for-log{
.monaco-editor{
.line-numbers{
color: #fff;
}
.current-line ~ .line-numbers{
color: #FFFAF0;
}
}
.view-lines{
background-color: #1e1e1e;
.mtk1{
color: #fff;
}
}
.margin-view-overlays{
background-color: #1e1e1e;
}
}
...@@ -22,7 +22,7 @@ $bgColor: #f2f2f2; ...@@ -22,7 +22,7 @@ $bgColor: #f2f2f2;
} }
.ant-tabs-nav .ant-tabs-tab-active{ .ant-tabs-nav .ant-tabs-tab-active{
color: $color; color: $color;
font-weight: 500; font-weight: 600;
background: #dedede; background: #dedede;
border-left: 3px solid ; border-left: 3px solid ;
} }
......
...@@ -5,6 +5,7 @@ $titleBgcolor: #b3b3b3; ...@@ -5,6 +5,7 @@ $titleBgcolor: #b3b3b3;
} }
.panelTitle{ .panelTitle{
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
width: 100%; width: 100%;
height: 38px; height: 38px;
background: $titleBgcolor; background: $titleBgcolor;
...@@ -17,8 +18,7 @@ $titleBgcolor: #b3b3b3; ...@@ -17,8 +18,7 @@ $titleBgcolor: #b3b3b3;
span{ span{
font-size: 18px; font-size: 18px;
font-weight: bold; font-weight: 600;
font-family: 'Segoe';
color: #333; color: #333;
line-height: 38px; line-height: 38px;
margin-left: 14px; margin-left: 14px;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
.status{ .status{
color: #0573bc; color: #0573bc;
font-size: 20px; font-size: 20px;
font-weight: bold; font-weight: 600;
margin-top: 5px; margin-top: 5px;
} }
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
.basic{ .basic{
line-height: 24px; line-height: 24px;
font-family: 'Segoe'; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
p{ p{
font-size: 14px; font-size: 14px;
color: #212121; color: #212121;
......
...@@ -10,8 +10,8 @@ $drowHoverBgColor: #e2e2e2; ...@@ -10,8 +10,8 @@ $drowHoverBgColor: #e2e2e2;
margin: 0 auto; margin: 0 auto;
position: relative; position: relative;
.tab{ .tab{
font-family: 'Segoe';
line-height: $barHeight; line-height: $barHeight;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
a{ a{
font-size: 18px; font-size: 18px;
color: #b8c7ce; color: #b8c7ce;
......
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