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
4bbffd17
"docs/source/Tutorial/Contributing.rst" did not exist on "a0ae02e6c5e096b70cb6bb1ecd643dddd81000ba"
Commit
4bbffd17
authored
Jul 17, 2019
by
suiguoxin
Browse files
Merge branch 'master' of
git://github.com/microsoft/nni
parents
d92c69f4
4592ba41
Changes
87
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
878 additions
and
301 deletions
+878
-301
docs/en_US/training_services.rst
docs/en_US/training_services.rst
+5
-5
docs/en_US/tuners.rst
docs/en_US/tuners.rst
+3
-3
docs/en_US/tutorials.rst
docs/en_US/tutorials.rst
+9
-8
src/sdk/pynni/nni/__main__.py
src/sdk/pynni/nni/__main__.py
+0
-2
src/sdk/pynni/nni/bohb_advisor/bohb_advisor.py
src/sdk/pynni/nni/bohb_advisor/bohb_advisor.py
+106
-46
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
+60
-38
src/sdk/pynni/nni/msg_dispatcher.py
src/sdk/pynni/nni/msg_dispatcher.py
+6
-5
src/sdk/pynni/nni/utils.py
src/sdk/pynni/nni/utils.py
+8
-0
src/webui/src/App.css
src/webui/src/App.css
+1
-0
src/webui/src/components/Modal/ExperimentDrawer.tsx
src/webui/src/components/Modal/ExperimentDrawer.tsx
+144
-0
src/webui/src/components/Modal/LogDrawer.tsx
src/webui/src/components/Modal/LogDrawer.tsx
+206
-0
src/webui/src/components/SlideBar.tsx
src/webui/src/components/SlideBar.tsx
+111
-186
src/webui/src/components/overview/Progress.tsx
src/webui/src/components/overview/Progress.tsx
+24
-3
src/webui/src/components/public-child/MonacoEditor.tsx
src/webui/src/components/public-child/MonacoEditor.tsx
+50
-0
src/webui/src/static/const.ts
src/webui/src/static/const.ts
+6
-1
src/webui/src/static/function.ts
src/webui/src/static/function.ts
+23
-1
src/webui/src/static/style/button.scss
src/webui/src/static/style/button.scss
+1
-0
src/webui/src/static/style/compare.scss
src/webui/src/static/style/compare.scss
+2
-2
src/webui/src/static/style/control.scss
src/webui/src/static/style/control.scss
+1
-1
src/webui/src/static/style/logDrawer.scss
src/webui/src/static/style/logDrawer.scss
+112
-0
No files found.
docs/en_US/training_services.rst
View file @
4bbffd17
...
...
@@ -2,8 +2,8 @@ Introduction to NNI Training Services
=====================================
.. toctree::
Local<LocalMode>
Remote<RemoteMachineMode>
OpenPAI<PaiMode>
Kubeflow<KubeflowMode>
FrameworkController<FrameworkControllerMode>
\ No newline at end of file
Local<./TrainingService/LocalMode>
Remote<./TrainingService/RemoteMachineMode>
OpenPAI<./TrainingService/PaiMode>
Kubeflow<./TrainingService/KubeflowMode>
FrameworkController<./TrainingService/FrameworkControllerMode>
\ No newline at end of file
docs/en_US/tuners.rst
View file @
4bbffd17
...
...
@@ -13,6 +13,6 @@ For details, please refer to the following tutorials:
.. toctree::
:maxdepth: 2
Builtin Tuners<BuiltinTuner>
Customized Tuners<CustomizeTuner>
Customized Advisor<CustomizeAdvisor>
\ No newline at end of file
Builtin Tuners <builtin_tuner>
Customized Tuners <Tuner/CustomizeTuner>
Customized Advisor <Tuner/CustomizeAdvisor>
docs/en_US/tutorials.rst
View file @
4bbffd17
...
...
@@ -5,12 +5,13 @@ Tutorials
.. toctree::
:maxdepth: 2
Installation
Write Trial
<
Trials>
Tuners<tuners>
Assessors<assessors>
WebUI
Training Platform<training_services>
How to use docker
<
HowToUseDocker>
Installation
<Tutorial/Installation>
Write Trial
<TrialExample/
Trials>
Tuners
<tuners>
Assessors
<assessors>
WebUI
<Tutorial/WebUI>
Training Platform
<training_services>
How to use docker
<Tutorial/
HowToUseDocker>
advanced
Debug HowTo<HowToDebug>
\ No newline at end of file
Debug HowTo <Tutorial/HowToDebug>
NNI on Windows <Tutorial/NniOnWindows>
\ No newline at end of file
src/sdk/pynni/nni/__main__.py
View file @
4bbffd17
...
...
@@ -130,8 +130,6 @@ def main():
if
args
.
advisor_class_name
:
# advisor is enabled and starts to run
if
args
.
multi_phase
:
raise
AssertionError
(
'multi_phase has not been supported in advisor'
)
if
args
.
advisor_class_name
in
AdvisorModuleName
:
dispatcher
=
create_builtin_class_instance
(
args
.
advisor_class_name
,
...
...
src/sdk/pynni/nni/bohb_advisor/bohb_advisor.py
View file @
4bbffd17
...
...
@@ -31,7 +31,8 @@ import ConfigSpace.hyperparameters as CSH
from
nni.protocol
import
CommandType
,
send
from
nni.msg_dispatcher_base
import
MsgDispatcherBase
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
,
randint_to_quniform
from
nni.utils
import
OptimizeMode
,
MetricType
,
extract_scalar_reward
,
randint_to_quniform
from
nni.common
import
multi_phase_enabled
from
.config_generator
import
CG_BOHB
...
...
@@ -79,7 +80,7 @@ def create_bracket_parameter_id(brackets_id, brackets_curr_decay, increased_id=-
return
params_id
class
Bracket
():
class
Bracket
(
object
):
"""
A bracket in BOHB, all the information of a bracket is managed by
an instance of this class.
...
...
@@ -329,11 +330,12 @@ class BOHB(MsgDispatcherBase):
# config generator
self
.
cg
=
None
def
load_checkpoint
(
self
):
pass
def
save_checkpoint
(
self
):
pass
# record the latest parameter_id of the trial job trial_job_id.
# if there is no running parameter_id, self.job_id_para_id_map[trial_job_id] == None
# new trial job is added to this dict and finished trial job is removed from it.
self
.
job_id_para_id_map
=
dict
()
# record the unsatisfied parameter request from trial jobs
self
.
unsatisfied_jobs
=
[]
def
handle_initialize
(
self
,
data
):
"""Initialize Tuner, including creating Bayesian optimization-based parametric models
...
...
@@ -399,7 +401,7 @@ class BOHB(MsgDispatcherBase):
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
def
_
reques
t_one_trial_job
(
self
):
def
_
ge
t_one_trial_job
(
self
):
"""get one trial job, i.e., one hyperparameter configuration.
If this function is called, Command will be sent by BOHB:
...
...
@@ -423,7 +425,7 @@ class BOHB(MsgDispatcherBase):
'parameters'
:
''
}
send
(
CommandType
.
NoMoreTrialJobs
,
json_tricks
.
dumps
(
ret
))
return
return
None
assert
self
.
generated_hyper_configs
params
=
self
.
generated_hyper_configs
.
pop
()
ret
=
{
...
...
@@ -432,8 +434,29 @@ class BOHB(MsgDispatcherBase):
'parameters'
:
params
[
1
]
}
self
.
parameters
[
params
[
0
]]
=
params
[
1
]
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
self
.
credit
-=
1
return
ret
def
_request_one_trial_job
(
self
):
"""get one trial job, i.e., one hyperparameter configuration.
If this function is called, Command will be sent by BOHB:
a. If there is a parameter need to run, will return "NewTrialJob" with a dict:
{
'parameter_id': id of new hyperparameter
'parameter_source': 'algorithm'
'parameters': value of new hyperparameter
}
b. If BOHB don't have parameter waiting, will return "NoMoreTrialJobs" with
{
'parameter_id': '-1_0_0',
'parameter_source': 'algorithm',
'parameters': ''
}
"""
ret
=
self
.
_get_one_trial_job
()
if
ret
is
not
None
:
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
self
.
credit
-=
1
def
handle_update_search_space
(
self
,
data
):
"""change json format to ConfigSpace format dict<dict> -> configspace
...
...
@@ -502,23 +525,38 @@ class BOHB(MsgDispatcherBase):
hyper_params: the hyperparameters (a string) generated and returned by tuner
"""
logger
.
debug
(
'Tuner handle trial end, result is %s'
,
data
)
hyper_params
=
json_tricks
.
loads
(
data
[
'hyper_params'
])
s
,
i
,
_
=
hyper_params
[
'parameter_id'
].
split
(
'_'
)
self
.
_handle_trial_end
(
hyper_params
[
'parameter_id'
])
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
del
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
def
_send_new_trial
(
self
):
while
self
.
unsatisfied_jobs
:
ret
=
self
.
_get_one_trial_job
()
if
ret
is
None
:
break
one_unsatisfied
=
self
.
unsatisfied_jobs
.
pop
(
0
)
ret
[
'trial_job_id'
]
=
one_unsatisfied
[
'trial_job_id'
]
ret
[
'parameter_index'
]
=
one_unsatisfied
[
'parameter_index'
]
# update parameter_id in self.job_id_para_id_map
self
.
job_id_para_id_map
[
ret
[
'trial_job_id'
]]
=
ret
[
'parameter_id'
]
send
(
CommandType
.
SendTrialJobParameter
,
json_tricks
.
dumps
(
ret
))
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
def
_handle_trial_end
(
self
,
parameter_id
):
s
,
i
,
_
=
parameter_id
.
split
(
'_'
)
hyper_configs
=
self
.
brackets
[
int
(
s
)].
inform_trial_end
(
int
(
i
))
if
hyper_configs
is
not
None
:
logger
.
debug
(
'bracket %s next round %s, hyper_configs: %s'
,
s
,
i
,
hyper_configs
)
self
.
generated_hyper_configs
=
self
.
generated_hyper_configs
+
hyper_configs
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
# Finish this bracket and generate a new bracket
elif
self
.
brackets
[
int
(
s
)].
no_more_trial
:
self
.
curr_s
-=
1
self
.
generate_new_bracket
()
for
_
in
range
(
self
.
credit
):
self
.
_request_one_trial_job
()
self
.
_send_new_trial
()
def
handle_report_metric_data
(
self
,
data
):
"""reveice the metric data and update Bayesian optimization with final result
...
...
@@ -535,36 +573,58 @@ class BOHB(MsgDispatcherBase):
"""
logger
.
debug
(
'handle report metric data = %s'
,
data
)
assert
'value'
in
data
value
=
extract_scalar_reward
(
data
[
'value'
])
if
self
.
optimize_mode
is
OptimizeMode
.
Maximize
:
reward
=
-
value
else
:
reward
=
value
assert
'parameter_id'
in
data
s
,
i
,
_
=
data
[
'parameter_id'
].
split
(
'_'
)
logger
.
debug
(
'bracket id = %s, metrics value = %s, type = %s'
,
s
,
value
,
data
[
'type'
])
s
=
int
(
s
)
assert
'type'
in
data
if
data
[
'type'
]
==
'FINAL'
:
# and PERIODICAL metric are independent, thus, not comparable.
assert
'sequence'
in
data
self
.
brackets
[
s
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
sys
.
maxsize
,
value
)
self
.
completed_hyper_configs
.
append
(
data
)
_parameters
=
self
.
parameters
[
data
[
'parameter_id'
]]
_parameters
.
pop
(
_KEY
)
# update BO with loss, max_s budget, hyperparameters
self
.
cg
.
new_result
(
loss
=
reward
,
budget
=
data
[
'sequence'
],
parameters
=
_parameters
,
update_model
=
True
)
elif
data
[
'type'
]
==
'PERIODICAL'
:
self
.
brackets
[
s
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
data
[
'sequence'
],
value
)
if
data
[
'type'
]
==
MetricType
.
REQUEST_PARAMETER
:
assert
multi_phase_enabled
()
assert
data
[
'trial_job_id'
]
is
not
None
assert
data
[
'parameter_index'
]
is
not
None
assert
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
self
.
_handle_trial_end
(
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]])
ret
=
self
.
_get_one_trial_job
()
if
ret
is
None
:
self
.
unsatisfied_jobs
.
append
({
'trial_job_id'
:
data
[
'trial_job_id'
],
'parameter_index'
:
data
[
'parameter_index'
]})
else
:
ret
[
'trial_job_id'
]
=
data
[
'trial_job_id'
]
ret
[
'parameter_index'
]
=
data
[
'parameter_index'
]
# update parameter_id in self.job_id_para_id_map
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
ret
[
'parameter_id'
]
send
(
CommandType
.
SendTrialJobParameter
,
json_tricks
.
dumps
(
ret
))
else
:
raise
ValueError
(
'Data type not supported: {}'
.
format
(
data
[
'type'
]))
assert
'value'
in
data
value
=
extract_scalar_reward
(
data
[
'value'
])
if
self
.
optimize_mode
is
OptimizeMode
.
Maximize
:
reward
=
-
value
else
:
reward
=
value
assert
'parameter_id'
in
data
s
,
i
,
_
=
data
[
'parameter_id'
].
split
(
'_'
)
logger
.
debug
(
'bracket id = %s, metrics value = %s, type = %s'
,
s
,
value
,
data
[
'type'
])
s
=
int
(
s
)
# add <trial_job_id, parameter_id> to self.job_id_para_id_map here,
# because when the first parameter_id is created, trial_job_id is not known yet.
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
assert
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
==
data
[
'parameter_id'
]
else
:
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
data
[
'parameter_id'
]
assert
'type'
in
data
if
data
[
'type'
]
==
MetricType
.
FINAL
:
# and PERIODICAL metric are independent, thus, not comparable.
assert
'sequence'
in
data
self
.
brackets
[
s
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
sys
.
maxsize
,
value
)
self
.
completed_hyper_configs
.
append
(
data
)
_parameters
=
self
.
parameters
[
data
[
'parameter_id'
]]
_parameters
.
pop
(
_KEY
)
# update BO with loss, max_s budget, hyperparameters
self
.
cg
.
new_result
(
loss
=
reward
,
budget
=
data
[
'sequence'
],
parameters
=
_parameters
,
update_model
=
True
)
elif
data
[
'type'
]
==
MetricType
.
PERIODICAL
:
self
.
brackets
[
s
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
data
[
'sequence'
],
value
)
else
:
raise
ValueError
(
'Data type not supported: {}'
.
format
(
data
[
'type'
]))
def
handle_add_customized_trial
(
self
,
data
):
pass
...
...
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
View file @
4bbffd17
...
...
@@ -30,8 +30,8 @@ import json_tricks
from
nni.protocol
import
CommandType
,
send
from
nni.msg_dispatcher_base
import
MsgDispatcherBase
from
nni.common
import
init_logger
from
nni.utils
import
NodeType
,
OptimizeMode
,
extract_scalar_reward
,
randint_to_quniform
from
nni.common
import
init_logger
,
multi_phase_enabled
from
nni.utils
import
NodeType
,
OptimizeMode
,
MetricType
,
extract_scalar_reward
,
randint_to_quniform
import
nni.parameter_expressions
as
parameter_expressions
_logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -277,7 +277,7 @@ class Hyperband(MsgDispatcherBase):
optimize_mode: str
optimize mode, 'maximize' or 'minimize'
"""
def
__init__
(
self
,
R
,
eta
=
3
,
optimize_mode
=
'maximize'
):
def
__init__
(
self
,
R
=
60
,
eta
=
3
,
optimize_mode
=
'maximize'
):
"""B = (s_max + 1)R"""
super
(
Hyperband
,
self
).
__init__
()
self
.
R
=
R
# pylint: disable=invalid-name
...
...
@@ -296,11 +296,10 @@ class Hyperband(MsgDispatcherBase):
# In this case, tuner increases self.credit to issue a trial config sometime later.
self
.
credit
=
0
def
load_checkpoint
(
self
):
pass
def
save_checkpoint
(
self
):
pass
# record the latest parameter_id of the trial job trial_job_id.
# if there is no running parameter_id, self.job_id_para_id_map[trial_job_id] == None
# new trial job is added to this dict and finished trial job is removed from it.
self
.
job_id_para_id_map
=
dict
()
def
handle_initialize
(
self
,
data
):
"""data is search space
...
...
@@ -321,9 +320,10 @@ class Hyperband(MsgDispatcherBase):
number of trial jobs
"""
for
_
in
range
(
data
):
self
.
_request_one_trial_job
()
ret
=
self
.
_get_one_trial_job
()
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
def
_
reques
t_one_trial_job
(
self
):
def
_
ge
t_one_trial_job
(
self
):
"""get one trial job, i.e., one hyperparameter configuration."""
if
not
self
.
generated_hyper_configs
:
if
self
.
curr_s
<
0
:
...
...
@@ -346,7 +346,8 @@ class Hyperband(MsgDispatcherBase):
'parameter_source'
:
'algorithm'
,
'parameters'
:
params
[
1
]
}
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
return
ret
def
handle_update_search_space
(
self
,
data
):
"""data: JSON object, which is search space
...
...
@@ -360,6 +361,18 @@ class Hyperband(MsgDispatcherBase):
randint_to_quniform
(
self
.
searchspace_json
)
self
.
random_state
=
np
.
random
.
RandomState
()
def
_handle_trial_end
(
self
,
parameter_id
):
"""
Parameters
----------
parameter_id: parameter id of the finished config
"""
bracket_id
,
i
,
_
=
parameter_id
.
split
(
'_'
)
hyper_configs
=
self
.
brackets
[
int
(
bracket_id
)].
inform_trial_end
(
int
(
i
))
if
hyper_configs
is
not
None
:
_logger
.
debug
(
'bracket %s next round %s, hyper_configs: %s'
,
bracket_id
,
i
,
hyper_configs
)
self
.
generated_hyper_configs
=
self
.
generated_hyper_configs
+
hyper_configs
def
handle_trial_end
(
self
,
data
):
"""
Parameters
...
...
@@ -371,22 +384,9 @@ class Hyperband(MsgDispatcherBase):
hyper_params: the hyperparameters (a string) generated and returned by tuner
"""
hyper_params
=
json_tricks
.
loads
(
data
[
'hyper_params'
])
bracket_id
,
i
,
_
=
hyper_params
[
'parameter_id'
].
split
(
'_'
)
hyper_configs
=
self
.
brackets
[
int
(
bracket_id
)].
inform_trial_end
(
int
(
i
))
if
hyper_configs
is
not
None
:
_logger
.
debug
(
'bracket %s next round %s, hyper_configs: %s'
,
bracket_id
,
i
,
hyper_configs
)
self
.
generated_hyper_configs
=
self
.
generated_hyper_configs
+
hyper_configs
for
_
in
range
(
self
.
credit
):
if
not
self
.
generated_hyper_configs
:
break
params
=
self
.
generated_hyper_configs
.
pop
()
ret
=
{
'parameter_id'
:
params
[
0
],
'parameter_source'
:
'algorithm'
,
'parameters'
:
params
[
1
]
}
send
(
CommandType
.
NewTrialJob
,
json_tricks
.
dumps
(
ret
))
self
.
credit
-=
1
self
.
_handle_trial_end
(
hyper_params
[
'parameter_id'
])
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
del
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
def
handle_report_metric_data
(
self
,
data
):
"""
...
...
@@ -400,18 +400,40 @@ class Hyperband(MsgDispatcherBase):
ValueError
Data type not supported
"""
value
=
extract_scalar_reward
(
data
[
'value'
])
bracket_id
,
i
,
_
=
data
[
'parameter_id'
].
split
(
'_'
)
bracket_id
=
int
(
bracket_id
)
if
data
[
'type'
]
==
'FINAL'
:
# sys.maxsize indicates this value is from FINAL metric data, because data['sequence'] from FINAL metric
# and PERIODICAL metric are independent, thus, not comparable.
self
.
brackets
[
bracket_id
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
sys
.
maxsize
,
value
)
self
.
completed_hyper_configs
.
append
(
data
)
elif
data
[
'type'
]
==
'PERIODICAL'
:
self
.
brackets
[
bracket_id
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
data
[
'sequence'
],
value
)
if
data
[
'type'
]
==
MetricType
.
REQUEST_PARAMETER
:
assert
multi_phase_enabled
()
assert
data
[
'trial_job_id'
]
is
not
None
assert
data
[
'parameter_index'
]
is
not
None
assert
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
self
.
_handle_trial_end
(
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]])
ret
=
self
.
_get_one_trial_job
()
if
data
[
'trial_job_id'
]
is
not
None
:
ret
[
'trial_job_id'
]
=
data
[
'trial_job_id'
]
if
data
[
'parameter_index'
]
is
not
None
:
ret
[
'parameter_index'
]
=
data
[
'parameter_index'
]
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
ret
[
'parameter_id'
]
send
(
CommandType
.
SendTrialJobParameter
,
json_tricks
.
dumps
(
ret
))
else
:
raise
ValueError
(
'Data type not supported: {}'
.
format
(
data
[
'type'
]))
value
=
extract_scalar_reward
(
data
[
'value'
])
bracket_id
,
i
,
_
=
data
[
'parameter_id'
].
split
(
'_'
)
bracket_id
=
int
(
bracket_id
)
# add <trial_job_id, parameter_id> to self.job_id_para_id_map here,
# because when the first parameter_id is created, trial_job_id is not known yet.
if
data
[
'trial_job_id'
]
in
self
.
job_id_para_id_map
:
assert
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
==
data
[
'parameter_id'
]
else
:
self
.
job_id_para_id_map
[
data
[
'trial_job_id'
]]
=
data
[
'parameter_id'
]
if
data
[
'type'
]
==
MetricType
.
FINAL
:
# sys.maxsize indicates this value is from FINAL metric data, because data['sequence'] from FINAL metric
# and PERIODICAL metric are independent, thus, not comparable.
self
.
brackets
[
bracket_id
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
sys
.
maxsize
,
value
)
self
.
completed_hyper_configs
.
append
(
data
)
elif
data
[
'type'
]
==
MetricType
.
PERIODICAL
:
self
.
brackets
[
bracket_id
].
set_config_perf
(
int
(
i
),
data
[
'parameter_id'
],
data
[
'sequence'
],
value
)
else
:
raise
ValueError
(
'Data type not supported: {}'
.
format
(
data
[
'type'
]))
def
handle_add_customized_trial
(
self
,
data
):
pass
...
...
src/sdk/pynni/nni/msg_dispatcher.py
View file @
4bbffd17
...
...
@@ -27,6 +27,7 @@ from .msg_dispatcher_base import MsgDispatcherBase
from
.assessor
import
AssessResult
from
.common
import
multi_thread_enabled
,
multi_phase_enabled
from
.env_vars
import
dispatcher_env_vars
from
.utils
import
MetricType
_logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -133,12 +134,12 @@ class MsgDispatcher(MsgDispatcherBase):
- 'value': metric value reported by nni.report_final_result()
- 'type': report type, support {'FINAL', 'PERIODICAL'}
"""
if
data
[
'type'
]
==
'
FINAL
'
:
if
data
[
'type'
]
==
MetricType
.
FINAL
:
self
.
_handle_final_metric_data
(
data
)
elif
data
[
'type'
]
==
'
PERIODICAL
'
:
elif
data
[
'type'
]
==
MetricType
.
PERIODICAL
:
if
self
.
assessor
is
not
None
:
self
.
_handle_intermediate_metric_data
(
data
)
elif
data
[
'type'
]
==
'
REQUEST_PARAMETER
'
:
elif
data
[
'type'
]
==
MetricType
.
REQUEST_PARAMETER
:
assert
multi_phase_enabled
()
assert
data
[
'trial_job_id'
]
is
not
None
assert
data
[
'parameter_index'
]
is
not
None
...
...
@@ -183,7 +184,7 @@ class MsgDispatcher(MsgDispatcherBase):
def
_handle_intermediate_metric_data
(
self
,
data
):
"""Call assessor to process intermediate results
"""
if
data
[
'type'
]
!=
'
PERIODICAL
'
:
if
data
[
'type'
]
!=
MetricType
.
PERIODICAL
:
return
if
self
.
assessor
is
None
:
return
...
...
@@ -224,7 +225,7 @@ class MsgDispatcher(MsgDispatcherBase):
trial is early stopped.
"""
_logger
.
debug
(
'Early stop notify tuner data: [%s]'
,
data
)
data
[
'type'
]
=
'
FINAL
'
data
[
'type'
]
=
MetricType
.
FINAL
if
multi_thread_enabled
():
self
.
_handle_final_metric_data
(
data
)
else
:
...
...
src/sdk/pynni/nni/utils.py
View file @
4bbffd17
...
...
@@ -51,6 +51,14 @@ class NodeType:
NAME
=
'_name'
class
MetricType
:
"""The types of metric data
"""
FINAL
=
'FINAL'
PERIODICAL
=
'PERIODICAL'
REQUEST_PARAMETER
=
'REQUEST_PARAMETER'
def
split_index
(
params
):
"""
Delete index infromation from params
...
...
src/webui/src/App.css
View file @
4bbffd17
.nni
{
font-family
:
'Segoe UI'
,
Tahoma
,
Geneva
,
Verdana
,
sans-serif
;
color
:
#212121
;
font-size
:
14px
;
background
:
#f2f2f2
;
...
...
src/webui/src/components/Modal/ExperimentDrawer.tsx
0 → 100644
View file @
4bbffd17
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
;
src/webui/src/components/Modal/LogDrawer.tsx
0 → 100644
View file @
4bbffd17
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
;
src/webui/src/components/SlideBar.tsx
View file @
4bbffd17
...
...
@@ -3,10 +3,11 @@ import { Link } from 'react-router';
import
axios
from
'
axios
'
;
import
{
MANAGER_IP
}
from
'
../static/const
'
;
import
MediaQuery
from
'
react-responsive
'
;
import
{
DOWNLOAD_IP
}
from
'
../static/const
'
;
import
{
Row
,
Col
,
Menu
,
Dropdown
,
Icon
,
Select
,
Button
}
from
'
antd
'
;
const
{
SubMenu
}
=
Menu
;
const
{
Option
}
=
Select
;
import
LogDrawer
from
'
./Modal/LogDrawer
'
;
import
ExperimentDrawer
from
'
./Modal/ExperimentDrawer
'
;
import
'
../static/style/slideBar.scss
'
;
import
'
../static/style/button.scss
'
;
...
...
@@ -15,6 +16,9 @@ interface SliderState {
menuVisible
:
boolean
;
navBarVisible
:
boolean
;
isdisabledFresh
:
boolean
;
isvisibleLogDrawer
:
boolean
;
isvisibleExperimentDrawer
:
boolean
;
activeKey
:
string
;
}
interface
SliderProps
{
...
...
@@ -38,124 +42,13 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
version
:
''
,
menuVisible
:
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
=
()
=>
{
axios
(
`
${
MANAGER_IP
}
/version`
,
{
method
:
'
GET
'
...
...
@@ -170,17 +63,23 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
handleMenuClick
=
(
e
:
EventPer
)
=>
{
if
(
this
.
_isMounted
)
{
this
.
setState
({
menuVisible
:
false
});
}
switch
(
e
.
key
)
{
// download experiment
related content
//
to see &
download experiment
parameters
case
'
1
'
:
this
.
downExperimentContent
();
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isvisibleExperimentDrawer
:
true
}));
}
break
;
// download nnimanager log
file
//
to see &
download nnimanager log
case
'
2
'
:
this
.
downnnimanagerLog
();
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
activeKey
:
'
nnimanager
'
,
isvisibleLogDrawer
:
true
}));
}
break
;
// download dispatcher log
file
//
to see &
download dispatcher log
case
'
3
'
:
this
.
downDispatcherlog
();
if
(
this
.
_isMounted
===
true
)
{
this
.
setState
(()
=>
({
isvisibleLogDrawer
:
true
,
activeKey
:
'
dispatcher
'
}));
}
break
;
case
'
close
'
:
case
'
10
'
:
...
...
@@ -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
()
{
this
.
_isMounted
=
true
;
this
.
getNNIversion
();
...
...
@@ -295,79 +208,91 @@ class SlideBar extends React.Component<SliderProps, SliderState> {
}
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
}
`
;
return
(
<
Row
>
<
Col
span
=
{
18
}
>
<
MediaQuery
query
=
"(min-width: 1299px)"
>
<
Row
className
=
"nav"
>
<
ul
className
=
"link"
>
<
li
className
=
"logo"
>
<
Row
>
<
Col
span
=
{
18
}
>
<
MediaQuery
query
=
"(min-width: 1299px)"
>
<
Row
className
=
"nav"
>
<
ul
className
=
"link"
>
<
li
className
=
"logo"
>
<
Link
to
=
{
'
/oview
'
}
>
<
img
src
=
{
require
(
'
../static/img/logo2.png
'
)
}
style
=
{
{
width
:
88
}
}
alt
=
"NNI logo"
/>
</
Link
>
</
li
>
<
li
className
=
"tab firstTab"
>
<
Link
to
=
{
'
/oview
'
}
activeClassName
=
"high"
>
Overview
</
Link
>
</
li
>
<
li
className
=
"tab"
>
<
Link
to
=
{
'
/detail
'
}
activeClassName
=
"high"
>
Trials detail
</
Link
>
</
li
>
<
li
className
=
"feedback"
>
<
Dropdown
className
=
"dropdown"
overlay
=
{
this
.
menu
()
}
onVisibleChange
=
{
this
.
handleVisibleChange
}
visible
=
{
menuVisible
}
trigger
=
{
[
'
click
'
]
}
>
<
a
className
=
"ant-dropdown-link"
href
=
"#"
>
Download
<
Icon
type
=
"down"
/>
</
a
>
</
Dropdown
>
<
a
href
=
{
feed
}
target
=
"_blank"
>
<
img
src
=
{
require
(
'
../static/img/icon/issue.png
'
)
}
alt
=
"NNI github issue"
/>
Feedback
</
a
>
<
span
className
=
"version"
>
Version:
{
version
}
</
span
>
</
li
>
</
ul
>
</
Row
>
</
MediaQuery
>
</
Col
>
<
Col
span
=
{
18
}
>
<
MediaQuery
query
=
"(max-width: 1299px)"
>
<
Row
className
=
"little"
>
<
Col
span
=
{
1
}
className
=
"menu"
>
<
Dropdown
overlay
=
{
this
.
navigationBar
()
}
trigger
=
{
[
'
click
'
]
}
>
<
Icon
type
=
"unordered-list"
className
=
"more"
/>
</
Dropdown
>
</
Col
>
<
Col
span
=
{
14
}
className
=
"logo"
>
<
Link
to
=
{
'
/oview
'
}
>
<
img
src
=
{
require
(
'
../static/img/logo2.png
'
)
}
style
=
{
{
width
:
8
8
}
}
style
=
{
{
width
:
8
0
}
}
alt
=
"NNI logo"
/>
</
Link
>
</
li
>
<
li
className
=
"tab firstTab"
>
<
Link
to
=
{
'
/oview
'
}
activeClassName
=
"high"
>
Overview
</
Link
>
</
li
>
<
li
className
=
"tab"
>
<
Link
to
=
{
'
/detail
'
}
activeClassName
=
"high"
>
Trials detail
</
Link
>
</
li
>
<
li
className
=
"feedback"
>
<
Dropdown
className
=
"dropdown"
overlay
=
{
this
.
menu
()
}
onVisibleChange
=
{
this
.
handleVisibleChange
}
visible
=
{
menuVisible
}
trigger
=
{
[
'
click
'
]
}
>
<
a
className
=
"ant-dropdown-link"
href
=
"#"
>
Download
<
Icon
type
=
"down"
/>
</
a
>
</
Dropdown
>
<
a
href
=
{
feed
}
target
=
"_blank"
>
<
img
src
=
{
require
(
'
../static/img/icon/issue.png
'
)
}
alt
=
"NNI github issue"
/>
Feedback
</
a
>
<
span
className
=
"version"
>
Version:
{
version
}
</
span
>
</
li
>
</
ul
>
</
Row
>
</
MediaQuery
>
</
Col
>
<
Col
span
=
{
18
}
>
<
MediaQuery
query
=
"(max-width: 1299px)"
>
<
Row
className
=
"little"
>
<
Col
span
=
{
1
}
className
=
"menu"
>
<
Dropdown
overlay
=
{
this
.
navigationBar
()
}
trigger
=
{
[
'
click
'
]
}
>
<
Icon
type
=
"unordered-list"
className
=
"more"
/>
</
Dropdown
>
</
Col
>
<
Col
span
=
{
14
}
className
=
"logo"
>
<
Link
to
=
{
'
/oview
'
}
>
<
img
src
=
{
require
(
'
../static/img/logo2.png
'
)
}
style
=
{
{
width
:
80
}
}
alt
=
"NNI logo"
/>
</
Link
>
</
Col
>
</
Row
>
</
MediaQuery
>
</
Col
>
<
Col
span
=
{
3
}
>
{
this
.
select
()
}
</
Col
>
</
Col
>
</
Row
>
</
MediaQuery
>
</
Col
>
<
Col
span
=
{
3
}
>
{
this
.
select
()
}
</
Col
>
</
Row
>
{
/* the drawer for dispatcher & nnimanager log message */
}
<
LogDrawer
isVisble
=
{
isvisibleLogDrawer
}
closeDrawer
=
{
this
.
closeLogDrawer
}
activeTab
=
{
activeKey
}
/>
<
ExperimentDrawer
isVisble
=
{
isvisibleExperimentDrawer
}
closeExpDrawer
=
{
this
.
closeExpDrawer
}
/>
</
Row
>
);
}
...
...
src/webui/src/components/overview/Progress.tsx
View file @
4bbffd17
...
...
@@ -7,6 +7,7 @@ import { MANAGER_IP, CONTROLTYPE } from '../../static/const';
import
{
Experiment
,
TrialNumber
}
from
'
../../static/interface
'
;
import
{
convertTime
}
from
'
../../static/function
'
;
import
ProgressBar
from
'
./ProgressItem
'
;
import
LogDrawer
from
'
../Modal/LogDrawer
'
;
import
'
../../static/style/progress.scss
'
;
import
'
../../static/style/probar.scss
'
;
...
...
@@ -24,6 +25,7 @@ interface ProgressState {
isEnable
:
boolean
;
userInputVal
:
string
;
// get user input
cancelSty
:
string
;
isShowLogDrawer
:
boolean
;
}
class
Progressed
extends
React
.
Component
<
ProgressProps
,
ProgressState
>
{
...
...
@@ -36,7 +38,8 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
btnName
:
'
Edit
'
,
isEnable
:
true
,
userInputVal
:
this
.
props
.
trialProfile
.
runConcurren
.
toString
(),
cancelSty
:
'
none
'
cancelSty
:
'
none
'
,
isShowLogDrawer
:
false
};
}
...
...
@@ -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
()
{
const
{
trialProfile
}
=
this
.
props
;
if
(
this
.
conInput
!==
null
)
{
...
...
@@ -156,7 +171,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
render
()
{
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
bar2Percent
=
(
bar2
/
trialProfile
.
MaxTrialNum
)
*
100
;
const
percent
=
(
trialProfile
.
execDuration
/
trialProfile
.
maxDuration
)
*
100
;
...
...
@@ -173,6 +188,7 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
errorContent
=
(
<
div
className
=
"errors"
>
{
errors
}
<
div
><
a
href
=
"#"
onClick
=
{
this
.
isShowDrawer
}
>
Learn about
</
a
></
div
>
</
div
>
);
}
...
...
@@ -282,8 +298,13 @@ class Progressed extends React.Component<ProgressProps, ProgressState> {
<
div
>
{
trialNumber
.
failTrial
}
</
div
>
</
Row
>
</
Col
>
</
Row
>
{
/* learn about click -> default active key is dispatcher. */
}
<
LogDrawer
isVisble
=
{
isShowLogDrawer
}
closeDrawer
=
{
this
.
closeDrawer
}
activeTab
=
"dispatcher"
/>
</
Row
>
);
}
...
...
src/webui/src/components/public-child/MonacoEditor.tsx
0 → 100644
View file @
4bbffd17
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
;
src/webui/src/static/const.ts
View file @
4bbffd17
...
...
@@ -19,6 +19,11 @@ const MONACO = {
readOnly
:
true
,
automaticLayout
:
true
};
const
DRAWEROPTION
=
{
minimap
:
{
enabled
:
false
},
readOnly
:
true
,
automaticLayout
:
true
};
const
COLUMN_INDEX
=
[
{
name
:
'
Trial No.
'
,
...
...
@@ -52,5 +57,5 @@ const COLUMN_INDEX = [
const
COLUMN
=
[
'
Trial No.
'
,
'
ID
'
,
'
Duration
'
,
'
Status
'
,
'
Default
'
,
'
Operation
'
,
'
Intermediate result
'
];
export
{
MANAGER_IP
,
DOWNLOAD_IP
,
trialJobStatus
,
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
CONTROLTYPE
,
MONACO
,
COLUMN
,
COLUMN_INDEX
,
DRAWEROPTION
};
src/webui/src/static/function.ts
View file @
4bbffd17
...
...
@@ -138,7 +138,29 @@ const filterDuration = (item: TableObj) => {
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
{
convertTime
,
convertDuration
,
getFinalResult
,
getFinal
,
convertTime
,
convertDuration
,
getFinalResult
,
getFinal
,
downFile
,
intermediateGraphOption
,
killJob
,
filterByStatus
,
filterDuration
};
src/webui/src/static/style/button.scss
View file @
4bbffd17
$btnBgcolor
:
#0071bc
;
Button
.tableButton
{
font-family
:
'Segoe UI'
,
Tahoma
,
Geneva
,
Verdana
,
sans-serif
;
background
:
$btnBgcolor
;
border-color
:
$btnBgcolor
;
height
:
26px
;
...
...
src/webui/src/static/style/compare.scss
View file @
4bbffd17
...
...
@@ -12,7 +12,7 @@
.column
{
max-width
:
124px
;
padding-left
:
18px
;
font-weight
:
7
00
;
font-weight
:
6
00
;
}
.value
{
max-width
:
152px
;
...
...
@@ -20,6 +20,6 @@
text-align
:
left
;
}
.idList
{
font-weight
:
7
00
;
font-weight
:
6
00
;
}
}
src/webui/src/static/style/control.scss
View file @
4bbffd17
...
...
@@ -55,7 +55,7 @@ div.addtitle{
font-size
:
20px
;
}
.line
{
font-weight
:
bold
;
font-weight
:
600
;
color
:
rgb
(
60
,
141
,
188
);
padding-right
:
20px
;
}
...
...
src/webui/src/static/style/logDrawer.scss
0 → 100644
View file @
4bbffd17
.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
;
}
}
Prev
1
2
3
4
5
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