Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
OpenDAS
nni
Commits
c785655e
Unverified
Commit
c785655e
authored
Oct 21, 2019
by
SparkSnail
Committed by
GitHub
Oct 21, 2019
Browse files
Merge pull request #207 from microsoft/master
merge master
parents
9fae194a
d6b61e2f
Changes
158
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1055 additions
and
916 deletions
+1055
-916
src/webui/src/components/public-child/DefaultMetrc.tsx
src/webui/src/components/public-child/DefaultMetrc.tsx
+6
-29
src/webui/src/components/public-child/IntermediateVal.tsx
src/webui/src/components/public-child/IntermediateVal.tsx
+3
-31
src/webui/src/components/public-child/OpenRow.tsx
src/webui/src/components/public-child/OpenRow.tsx
+30
-57
src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
+112
-253
src/webui/src/components/trial-detail/Duration.tsx
src/webui/src/components/trial-detail/Duration.tsx
+4
-13
src/webui/src/components/trial-detail/Intermediate.tsx
src/webui/src/components/trial-detail/Intermediate.tsx
+47
-67
src/webui/src/components/trial-detail/Para.tsx
src/webui/src/components/trial-detail/Para.tsx
+36
-63
src/webui/src/components/trial-detail/TableList.tsx
src/webui/src/components/trial-detail/TableList.tsx
+209
-313
src/webui/src/index.css
src/webui/src/index.css
+2
-2
src/webui/src/static/const.ts
src/webui/src/static/const.ts
+11
-6
src/webui/src/static/datamodel.ts
src/webui/src/static/datamodel.ts
+7
-0
src/webui/src/static/function.ts
src/webui/src/static/function.ts
+40
-16
src/webui/src/static/interface.ts
src/webui/src/static/interface.ts
+101
-45
src/webui/src/static/model/experiment.ts
src/webui/src/static/model/experiment.ts
+87
-0
src/webui/src/static/model/trial.ts
src/webui/src/static/model/trial.ts
+195
-0
src/webui/src/static/model/trialmanager.ts
src/webui/src/static/model/trialmanager.ts
+156
-0
src/webui/tslint.json
src/webui/tslint.json
+2
-17
test/config_test/multi_phase/multi_phase.py
test/config_test/multi_phase/multi_phase.py
+3
-0
test/config_test/multi_phase/multi_phase_batch.test.yml
test/config_test/multi_phase/multi_phase_batch.test.yml
+2
-2
test/config_test/multi_phase/multi_phase_grid.test.yml
test/config_test/multi_phase/multi_phase_grid.test.yml
+2
-2
No files found.
src/webui/src/components/public-child/DefaultMetrc.tsx
View file @
c785655e
import
*
as
React
from
'
react
'
;
import
{
TableObj
}
from
'
../../static/interface
'
;
import
{
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
formatAccuracy
}
from
'
../../static/function
'
;
interface
DefaultMetricProps
{
record
:
TableObj
;
trialId
:
string
;
}
class
DefaultMetric
extends
React
.
Component
<
DefaultMetricProps
,
{}
>
{
constructor
(
props
:
DefaultMetricProps
)
{
super
(
props
);
}
render
()
{
const
{
record
}
=
this
.
props
;
let
accuracy
;
if
(
record
.
acc
!==
undefined
)
{
accuracy
=
record
.
acc
.
default
;
}
let
wei
=
0
;
if
(
accuracy
!==
undefined
)
{
if
(
accuracy
.
toString
().
indexOf
(
'
.
'
)
!==
-
1
)
{
wei
=
accuracy
.
toString
().
length
-
accuracy
.
toString
().
indexOf
(
'
.
'
)
-
1
;
}
}
const
accuracy
=
TRIALS
.
getTrial
(
this
.
props
.
trialId
).
accuracy
;
return
(
<
div
>
{
record
.
acc
!==
undefined
&&
record
.
acc
.
default
!==
undefined
?
wei
>
6
?
JSON
.
parse
(
record
.
acc
.
default
).
toFixed
(
6
)
:
record
.
acc
.
default
:
'
--
'
}
</
div
>
<
div
>
{
accuracy
!==
undefined
?
formatAccuracy
(
accuracy
)
:
'
--
'
}
</
div
>
);
}
}
export
default
DefaultMetric
;
\ No newline at end of file
export
default
DefaultMetric
;
src/webui/src/components/public-child/IntermediateVal.tsx
View file @
c785655e
import
*
as
React
from
'
react
'
;
import
{
T
ableObj
}
from
'
../../static/
interface
'
;
import
{
T
RIALS
}
from
'
../../static/
datamodel
'
;
interface
IntermediateValProps
{
record
:
TableObj
;
trialId
:
string
;
}
class
IntermediateVal
extends
React
.
Component
<
IntermediateValProps
,
{}
>
{
constructor
(
props
:
IntermediateValProps
)
{
super
(
props
);
}
render
()
{
const
{
record
}
=
this
.
props
;
const
interArr
=
record
.
description
.
intermediate
;
let
lastVal
;
let
wei
=
0
;
if
(
interArr
!==
undefined
)
{
lastVal
=
interArr
[
interArr
.
length
-
1
];
}
let
result
:
string
=
JSON
.
stringify
(
lastVal
);
if
(
lastVal
!==
undefined
)
{
if
(
lastVal
.
toString
().
indexOf
(
'
.
'
)
!==
-
1
)
{
wei
=
lastVal
.
toString
().
length
-
lastVal
.
toString
().
indexOf
(
'
.
'
)
-
1
;
if
(
wei
>
6
)
{
result
=
`
${
lastVal
.
toFixed
(
6
)}
`
;
}
}
// some trial haven't final result
if
(
record
.
acc
!==
undefined
)
{
if
(
record
.
acc
.
default
!==
undefined
)
{
result
=
`
${
result
}
(FINAL)`
;
}
}
else
{
result
=
`
${
result
}
(LATEST)`
;
}
}
else
{
result
=
'
--
'
;
}
return
(
<
div
>
{
result
}
</
div
>
<
div
>
{
TRIALS
.
getTrial
(
this
.
props
.
trialId
).
formatLatestAccuracy
()
}
</
div
>
);
}
}
...
...
src/webui/src/components/public-child/OpenRow.tsx
View file @
c785655e
...
...
@@ -2,7 +2,8 @@ import * as React from 'react';
import
*
as
copy
from
'
copy-to-clipboard
'
;
import
PaiTrialLog
from
'
../public-child/PaiTrialLog
'
;
import
TrialLog
from
'
../public-child/TrialLog
'
;
import
{
TableObj
}
from
'
../../static/interface
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
Trial
}
from
'
../../static/model/trial
'
;
import
{
Row
,
Tabs
,
Button
,
message
,
Modal
}
from
'
antd
'
;
import
{
MANAGER_IP
}
from
'
../../static/const
'
;
import
'
../../static/style/overview.scss
'
;
...
...
@@ -11,10 +12,7 @@ import JSONTree from 'react-json-tree';
const
TabPane
=
Tabs
.
TabPane
;
interface
OpenRowProps
{
trainingPlatform
:
string
;
record
:
TableObj
;
logCollection
:
boolean
;
multiphase
:
boolean
;
trialId
:
string
;
}
interface
OpenRowState
{
...
...
@@ -24,7 +22,6 @@ interface OpenRowState {
class
OpenRow
extends
React
.
Component
<
OpenRowProps
,
OpenRowState
>
{
public
_isMounted
:
boolean
;
constructor
(
props
:
OpenRowProps
)
{
super
(
props
);
this
.
state
=
{
...
...
@@ -33,20 +30,16 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
};
}
showFormatModal
=
(
record
:
TableObj
)
=>
{
showFormatModal
=
(
trial
:
Trial
)
=>
{
// get copy parameters
const
params
=
JSON
.
stringify
(
record
.
description
.
p
arameters
,
null
,
4
);
const
params
=
JSON
.
stringify
(
trial
.
info
.
hyperP
arameters
,
null
,
4
);
// open modal with format string
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isShowFormatModal
:
true
,
formatStr
:
params
}));
}
this
.
setState
({
isShowFormatModal
:
true
,
formatStr
:
params
});
}
hideFormatModal
=
()
=>
{
// close modal, destroy state format string data
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isShowFormatModal
:
false
,
formatStr
:
''
}));
}
this
.
setState
({
isShowFormatModal
:
false
,
formatStr
:
''
});
}
copyParams
=
()
=>
{
...
...
@@ -62,68 +55,47 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
this
.
hideFormatModal
();
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
}
componentWillUnmount
()
{
this
.
_isMounted
=
false
;
}
render
()
{
const
{
trainingPlatform
,
record
,
logCollection
,
multiphase
}
=
this
.
props
;
const
{
isShowFormatModal
,
formatStr
}
=
this
.
state
;
let
isClick
=
false
;
let
isHasParameters
=
true
;
if
(
record
.
description
.
parameters
.
error
)
{
isHasParameters
=
false
;
}
const
openRowDataSource
=
record
.
description
.
parameters
;
const
trialink
:
string
=
`
${
MANAGER_IP
}
/trial-jobs/
${
record
.
id
}
`
;
const
logPathRow
=
record
.
description
.
logPath
!==
undefined
?
record
.
description
.
logPath
:
'
This trial
\'
s log path are not available.
'
;
const
trialId
=
this
.
props
.
trialId
;
const
trial
=
TRIALS
.
getTrial
(
trialId
);
const
trialLink
:
string
=
`
${
MANAGER_IP
}
/trial-jobs/
${
trialId
}
`
;
const
logPathRow
=
trial
.
info
.
logPath
||
'
This trial
\'
s log path is not available.
'
;
const
multiProgress
=
trial
.
info
.
hyperParameters
===
undefined
?
0
:
trial
.
info
.
hyperParameters
.
length
;
return
(
<
Row
className
=
"openRowContent hyperpar"
>
<
Tabs
tabPosition
=
"left"
className
=
"card"
>
<
TabPane
tab
=
"Parameters"
key
=
"1"
>
{
multi
p
hase
EXPERIMENT
.
multi
P
hase
?
<
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
>
".
<
br
/>
Current Phase:
{
record
.
description
.
multiProgress
}
.
<
a
href
=
{
trial
L
ink
}
target
=
"_blank"
>
{
trial
L
ink
}
</
a
>
".
<
br
/>
Current Phase:
{
multiProgress
}
.
</
Row
>
:
<
div
/>
}
{
isHasParameters
trial
.
info
.
hyperParameters
!==
undefined
?
<
Row
id
=
"description"
>
<
Row
className
=
"bgHyper"
>
{
isClick
?
<
pre
>
{
JSON
.
stringify
(
openRowDataSource
,
null
,
4
)
}
</
pre
>
:
<
JSONTree
hideRoot
=
{
true
}
shouldExpandNode
=
{
()
=>
true
}
// default expandNode
getItemString
=
{
()
=>
(<
span
/>)
}
// remove the {} items
data
=
{
openRowDataSource
}
/>
}
<
JSONTree
hideRoot
=
{
true
}
shouldExpandNode
=
{
()
=>
true
}
// default expandNode
getItemString
=
{
()
=>
(<
span
/>)
}
// remove the {} items
data
=
{
trial
.
description
.
parameters
}
/>
</
Row
>
<
Row
className
=
"copy"
>
<
Button
onClick
=
{
this
.
showFormatModal
.
bind
(
this
,
record
)
}
onClick
=
{
this
.
showFormatModal
.
bind
(
this
,
trial
)
}
>
Copy as json
</
Button
>
...
...
@@ -138,15 +110,16 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
</
TabPane
>
<
TabPane
tab
=
"Log"
key
=
"2"
>
{
trainingPlatform
!==
'
local
'
// FIXME: this should not be handled in web UI side
EXPERIMENT
.
trainingServicePlatform
!==
'
local
'
?
<
PaiTrialLog
logStr
=
{
logPathRow
}
id
=
{
record
.
i
d
}
logCollection
=
{
logCollection
}
id
=
{
trialI
d
}
logCollection
=
{
EXPERIMENT
.
logCollection
Enabled
}
/>
:
<
TrialLog
logStr
=
{
logPathRow
}
id
=
{
record
.
i
d
}
/>
<
TrialLog
logStr
=
{
logPathRow
}
id
=
{
trialI
d
}
/>
}
</
TabPane
>
</
Tabs
>
...
...
@@ -170,4 +143,4 @@ class OpenRow extends React.Component<OpenRowProps, OpenRowState> {
}
}
export
default
OpenRow
;
\ No newline at end of file
export
default
OpenRow
;
src/webui/src/components/trial-detail/DefaultMetricPoint.tsx
View file @
c785655e
import
*
as
React
from
'
react
'
;
import
{
Switch
}
from
'
antd
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
filterByStatus
}
from
'
../../static/function
'
;
import
{
TableObj
,
DetailAccurPoint
,
TooltipForAccuracy
}
from
'
../../static/interface
'
;
import
{
EXPERIMENT
,
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
Trial
}
from
'
../../static/model/trial
'
;
import
{
TooltipForAccuracy
}
from
'
../../static/interface
'
;
require
(
'
echarts/lib/chart/scatter
'
);
require
(
'
echarts/lib/component/tooltip
'
);
require
(
'
echarts/lib/component/title
'
);
interface
DefaultPointProps
{
showSource
:
Array
<
TableObj
>
;
height
:
number
;
whichGraph
:
string
;
optimize
:
string
;
trialIds
:
string
[];
visible
:
boolean
;
trialsUpdateBroadcast
:
number
;
}
interface
DefaultPointState
{
defaultSource
:
object
;
accNodata
:
string
;
succeedTrials
:
number
;
isViewBestCurve
:
boolean
;
bestCurveEnabled
:
boolean
;
}
class
DefaultPoint
extends
React
.
Component
<
DefaultPointProps
,
DefaultPointState
>
{
public
_isDefaultMounted
=
false
;
constructor
(
props
:
DefaultPointProps
)
{
super
(
props
);
this
.
state
=
{
defaultSource
:
{},
accNodata
:
''
,
succeedTrials
:
10000000
,
isViewBestCurve
:
false
};
}
defaultMetric
=
(
succeedSource
:
Array
<
TableObj
>
,
isCurve
:
boolean
)
=>
{
const
{
optimize
}
=
this
.
props
;
const
accSource
:
Array
<
DetailAccurPoint
>
=
[];
const
drawSource
:
Array
<
TableObj
>
=
succeedSource
.
filter
(
filterByStatus
);
const
lengthOfSource
=
drawSource
.
length
;
const
tooltipDefault
=
lengthOfSource
===
0
?
'
No data
'
:
''
;
if
(
this
.
_isDefaultMounted
===
true
)
{
this
.
setState
(()
=>
({
succeedTrials
:
lengthOfSource
,
accNodata
:
tooltipDefault
}));
}
if
(
lengthOfSource
===
0
)
{
const
nullGraph
=
{
grid
:
{
left
:
'
8%
'
},
xAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
},
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
}
};
if
(
this
.
_isDefaultMounted
===
true
)
{
this
.
setState
(()
=>
({
defaultSource
:
nullGraph
}));
}
}
else
{
const
resultList
:
Array
<
number
|
object
>
[]
=
[];
// lineListDefault: [[sequenceId, default metric], []]
const
lineListDefault
:
Array
<
number
>
[]
=
[];
Object
.
keys
(
drawSource
).
map
(
item
=>
{
const
temp
=
drawSource
[
item
];
if
(
temp
.
acc
!==
undefined
)
{
if
(
temp
.
acc
.
default
!==
undefined
)
{
const
searchSpace
=
temp
.
description
.
parameters
;
lineListDefault
.
push
([
temp
.
sequenceId
,
temp
.
acc
.
default
]);
accSource
.
push
({
acc
:
temp
.
acc
.
default
,
index
:
temp
.
sequenceId
,
searchSpace
:
searchSpace
});
}
}
});
// deal with best metric line
const
bestCurve
:
Array
<
number
|
object
>
[]
=
[];
// best curve data source
if
(
lineListDefault
[
0
]
!==
undefined
)
{
bestCurve
.
push
([
lineListDefault
[
0
][
0
],
lineListDefault
[
0
][
1
],
accSource
[
0
].
searchSpace
]);
}
if
(
optimize
===
'
maximize
'
)
{
for
(
let
i
=
1
;
i
<
lineListDefault
.
length
;
i
++
)
{
const
val
=
lineListDefault
[
i
][
1
];
const
latest
=
bestCurve
[
bestCurve
.
length
-
1
][
1
];
if
(
val
>=
latest
)
{
bestCurve
.
push
([
lineListDefault
[
i
][
0
],
val
,
accSource
[
i
].
searchSpace
]);
}
else
{
bestCurve
.
push
([
lineListDefault
[
i
][
0
],
latest
,
accSource
[
i
].
searchSpace
]);
}
}
}
else
{
for
(
let
i
=
1
;
i
<
lineListDefault
.
length
;
i
++
)
{
const
val
=
lineListDefault
[
i
][
1
];
const
latest
=
bestCurve
[
bestCurve
.
length
-
1
][
1
];
if
(
val
<=
latest
)
{
bestCurve
.
push
([
lineListDefault
[
i
][
0
],
val
,
accSource
[
i
].
searchSpace
]);
}
else
{
bestCurve
.
push
([
lineListDefault
[
i
][
0
],
latest
,
accSource
[
i
].
searchSpace
]);
}
}
}
Object
.
keys
(
accSource
).
map
(
item
=>
{
const
items
=
accSource
[
item
];
let
temp
:
Array
<
number
|
object
>
;
temp
=
[
items
.
index
,
items
.
acc
,
items
.
searchSpace
];
resultList
.
push
(
temp
);
});
// isViewBestCurve: false show default metric graph
// isViewBestCurve: true show best curve
if
(
isCurve
===
true
)
{
if
(
this
.
_isDefaultMounted
===
true
)
{
this
.
setState
(()
=>
({
defaultSource
:
this
.
drawBestcurve
(
bestCurve
,
resultList
)
}));
}
}
else
{
if
(
this
.
_isDefaultMounted
===
true
)
{
this
.
setState
(()
=>
({
defaultSource
:
this
.
drawDefaultMetric
(
resultList
)
}));
}
}
}
}
drawBestcurve
=
(
realDefault
:
Array
<
number
|
object
>
[],
resultList
:
Array
<
number
|
object
>
[])
=>
{
return
{
grid
:
{
left
:
'
8%
'
},
tooltip
:
{
trigger
:
'
item
'
,
enterable
:
true
,
position
:
function
(
point
:
Array
<
number
>
,
data
:
TooltipForAccuracy
)
{
if
(
data
.
data
[
0
]
<
realDefault
.
length
/
2
)
{
return
[
point
[
0
],
80
];
}
else
{
return
[
point
[
0
]
-
300
,
80
];
}
},
formatter
:
function
(
data
:
TooltipForAccuracy
)
{
const
result
=
'
<div class="tooldetailAccuracy">
'
+
'
<div>Trial No.:
'
+
data
.
data
[
0
]
+
'
</div>
'
+
'
<div>Optimization curve:
'
+
data
.
data
[
1
]
+
'
</div>
'
+
'
<div>Parameters:
'
+
'
<pre>
'
+
JSON
.
stringify
(
data
.
data
[
2
],
null
,
4
)
+
'
</pre>
'
+
'
</div>
'
+
'
</div>
'
;
return
result
;
}
},
xAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
},
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
scale
:
true
},
series
:
[
{
type
:
'
line
'
,
lineStyle
:
{
color
:
'
#FF6600
'
},
data
:
realDefault
},
{
symbolSize
:
6
,
type
:
'
scatter
'
,
data
:
resultList
}]
};
}
drawDefaultMetric
=
(
resultList
:
Array
<
number
|
object
>
[])
=>
{
return
{
grid
:
{
left
:
'
8%
'
},
tooltip
:
{
trigger
:
'
item
'
,
enterable
:
true
,
position
:
function
(
point
:
Array
<
number
>
,
data
:
TooltipForAccuracy
)
{
if
(
data
.
data
[
0
]
<
resultList
.
length
/
2
)
{
return
[
point
[
0
],
80
];
}
else
{
return
[
point
[
0
]
-
300
,
80
];
}
},
formatter
:
function
(
data
:
TooltipForAccuracy
)
{
const
result
=
'
<div class="tooldetailAccuracy">
'
+
'
<div>Trial No.:
'
+
data
.
data
[
0
]
+
'
</div>
'
+
'
<div>Default metric:
'
+
data
.
data
[
1
]
+
'
</div>
'
+
'
<div>Parameters:
'
+
'
<pre>
'
+
JSON
.
stringify
(
data
.
data
[
2
],
null
,
4
)
+
'
</pre>
'
+
'
</div>
'
+
'
</div>
'
;
return
result
;
}
},
xAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
},
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
scale
:
true
},
series
:
[{
symbolSize
:
6
,
type
:
'
scatter
'
,
data
:
resultList
}]
};
this
.
state
=
{
bestCurveEnabled
:
false
};
}
loadDefault
=
(
checked
:
boolean
)
=>
{
// checked: true show best metric curve
const
{
showSource
}
=
this
.
props
;
if
(
this
.
_isDefaultMounted
===
true
)
{
this
.
defaultMetric
(
showSource
,
checked
);
// ** deal with data and then update view layer
this
.
setState
(()
=>
({
isViewBestCurve
:
checked
}));
}
}
// update parent component state
componentWillReceiveProps
(
nextProps
:
DefaultPointProps
)
{
const
{
whichGraph
,
showSource
}
=
nextProps
;
const
{
isViewBestCurve
}
=
this
.
state
;
if
(
whichGraph
===
'
1
'
)
{
this
.
defaultMetric
(
showSource
,
isViewBestCurve
);
}
this
.
setState
({
bestCurveEnabled
:
checked
});
}
shouldComponentUpdate
(
nextProps
:
DefaultPointProps
,
nextState
:
DefaultPointState
)
{
const
{
whichGraph
}
=
nextProps
;
if
(
whichGraph
===
'
1
'
)
{
const
{
succeedTrials
,
isViewBestCurve
}
=
nextState
;
const
succTrial
=
this
.
state
.
succeedTrials
;
const
isViewBestCurveBefore
=
this
.
state
.
isViewBestCurve
;
if
(
isViewBestCurveBefore
!==
isViewBestCurve
)
{
return
true
;
}
if
(
succeedTrials
!==
succTrial
)
{
return
true
;
}
}
// only whichGraph !== '1', default metric can't update
return
false
;
}
componentDidMount
()
{
this
.
_isDefaultMounted
=
true
;
}
componentWillUnmount
()
{
this
.
_isDefaultMounted
=
false
;
return
nextProps
.
visible
;
}
render
()
{
const
{
height
}
=
this
.
props
;
const
{
defaultSource
,
accNodata
}
=
this
.
state
;
const
graph
=
this
.
generateGraph
();
const
accNodata
=
(
graph
===
EmptyGraph
?
'
No data
'
:
''
);
return
(
<
div
>
<
div
className
=
"default-metric"
>
...
...
@@ -282,10 +45,10 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
</
div
>
</
div
>
<
ReactEcharts
option
=
{
defaultSource
}
option
=
{
graph
}
style
=
{
{
width
:
'
100%
'
,
height
:
height
,
height
:
402
,
margin
:
'
0 auto
'
,
}
}
theme
=
"my_theme"
...
...
@@ -295,6 +58,102 @@ class DefaultPoint extends React.Component<DefaultPointProps, DefaultPointState>
</
div
>
);
}
private
generateGraph
()
{
const
trials
=
TRIALS
.
getTrials
(
this
.
props
.
trialIds
).
filter
(
trial
=>
trial
.
sortable
);
if
(
trials
.
length
===
0
)
{
return
EmptyGraph
;
}
const
graph
=
generateGraphConfig
(
trials
[
trials
.
length
-
1
].
sequenceId
);
if
(
this
.
state
.
bestCurveEnabled
)
{
(
graph
as
any
).
series
=
[
generateBestCurveSeries
(
trials
),
generateScatterSeries
(
trials
)
];
}
else
{
(
graph
as
any
).
series
=
[
generateScatterSeries
(
trials
)
];
}
return
graph
;
}
}
const
EmptyGraph
=
{
grid
:
{
left
:
'
8%
'
},
xAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
},
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
}
};
function
generateGraphConfig
(
maxSequenceId
:
number
)
{
return
{
grid
:
{
left
:
'
8%
'
,
},
tooltip
:
{
trigger
:
'
item
'
,
enterable
:
true
,
position
:
(
point
:
Array
<
number
>
,
data
:
TooltipForAccuracy
)
=>
(
[
(
data
.
data
[
0
]
<
maxSequenceId
?
point
[
0
]
:
(
point
[
0
]
-
300
)),
80
]
),
formatter
:
(
data
:
TooltipForAccuracy
)
=>
(
'
<div class="tooldetailAccuracy">
'
+
'
<div>Trial No.:
'
+
data
.
data
[
0
]
+
'
</div>
'
+
'
<div>Default metric:
'
+
data
.
data
[
1
]
+
'
</div>
'
+
'
<div>Parameters: <pre>
'
+
JSON
.
stringify
(
data
.
data
[
2
],
null
,
4
)
+
'
</pre></div>
'
+
'
</div>
'
),
},
xAxis
:
{
name
:
'
Trial
'
,
type
:
'
category
'
,
},
yAxis
:
{
name
:
'
Default metric
'
,
type
:
'
value
'
,
scale
:
true
,
},
series
:
undefined
,
};
}
function
generateScatterSeries
(
trials
:
Trial
[])
{
const
data
=
trials
.
map
(
trial
=>
[
trial
.
sequenceId
,
trial
.
accuracy
,
trial
.
description
.
parameters
,
]);
return
{
symbolSize
:
6
,
type
:
'
scatter
'
,
data
,
};
}
function
generateBestCurveSeries
(
trials
:
Trial
[])
{
let
best
=
trials
[
0
];
const
data
=
[[
best
.
sequenceId
,
best
.
accuracy
,
best
.
info
.
hyperParameters
]];
for
(
let
i
=
1
;
i
<
trials
.
length
;
i
++
)
{
const
trial
=
trials
[
i
];
const
delta
=
trial
.
accuracy
!
-
best
.
accuracy
!
;
const
better
=
(
EXPERIMENT
.
optimizeMode
===
'
minimize
'
)
?
(
delta
<
0
)
:
(
delta
>
0
);
if
(
better
)
{
data
.
push
([
trial
.
sequenceId
,
trial
.
accuracy
,
trial
.
info
.
hyperParameters
]);
best
=
trial
;
}
else
{
data
.
push
([
trial
.
sequenceId
,
best
.
accuracy
,
trial
.
info
.
hyperParameters
]);
}
}
return
{
type
:
'
line
'
,
lineStyle
:
{
color
:
'
#FF6600
'
},
data
,
};
}
export
default
DefaultPoint
;
\ No newline at end of file
export
default
DefaultPoint
;
src/webui/src/components/trial-detail/Duration.tsx
View file @
c785655e
...
...
@@ -22,8 +22,6 @@ interface DurationState {
class
Duration
extends
React
.
Component
<
DurationProps
,
DurationState
>
{
public
_isMounted
=
false
;
constructor
(
props
:
DurationProps
)
{
super
(
props
);
...
...
@@ -142,15 +140,12 @@ class Duration extends React.Component<DurationProps, DurationState> {
trialId
:
trialId
,
trialTime
:
trialTime
});
if
(
this
.
_isMounted
)
{
this
.
setState
({
durationSource
:
this
.
getOption
(
trialRun
[
0
])
});
}
this
.
setState
({
durationSource
:
this
.
getOption
(
trialRun
[
0
])
});
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
const
{
source
}
=
this
.
props
;
this
.
drawDurationGraph
(
source
);
}
...
...
@@ -187,10 +182,6 @@ class Duration extends React.Component<DurationProps, DurationState> {
return
false
;
}
componentWillUnmount
()
{
this
.
_isMounted
=
false
;
}
render
()
{
const
{
durationSource
}
=
this
.
state
;
return
(
...
...
@@ -206,4 +197,4 @@ class Duration extends React.Component<DurationProps, DurationState> {
}
}
export
default
Duration
;
\ No newline at end of file
export
default
Duration
;
src/webui/src/components/trial-detail/Intermediate.tsx
View file @
c785655e
...
...
@@ -24,7 +24,6 @@ interface IntermediateProps {
class
Intermediate
extends
React
.
Component
<
IntermediateProps
,
IntermediateState
>
{
static
intervalMediate
=
1
;
public
_isMounted
=
false
;
public
pointInput
:
HTMLInputElement
|
null
;
public
minValInput
:
HTMLInputElement
|
null
;
public
maxValInput
:
HTMLInputElement
|
null
;
...
...
@@ -45,12 +44,10 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
drawIntermediate
=
(
source
:
Array
<
TableObj
>
)
=>
{
if
(
source
.
length
>
0
)
{
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
length
:
source
.
length
,
detailSource
:
source
}));
}
this
.
setState
({
length
:
source
.
length
,
detailSource
:
source
});
const
trialIntermediate
:
Array
<
Intermedia
>
=
[];
Object
.
keys
(
source
).
map
(
item
=>
{
const
temp
=
source
[
item
];
...
...
@@ -118,11 +115,9 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
},
series
:
trialIntermediate
};
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
interSource
:
option
}));
}
this
.
setState
({
interSource
:
option
});
}
else
{
const
nullData
=
{
grid
:
{
...
...
@@ -139,71 +134,60 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
name
:
'
Metric
'
}
};
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
interSource
:
nullData
}));
}
this
.
setState
({
interSource
:
nullData
});
}
}
// confirm btn function [filter data]
filterLines
=
()
=>
{
if
(
this
.
_isMounted
)
{
const
filterSource
:
Array
<
TableObj
>
=
[];
this
.
setState
({
isLoadconfirmBtn
:
true
},
()
=>
{
const
{
source
}
=
this
.
props
;
// get input value
const
pointVal
=
this
.
pointInput
!==
null
?
this
.
pointInput
.
value
:
''
;
const
minVal
=
this
.
minValInput
!==
null
?
this
.
minValInput
.
value
:
''
;
const
maxVal
=
this
.
maxValInput
!==
null
?
this
.
maxValInput
.
value
:
''
;
// user not input message
if
(
pointVal
===
''
||
minVal
===
''
)
{
alert
(
'
Please input filter message
'
);
const
filterSource
:
Array
<
TableObj
>
=
[];
this
.
setState
({
isLoadconfirmBtn
:
true
},
()
=>
{
const
{
source
}
=
this
.
props
;
// get input value
const
pointVal
=
this
.
pointInput
!==
null
?
this
.
pointInput
.
value
:
''
;
const
minVal
=
this
.
minValInput
!==
null
?
this
.
minValInput
.
value
:
''
;
const
maxVal
=
this
.
maxValInput
!==
null
?
this
.
maxValInput
.
value
:
''
;
// user not input message
if
(
pointVal
===
''
||
minVal
===
''
)
{
alert
(
'
Please input filter message
'
);
}
else
{
// user not input max value
const
position
=
JSON
.
parse
(
pointVal
);
const
min
=
JSON
.
parse
(
minVal
);
if
(
maxVal
===
''
)
{
Object
.
keys
(
source
).
map
(
item
=>
{
const
temp
=
source
[
item
];
const
val
=
temp
.
description
.
intermediate
[
position
-
1
];
if
(
val
>=
min
)
{
filterSource
.
push
(
temp
);
}
});
}
else
{
// user not input max value
const
position
=
JSON
.
parse
(
pointVal
);
const
min
=
JSON
.
parse
(
minVal
);
if
(
maxVal
===
''
)
{
Object
.
keys
(
source
).
map
(
item
=>
{
const
temp
=
source
[
item
];
const
val
=
temp
.
description
.
intermediate
[
position
-
1
];
if
(
val
>=
min
)
{
filterSource
.
push
(
temp
);
}
});
}
else
{
const
max
=
JSON
.
parse
(
maxVal
);
Object
.
keys
(
source
).
map
(
item
=>
{
const
temp
=
source
[
item
];
const
val
=
temp
.
description
.
intermediate
[
position
-
1
];
if
(
val
>=
min
&&
val
<=
max
)
{
filterSource
.
push
(
temp
);
}
});
}
if
(
this
.
_isMounted
)
{
this
.
setState
({
filterSource
:
filterSource
});
}
this
.
drawIntermediate
(
filterSource
);
}
const
counts
=
this
.
state
.
clickCounts
+
1
;
if
(
this
.
_isMounted
)
{
this
.
setState
({
isLoadconfirmBtn
:
false
,
clickCounts
:
counts
});
const
max
=
JSON
.
parse
(
maxVal
);
Object
.
keys
(
source
).
map
(
item
=>
{
const
temp
=
source
[
item
];
const
val
=
temp
.
description
.
intermediate
[
position
-
1
];
if
(
val
>=
min
&&
val
<=
max
)
{
filterSource
.
push
(
temp
);
}
});
}
});
}
this
.
setState
({
filterSource
:
filterSource
});
this
.
drawIntermediate
(
filterSource
);
}
const
counts
=
this
.
state
.
clickCounts
+
1
;
this
.
setState
({
isLoadconfirmBtn
:
false
,
clickCounts
:
counts
});
});
}
switchTurn
=
(
checked
:
boolean
)
=>
{
if
(
this
.
_isMounted
)
{
this
.
setState
({
isFilter
:
checked
});
}
this
.
setState
({
isFilter
:
checked
});
if
(
checked
===
false
)
{
this
.
drawIntermediate
(
this
.
props
.
source
);
}
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
const
{
source
}
=
this
.
props
;
this
.
drawIntermediate
(
source
);
}
...
...
@@ -272,10 +256,6 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
return
false
;
}
componentWillUnmount
()
{
this
.
_isMounted
=
false
;
}
render
()
{
const
{
interSource
,
isLoadconfirmBtn
,
isFilter
}
=
this
.
state
;
return
(
...
...
@@ -292,7 +272,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
isFilter
?
<
span
>
<
span
className
=
"filter-x"
>
# Intermediate
</
span
>
<
span
className
=
"filter-x"
>
# Intermediate
result
</
span
>
<
input
// placeholder="point"
ref
=
{
input
=>
this
.
pointInput
=
input
}
...
...
@@ -327,7 +307,7 @@ class Intermediate extends React.Component<IntermediateProps, IntermediateState>
style
=
{
{
width
:
'
100%
'
,
height
:
418
,
margin
:
'
0 auto
'
}
}
notMerge
=
{
true
}
// update now
/>
<
div
className
=
"yAxis"
>
# Intermediate
</
div
>
<
div
className
=
"yAxis"
>
# Intermediate
result
</
div
>
</
Row
>
</
div
>
);
...
...
src/webui/src/components/trial-detail/Para.tsx
View file @
c785655e
...
...
@@ -40,8 +40,6 @@ message.config({
class
Para
extends
React
.
Component
<
ParaProps
,
ParaState
>
{
public
_isMounted
=
false
;
private
chartMulineStyle
=
{
width
:
'
100%
'
,
height
:
392
,
...
...
@@ -121,15 +119,12 @@ class Para extends React.Component<ParaProps, ParaState> {
this
.
swapGraph
(
paraData
,
swapAxisArr
);
}
this
.
getOption
(
paraData
,
lengthofTrials
);
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
paraBack
:
paraData
}));
}
this
.
setState
({
paraBack
:
paraData
});
}
hyperParaPic
=
(
source
:
Array
<
TableObj
>
,
searchSpace
:
string
)
=>
{
// filter succeed trials [{}, {}, {}]
const
origin
=
source
.
filter
(
filterByStatus
);
const
dataSource
:
Array
<
TableObj
>
=
JSON
.
parse
(
JSON
.
stringify
(
origin
));
const
dataSource
=
source
.
filter
(
filterByStatus
);
const
lenOfDataSource
:
number
=
dataSource
.
length
;
const
accPara
:
Array
<
number
>
=
[];
// specific value array
...
...
@@ -139,15 +134,13 @@ class Para extends React.Component<ParaProps, ParaState> {
// nest search space
let
isNested
:
boolean
=
false
;
Object
.
keys
(
searchRange
).
map
(
item
=>
{
if
(
typeof
searchRange
[
item
].
_value
[
0
]
===
'
object
'
)
{
if
(
searchRange
[
item
].
_value
&&
typeof
searchRange
[
item
].
_value
[
0
]
===
'
object
'
)
{
isNested
=
true
;
return
;
}
});
const
dimName
=
Object
.
keys
(
searchRange
);
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
dimName
:
dimName
}));
}
this
.
setState
({
dimName
:
dimName
});
const
parallelAxis
:
Array
<
Dimobj
>
=
[];
// search space range and specific value [only number]
...
...
@@ -324,23 +317,21 @@ class Para extends React.Component<ParaProps, ParaState> {
color
:
[
'
#CA0000
'
,
'
#FFC400
'
,
'
#90EE90
'
]
}
};
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
({
paraNodata
:
'
No data
'
,
option
:
optionOfNull
,
sutrialCount
:
0
,
succeedRenderCount
:
0
});
}
this
.
setState
({
paraNodata
:
'
No data
'
,
option
:
optionOfNull
,
sutrialCount
:
0
,
succeedRenderCount
:
0
});
}
else
{
Object
.
keys
(
dataSource
).
map
(
item
=>
{
const
t
emp
=
dataSource
[
item
];
eachTrialParams
.
push
(
t
emp
.
description
.
parameters
);
const
t
rial
=
dataSource
[
item
];
eachTrialParams
.
push
(
t
rial
.
description
.
parameters
||
''
);
// may be a succeed trial hasn't final result
// all detail page may be break down if havn't if
if
(
t
emp
.
acc
!==
undefined
)
{
if
(
t
emp
.
acc
.
default
!==
undefined
)
{
accPara
.
push
(
temp
.
acc
.
default
);
if
(
t
rial
.
acc
!==
undefined
)
{
if
(
t
rial
.
acc
.
default
!==
undefined
)
{
accPara
.
push
(
JSON
.
parse
(
trial
.
acc
.
default
)
)
;
}
}
});
...
...
@@ -361,14 +352,12 @@ class Para extends React.Component<ParaProps, ParaState> {
});
});
}
if
(
this
.
_isMounted
)
{
// if not return final result
const
maxVal
=
accPara
.
length
===
0
?
1
:
Math
.
max
(...
accPara
);
const
minVal
=
accPara
.
length
===
0
?
1
:
Math
.
min
(...
accPara
);
this
.
setState
({
max
:
maxVal
,
min
:
minVal
},
()
=>
{
this
.
getParallelAxis
(
dimName
,
parallelAxis
,
accPara
,
eachTrialParams
,
lenOfDataSource
);
});
}
// if not return final result
const
maxVal
=
accPara
.
length
===
0
?
1
:
Math
.
max
(...
accPara
);
const
minVal
=
accPara
.
length
===
0
?
1
:
Math
.
min
(...
accPara
);
this
.
setState
({
max
:
maxVal
,
min
:
minVal
},
()
=>
{
this
.
getParallelAxis
(
dimName
,
parallelAxis
,
accPara
,
eachTrialParams
,
lenOfDataSource
);
});
}
}
...
...
@@ -376,11 +365,9 @@ class Para extends React.Component<ParaProps, ParaState> {
percentNum
=
(
value
:
string
)
=>
{
let
vals
=
parseFloat
(
value
);
if
(
this
.
_isMounted
)
{
this
.
setState
({
percent
:
vals
},
()
=>
{
this
.
reInit
();
});
}
this
.
setState
({
percent
:
vals
},
()
=>
{
this
.
reInit
();
});
}
// deal with response data into pic data
...
...
@@ -445,22 +432,17 @@ class Para extends React.Component<ParaProps, ParaState> {
}
};
// please wait the data
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
option
:
optionown
,
paraNodata
:
''
,
succeedRenderCount
:
lengthofTrials
,
sutrialCount
:
paralleData
.
length
}));
}
this
.
setState
({
option
:
optionown
,
paraNodata
:
''
,
succeedRenderCount
:
lengthofTrials
,
sutrialCount
:
paralleData
.
length
});
}
// get swap parallel axis
getSwapArr
=
(
value
:
Array
<
string
>
)
=>
{
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
swapAxisArr
:
value
}));
}
this
.
setState
({
swapAxisArr
:
value
});
}
reInit
=
()
=>
{
...
...
@@ -471,9 +453,7 @@ class Para extends React.Component<ParaProps, ParaState> {
swapReInit
=
()
=>
{
const
{
clickCounts
,
succeedRenderCount
}
=
this
.
state
;
const
val
=
clickCounts
+
1
;
if
(
this
.
_isMounted
)
{
this
.
setState
({
isLoadConfirm
:
true
,
clickCounts
:
val
,
});
}
this
.
setState
({
isLoadConfirm
:
true
,
clickCounts
:
val
,
});
const
{
paraBack
,
swapAxisArr
}
=
this
.
state
;
const
paralDim
=
paraBack
.
parallelAxis
;
const
paraData
=
paraBack
.
data
;
...
...
@@ -523,11 +503,9 @@ class Para extends React.Component<ParaProps, ParaState> {
});
this
.
getOption
(
paraBack
,
succeedRenderCount
);
// please wait the data
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
isLoadConfirm
:
false
}));
}
this
.
setState
({
isLoadConfirm
:
false
});
}
sortDimY
=
(
a
:
Dimobj
,
b
:
Dimobj
)
=>
{
...
...
@@ -585,7 +563,6 @@ class Para extends React.Component<ParaProps, ParaState> {
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
this
.
reInit
();
}
...
...
@@ -623,10 +600,6 @@ class Para extends React.Component<ParaProps, ParaState> {
return
false
;
}
componentWillUnmount
()
{
this
.
_isMounted
=
false
;
}
render
()
{
const
{
option
,
paraNodata
,
dimName
,
isLoadConfirm
}
=
this
.
state
;
return
(
...
...
@@ -687,4 +660,4 @@ class Para extends React.Component<ParaProps, ParaState> {
}
}
export
default
Para
;
\ No newline at end of file
export
default
Para
;
src/webui/src/components/trial-detail/TableList.tsx
View file @
c785655e
...
...
@@ -2,14 +2,15 @@ import * as React from 'react';
import
axios
from
'
axios
'
;
import
ReactEcharts
from
'
echarts-for-react
'
;
import
{
Row
,
Table
,
Button
,
Popconfirm
,
Modal
,
Checkbox
,
Select
,
Icon
}
from
'
antd
'
;
import
{
ColumnProps
}
from
'
antd/lib/table
'
;
const
Option
=
Select
.
Option
;
const
CheckboxGroup
=
Checkbox
.
Group
;
import
{
MANAGER_IP
,
trialJobStatus
,
COLUMN_INDEX
,
COLUMNPro
}
from
'
../../static/const
'
;
import
{
convertDuration
,
intermediateGraphOption
,
killJob
,
filterByStatus
}
from
'
../../static/function
'
;
import
{
TableObj
,
TrialJob
}
from
'
../../static/interface
'
;
import
{
convertDuration
,
formatTimestamp
,
intermediateGraphOption
,
killJob
}
from
'
../../static/function
'
;
import
{
TRIALS
}
from
'
../../static/datamodel
'
;
import
{
TableRecord
}
from
'
../../static/interface
'
;
import
OpenRow
from
'
../public-child/OpenRow
'
;
import
Compare
from
'
../Modal/Compare
'
;
import
IntermediateVal
from
'
../public-child/IntermediateVal
'
;
// table default metric column
import
'
../../static/style/search.scss
'
;
require
(
'
../../static/style/tableStatus.css
'
);
require
(
'
../../static/style/logPath.scss
'
);
...
...
@@ -26,14 +27,11 @@ echarts.registerTheme('my_theme', {
});
interface
TableListProps
{
entries
:
number
;
tableSource
:
Array
<
TableObj
>
;
updateList
:
Function
;
platform
:
string
;
logCollection
:
boolean
;
isMultiPhase
:
boolean
;
pageSize
:
number
;
tableSource
:
Array
<
TableRecord
>
;
columnList
:
Array
<
string
>
;
// user select columnKeys
changeColumn
:
(
val
:
Array
<
string
>
)
=>
void
;
trialsUpdateBroadcast
:
number
;
}
interface
TableListState
{
...
...
@@ -41,7 +39,7 @@ interface TableListState {
modalVisible
:
boolean
;
isObjFinal
:
boolean
;
isShowColumn
:
boolean
;
selectRows
:
Array
<
Table
Obj
>
;
selectRows
:
Array
<
Table
Record
>
;
isShowCompareModal
:
boolean
;
selectedRowKeys
:
string
[]
|
number
[];
intermediateData
:
Array
<
object
>
;
// a trial's intermediate results (include dict)
...
...
@@ -56,10 +54,9 @@ interface ColumnIndex {
class
TableList
extends
React
.
Component
<
TableListProps
,
TableListState
>
{
public
_isMounted
=
false
;
public
intervalTrialLog
=
10
;
public
_trialId
:
string
;
public
tables
:
Table
<
Table
Obj
>
|
null
;
public
tables
:
Table
<
Table
Record
>
|
null
;
constructor
(
props
:
TableListProps
)
{
super
(
props
);
...
...
@@ -78,46 +75,35 @@ class TableList extends React.Component<TableListProps, TableListState> {
};
}
showIntermediateModal
=
(
id
:
string
)
=>
{
axios
(
`
${
MANAGER_IP
}
/metric-data/
${
id
}
`
,
{
method
:
'
GET
'
})
.
then
(
res
=>
{
if
(
res
.
status
===
200
)
{
const
intermediateArr
:
number
[]
=
[];
// support intermediate result is dict because the last intermediate result is
// final result in a succeed trial, it may be a dict.
// get intermediate result dict keys array
let
otherkeys
:
Array
<
string
>
=
[
'
default
'
];
if
(
res
.
data
.
length
!==
0
)
{
otherkeys
=
Object
.
keys
(
JSON
.
parse
(
res
.
data
[
0
].
data
));
}
// intermediateArr just store default val
Object
.
keys
(
res
.
data
).
map
(
item
=>
{
const
temp
=
JSON
.
parse
(
res
.
data
[
item
].
data
);
if
(
typeof
temp
===
'
object
'
)
{
intermediateArr
.
push
(
temp
.
default
);
}
else
{
intermediateArr
.
push
(
temp
);
}
});
const
intermediate
=
intermediateGraphOption
(
intermediateArr
,
id
);
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
intermediateData
:
res
.
data
,
// store origin intermediate data for a trial
intermediateOption
:
intermediate
,
intermediateOtherKeys
:
otherkeys
,
intermediateId
:
id
}));
}
showIntermediateModal
=
async
(
id
:
string
)
=>
{
const
res
=
await
axios
.
get
(
`
${
MANAGER_IP
}
/metric-data/
${
id
}
`
);
if
(
res
.
status
===
200
)
{
const
intermediateArr
:
number
[]
=
[];
// support intermediate result is dict because the last intermediate result is
// final result in a succeed trial, it may be a dict.
// get intermediate result dict keys array
let
otherkeys
:
Array
<
string
>
=
[
'
default
'
];
if
(
res
.
data
.
length
!==
0
)
{
otherkeys
=
Object
.
keys
(
JSON
.
parse
(
res
.
data
[
0
].
data
));
}
// intermediateArr just store default val
Object
.
keys
(
res
.
data
).
map
(
item
=>
{
const
temp
=
JSON
.
parse
(
res
.
data
[
item
].
data
);
if
(
typeof
temp
===
'
object
'
)
{
intermediateArr
.
push
(
temp
.
default
);
}
else
{
intermediateArr
.
push
(
temp
);
}
});
if
(
this
.
_isMounted
)
{
const
intermediate
=
intermediateGraphOption
(
intermediateArr
,
id
);
this
.
setState
({
modalVisible
:
true
intermediateData
:
res
.
data
,
// store origin intermediate data for a trial
intermediateOption
:
intermediate
,
intermediateOtherKeys
:
otherkeys
,
intermediateId
:
id
});
}
this
.
setState
({
modalVisible
:
true
});
}
// intermediate button click -> intermediate graph for each trial
...
...
@@ -147,43 +133,36 @@ class TableList extends React.Component<TableListProps, TableListState> {
}
const
intermediate
=
intermediateGraphOption
(
intermediateArr
,
intermediateId
);
// re-render
if
(
this
.
_isMounted
)
{
this
.
setState
(()
=>
({
intermediateOption
:
intermediate
}));
}
this
.
setState
({
intermediateOption
:
intermediate
});
}
hideIntermediateModal
=
()
=>
{
if
(
this
.
_isMounted
)
{
this
.
setState
({
modalVisible
:
false
});
}
this
.
setState
({
modalVisible
:
false
});
}
hideShowColumnModal
=
()
=>
{
if
(
this
.
_isMounted
)
{
this
.
setState
({
isShowColumn
:
false
});
}
this
.
setState
({
isShowColumn
:
false
});
}
// click add column btn, just show the modal of addcolumn
addColumn
=
()
=>
{
// show user select check button
if
(
this
.
_isMounted
)
{
this
.
setState
({
isShowColumn
:
true
});
}
this
.
setState
({
isShowColumn
:
true
});
}
// checkbox for coloumn
selectedColumn
=
(
checkedValues
:
Array
<
string
>
)
=>
{
// 7: because have seven common column, "Intermediate count" is hidden by default
let
count
=
7
;
// 9: because have nine common column,
// [Intermediate count, Start Time, End Time] is hidden by default
let
count
=
9
;
const
want
:
Array
<
object
>
=
[];
const
finalKeys
:
Array
<
string
>
=
[];
const
wantResult
:
Array
<
string
>
=
[];
...
...
@@ -191,13 +170,13 @@ class TableList extends React.Component<TableListProps, TableListState> {
switch
(
checkedValues
[
m
])
{
case
'
Trial No.
'
:
case
'
ID
'
:
case
'
StartTime
'
:
case
'
EndTime
'
:
case
'
Start
Time
'
:
case
'
End
Time
'
:
case
'
Duration
'
:
case
'
Status
'
:
case
'
Operation
'
:
case
'
Default
'
:
case
'
Intermediate
coun
t
'
:
case
'
Intermediate
resul
t
'
:
break
;
default
:
finalKeys
.
push
(
checkedValues
[
m
]);
...
...
@@ -229,27 +208,17 @@ class TableList extends React.Component<TableListProps, TableListState> {
wantResult
.
push
(
want
[
i
].
name
);
});
if
(
this
.
_isMounted
)
{
this
.
props
.
changeColumn
(
wantResult
);
}
this
.
props
.
changeColumn
(
wantResult
);
}
openRow
=
(
record
:
TableObj
)
=>
{
const
{
platform
,
logCollection
,
isMultiPhase
}
=
this
.
props
;
openRow
=
(
record
:
TableRecord
)
=>
{
return
(
<
OpenRow
trainingPlatform
=
{
platform
}
record
=
{
record
}
logCollection
=
{
logCollection
}
multiphase
=
{
isMultiPhase
}
/>
<
OpenRow
trialId
=
{
record
.
id
}
/>
);
}
fillSelectedRowsTostate
=
(
selected
:
number
[]
|
string
[],
selectedRows
:
Array
<
TableObj
>
)
=>
{
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
selectRows
:
selectedRows
,
selectedRowKeys
:
selected
}));
}
fillSelectedRowsTostate
=
(
selected
:
number
[]
|
string
[],
selectedRows
:
Array
<
TableRecord
>
)
=>
{
this
.
setState
({
selectRows
:
selectedRows
,
selectedRowKeys
:
selected
});
}
// open Compare-modal
compareBtn
=
()
=>
{
...
...
@@ -258,222 +227,87 @@ class TableList extends React.Component<TableListProps, TableListState> {
if
(
selectRows
.
length
===
0
)
{
alert
(
'
Please select datas you want to compare!
'
);
}
else
{
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
({
isShowCompareModal
:
true
});
}
this
.
setState
({
isShowCompareModal
:
true
});
}
}
// close Compare-modal
hideCompareModal
=
()
=>
{
// close modal. clear select rows data, clear selected track
if
(
this
.
_isMounted
)
{
this
.
setState
({
isShowCompareModal
:
false
,
selectedRowKeys
:
[],
selectRows
:
[]
});
}
}
componentDidMount
()
{
this
.
_isMounted
=
true
;
}
componentWillUnmount
()
{
this
.
_isMounted
=
false
;
this
.
setState
({
isShowCompareModal
:
false
,
selectedRowKeys
:
[],
selectRows
:
[]
});
}
render
()
{
const
{
entries
,
tableSource
,
updateList
,
columnList
}
=
this
.
props
;
const
{
pageSize
,
columnList
}
=
this
.
props
;
const
tableSource
:
Array
<
TableRecord
>
=
JSON
.
parse
(
JSON
.
stringify
(
this
.
props
.
tableSource
))
;
const
{
intermediateOption
,
modalVisible
,
isShowColumn
,
selectRows
,
isShowCompareModal
,
selectedRowKeys
,
intermediateOtherKeys
}
=
this
.
state
;
const
rowSelection
=
{
selectedRowKeys
:
selectedRowKeys
,
onChange
:
(
selected
:
string
[]
|
number
[],
selectedRows
:
Array
<
Table
Obj
>
)
=>
{
onChange
:
(
selected
:
string
[]
|
number
[],
selectedRows
:
Array
<
Table
Record
>
)
=>
{
this
.
fillSelectedRowsTostate
(
selected
,
selectedRows
);
}
};
let
showTitle
=
COLUMNPro
;
let
bgColor
=
''
;
const
trialJob
:
Array
<
TrialJob
>
=
[];
const
showColumn
:
Array
<
object
>
=
[];
// parameter as table column
const
trialMess
=
TRIALS
.
getTrial
(
tableSource
[
0
].
id
);
const
trial
=
trialMess
.
description
.
parameters
;
const
parameterColumn
:
Array
<
string
>
=
Object
.
keys
(
trial
);
const
parameterStr
:
Array
<
string
>
=
[];
parameterColumn
.
forEach
(
value
=>
{
parameterStr
.
push
(
`
${
value
}
(search space)`
);
});
showTitle
=
COLUMNPro
.
concat
(
parameterStr
);
// only succeed trials have final keys
if
(
tableSource
.
filter
(
filterByStatus
).
length
>=
1
)
{
const
temp
=
tableSource
.
filter
(
filterByStatus
)[
0
].
acc
;
if
(
tableSource
.
filter
(
record
=>
record
.
status
===
'
SUCCEEDED
'
).
length
>=
1
)
{
const
temp
=
tableSource
.
filter
(
record
=>
record
.
status
===
'
SUCCEEDED
'
)[
0
].
acc
uracy
;
if
(
temp
!==
undefined
&&
typeof
temp
===
'
object
'
)
{
if
(
this
.
_isMounted
)
{
// concat default column and finalkeys
const
item
=
Object
.
keys
(
temp
);
// item: ['default', 'other-keys', 'maybe loss']
if
(
item
.
length
>
1
)
{
const
want
:
Array
<
string
>
=
[];
item
.
forEach
(
value
=>
{
if
(
value
!==
'
default
'
)
{
want
.
push
(
value
);
}
});
showTitle
=
COLUMNPro
.
concat
(
want
);
}
// concat default column and finalkeys
const
item
=
Object
.
keys
(
temp
);
// item: ['default', 'other-keys', 'maybe loss']
if
(
item
.
length
>
1
)
{
const
want
:
Array
<
string
>
=
[];
item
.
forEach
(
value
=>
{
if
(
value
!==
'
default
'
)
{
want
.
push
(
value
);
}
});
showTitle
=
COLUMNPro
.
concat
(
want
);
}
}
}
trialJobStatus
.
map
(
item
=>
{
trialJob
.
push
({
text
:
item
,
value
:
item
});
});
Object
.
keys
(
columnList
).
map
(
key
=>
{
const
item
=
columnList
[
key
];
for
(
const
item
of
columnList
)
{
const
paraColumn
=
item
.
match
(
/
\(
search space
\)
$/
);
let
cc
;
if
(
paraColumn
!==
null
)
{
cc
=
paraColumn
.
input
;
}
switch
(
item
)
{
case
'
Trial No.
'
:
showColumn
.
push
({
title
:
'
Trial No.
'
,
dataIndex
:
'
sequenceId
'
,
key
:
'
sequenceId
'
,
width
:
120
,
className
:
'
tableHead
'
,
sorter
:
(
a
:
TableObj
,
b
:
TableObj
)
=>
(
a
.
sequenceId
as
number
)
-
(
b
.
sequenceId
as
number
)
});
showColumn
.
push
(
SequenceIdColumnConfig
);
break
;
case
'
ID
'
:
showColumn
.
push
({
title
:
'
ID
'
,
dataIndex
:
'
id
'
,
key
:
'
id
'
,
width
:
60
,
className
:
'
tableHead leftTitle
'
,
// the sort of string
sorter
:
(
a
:
TableObj
,
b
:
TableObj
):
number
=>
a
.
id
.
localeCompare
(
b
.
id
),
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
return
(
<
div
>
{
record
.
id
}
</
div
>
);
}
});
showColumn
.
push
(
IdColumnConfig
);
break
;
case
'
StartTime
'
:
showColumn
.
push
({
title
:
'
StartTime
'
,
dataIndex
:
'
startTime
'
,
key
:
'
startTime
'
,
width
:
160
,
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
const
start
=
record
.
startTime
!==
undefined
?
record
.
startTime
:
-
1
;
return
(
<
span
>
{
start
!==
-
1
?
new
Date
(
start
).
toLocaleString
(
'
en-US
'
)
:
'
--
'
}
</
span
>
);
},
});
case
'
Start Time
'
:
showColumn
.
push
(
StartTimeColumnConfig
);
break
;
case
'
EndTime
'
:
showColumn
.
push
({
title
:
'
EndTime
'
,
dataIndex
:
'
endTime
'
,
key
:
'
endTime
'
,
width
:
160
,
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
const
end
=
record
.
endTime
!==
undefined
?
record
.
endTime
:
-
1
;
return
(
<
span
>
{
end
!==
-
1
?
new
Date
(
end
).
toLocaleString
(
'
en-US
'
)
:
'
--
'
}
</
span
>
);
},
});
case
'
End Time
'
:
showColumn
.
push
(
EndTimeColumnConfig
);
break
;
case
'
Duration
'
:
showColumn
.
push
({
title
:
'
Duration
'
,
dataIndex
:
'
duration
'
,
key
:
'
duration
'
,
width
:
100
,
// the sort of number
sorter
:
(
a
:
TableObj
,
b
:
TableObj
)
=>
(
a
.
duration
as
number
)
-
(
b
.
duration
as
number
),
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
let
duration
;
if
(
record
.
duration
!==
undefined
)
{
// duration is nagative number(-1) & 0-1
if
(
record
.
duration
>
0
&&
record
.
duration
<
1
||
record
.
duration
<
0
)
{
duration
=
`
${
record
.
duration
}
s`
;
}
else
{
duration
=
convertDuration
(
record
.
duration
);
}
}
else
{
duration
=
0
;
}
return
(
<
div
className
=
"durationsty"
><
div
>
{
duration
}
</
div
></
div
>
);
},
});
showColumn
.
push
(
DurationColumnConfig
);
break
;
case
'
Status
'
:
showColumn
.
push
({
title
:
'
Status
'
,
dataIndex
:
'
status
'
,
key
:
'
status
'
,
width
:
150
,
className
:
'
tableStatus
'
,
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
bgColor
=
record
.
status
;
return
(
<
span
className
=
{
`
${
bgColor
}
commonStyle`
}
>
{
record
.
status
}
</
span
>
);
},
filters
:
trialJob
,
onFilter
:
(
value
:
string
,
record
:
TableObj
)
=>
{
return
record
.
status
.
indexOf
(
value
)
===
0
;
},
// onFilter: (value: string, record: TableObj) => record.status.indexOf(value) === 0,
sorter
:
(
a
:
TableObj
,
b
:
TableObj
):
number
=>
a
.
status
.
localeCompare
(
b
.
status
)
});
showColumn
.
push
(
StatusColumnConfig
);
break
;
case
'
Intermediate count
'
:
showColumn
.
push
({
title
:
'
Intermediate count
'
,
dataIndex
:
'
progress
'
,
key
:
'
progress
'
,
width
:
86
,
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
return
(
<
span
>
{
`#
${
record
.
description
.
intermediate
.
length
}
`
}
</
span
>
);
},
});
case
'
Intermediate result
'
:
showColumn
.
push
(
IntermediateCountColumnConfig
);
break
;
case
'
Default
'
:
showColumn
.
push
({
title
:
'
Default metric
'
,
className
:
'
leftTitle
'
,
dataIndex
:
'
acc
'
,
key
:
'
acc
'
,
width
:
120
,
sorter
:
(
a
:
TableObj
,
b
:
TableObj
)
=>
{
const
oneArr
=
a
.
description
.
intermediate
;
const
otherArr
=
b
.
description
.
intermediate
;
const
one
=
(
oneArr
[
oneArr
.
length
-
1
]
!==
undefined
)
?
oneArr
[
oneArr
.
length
-
1
]
:
0
;
const
other
=
(
otherArr
[
otherArr
.
length
-
1
]
!==
undefined
)
?
otherArr
[
otherArr
.
length
-
1
]
:
0
;
return
one
-
other
;
},
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
return
(
<
IntermediateVal
record
=
{
record
}
/>
);
}
});
showColumn
.
push
(
AccuracyColumnConfig
);
break
;
case
'
Operation
'
:
showColumn
.
push
({
...
...
@@ -481,7 +315,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
dataIndex
:
'
operation
'
,
key
:
'
operation
'
,
width
:
120
,
render
:
(
text
:
string
,
record
:
Table
Obj
)
=>
{
render
:
(
text
:
string
,
record
:
Table
Record
)
=>
{
let
trialStatus
=
record
.
status
;
const
flag
:
boolean
=
(
trialStatus
===
'
RUNNING
'
)
?
false
:
true
;
return
(
...
...
@@ -499,7 +333,7 @@ class TableList extends React.Component<TableListProps, TableListState> {
<
Popconfirm
title
=
"Are you sure to cancel this trial?"
onConfirm
=
{
killJob
.
bind
(
this
,
record
.
key
,
record
.
id
,
record
.
status
,
updateList
)
}
bind
(
this
,
record
.
key
,
record
.
id
,
record
.
status
)
}
>
<
Button
type
=
"default"
...
...
@@ -515,67 +349,40 @@ class TableList extends React.Component<TableListProps, TableListState> {
},
});
break
;
case
'
Intermediate result
'
:
case
(
cc
):
// remove SEARCH_SPACE title
const
realItem
=
item
.
replace
(
'
(search space)
'
,
''
);
showColumn
.
push
({
title
:
'
Intermediate result
'
,
dataIndex
:
'
intermediate
'
,
key
:
'
intermediate
'
,
width
:
'
16%
'
,
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
title
:
realItem
,
dataIndex
:
item
,
key
:
item
,
width
:
'
6%
'
,
render
:
(
text
:
string
,
record
:
TableRecord
)
=>
{
const
eachTrial
=
TRIALS
.
getTrial
(
record
.
id
);
return
(
<
Button
type
=
"primary"
className
=
"tableButton"
onClick
=
{
this
.
showIntermediateModal
.
bind
(
this
,
record
.
id
)
}
>
Intermediate
</
Button
>
<
span
>
{
eachTrial
.
description
.
parameters
[
realItem
]
}
</
span
>
);
},
});
break
;
default
:
showColumn
.
push
({
title
:
item
,
dataIndex
:
item
,
key
:
item
,
width
:
150
,
render
:
(
text
:
string
,
record
:
TableObj
)
=>
{
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
();
}
}
}
else
{
other
=
'
--
'
;
}
return
(
<
div
>
{
other
}
</
div
>
);
}
});
// FIXME
alert
(
'
Unexpected column type
'
);
}
}
);
}
return
(
<
Row
className
=
"tableList"
>
<
div
id
=
"tableList"
>
<
Table
ref
=
{
(
table
:
Table
<
Table
Obj
>
|
null
)
=>
this
.
tables
=
table
}
ref
=
{
(
table
:
Table
<
Table
Record
>
|
null
)
=>
this
.
tables
=
table
}
columns
=
{
showColumn
}
rowSelection
=
{
rowSelection
}
expandedRowRender
=
{
this
.
openRow
}
dataSource
=
{
tableSource
}
className
=
"commonTableStyle"
pagination
=
{
{
pageSize
:
entries
}
}
scroll
=
{
{
x
:
'
max-content
'
}
}
pagination
=
{
pageSize
>
0
?
{
pageSize
}
:
false
}
/>
{
/* Intermediate Result Modal */
}
<
Modal
...
...
@@ -640,4 +447,93 @@ class TableList extends React.Component<TableListProps, TableListState> {
}
}
const
SequenceIdColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Trial No.
'
,
dataIndex
:
'
sequenceId
'
,
width
:
120
,
className
:
'
tableHead
'
,
sorter
:
(
a
,
b
)
=>
a
.
sequenceId
-
b
.
sequenceId
};
const
IdColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
ID
'
,
dataIndex
:
'
id
'
,
width
:
60
,
className
:
'
tableHead leftTitle
'
,
sorter
:
(
a
,
b
)
=>
a
.
id
.
localeCompare
(
b
.
id
),
render
:
(
text
,
record
)
=>
(
<
div
>
{
record
.
id
}
</
div
>
)
};
const
StartTimeColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Start Time
'
,
dataIndex
:
'
startTime
'
,
width
:
160
,
render
:
(
text
,
record
)
=>
(
<
span
>
{
formatTimestamp
(
record
.
startTime
)
}
</
span
>
)
};
const
EndTimeColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
End Time
'
,
dataIndex
:
'
endTime
'
,
width
:
160
,
render
:
(
text
,
record
)
=>
(
<
span
>
{
formatTimestamp
(
record
.
endTime
,
'
--
'
)
}
</
span
>
)
};
const
DurationColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Duration
'
,
dataIndex
:
'
duration
'
,
width
:
100
,
sorter
:
(
a
,
b
)
=>
a
.
duration
-
b
.
duration
,
render
:
(
text
,
record
)
=>
(
<
div
className
=
"durationsty"
><
div
>
{
convertDuration
(
record
.
duration
)
}
</
div
></
div
>
)
};
const
StatusColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Status
'
,
dataIndex
:
'
status
'
,
width
:
150
,
className
:
'
tableStatus
'
,
render
:
(
text
,
record
)
=>
(
<
span
className
=
{
`
${
record
.
status
}
commonStyle`
}
>
{
record
.
status
}
</
span
>
),
sorter
:
(
a
,
b
)
=>
a
.
status
.
localeCompare
(
b
.
status
),
filters
:
trialJobStatus
.
map
(
status
=>
({
text
:
status
,
value
:
status
})),
onFilter
:
(
value
,
record
)
=>
(
record
.
status
===
value
)
};
const
IntermediateCountColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Intermediate result
'
,
dataIndex
:
'
intermediateCount
'
,
width
:
86
,
render
:
(
text
,
record
)
=>
(
<
span
>
{
`#
${
record
.
intermediateCount
}
`
}
</
span
>
)
};
const
AccuracyColumnConfig
:
ColumnProps
<
TableRecord
>
=
{
title
:
'
Default metric
'
,
className
:
'
leftTitle
'
,
dataIndex
:
'
accuracy
'
,
width
:
120
,
sorter
:
(
a
,
b
,
sortOrder
)
=>
{
if
(
a
.
accuracy
===
undefined
)
{
return
sortOrder
===
'
ascend
'
?
-
1
:
1
;
}
else
if
(
b
.
accuracy
===
undefined
)
{
return
sortOrder
===
'
ascend
'
?
1
:
-
1
;
}
else
{
return
a
.
accuracy
-
b
.
accuracy
;
}
},
render
:
(
text
,
record
)
=>
(
// TODO: is this needed?
<
div
>
{
record
.
latestAccuracy
}
</
div
>
)
};
export
default
TableList
;
src/webui/src/index.css
View file @
c785655e
...
...
@@ -19,8 +19,8 @@ time, mark, audio, video {
margin
:
0
;
padding
:
0
;
border
:
0
;
font
:
inherit
;
font-size
:
100%
;
font
:
inherit
;
}
/* HTML5 display-role reset for older browsers */
article
,
aside
,
details
,
figcaption
,
figure
,
...
...
@@ -48,4 +48,4 @@ q:before, q:after {
table
{
border-collapse
:
collapse
;
border-spacing
:
0
;
}
\ No newline at end of file
}
src/webui/src/static/const.ts
View file @
c785655e
// when there are more trials than this threshold, metrics will be updated in group of this size to avoid freezing
const
METRIC_GROUP_UPDATE_THRESHOLD
=
100
;
const
METRIC_GROUP_UPDATE_SIZE
=
20
;
const
MANAGER_IP
=
`/api/v1/nni`
;
const
DOWNLOAD_IP
=
`/logs`
;
const
trialJobStatus
=
[
...
...
@@ -34,11 +38,11 @@ const COLUMN_INDEX = [
index
:
2
},
{
name
:
'
StartTime
'
,
name
:
'
Start
Time
'
,
index
:
3
},
{
name
:
'
EndTime
'
,
name
:
'
End
Time
'
,
index
:
4
},
{
...
...
@@ -50,7 +54,7 @@ const COLUMN_INDEX = [
index
:
6
},
{
name
:
'
Intermediate
coun
t
'
,
name
:
'
Intermediate
resul
t
'
,
index
:
7
},
{
...
...
@@ -65,9 +69,10 @@ const COLUMN_INDEX = [
// defatult selected column
const
COLUMN
=
[
'
Trial No.
'
,
'
ID
'
,
'
Duration
'
,
'
Status
'
,
'
Default
'
,
'
Operation
'
];
// all choice column !dictory final
const
COLUMNPro
=
[
'
Trial No.
'
,
'
ID
'
,
'
StartTime
'
,
'
EndTime
'
,
'
Duration
'
,
'
Status
'
,
'
Intermediate
coun
t
'
,
'
Default
'
,
'
Operation
'
];
const
COLUMNPro
=
[
'
Trial No.
'
,
'
ID
'
,
'
Start
Time
'
,
'
End
Time
'
,
'
Duration
'
,
'
Status
'
,
'
Intermediate
resul
t
'
,
'
Default
'
,
'
Operation
'
];
export
{
MANAGER_IP
,
DOWNLOAD_IP
,
trialJobStatus
,
COLUMNPro
,
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
,
DRAWEROPTION
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
,
DRAWEROPTION
,
METRIC_GROUP_UPDATE_THRESHOLD
,
METRIC_GROUP_UPDATE_SIZE
,
};
src/webui/src/static/datamodel.ts
0 → 100644
View file @
c785655e
import
{
Experiment
}
from
'
./model/experiment
'
;
import
{
TrialManager
}
from
'
./model/trialmanager
'
;
const
EXPERIMENT
=
new
Experiment
();
const
TRIALS
=
new
TrialManager
();
export
{
EXPERIMENT
,
TRIALS
};
src/webui/src/static/function.ts
View file @
c785655e
import
axios
from
'
axios
'
;
import
{
message
}
from
'
antd
'
;
import
{
MANAGER_IP
}
from
'
./const
'
;
import
{
FinalResult
,
FinalType
,
TableObj
}
from
'
./interface
'
;
import
{
MetricDataRecord
,
FinalType
,
TableObj
}
from
'
./interface
'
;
const
convertTime
=
(
num
:
number
)
=>
{
if
(
num
<=
0
)
{
return
'
0
'
;
}
if
(
num
%
3600
===
0
)
{
return
num
/
3600
+
'
h
'
;
}
else
{
...
...
@@ -15,24 +18,28 @@ const convertTime = (num: number) => {
// trial's duration, accurate to seconds for example 10min 30s
const
convertDuration
=
(
num
:
number
)
=>
{
if
(
num
<
1
)
{
return
'
0s
'
;
}
const
hour
=
Math
.
floor
(
num
/
3600
);
const
min
=
Math
.
floor
(
num
/
60
%
60
);
const
min
ute
=
Math
.
floor
(
num
/
60
%
60
);
const
second
=
Math
.
floor
(
num
%
60
);
cons
t
result
=
hour
>
0
?
`
${
hour
}
h
${
min
}
min
${
second
}
s`
:
`
${
min
}
min
${
second
}
s`
;
if
(
hour
<=
0
&&
min
===
0
&&
second
!==
0
)
{
re
turn
`
${
second
}
s`
;
}
else
if
(
hour
===
0
&&
min
!==
0
&&
second
===
0
)
{
return
`
${
min
}
min`
;
}
else
if
(
hour
===
0
&&
min
!==
0
&&
second
!==
0
)
{
return
`
${
min
}
min
${
second
}
s`
;
}
else
{
re
turn
result
;
le
t
result
=
[
]
;
if
(
hour
>
0
)
{
re
sult
.
push
(
`
${
hour
}
h`
)
;
}
if
(
minute
>
0
)
{
result
.
push
(
`
${
minute
}
min`
);
}
if
(
second
>
0
)
{
re
sult
.
push
(
`
${
second
}
s`
)
;
}
return
result
.
join
(
'
'
);
};
// get final result value
// draw Accuracy point graph
const
getFinalResult
=
(
final
:
Array
<
FinalResult
>
)
=>
{
const
getFinalResult
=
(
final
?
:
MetricDataRecord
[]
)
=>
{
let
acc
;
let
showDefault
=
0
;
if
(
final
)
{
...
...
@@ -51,7 +58,7 @@ const getFinalResult = (final: Array<FinalResult>) => {
};
// get final result value // acc obj
const
getFinal
=
(
final
:
Array
<
FinalResult
>
)
=>
{
const
getFinal
=
(
final
?
:
MetricDataRecord
[]
)
=>
{
let
showDefault
:
FinalType
;
if
(
final
)
{
showDefault
=
JSON
.
parse
(
final
[
final
.
length
-
1
].
data
);
...
...
@@ -101,7 +108,7 @@ const intermediateGraphOption = (intermediateArr: number[], id: string) => {
};
// kill job
const
killJob
=
(
key
:
number
,
id
:
string
,
status
:
string
,
updateList
:
Function
)
=>
{
const
killJob
=
(
key
:
number
,
id
:
string
,
status
:
string
,
updateList
?
:
Function
)
=>
{
axios
(
`
${
MANAGER_IP
}
/trial-jobs/
${
id
}
`
,
{
method
:
'
DELETE
'
,
headers
:
{
...
...
@@ -113,7 +120,9 @@ const killJob = (key: number, id: string, status: string, updateList: Function)
message
.
destroy
();
message
.
success
(
'
Cancel the job successfully
'
);
// render the table
updateList
();
if
(
updateList
)
{
updateList
();
// FIXME
}
}
else
{
message
.
error
(
'
fail to cancel the job
'
);
}
...
...
@@ -160,7 +169,22 @@ const downFile = (content: string, fileName: string) => {
}
};
function
formatTimestamp
(
timestamp
?:
number
,
placeholder
?:
string
=
'
N/A
'
):
string
{
return
timestamp
?
new
Date
(
timestamp
).
toLocaleString
(
'
en-US
'
)
:
placeholder
;
}
function
metricAccuracy
(
metric
:
MetricDataRecord
):
number
{
const
data
=
JSON
.
parse
(
metric
.
data
);
return
typeof
data
===
'
number
'
?
data
:
NaN
;
}
function
formatAccuracy
(
accuracy
:
number
):
string
{
// TODO: how to format NaN?
return
accuracy
.
toFixed
(
6
).
replace
(
/0+$/
,
''
).
replace
(
/
\.
$/
,
''
);
}
export
{
convertTime
,
convertDuration
,
getFinalResult
,
getFinal
,
downFile
,
intermediateGraphOption
,
killJob
,
filterByStatus
,
filterDuration
intermediateGraphOption
,
killJob
,
filterByStatus
,
filterDuration
,
formatAccuracy
,
formatTimestamp
,
metricAccuracy
,
};
src/webui/src/static/interface.ts
View file @
c785655e
// tslint:disable:no-any
// draw accuracy graph data interface
interface
TableObj
{
key
:
number
;
...
...
@@ -12,6 +14,19 @@ interface TableObj {
endTime
?:
number
;
}
interface
TableRecord
{
key
:
string
;
sequenceId
:
number
;
startTime
:
number
;
endTime
?:
number
;
id
:
string
;
duration
:
number
;
status
:
string
;
intermediateCount
:
number
;
accuracy
?:
number
;
latestAccuracy
:
string
;
// formatted string
}
interface
SearchSpace
{
_value
:
Array
<
number
|
string
>
;
_type
:
string
;
...
...
@@ -32,26 +47,6 @@ interface Parameters {
multiProgress
?:
number
;
}
interface
Experiment
{
id
:
string
;
author
:
string
;
revision
?:
number
;
experName
:
string
;
logDir
?:
string
;
runConcurren
:
number
;
maxDuration
:
number
;
execDuration
:
number
;
MaxTrialNum
:
number
;
startTime
:
number
;
endTime
?:
number
;
trainingServicePlatform
:
string
;
tuner
:
object
;
assessor
?:
object
;
advisor
?:
object
;
clusterMetaData
?:
object
;
logCollection
?:
string
;
}
// trial accuracy
interface
AccurPoint
{
acc
:
number
;
...
...
@@ -74,21 +69,6 @@ interface TooltipForAccuracy {
data
:
Array
<
number
|
object
>
;
}
interface
TrialNumber
{
succTrial
:
number
;
failTrial
:
number
;
stopTrial
:
number
;
waitTrial
:
number
;
runTrial
:
number
;
unknowTrial
:
number
;
totalCurrentTrial
:
number
;
}
interface
TrialJob
{
text
:
string
;
value
:
string
;
}
interface
Dimobj
{
dim
:
number
;
name
:
string
;
...
...
@@ -108,10 +88,6 @@ interface ParaObj {
parallelAxis
:
Array
<
Dimobj
>
;
}
interface
FinalResult
{
data
:
string
;
}
interface
Intermedia
{
name
:
string
;
// id
type
:
string
;
...
...
@@ -119,13 +95,93 @@ interface Intermedia {
hyperPara
:
object
;
// each trial hyperpara value
}
interface
ExperimentInfo
{
platform
:
string
;
optimizeMode
:
string
;
interface
MetricDataRecord
{
timestamp
:
number
;
trialJobId
:
string
;
parameterId
:
string
;
type
:
string
;
sequence
:
number
;
data
:
string
;
}
interface
TrialJobInfo
{
id
:
string
;
sequenceId
:
number
;
status
:
string
;
startTime
?:
number
;
endTime
?:
number
;
hyperParameters
?:
string
[];
logPath
?:
string
;
finalMetricData
?:
MetricDataRecord
[];
stderrPath
?:
string
;
}
interface
ExperimentParams
{
authorName
:
string
;
experimentName
:
string
;
description
?:
string
;
trialConcurrency
:
number
;
maxExecDuration
:
number
;
// seconds
maxTrialNum
:
number
;
searchSpace
:
string
;
trainingServicePlatform
:
string
;
multiPhase
?:
boolean
;
multiThread
?:
boolean
;
versionCheck
?:
boolean
;
logCollection
?:
string
;
tuner
?:
{
className
:
string
;
builtinTunerName
?:
string
;
codeDir
?:
string
;
classArgs
?:
any
;
classFileName
?:
string
;
checkpointDir
:
string
;
gpuNum
?:
number
;
includeIntermediateResults
?:
boolean
;
};
assessor
?:
{
className
:
string
;
builtinAssessorName
?:
string
;
codeDir
?:
string
;
classArgs
?:
any
;
classFileName
?:
string
;
checkpointDir
:
string
;
gpuNum
?:
number
;
};
advisor
?:
{
className
:
string
;
builtinAdvisorName
?:
string
;
codeDir
?:
string
;
classArgs
?:
any
;
classFileName
?:
string
;
checkpointDir
:
string
;
gpuNum
?:
number
;
};
clusterMetaData
?:
{
key
:
string
;
value
:
string
;
}[];
}
interface
ExperimentProfile
{
params
:
ExperimentParams
;
id
:
string
;
execDuration
:
number
;
logDir
?:
string
;
startTime
?:
number
;
endTime
?:
number
;
maxSequenceId
:
number
;
revision
:
number
;
}
interface
NNIManagerStatus
{
status
:
string
;
errors
:
string
[];
}
export
{
TableObj
,
Parameters
,
Experiment
,
AccurPoint
,
TrialNumber
,
TrialJob
,
DetailAccurPoint
,
TooltipForAccuracy
,
ParaObj
,
Dimobj
,
FinalResult
,
FinalType
,
TooltipForIntermediate
,
SearchSpace
,
Intermedia
,
ExperimentInfo
TableObj
,
TableRecord
,
Parameters
,
ExperimentProfile
,
AccurPoint
,
DetailAccurPoint
,
TooltipForAccuracy
,
ParaObj
,
Dimobj
,
FinalType
,
TooltipForIntermediate
,
SearchSpace
,
Intermedia
,
MetricDataRecord
,
TrialJobInfo
,
NNIManagerStatus
,
};
src/webui/src/static/model/experiment.ts
0 → 100644
View file @
c785655e
import
axios
from
'
axios
'
;
import
{
MANAGER_IP
}
from
'
../const
'
;
import
{
ExperimentProfile
,
NNIManagerStatus
}
from
'
../interface
'
;
function
compareProfiles
(
profile1
?:
ExperimentProfile
,
profile2
?:
ExperimentProfile
):
boolean
{
if
(
!
profile1
||
!
profile2
)
{
return
false
;
}
const
copy1
=
Object
.
assign
({},
profile1
,
{
execDuration
:
undefined
});
const
copy2
=
Object
.
assign
({},
profile2
,
{
execDuration
:
undefined
});
return
JSON
.
stringify
(
copy1
)
===
JSON
.
stringify
(
copy2
);
}
class
Experiment
{
private
profileField
?:
ExperimentProfile
=
undefined
;
private
statusField
?:
NNIManagerStatus
=
undefined
;
public
async
init
():
Promise
<
void
>
{
while
(
!
this
.
profileField
||
!
this
.
statusField
)
{
await
this
.
update
();
}
}
public
async
update
():
Promise
<
boolean
>
{
const
profilePromise
=
axios
.
get
(
`
${
MANAGER_IP
}
/experiment`
);
const
statusPromise
=
axios
.
get
(
`
${
MANAGER_IP
}
/check-status`
);
const
[
profileResponse
,
statusResponse
]
=
await
Promise
.
all
([
profilePromise
,
statusPromise
]);
let
updated
=
false
;
if
(
statusResponse
.
status
===
200
)
{
updated
=
JSON
.
stringify
(
this
.
statusField
)
===
JSON
.
stringify
(
statusResponse
.
data
);
this
.
statusField
=
statusResponse
.
data
;
}
if
(
profileResponse
.
status
===
200
)
{
updated
=
updated
||
compareProfiles
(
this
.
profileField
,
profileResponse
.
data
);
this
.
profileField
=
profileResponse
.
data
;
}
return
updated
;
}
get
profile
():
ExperimentProfile
{
if
(
!
this
.
profileField
)
{
throw
Error
(
'
Experiment profile not initialized
'
);
}
return
this
.
profileField
!
;
}
get
trialConcurrency
():
number
{
return
this
.
profile
.
params
.
trialConcurrency
;
}
get
optimizeMode
():
string
{
const
tuner
=
this
.
profile
.
params
.
tuner
;
return
(
tuner
&&
tuner
.
classArgs
&&
tuner
.
classArgs
.
optimize_mode
)
?
tuner
.
classArgs
.
optimize_mode
:
'
unknown
'
;
}
get
trainingServicePlatform
():
string
{
return
this
.
profile
.
params
.
trainingServicePlatform
;
}
get
searchSpace
():
object
{
return
JSON
.
parse
(
this
.
profile
.
params
.
searchSpace
);
}
get
logCollectionEnabled
():
boolean
{
return
!!
(
this
.
profile
.
params
.
logCollection
&&
this
.
profile
.
params
.
logCollection
!==
'
none
'
);
}
get
multiPhase
():
boolean
{
return
!!
(
this
.
profile
.
params
.
multiPhase
);
}
get
status
():
string
{
if
(
!
this
.
statusField
)
{
throw
Error
(
'
Experiment status not initialized
'
);
}
return
this
.
statusField
!
.
status
;
}
get
error
():
string
{
if
(
!
this
.
statusField
)
{
throw
Error
(
'
Experiment status not initialized
'
);
}
return
this
.
statusField
!
.
errors
[
0
]
||
''
;
}
}
export
{
Experiment
};
src/webui/src/static/model/trial.ts
0 → 100644
View file @
c785655e
import
{
MetricDataRecord
,
TrialJobInfo
,
TableObj
,
TableRecord
,
Parameters
,
FinalType
}
from
'
../interface
'
;
import
{
getFinal
,
formatAccuracy
,
metricAccuracy
}
from
'
../function
'
;
class
Trial
implements
TableObj
{
private
metricsInitialized
:
boolean
=
false
;
private
infoField
:
TrialJobInfo
|
undefined
;
private
intermediates
:
(
MetricDataRecord
|
undefined
)[]
=
[
];
private
final
:
MetricDataRecord
|
undefined
;
private
finalAcc
:
number
|
undefined
;
constructor
(
info
?:
TrialJobInfo
,
metrics
?:
MetricDataRecord
[])
{
this
.
infoField
=
info
;
if
(
metrics
)
{
this
.
updateMetrics
(
metrics
);
}
}
public
compareAccuracy
(
otherTrial
:
Trial
):
number
|
undefined
{
if
(
!
this
.
sortable
||
!
otherTrial
.
sortable
)
{
return
undefined
;
}
return
this
.
finalAcc
!
-
otherTrial
.
finalAcc
!
;
}
get
info
():
TrialJobInfo
{
return
this
.
infoField
!
;
}
get
intermediateMetrics
():
MetricDataRecord
[]
{
const
ret
:
MetricDataRecord
[]
=
[
];
for
(
let
i
=
0
;
i
<
this
.
intermediates
.
length
;
i
++
)
{
if
(
this
.
intermediates
[
i
])
{
ret
.
push
(
this
.
intermediates
[
i
]
!
);
}
else
{
break
;
}
}
return
ret
;
}
get
accuracy
():
number
|
undefined
{
return
this
.
finalAcc
;
}
get
sortable
():
boolean
{
return
this
.
finalAcc
!==
undefined
&&
!
isNaN
(
this
.
finalAcc
);
}
/* table obj start */
get
tableRecord
():
TableRecord
{
const
endTime
=
this
.
info
.
endTime
||
new
Date
().
getTime
();
const
duration
=
(
endTime
-
this
.
info
.
startTime
!
)
/
1000
;
return
{
key
:
this
.
info
.
id
,
sequenceId
:
this
.
info
.
sequenceId
,
id
:
this
.
info
.
id
,
startTime
:
this
.
info
.
startTime
!
,
endTime
:
this
.
info
.
endTime
,
duration
,
status
:
this
.
info
.
status
,
intermediateCount
:
this
.
intermediates
.
length
,
accuracy
:
this
.
finalAcc
,
latestAccuracy
:
this
.
formatLatestAccuracy
(),
};
}
get
key
():
number
{
return
this
.
info
.
sequenceId
;
}
get
sequenceId
():
number
{
return
this
.
info
.
sequenceId
;
}
get
id
():
string
{
return
this
.
info
.
id
;
}
get
duration
():
number
{
const
endTime
=
this
.
info
.
endTime
||
new
Date
().
getTime
();
return
(
endTime
-
this
.
info
.
startTime
!
)
/
1000
;
}
get
status
():
string
{
return
this
.
info
.
status
;
}
get
acc
():
FinalType
|
undefined
{
return
getFinal
(
this
.
info
.
finalMetricData
);
}
get
description
():
Parameters
{
let
ret
:
Parameters
=
{
parameters
:
{
},
intermediate
:
[
],
multiProgress
:
1
};
const
tempHyper
=
this
.
info
.
hyperParameters
;
if
(
tempHyper
!==
undefined
)
{
const
getPara
=
JSON
.
parse
(
tempHyper
[
tempHyper
.
length
-
1
]).
parameters
;
ret
.
multiProgress
=
tempHyper
.
length
;
if
(
typeof
getPara
===
'
string
'
)
{
ret
.
parameters
=
JSON
.
parse
(
getPara
);
}
else
{
ret
.
parameters
=
getPara
;
}
}
else
{
ret
.
parameters
=
{
error
:
'
This trial
\'
s parameters are not available.
'
};
}
if
(
this
.
info
.
logPath
!==
undefined
)
{
ret
.
logPath
=
this
.
info
.
logPath
;
}
const
mediate
:
number
[]
=
[
];
for
(
const
items
of
this
.
intermediateMetrics
)
{
if
(
typeof
JSON
.
parse
(
items
.
data
)
===
'
object
'
)
{
mediate
.
push
(
JSON
.
parse
(
items
.
data
).
default
);
}
else
{
mediate
.
push
(
JSON
.
parse
(
items
.
data
));
}
}
ret
.
intermediate
=
mediate
;
return
ret
;
}
get
color
():
string
|
undefined
{
return
undefined
;
}
/* table obj end */
public
initialized
():
boolean
{
return
!!
(
this
.
infoField
&&
this
.
metricsInitialized
);
}
public
updateMetrics
(
metrics
:
MetricDataRecord
[]):
boolean
{
// parameter `metrics` must contain all known metrics of this trial
this
.
metricsInitialized
=
true
;
const
prevMetricCnt
=
this
.
intermediates
.
length
+
(
this
.
final
?
1
:
0
);
if
(
metrics
.
length
<=
prevMetricCnt
)
{
return
false
;
}
for
(
const
metric
of
metrics
)
{
if
(
metric
.
type
===
'
PERIODICAL
'
)
{
this
.
intermediates
[
metric
.
sequence
]
=
metric
;
}
else
{
this
.
final
=
metric
;
this
.
finalAcc
=
metricAccuracy
(
metric
);
}
}
return
true
;
}
public
updateLatestMetrics
(
metrics
:
MetricDataRecord
[]):
boolean
{
// this method is effectively identical to `updateMetrics`, but has worse performance
this
.
metricsInitialized
=
true
;
let
updated
=
false
;
for
(
const
metric
of
metrics
)
{
if
(
metric
.
type
===
'
PERIODICAL
'
)
{
updated
=
updated
||
!
this
.
intermediates
[
metric
.
sequence
];
this
.
intermediates
[
metric
.
sequence
]
=
metric
;
}
else
{
updated
=
updated
||
!
this
.
final
;
this
.
final
=
metric
;
this
.
finalAcc
=
metricAccuracy
(
metric
);
}
}
return
updated
;
}
public
updateTrialJobInfo
(
trialJobInfo
:
TrialJobInfo
):
boolean
{
const
same
=
(
this
.
infoField
&&
this
.
infoField
.
status
===
trialJobInfo
.
status
);
this
.
infoField
=
trialJobInfo
;
if
(
trialJobInfo
.
finalMetricData
)
{
this
.
final
=
trialJobInfo
.
finalMetricData
[
trialJobInfo
.
finalMetricData
.
length
-
1
];
this
.
finalAcc
=
metricAccuracy
(
this
.
final
);
}
return
!
same
;
}
public
formatLatestAccuracy
():
string
{
// TODO: this should be private
if
(
this
.
accuracy
!==
undefined
)
{
return
`
${
formatAccuracy
(
this
.
accuracy
)}
(FINAL)`
;
}
else
if
(
this
.
intermediates
.
length
===
0
)
{
return
'
--
'
;
}
else
{
const
latest
=
this
.
intermediates
[
this
.
intermediates
.
length
-
1
]
!
;
return
`
${
formatAccuracy
(
metricAccuracy
(
latest
))}
(LATEST)`
;
}
}
}
export
{
Trial
};
src/webui/src/static/model/trialmanager.ts
0 → 100644
View file @
c785655e
import
axios
from
'
axios
'
;
import
{
MANAGER_IP
,
METRIC_GROUP_UPDATE_THRESHOLD
,
METRIC_GROUP_UPDATE_SIZE
}
from
'
../const
'
;
import
{
MetricDataRecord
,
TableRecord
,
TrialJobInfo
}
from
'
../interface
'
;
import
{
Trial
}
from
'
./trial
'
;
class
TrialManager
{
private
trials
:
Map
<
string
,
Trial
>
=
new
Map
<
string
,
Trial
>
();
private
infoInitialized
:
boolean
=
false
;
private
metricInitialized
:
boolean
=
false
;
private
maxSequenceId
:
number
=
0
;
private
doingBatchUpdate
:
boolean
=
false
;
private
batchUpdatedAfterReading
:
boolean
=
false
;
public
async
init
():
Promise
<
void
>
{
while
(
!
this
.
infoInitialized
||
!
this
.
metricInitialized
)
{
await
this
.
update
();
}
}
public
async
update
(
lastTime
?:
boolean
):
Promise
<
boolean
>
{
const
[
infoUpdated
,
metricUpdated
]
=
await
Promise
.
all
([
this
.
updateInfo
(),
this
.
updateMetrics
(
lastTime
)
]);
return
infoUpdated
||
metricUpdated
;
}
public
getTrial
(
trialId
:
string
):
Trial
{
return
this
.
trials
.
get
(
trialId
)
!
;
}
public
getTrials
(
trialIds
:
string
[]):
Trial
[]
{
return
trialIds
.
map
(
trialId
=>
this
.
trials
.
get
(
trialId
)
!
);
}
public
table
(
trialIds
:
string
[]):
TableRecord
[]
{
return
trialIds
.
map
(
trialId
=>
this
.
trials
.
get
(
trialId
)
!
.
tableRecord
);
}
public
toArray
():
Trial
[]
{
const
trials
=
Array
.
from
(
this
.
trials
.
values
()).
filter
(
trial
=>
trial
.
initialized
());
return
trials
.
sort
((
trial1
,
trial2
)
=>
trial1
.
sequenceId
-
trial2
.
sequenceId
);
}
public
filter
(
callback
:
(
trial
:
Trial
)
=>
boolean
):
Trial
[]
{
const
trials
=
Array
.
from
(
this
.
trials
.
values
()).
filter
(
trial
=>
trial
.
initialized
()
&&
callback
(
trial
));
return
trials
.
sort
((
trial1
,
trial2
)
=>
trial1
.
sequenceId
-
trial2
.
sequenceId
);
}
public
succeededTrials
():
Trial
[]
{
return
this
.
filter
(
trial
=>
trial
.
status
===
'
SUCCEEDED
'
);
}
public
sort
():
Trial
[]
{
return
this
.
filter
(
trial
=>
trial
.
sortable
).
sort
((
trial1
,
trial2
)
=>
trial1
.
compareAccuracy
(
trial2
)
!
);
}
public
countStatus
():
Map
<
string
,
number
>
{
const
cnt
=
new
Map
<
string
,
number
>
([
[
'
UNKNOWN
'
,
0
],
[
'
WAITING
'
,
0
],
[
'
RUNNING
'
,
0
],
[
'
SUCCEEDED
'
,
0
],
[
'
FAILED
'
,
0
],
[
'
USER_CANCELED
'
,
0
],
[
'
SYS_CANCELED
'
,
0
],
[
'
EARLY_STOPPED
'
,
0
],
]);
for
(
const
trial
of
this
.
trials
.
values
())
{
if
(
trial
.
initialized
())
{
cnt
.
set
(
trial
.
info
.
status
,
cnt
.
get
(
trial
.
info
.
status
)
!
+
1
);
}
}
return
cnt
;
}
private
async
updateInfo
():
Promise
<
boolean
>
{
const
response
=
await
axios
.
get
(
`
${
MANAGER_IP
}
/trial-jobs`
);
let
updated
=
false
;
if
(
response
.
status
===
200
)
{
for
(
const
info
of
response
.
data
as
TrialJobInfo
[])
{
if
(
this
.
trials
.
has
(
info
.
id
))
{
updated
=
this
.
trials
.
get
(
info
.
id
)
!
.
updateTrialJobInfo
(
info
)
||
updated
;
}
else
{
this
.
trials
.
set
(
info
.
id
,
new
Trial
(
info
,
undefined
));
updated
=
true
;
}
this
.
maxSequenceId
=
Math
.
max
(
this
.
maxSequenceId
,
info
.
sequenceId
);
}
this
.
infoInitialized
=
true
;
}
return
updated
;
}
private
async
updateMetrics
(
lastTime
?:
boolean
):
Promise
<
boolean
>
{
if
(
this
.
trials
.
size
<
METRIC_GROUP_UPDATE_THRESHOLD
||
lastTime
)
{
return
await
this
.
updateAllMetrics
();
}
else
{
this
.
updateManyMetrics
();
const
ret
=
(
await
this
.
updateLatestMetrics
())
||
this
.
batchUpdatedAfterReading
;
this
.
batchUpdatedAfterReading
=
false
;
return
ret
;
}
}
private
async
updateAllMetrics
():
Promise
<
boolean
>
{
const
response
=
await
axios
.
get
(
`
${
MANAGER_IP
}
/metric-data`
);
return
(
response
.
status
===
200
)
&&
this
.
doUpdateMetrics
(
response
.
data
as
MetricDataRecord
[],
false
);
}
private
async
updateLatestMetrics
():
Promise
<
boolean
>
{
const
response
=
await
axios
.
get
(
`
${
MANAGER_IP
}
/metric-data-latest`
);
return
(
response
.
status
===
200
)
&&
this
.
doUpdateMetrics
(
response
.
data
as
MetricDataRecord
[],
true
);
}
private
async
updateManyMetrics
():
Promise
<
void
>
{
if
(
this
.
doingBatchUpdate
)
{
return
;
}
this
.
doingBatchUpdate
=
true
;
for
(
let
i
=
0
;
i
<
this
.
maxSequenceId
;
i
+=
METRIC_GROUP_UPDATE_SIZE
)
{
const
response
=
await
axios
.
get
(
`
${
MANAGER_IP
}
/metric-data-range/
${
i
}
/
${
i
+
METRIC_GROUP_UPDATE_SIZE
}
`
);
if
(
response
.
status
===
200
)
{
const
updated
=
this
.
doUpdateMetrics
(
response
.
data
as
MetricDataRecord
[],
false
);
this
.
batchUpdatedAfterReading
=
this
.
batchUpdatedAfterReading
||
updated
;
}
}
this
.
doingBatchUpdate
=
false
;
}
private
doUpdateMetrics
(
allMetrics
:
MetricDataRecord
[],
latestOnly
:
boolean
):
boolean
{
let
updated
=
false
;
for
(
const
[
trialId
,
metrics
]
of
groupMetricsByTrial
(
allMetrics
).
entries
())
{
if
(
this
.
trials
.
has
(
trialId
))
{
const
trial
=
this
.
trials
.
get
(
trialId
)
!
;
updated
=
(
latestOnly
?
trial
.
updateLatestMetrics
(
metrics
)
:
trial
.
updateMetrics
(
metrics
))
||
updated
;
}
else
{
this
.
trials
.
set
(
trialId
,
new
Trial
(
undefined
,
metrics
));
updated
=
true
;
}
}
this
.
metricInitialized
=
true
;
return
updated
;
}
}
function
groupMetricsByTrial
(
metrics
:
MetricDataRecord
[]):
Map
<
string
,
MetricDataRecord
[]
>
{
const
ret
=
new
Map
<
string
,
MetricDataRecord
[]
>
();
for
(
const
metric
of
metrics
)
{
if
(
ret
.
has
(
metric
.
trialJobId
))
{
ret
.
get
(
metric
.
trialJobId
)
!
.
push
(
metric
);
}
else
{
ret
.
set
(
metric
.
trialJobId
,
[
metric
]);
}
}
return
ret
;
}
export
{
TrialManager
};
src/webui/tslint.json
View file @
c785655e
...
...
@@ -11,10 +11,6 @@
],
"ban"
:
false
,
"class-name"
:
true
,
"comment-format"
:
[
true
,
"check-space"
],
"curly"
:
true
,
"eofline"
:
false
,
"forin"
:
true
,
...
...
@@ -40,19 +36,9 @@
"static-before-instance"
,
"variables-before-functions"
],
"no-any"
:
true
,
"no-arg"
:
true
,
"no-bitwise"
:
true
,
"no-console"
:
[
true
,
"log"
,
"error"
,
"debug"
,
"info"
,
"time"
,
"timeEnd"
,
"trace"
],
"no-console"
:
false
,
"no-consecutive-blank-lines"
:
true
,
"no-construct"
:
true
,
"no-debugger"
:
true
,
...
...
@@ -64,7 +50,6 @@
"no-switch-case-fall-through"
:
true
,
"no-trailing-whitespace"
:
false
,
"no-unused-expression"
:
true
,
"no-use-before-declare"
:
true
,
"one-line"
:
[
true
,
"check-catch"
,
...
...
@@ -123,4 +108,4 @@
"check-typecast"
]
}
}
\ No newline at end of file
}
test/config_test/multi_phase/multi_phase.py
View file @
c785655e
...
...
@@ -4,5 +4,8 @@ import nni
if
__name__
==
'__main__'
:
for
i
in
range
(
5
):
hyper_params
=
nni
.
get_next_parameter
()
print
(
'hyper_params:[{}]'
.
format
(
hyper_params
))
if
hyper_params
is
None
:
break
nni
.
report_final_result
(
0.1
*
i
)
time
.
sleep
(
3
)
test/config_test/multi_phase/multi_phase_batch.test.yml
View file @
c785655e
authorName
:
nni
experimentName
:
default_test
maxExecDuration
:
5m
maxTrialNum
:
8
trialConcurrency
:
4
maxTrialNum
:
2
trialConcurrency
:
2
searchSpacePath
:
./search_space.json
tuner
:
...
...
test/config_test/multi_phase/multi_phase_grid.test.yml
View file @
c785655e
authorName
:
nni
experimentName
:
default_test
maxExecDuration
:
5m
maxTrialNum
:
8
trialConcurrency
:
4
maxTrialNum
:
2
trialConcurrency
:
2
searchSpacePath
:
./search_space.json
tuner
:
...
...
Prev
1
…
3
4
5
6
7
8
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment