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
a5764016
Unverified
Commit
a5764016
authored
Jun 23, 2020
by
chicm-ms
Committed by
GitHub
Jun 23, 2020
Browse files
Install builtin tuners (#2439)
parent
0f7f9460
Changes
54
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
993 additions
and
514 deletions
+993
-514
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
+10
-0
src/sdk/pynni/nni/hyperopt_tuner/hyperopt_tuner.py
src/sdk/pynni/nni/hyperopt_tuner/hyperopt_tuner.py
+9
-0
src/sdk/pynni/nni/medianstop_assessor/medianstop_assessor.py
src/sdk/pynni/nni/medianstop_assessor/medianstop_assessor.py
+10
-0
src/sdk/pynni/nni/metis_tuner/metis_tuner.py
src/sdk/pynni/nni/metis_tuner/metis_tuner.py
+11
-0
src/sdk/pynni/nni/networkmorphism_tuner/networkmorphism_tuner.py
.../pynni/nni/networkmorphism_tuner/networkmorphism_tuner.py
+11
-2
src/sdk/pynni/nni/package_utils.py
src/sdk/pynni/nni/package_utils.py
+373
-0
src/sdk/pynni/nni/pbt_tuner/pbt_tuner.py
src/sdk/pynni/nni/pbt_tuner/pbt_tuner.py
+11
-0
src/sdk/pynni/nni/ppo_tuner/ppo_tuner.py
src/sdk/pynni/nni/ppo_tuner/ppo_tuner.py
+17
-0
src/sdk/pynni/nni/smac_tuner/smac_tuner.py
src/sdk/pynni/nni/smac_tuner/smac_tuner.py
+9
-0
src/sdk/pynni/nni/utils.py
src/sdk/pynni/nni/utils.py
+62
-1
test/scripts/unittest.sh
test/scripts/unittest.sh
+6
-0
tools/nni_cmd/command_utils.py
tools/nni_cmd/command_utils.py
+9
-1
tools/nni_cmd/common_utils.py
tools/nni_cmd/common_utils.py
+14
-55
tools/nni_cmd/config_schema.py
tools/nni_cmd/config_schema.py
+208
-193
tools/nni_cmd/constants.py
tools/nni_cmd/constants.py
+22
-18
tools/nni_cmd/launcher.py
tools/nni_cmd/launcher.py
+15
-7
tools/nni_cmd/launcher_utils.py
tools/nni_cmd/launcher_utils.py
+9
-222
tools/nni_cmd/nnictl.py
tools/nni_cmd/nnictl.py
+13
-2
tools/nni_cmd/nnictl_utils.py
tools/nni_cmd/nnictl_utils.py
+2
-1
tools/nni_cmd/package_management.py
tools/nni_cmd/package_management.py
+172
-12
No files found.
src/sdk/pynni/nni/hyperband_advisor/hyperband_advisor.py
View file @
a5764016
...
@@ -12,6 +12,9 @@ import sys
...
@@ -12,6 +12,9 @@ import sys
import
json_tricks
import
json_tricks
import
numpy
as
np
import
numpy
as
np
from
schema
import
Schema
,
Optional
from
nni
import
ClassArgsValidator
from
nni.common
import
multi_phase_enabled
from
nni.common
import
multi_phase_enabled
from
nni.msg_dispatcher_base
import
MsgDispatcherBase
from
nni.msg_dispatcher_base
import
MsgDispatcherBase
from
nni.protocol
import
CommandType
,
send
from
nni.protocol
import
CommandType
,
send
...
@@ -249,6 +252,13 @@ class Bracket():
...
@@ -249,6 +252,13 @@ class Bracket():
self
.
num_configs_to_run
.
append
(
len
(
hyper_configs
))
self
.
num_configs_to_run
.
append
(
len
(
hyper_configs
))
self
.
increase_i
()
self
.
increase_i
()
class
HyperbandClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
'optimize_mode'
:
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'R'
):
int
,
Optional
(
'eta'
):
int
}).
validate
(
kwargs
)
class
Hyperband
(
MsgDispatcherBase
):
class
Hyperband
(
MsgDispatcherBase
):
"""Hyperband inherit from MsgDispatcherBase rather than Tuner, because it integrates both tuner's functions and assessor's functions.
"""Hyperband inherit from MsgDispatcherBase rather than Tuner, because it integrates both tuner's functions and assessor's functions.
...
...
src/sdk/pynni/nni/hyperopt_tuner/hyperopt_tuner.py
View file @
a5764016
...
@@ -10,6 +10,8 @@ import logging
...
@@ -10,6 +10,8 @@ import logging
import
hyperopt
as
hp
import
hyperopt
as
hp
import
numpy
as
np
import
numpy
as
np
from
schema
import
Optional
,
Schema
from
nni
import
ClassArgsValidator
from
nni.tuner
import
Tuner
from
nni.tuner
import
Tuner
from
nni.utils
import
NodeType
,
OptimizeMode
,
extract_scalar_reward
,
split_index
from
nni.utils
import
NodeType
,
OptimizeMode
,
extract_scalar_reward
,
split_index
...
@@ -178,6 +180,13 @@ def _add_index(in_x, parameter):
...
@@ -178,6 +180,13 @@ def _add_index(in_x, parameter):
return
parameter
return
parameter
return
None
# note: this is not written by original author, feel free to modify if you think it's incorrect
return
None
# note: this is not written by original author, feel free to modify if you think it's incorrect
class
HyperoptClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
Optional
(
'optimize_mode'
):
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'parallel_optimize'
):
bool
,
Optional
(
'constant_liar_type'
):
self
.
choices
(
'constant_liar_type'
,
'min'
,
'max'
,
'mean'
)
}).
validate
(
kwargs
)
class
HyperoptTuner
(
Tuner
):
class
HyperoptTuner
(
Tuner
):
"""
"""
...
...
src/sdk/pynni/nni/medianstop_assessor/medianstop_assessor.py
View file @
a5764016
...
@@ -2,11 +2,21 @@
...
@@ -2,11 +2,21 @@
# Licensed under the MIT license.
# Licensed under the MIT license.
import
logging
import
logging
from
schema
import
Schema
,
Optional
from
nni
import
ClassArgsValidator
from
nni.assessor
import
Assessor
,
AssessResult
from
nni.assessor
import
Assessor
,
AssessResult
from
nni.utils
import
extract_scalar_history
from
nni.utils
import
extract_scalar_history
logger
=
logging
.
getLogger
(
'medianstop_Assessor'
)
logger
=
logging
.
getLogger
(
'medianstop_Assessor'
)
class
MedianstopClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
Optional
(
'optimize_mode'
):
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'start_step'
):
self
.
range
(
'start_step'
,
int
,
0
,
9999
),
}).
validate
(
kwargs
)
class
MedianstopAssessor
(
Assessor
):
class
MedianstopAssessor
(
Assessor
):
"""MedianstopAssessor is The median stopping rule stops a pending trial X at step S
"""MedianstopAssessor is The median stopping rule stops a pending trial X at step S
if the trial’s best objective value by step S is strictly worse than the median value
if the trial’s best objective value by step S is strictly worse than the median value
...
...
src/sdk/pynni/nni/metis_tuner/metis_tuner.py
View file @
a5764016
...
@@ -12,7 +12,9 @@ import statistics
...
@@ -12,7 +12,9 @@ import statistics
import
warnings
import
warnings
from
multiprocessing.dummy
import
Pool
as
ThreadPool
from
multiprocessing.dummy
import
Pool
as
ThreadPool
import
numpy
as
np
import
numpy
as
np
from
schema
import
Schema
,
Optional
from
nni
import
ClassArgsValidator
import
nni.metis_tuner.lib_constraint_summation
as
lib_constraint_summation
import
nni.metis_tuner.lib_constraint_summation
as
lib_constraint_summation
import
nni.metis_tuner.lib_data
as
lib_data
import
nni.metis_tuner.lib_data
as
lib_data
import
nni.metis_tuner.Regression_GMM.CreateModel
as
gmm_create_model
import
nni.metis_tuner.Regression_GMM.CreateModel
as
gmm_create_model
...
@@ -31,6 +33,15 @@ CONSTRAINT_LOWERBOUND = None
...
@@ -31,6 +33,15 @@ CONSTRAINT_LOWERBOUND = None
CONSTRAINT_UPPERBOUND
=
None
CONSTRAINT_UPPERBOUND
=
None
CONSTRAINT_PARAMS_IDX
=
[]
CONSTRAINT_PARAMS_IDX
=
[]
class
MetisClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
Optional
(
'optimize_mode'
):
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'no_resampling'
):
bool
,
Optional
(
'no_candidates'
):
bool
,
Optional
(
'selection_num_starting_points'
):
int
,
Optional
(
'cold_start_num'
):
int
,
}).
validate
(
kwargs
)
class
MetisTuner
(
Tuner
):
class
MetisTuner
(
Tuner
):
"""
"""
...
...
src/sdk/pynni/nni/networkmorphism_tuner/networkmorphism_tuner.py
View file @
a5764016
...
@@ -7,17 +7,26 @@ networkmorphsim_tuner.py
...
@@ -7,17 +7,26 @@ networkmorphsim_tuner.py
import
logging
import
logging
import
os
import
os
from
schema
import
Optional
,
Schema
from
nni.tuner
import
Tuner
from
nni.tuner
import
Tuner
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
from
nni.networkmorphism_tuner.bayesian
import
BayesianOptimizer
from
nni.networkmorphism_tuner.bayesian
import
BayesianOptimizer
from
nni.networkmorphism_tuner.nn
import
CnnGenerator
,
MlpGenerator
from
nni.networkmorphism_tuner.nn
import
CnnGenerator
,
MlpGenerator
from
nni.networkmorphism_tuner.utils
import
Constant
from
nni.networkmorphism_tuner.utils
import
Constant
from
nni.networkmorphism_tuner.graph
import
graph_to_json
,
json_to_graph
from
nni.networkmorphism_tuner.graph
import
graph_to_json
,
json_to_graph
from
nni
import
ClassArgsValidator
logger
=
logging
.
getLogger
(
"NetworkMorphism_AutoML"
)
logger
=
logging
.
getLogger
(
"NetworkMorphism_AutoML"
)
class
NetworkMorphismClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
Optional
(
'optimize_mode'
):
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'task'
):
self
.
choices
(
'task'
,
'cv'
,
'nlp'
,
'common'
),
Optional
(
'input_width'
):
int
,
Optional
(
'input_channel'
):
int
,
Optional
(
'n_output_node'
):
int
}).
validate
(
kwargs
)
class
NetworkMorphismTuner
(
Tuner
):
class
NetworkMorphismTuner
(
Tuner
):
"""
"""
...
...
src/sdk/pynni/nni/package_utils.py
0 → 100644
View file @
a5764016
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.
import
os
import
site
import
sys
from
collections
import
defaultdict
from
pathlib
import
Path
import
importlib
import
ruamel.yaml
as
yaml
from
.constants
import
BuiltinAlgorithms
ALGO_TYPES
=
[
'tuners'
,
'assessors'
,
'advisors'
]
def
get_all_builtin_names
(
algo_type
):
"""Get all valid builtin names, including:
1. BuiltinAlgorithms which is pre-installed.
2. User installed packages in <nni_installation_path>/config/installed_packages.yml
Parameters
----------
algo_type: str
can be one of 'tuners', 'assessors' or 'advisors'
Returns: list of string
-------
All builtin names of specified type, for example, if algo_type is 'tuners', returns
all builtin tuner names.
"""
assert
algo_type
in
ALGO_TYPES
merged_dict
=
_get_merged_builtin_dict
()
builtin_names
=
[
x
[
'name'
]
for
x
in
merged_dict
[
algo_type
]]
return
builtin_names
def
get_not_installable_builtin_names
(
algo_type
=
None
):
"""Get builtin names in BuiltinAlgorithms which do not need to be installed
and can be used once NNI is installed.
Parameters
----------
algo_type: str | None
can be one of 'tuners', 'assessors', 'advisors' or None
Returns: list of string
-------
All builtin names of specified type, for example, if algo_type is 'tuners', returns
all builtin tuner names.
If algo_type is None, returns all builtin names of all types.
"""
if
algo_type
is
None
:
meta
=
BuiltinAlgorithms
else
:
assert
algo_type
in
ALGO_TYPES
meta
=
{
algo_type
:
BuiltinAlgorithms
[
algo_type
]
}
names
=
[]
for
t
in
ALGO_TYPES
:
if
t
in
meta
:
names
.
extend
([
x
[
'name'
]
for
x
in
meta
[
t
]])
return
names
def
get_builtin_algo_meta
(
algo_type
=
None
,
builtin_name
=
None
):
""" Get meta information of builtin algorithms from:
1. Pre-installed BuiltinAlgorithms
2. User installed packages in <nni_installation_path>/config/installed_packages.yml
Parameters
----------
algo_type: str | None
can be one of 'tuners', 'assessors', 'advisors' or None
builtin_name: str | None
builtin name.
Returns: dict | list of dict | None
-------
If builtin_name is specified, returns meta information of speicified builtin
alogorithms, for example:
{
'name': 'Random',
'class_name': 'nni.hyperopt_tuner.hyperopt_tuner.HyperoptTuner',
'class_args': {
'algorithm_name': 'random_search'
},
'accept_class_args': False,
'class_args_validator': 'nni.hyperopt_tuner.hyperopt_tuner.HyperoptClassArgsValidator'
}
If builtin_name is None, returns multiple meta information in a list.
"""
merged_dict
=
_get_merged_builtin_dict
()
if
algo_type
is
None
and
builtin_name
is
None
:
return
merged_dict
if
algo_type
:
assert
algo_type
in
ALGO_TYPES
metas
=
merged_dict
[
algo_type
]
else
:
metas
=
merged_dict
[
'tuners'
]
+
merged_dict
[
'assessors'
]
+
merged_dict
[
'advisors'
]
if
builtin_name
:
for
m
in
metas
:
if
m
[
'name'
]
==
builtin_name
:
return
m
else
:
return
metas
return
None
def
get_installed_package_meta
(
algo_type
,
builtin_name
):
""" Get meta information of user installed algorithms from:
<nni_installation_path>/config/installed_packages.yml
Parameters
----------
algo_type: str | None
can be one of 'tuners', 'assessors', 'advisors' or None
builtin_name: str
builtin name.
Returns: dict | None
-------
Returns meta information of speicified builtin alogorithms, for example:
{
'class_args_validator': 'nni.smac_tuner.smac_tuner.SMACClassArgsValidator',
'class_name': 'nni.smac_tuner.smac_tuner.SMACTuner',
'name': 'SMAC'
}
"""
assert
builtin_name
is
not
None
if
algo_type
:
assert
algo_type
in
ALGO_TYPES
config
=
read_installed_package_meta
()
candidates
=
[]
if
algo_type
:
candidates
=
config
[
algo_type
]
else
:
for
algo_type
in
ALGO_TYPES
:
candidates
.
extend
(
config
[
algo_type
])
for
meta
in
candidates
:
if
meta
[
'name'
]
==
builtin_name
:
return
meta
return
None
def
_parse_full_class_name
(
full_class_name
):
if
not
full_class_name
:
return
None
,
None
parts
=
full_class_name
.
split
(
'.'
)
module_name
,
class_name
=
'.'
.
join
(
parts
[:
-
1
]),
parts
[
-
1
]
return
module_name
,
class_name
def
get_builtin_module_class_name
(
algo_type
,
builtin_name
):
"""Get module name and class name of all builtin algorithms
Parameters
----------
algo_type: str
can be one of 'tuners', 'assessors', 'advisors'
builtin_name: str
builtin name.
Returns: tuple
-------
tuple of (module name, class name)
"""
assert
algo_type
in
ALGO_TYPES
assert
builtin_name
is
not
None
meta
=
get_builtin_algo_meta
(
algo_type
,
builtin_name
)
if
not
meta
:
return
None
,
None
return
_parse_full_class_name
(
meta
[
'class_name'
])
def
create_validator_instance
(
algo_type
,
builtin_name
):
"""Create instance of validator class
Parameters
----------
algo_type: str
can be one of 'tuners', 'assessors', 'advisors'
builtin_name: str
builtin name.
Returns: object | None
-------
Returns validator class instance.
If specified validator class does not exist, returns None.
"""
assert
algo_type
in
ALGO_TYPES
assert
builtin_name
is
not
None
meta
=
get_builtin_algo_meta
(
algo_type
,
builtin_name
)
if
not
meta
or
'class_args_validator'
not
in
meta
:
return
None
module_name
,
class_name
=
_parse_full_class_name
(
meta
[
'class_args_validator'
])
class_module
=
importlib
.
import_module
(
module_name
)
class_constructor
=
getattr
(
class_module
,
class_name
)
return
class_constructor
()
def
create_builtin_class_instance
(
builtin_name
,
input_class_args
,
algo_type
):
"""Create instance of builtin algorithms
Parameters
----------
builtin_name: str
builtin name.
input_class_args: dict
kwargs for builtin class constructor
algo_type: str
can be one of 'tuners', 'assessors', 'advisors'
Returns: object
-------
Returns builtin class instance.
"""
assert
algo_type
in
ALGO_TYPES
if
builtin_name
not
in
get_all_builtin_names
(
algo_type
):
raise
RuntimeError
(
'Builtin name is not found: {}'
.
format
(
builtin_name
))
def
parse_algo_meta
(
algo_meta
,
input_class_args
):
"""
1. parse class_name field in meta data into module name and class name,
for example:
parse class_name 'nni.hyperopt_tuner.hyperopt_tuner.HyperoptTuner' in meta data into:
module name: nni.hyperopt_tuner.hyperopt_tuner
class name: HyperoptTuner
2. merge user specified class args together with builtin class args.
"""
assert
algo_meta
module_name
,
class_name
=
_parse_full_class_name
(
algo_meta
[
'class_name'
])
class_args
=
{}
if
'class_args'
in
algo_meta
:
class_args
=
algo_meta
[
'class_args'
]
if
input_class_args
is
not
None
:
class_args
.
update
(
input_class_args
)
return
module_name
,
class_name
,
class_args
algo_meta
=
get_builtin_algo_meta
(
algo_type
,
builtin_name
)
module_name
,
class_name
,
class_args
=
parse_algo_meta
(
algo_meta
,
input_class_args
)
if
importlib
.
util
.
find_spec
(
module_name
)
is
None
:
raise
RuntimeError
(
'Builtin module can not be loaded: {}'
.
format
(
module_name
))
class_module
=
importlib
.
import_module
(
module_name
)
class_constructor
=
getattr
(
class_module
,
class_name
)
instance
=
class_constructor
(
**
class_args
)
return
instance
def
create_customized_class_instance
(
class_params
):
"""Create instance of customized algorithms
Parameters
----------
class_params: dict
class_params should contains following keys:
codeDir: code directory
classFileName: python file name of the class
className: class name
classArgs (optional): kwargs pass to class constructor
Returns: object
-------
Returns customized class instance.
"""
code_dir
=
class_params
.
get
(
'codeDir'
)
class_filename
=
class_params
.
get
(
'classFileName'
)
class_name
=
class_params
.
get
(
'className'
)
class_args
=
class_params
.
get
(
'classArgs'
)
if
not
os
.
path
.
isfile
(
os
.
path
.
join
(
code_dir
,
class_filename
)):
raise
ValueError
(
'Class file not found: {}'
.
format
(
os
.
path
.
join
(
code_dir
,
class_filename
)))
sys
.
path
.
append
(
code_dir
)
module_name
=
os
.
path
.
splitext
(
class_filename
)[
0
]
class_module
=
importlib
.
import_module
(
module_name
)
class_constructor
=
getattr
(
class_module
,
class_name
)
if
class_args
is
None
:
class_args
=
{}
instance
=
class_constructor
(
**
class_args
)
return
instance
def
get_python_dir
(
sitepackages_path
):
if
sys
.
platform
==
"win32"
:
return
str
(
Path
(
sitepackages_path
))
else
:
return
str
(
Path
(
sitepackages_path
).
parents
[
2
])
def
get_nni_installation_parent_dir
():
''' Find nni installation parent directory
'''
def
try_installation_path_sequentially
(
*
sitepackages
):
'''Try different installation path sequentially util nni is found.
Return None if nothing is found
'''
def
_generate_installation_path
(
sitepackages_path
):
python_dir
=
get_python_dir
(
sitepackages_path
)
entry_file
=
os
.
path
.
join
(
python_dir
,
'nni'
,
'main.js'
)
if
os
.
path
.
isfile
(
entry_file
):
return
python_dir
return
None
for
sitepackage
in
sitepackages
:
python_dir
=
_generate_installation_path
(
sitepackage
)
if
python_dir
:
return
python_dir
return
None
if
os
.
getenv
(
'VIRTUAL_ENV'
):
# if 'virtualenv' package is used, `site` has not attr getsitepackages, so we will instead use VIRTUAL_ENV
# Note that conda venv will not have VIRTUAL_ENV
python_dir
=
os
.
getenv
(
'VIRTUAL_ENV'
)
else
:
python_sitepackage
=
site
.
getsitepackages
()[
0
]
# If system-wide python is used, we will give priority to using `local sitepackage`--"usersitepackages()" given
# that nni exists there
if
python_sitepackage
.
startswith
(
'/usr'
)
or
python_sitepackage
.
startswith
(
'/Library'
):
python_dir
=
try_installation_path_sequentially
(
site
.
getusersitepackages
(),
site
.
getsitepackages
()[
0
])
else
:
python_dir
=
try_installation_path_sequentially
(
site
.
getsitepackages
()[
0
],
site
.
getusersitepackages
())
return
python_dir
def
get_nni_installation_path
():
''' Find nni installation directory
'''
parent_dir
=
get_nni_installation_parent_dir
()
if
parent_dir
:
entry_file
=
os
.
path
.
join
(
parent_dir
,
'nni'
,
'main.js'
)
if
os
.
path
.
isfile
(
entry_file
):
return
os
.
path
.
join
(
parent_dir
,
'nni'
)
return
None
def
get_nni_config_dir
():
return
os
.
path
.
join
(
get_nni_installation_path
(),
'config'
)
def
get_package_config_path
():
config_dir
=
get_nni_config_dir
()
if
not
os
.
path
.
exists
(
config_dir
):
os
.
makedirs
(
config_dir
,
exist_ok
=
True
)
return
os
.
path
.
join
(
config_dir
,
'installed_packages.yml'
)
def
read_installed_package_meta
():
config_file
=
get_package_config_path
()
if
os
.
path
.
exists
(
config_file
):
with
open
(
config_file
,
'r'
)
as
f
:
config
=
yaml
.
load
(
f
,
Loader
=
yaml
.
Loader
)
else
:
config
=
defaultdict
(
list
)
for
t
in
ALGO_TYPES
:
if
t
not
in
config
:
config
[
t
]
=
[]
return
config
def
write_package_meta
(
config
):
config_file
=
get_package_config_path
()
with
open
(
config_file
,
'w'
)
as
f
:
f
.
write
(
yaml
.
dump
(
dict
(
config
),
default_flow_style
=
False
))
def
_get_merged_builtin_dict
():
def
merge_meta_dict
(
d1
,
d2
):
res
=
defaultdict
(
list
)
for
t
in
ALGO_TYPES
:
res
[
t
]
=
d1
[
t
]
+
d2
[
t
]
return
res
return
merge_meta_dict
(
BuiltinAlgorithms
,
read_installed_package_meta
())
src/sdk/pynni/nni/pbt_tuner/pbt_tuner.py
View file @
a5764016
...
@@ -6,8 +6,10 @@ import logging
...
@@ -6,8 +6,10 @@ import logging
import
os
import
os
import
random
import
random
import
numpy
as
np
import
numpy
as
np
from
schema
import
Schema
,
Optional
import
nni
import
nni
from
nni
import
ClassArgsValidator
import
nni.parameter_expressions
import
nni.parameter_expressions
from
nni.tuner
import
Tuner
from
nni.tuner
import
Tuner
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
,
split_index
,
json2parameter
,
json2space
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
,
split_index
,
json2parameter
,
json2space
...
@@ -157,6 +159,15 @@ class TrialInfo:
...
@@ -157,6 +159,15 @@ class TrialInfo:
def
clean_id
(
self
):
def
clean_id
(
self
):
self
.
parameter_id
=
None
self
.
parameter_id
=
None
class
PBTClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
'optimize_mode'
:
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'all_checkpoint_dir'
):
str
,
Optional
(
'population_size'
):
self
.
range
(
'population_size'
,
int
,
0
,
99999
),
Optional
(
'factors'
):
float
,
Optional
(
'fraction'
):
float
,
}).
validate
(
kwargs
)
class
PBTTuner
(
Tuner
):
class
PBTTuner
(
Tuner
):
def
__init__
(
self
,
optimize_mode
=
"maximize"
,
all_checkpoint_dir
=
None
,
population_size
=
10
,
factor
=
0.2
,
def
__init__
(
self
,
optimize_mode
=
"maximize"
,
all_checkpoint_dir
=
None
,
population_size
=
10
,
factor
=
0.2
,
...
...
src/sdk/pynni/nni/ppo_tuner/ppo_tuner.py
View file @
a5764016
...
@@ -10,8 +10,10 @@ import copy
...
@@ -10,8 +10,10 @@ import copy
import
logging
import
logging
import
numpy
as
np
import
numpy
as
np
from
gym
import
spaces
from
gym
import
spaces
from
schema
import
Schema
,
Optional
import
nni
import
nni
from
nni
import
ClassArgsValidator
from
nni.tuner
import
Tuner
from
nni.tuner
import
Tuner
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
...
@@ -285,6 +287,21 @@ class PPOModel:
...
@@ -285,6 +287,21 @@ class PPOModel:
mbstates
=
states
[
mbenvinds
]
mbstates
=
states
[
mbenvinds
]
self
.
model
.
train
(
lrnow
,
cliprangenow
,
*
slices
,
mbstates
)
self
.
model
.
train
(
lrnow
,
cliprangenow
,
*
slices
,
mbstates
)
class
PPOClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
'optimize_mode'
:
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'trials_per_update'
):
self
.
range
(
'trials_per_update'
,
int
,
0
,
99999
),
Optional
(
'epochs_per_update'
):
self
.
range
(
'epochs_per_update'
,
int
,
0
,
99999
),
Optional
(
'minibatch_size'
):
self
.
range
(
'minibatch_size'
,
int
,
0
,
99999
),
Optional
(
'ent_coef'
):
float
,
Optional
(
'lr'
):
float
,
Optional
(
'vf_coef'
):
float
,
Optional
(
'max_grad_norm'
):
float
,
Optional
(
'gamma'
):
float
,
Optional
(
'lam'
):
float
,
Optional
(
'cliprange'
):
float
,
}).
validate
(
kwargs
)
class
PPOTuner
(
Tuner
):
class
PPOTuner
(
Tuner
):
"""
"""
...
...
src/sdk/pynni/nni/smac_tuner/smac_tuner.py
View file @
a5764016
...
@@ -9,6 +9,7 @@ import logging
...
@@ -9,6 +9,7 @@ import logging
import
sys
import
sys
import
numpy
as
np
import
numpy
as
np
from
schema
import
Schema
,
Optional
from
smac.facade.epils_facade
import
EPILS
from
smac.facade.epils_facade
import
EPILS
from
smac.facade.roar_facade
import
ROAR
from
smac.facade.roar_facade
import
ROAR
...
@@ -19,6 +20,7 @@ from smac.utils.io.cmd_reader import CMDReader
...
@@ -19,6 +20,7 @@ from smac.utils.io.cmd_reader import CMDReader
from
ConfigSpaceNNI
import
Configuration
from
ConfigSpaceNNI
import
Configuration
import
nni
import
nni
from
nni
import
ClassArgsValidator
from
nni.tuner
import
Tuner
from
nni.tuner
import
Tuner
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
from
nni.utils
import
OptimizeMode
,
extract_scalar_reward
...
@@ -26,6 +28,13 @@ from .convert_ss_to_scenario import generate_scenario
...
@@ -26,6 +28,13 @@ from .convert_ss_to_scenario import generate_scenario
logger
=
logging
.
getLogger
(
'smac_AutoML'
)
logger
=
logging
.
getLogger
(
'smac_AutoML'
)
class
SMACClassArgsValidator
(
ClassArgsValidator
):
def
validate_class_args
(
self
,
**
kwargs
):
Schema
({
'optimize_mode'
:
self
.
choices
(
'optimize_mode'
,
'maximize'
,
'minimize'
),
Optional
(
'config_dedup'
):
bool
}).
validate
(
kwargs
)
class
SMACTuner
(
Tuner
):
class
SMACTuner
(
Tuner
):
"""
"""
This is a wrapper of [SMAC](https://github.com/automl/SMAC3) following NNI tuner interface.
This is a wrapper of [SMAC](https://github.com/automl/SMAC3) following NNI tuner interface.
...
...
src/sdk/pynni/nni/utils.py
View file @
a5764016
...
@@ -6,6 +6,7 @@ import copy
...
@@ -6,6 +6,7 @@ import copy
import
functools
import
functools
from
enum
import
Enum
,
unique
from
enum
import
Enum
,
unique
import
json_tricks
import
json_tricks
from
schema
import
And
from
.
import
parameter_expressions
from
.
import
parameter_expressions
from
.common
import
init_logger
from
.common
import
init_logger
...
@@ -217,7 +218,6 @@ def json2parameter(x, is_rand, random_state, oldy=None, Rand=False, name=NodeTyp
...
@@ -217,7 +218,6 @@ def json2parameter(x, is_rand, random_state, oldy=None, Rand=False, name=NodeTyp
y
=
copy
.
deepcopy
(
x
)
y
=
copy
.
deepcopy
(
x
)
return
y
return
y
def
merge_parameter
(
base_params
,
override_params
):
def
merge_parameter
(
base_params
,
override_params
):
"""
"""
Update the parameters in ``base_params`` with ``override_params``.
Update the parameters in ``base_params`` with ``override_params``.
...
@@ -256,3 +256,64 @@ def merge_parameter(base_params, override_params):
...
@@ -256,3 +256,64 @@ def merge_parameter(base_params, override_params):
(
k
,
type
(
getattr
(
base_params
,
k
)),
type
(
v
)))
(
k
,
type
(
getattr
(
base_params
,
k
)),
type
(
v
)))
setattr
(
base_params
,
k
,
v
)
setattr
(
base_params
,
k
,
v
)
return
base_params
return
base_params
class
ClassArgsValidator
(
object
):
"""
NNI tuners/assessors/adivisors accept a `classArgs` parameter in experiment configuration file.
This ClassArgsValidator interface is used to validate the classArgs section in exeperiment
configuration file.
"""
def
validate_class_args
(
self
,
**
kwargs
):
"""
Validate the classArgs configuration in experiment configuration file.
Parameters
----------
kwargs: dict
kwargs passed to tuner/assessor/advisor constructor
Raises:
Raise an execption if the kwargs is invalid.
"""
pass
def
choices
(
self
,
key
,
*
args
):
"""
Utility method to create a scheme to check whether the `key` is one of the `args`.
Parameters:
----------
key: str
key name of the data to be validated
args: list of str
list of the choices
Returns: Schema
--------
A scheme to check whether the `key` is one of the `args`.
"""
return
And
(
lambda
n
:
n
in
args
,
error
=
'%s should be in [%s]!'
%
(
key
,
str
(
args
)))
def
range
(
self
,
key
,
keyType
,
start
,
end
):
"""
Utility method to create a schema to check whether the `key` is in the range of [start, end].
Parameters:
----------
key: str
key name of the data to be validated
keyType: type
python data type, such as int, float
start: type is specified by keyType
start of the range
end: type is specified by keyType
end of the range
Returns: Schema
--------
A scheme to check whether the `key` is in the range of [start, end].
"""
return
And
(
And
(
keyType
,
error
=
'%s should be %s type!'
%
(
key
,
keyType
.
__name__
)),
And
(
lambda
n
:
start
<=
n
<=
end
,
error
=
'%s should be in range of (%s, %s)!'
%
(
key
,
start
,
end
))
)
test/scripts/unittest.sh
View file @
a5764016
...
@@ -25,3 +25,9 @@ cd ${CWD}/../src/nni_manager
...
@@ -25,3 +25,9 @@ cd ${CWD}/../src/nni_manager
echo
""
echo
""
echo
"===========================Testing: nni_manager==========================="
echo
"===========================Testing: nni_manager==========================="
npm run
test
npm run
test
## ------Run nnictl unit test------
echo
""
echo
"===========================Testing: nnictl==========================="
cd
${
CWD
}
/../tools/nni_cmd/
python3
-m
unittest discover
-v
tests
tools/nni_cmd/command_utils.py
View file @
a5764016
...
@@ -62,7 +62,7 @@ def install_requirements_command(requirements_path):
...
@@ -62,7 +62,7 @@ def install_requirements_command(requirements_path):
requirements_path: str
requirements_path: str
Path to the directory that contains `requirements.txt`.
Path to the directory that contains `requirements.txt`.
"""
"""
call
(
_get_pip_install
()
+
[
"-r"
,
os
.
path
.
join
(
requirements_path
,
"requirements.txt"
)
],
shell
=
False
)
return
call
(
_get_pip_install
()
+
[
"-r"
,
requirements_path
],
shell
=
False
)
def
_get_pip_install
():
def
_get_pip_install
():
...
@@ -72,3 +72,11 @@ def _get_pip_install():
...
@@ -72,3 +72,11 @@ def _get_pip_install():
(
sys
.
platform
!=
"win32"
and
os
.
getuid
()
!=
0
):
# on unix and not running in root
(
sys
.
platform
!=
"win32"
and
os
.
getuid
()
!=
0
):
# on unix and not running in root
ret
.
append
(
"--user"
)
# not in virtualenv or conda
ret
.
append
(
"--user"
)
# not in virtualenv or conda
return
ret
return
ret
def
call_pip_install
(
source
):
return
call
(
_get_pip_install
()
+
[
source
])
def
call_pip_uninstall
(
module_name
):
python
=
"python"
if
sys
.
platform
==
"win32"
else
"python3"
cmd
=
[
python
,
"-m"
,
"pip"
,
"uninstall"
,
module_name
]
return
call
(
cmd
)
tools/nni_cmd/common_utils.py
View file @
a5764016
...
@@ -2,14 +2,14 @@
...
@@ -2,14 +2,14 @@
# Licensed under the MIT license.
# Licensed under the MIT license.
import
os
import
os
import
site
import
sys
import
sys
import
json
import
json
import
socket
import
socket
from
pathlib
import
Path
import
ruamel.yaml
as
yaml
import
ruamel.yaml
as
yaml
import
psutil
import
psutil
from
.constants
import
ERROR_INFO
,
NORMAL_INFO
,
WARNING_INFO
,
COLOR_RED_FORMAT
,
COLOR_YELLOW_FORMAT
from
colorama
import
Fore
from
.constants
import
ERROR_INFO
,
NORMAL_INFO
,
WARNING_INFO
def
get_yml_content
(
file_path
):
def
get_yml_content
(
file_path
):
'''Load yaml file content'''
'''Load yaml file content'''
...
@@ -34,17 +34,22 @@ def get_json_content(file_path):
...
@@ -34,17 +34,22 @@ def get_json_content(file_path):
print_error
(
err
)
print_error
(
err
)
return
None
return
None
def
print_error
(
content
):
def
print_error
(
*
content
):
'''Print error information to screen'''
'''Print error information to screen'''
print
(
COLOR_RED_FORMAT
%
(
ERROR_INFO
%
content
))
print
(
Fore
.
RED
+
ERROR_INFO
+
' '
.
join
([
str
(
c
)
for
c
in
content
])
+
Fore
.
RESET
)
def
print_green
(
*
content
):
'''Print information to screen in green'''
print
(
Fore
.
GREEN
+
' '
.
join
([
str
(
c
)
for
c
in
content
])
+
Fore
.
RESET
)
def
print_normal
(
content
):
def
print_normal
(
*
content
):
'''Print error information to screen'''
'''Print error information to screen'''
print
(
NORMAL_INFO
%
content
)
print
(
NORMAL_INFO
,
*
content
)
def
print_warning
(
content
):
def
print_warning
(
*
content
):
'''Print warning information to screen'''
'''Print warning information to screen'''
print
(
COLOR_YELLOW_FORMAT
%
(
WARNING_INFO
%
content
)
)
print
(
Fore
.
YELLOW
+
WARNING_INFO
+
' '
.
join
([
str
(
c
)
for
c
in
content
])
+
Fore
.
RESET
)
def
detect_process
(
pid
):
def
detect_process
(
pid
):
'''Detect if a process is alive'''
'''Detect if a process is alive'''
...
@@ -70,12 +75,6 @@ def get_user():
...
@@ -70,12 +75,6 @@ def get_user():
else
:
else
:
return
os
.
environ
[
'USER'
]
return
os
.
environ
[
'USER'
]
def
get_python_dir
(
sitepackages_path
):
if
sys
.
platform
==
"win32"
:
return
str
(
Path
(
sitepackages_path
))
else
:
return
str
(
Path
(
sitepackages_path
).
parents
[
2
])
def
check_tensorboard_version
():
def
check_tensorboard_version
():
try
:
try
:
import
tensorboard
import
tensorboard
...
@@ -84,43 +83,3 @@ def check_tensorboard_version():
...
@@ -84,43 +83,3 @@ def check_tensorboard_version():
print_error
(
'import tensorboard error!'
)
print_error
(
'import tensorboard error!'
)
exit
(
1
)
exit
(
1
)
def
get_nni_installation_path
():
''' Find nni lib from the following locations in order
Return nni root directory if it exists
'''
def
try_installation_path_sequentially
(
*
sitepackages
):
'''Try different installation path sequentially util nni is found.
Return None if nothing is found
'''
def
_generate_installation_path
(
sitepackages_path
):
python_dir
=
get_python_dir
(
sitepackages_path
)
entry_file
=
os
.
path
.
join
(
python_dir
,
'nni'
,
'main.js'
)
if
os
.
path
.
isfile
(
entry_file
):
return
python_dir
return
None
for
sitepackage
in
sitepackages
:
python_dir
=
_generate_installation_path
(
sitepackage
)
if
python_dir
:
return
python_dir
return
None
if
os
.
getenv
(
'VIRTUAL_ENV'
):
# if 'virtualenv' package is used, `site` has not attr getsitepackages, so we will instead use VIRTUAL_ENV
# Note that conda venv will not have VIRTUAL_ENV
python_dir
=
os
.
getenv
(
'VIRTUAL_ENV'
)
else
:
python_sitepackage
=
site
.
getsitepackages
()[
0
]
# If system-wide python is used, we will give priority to using `local sitepackage`--"usersitepackages()" given
# that nni exists there
if
python_sitepackage
.
startswith
(
'/usr'
)
or
python_sitepackage
.
startswith
(
'/Library'
):
python_dir
=
try_installation_path_sequentially
(
site
.
getusersitepackages
(),
site
.
getsitepackages
()[
0
])
else
:
python_dir
=
try_installation_path_sequentially
(
site
.
getsitepackages
()[
0
],
site
.
getusersitepackages
())
if
python_dir
:
entry_file
=
os
.
path
.
join
(
python_dir
,
'nni'
,
'main.js'
)
if
os
.
path
.
isfile
(
entry_file
):
return
os
.
path
.
join
(
python_dir
,
'nni'
)
print_error
(
'Fail to find nni under python library'
)
exit
(
1
)
\ No newline at end of file
tools/nni_cmd/config_schema.py
View file @
a5764016
This diff is collapsed.
Click to expand it.
tools/nni_cmd/constants.py
View file @
a5764016
...
@@ -6,14 +6,11 @@ from colorama import Fore
...
@@ -6,14 +6,11 @@ from colorama import Fore
NNICTL_HOME_DIR
=
os
.
path
.
join
(
os
.
path
.
expanduser
(
'~'
),
'.local'
,
'nnictl'
)
NNICTL_HOME_DIR
=
os
.
path
.
join
(
os
.
path
.
expanduser
(
'~'
),
'.local'
,
'nnictl'
)
ERROR_INFO
=
'ERROR: %s'
ERROR_INFO
=
'ERROR: '
NORMAL_INFO
=
'INFO: '
NORMAL_INFO
=
'INFO: %s'
WARNING_INFO
=
'WARNING: '
WARNING_INFO
=
'WARNING: %s'
DEFAULT_REST_PORT
=
8080
DEFAULT_REST_PORT
=
8080
REST_TIME_OUT
=
20
REST_TIME_OUT
=
20
EXPERIMENT_SUCCESS_INFO
=
Fore
.
GREEN
+
'Successfully started experiment!
\n
'
+
Fore
.
RESET
+
\
EXPERIMENT_SUCCESS_INFO
=
Fore
.
GREEN
+
'Successfully started experiment!
\n
'
+
Fore
.
RESET
+
\
...
@@ -62,10 +59,25 @@ TRIAL_MONITOR_CONTENT = '%-15s %-25s %-25s %-15s'
...
@@ -62,10 +59,25 @@ TRIAL_MONITOR_CONTENT = '%-15s %-25s %-25s %-15s'
TRIAL_MONITOR_TAIL
=
'-------------------------------------------------------------------------------------
\n\n\n
'
TRIAL_MONITOR_TAIL
=
'-------------------------------------------------------------------------------------
\n\n\n
'
PACKAGE_REQUIREMENTS
=
{
INSTALLABLE_PACKAGE_META
=
{
'SMAC'
:
'smac_tuner'
,
'SMAC'
:
{
'BOHB'
:
'bohb_advisor'
,
'type'
:
'tuner'
,
'PPOTuner'
:
'ppo_tuner'
'class_name'
:
'nni.smac_tuner.smac_tuner.SMACTuner'
,
'code_sub_dir'
:
'smac_tuner'
,
'class_args_validator'
:
'nni.smac_tuner.smac_tuner.SMACClassArgsValidator'
},
'BOHB'
:
{
'type'
:
'advisor'
,
'class_name'
:
'nni.bohb_advisor.bohb_advisor.BOHB'
,
'code_sub_dir'
:
'bohb_advisor'
,
'class_args_validator'
:
'nni.bohb_advisor.bohb_advisor.BOHBClassArgsValidator'
},
'PPOTuner'
:
{
'type'
:
'tuner'
,
'class_name'
:
'nni.ppo_tuner.ppo_tuner.PPOTuner'
,
'code_sub_dir'
:
'ppo_tuner'
,
'class_args_validator'
:
'nni.ppo_tuner.ppo_tuner.PPOClassArgsValidator'
}
}
}
TUNERS_SUPPORTING_IMPORT_DATA
=
{
TUNERS_SUPPORTING_IMPORT_DATA
=
{
...
@@ -83,14 +95,6 @@ TUNERS_NO_NEED_TO_IMPORT_DATA = {
...
@@ -83,14 +95,6 @@ TUNERS_NO_NEED_TO_IMPORT_DATA = {
'Hyperband'
'Hyperband'
}
}
COLOR_RED_FORMAT
=
Fore
.
RED
+
'%s'
COLOR_GREEN_FORMAT
=
Fore
.
GREEN
+
'%s'
COLOR_YELLOW_FORMAT
=
Fore
.
YELLOW
+
'%s'
SCHEMA_TYPE_ERROR
=
'%s should be %s type!'
SCHEMA_TYPE_ERROR
=
'%s should be %s type!'
SCHEMA_RANGE_ERROR
=
'%s should be in range of %s!'
SCHEMA_RANGE_ERROR
=
'%s should be in range of %s!'
SCHEMA_PATH_ERROR
=
'%s path not exist!'
SCHEMA_PATH_ERROR
=
'%s path not exist!'
tools/nni_cmd/launcher.py
View file @
a5764016
...
@@ -10,14 +10,15 @@ import time
...
@@ -10,14 +10,15 @@ import time
import
tempfile
import
tempfile
from
subprocess
import
Popen
,
check_call
,
CalledProcessError
,
PIPE
,
STDOUT
from
subprocess
import
Popen
,
check_call
,
CalledProcessError
,
PIPE
,
STDOUT
from
nni_annotation
import
expand_annotations
,
generate_search_space
from
nni_annotation
import
expand_annotations
,
generate_search_space
from
nni.
constants
import
ModuleName
,
AdvisorModuleName
from
nni.
package_utils
import
get_builtin_module_class_name
,
get_nni_installation_path
from
.launcher_utils
import
validate_all_content
from
.launcher_utils
import
validate_all_content
from
.rest_utils
import
rest_put
,
rest_post
,
check_rest_server
,
check_response
from
.rest_utils
import
rest_put
,
rest_post
,
check_rest_server
,
check_response
from
.url_utils
import
cluster_metadata_url
,
experiment_url
,
get_local_urls
from
.url_utils
import
cluster_metadata_url
,
experiment_url
,
get_local_urls
from
.config_utils
import
Config
,
Experiments
from
.config_utils
import
Config
,
Experiments
from
.common_utils
import
get_yml_content
,
get_json_content
,
print_error
,
print_normal
,
\
from
.common_utils
import
get_yml_content
,
get_json_content
,
print_error
,
print_normal
,
\
detect_port
,
get_user
,
get_nni_installation_path
detect_port
,
get_user
from
.constants
import
NNICTL_HOME_DIR
,
ERROR_INFO
,
REST_TIME_OUT
,
EXPERIMENT_SUCCESS_INFO
,
LOG_HEADER
,
PACKAGE_REQUIREMENTS
from
.constants
import
NNICTL_HOME_DIR
,
ERROR_INFO
,
REST_TIME_OUT
,
EXPERIMENT_SUCCESS_INFO
,
LOG_HEADER
,
INSTALLABLE_PACKAGE_META
from
.command_utils
import
check_output_command
,
kill_command
from
.command_utils
import
check_output_command
,
kill_command
from
.nnictl_utils
import
update_experiment
from
.nnictl_utils
import
update_experiment
...
@@ -52,6 +53,9 @@ def start_rest_server(port, platform, mode, config_file_name, foreground=False,
...
@@ -52,6 +53,9 @@ def start_rest_server(port, platform, mode, config_file_name, foreground=False,
print_normal
(
'Starting restful server...'
)
print_normal
(
'Starting restful server...'
)
entry_dir
=
get_nni_installation_path
()
entry_dir
=
get_nni_installation_path
()
if
(
not
entry_dir
)
or
(
not
os
.
path
.
exists
(
entry_dir
)):
print_error
(
'Fail to find nni under python library'
)
exit
(
1
)
entry_file
=
os
.
path
.
join
(
entry_dir
,
'main.js'
)
entry_file
=
os
.
path
.
join
(
entry_dir
,
'main.js'
)
node_command
=
'node'
node_command
=
'node'
...
@@ -390,10 +394,10 @@ def launch_experiment(args, experiment_config, mode, config_file_name, experimen
...
@@ -390,10 +394,10 @@ def launch_experiment(args, experiment_config, mode, config_file_name, experimen
package_name
,
module_name
=
None
,
None
package_name
,
module_name
=
None
,
None
if
experiment_config
.
get
(
'tuner'
)
and
experiment_config
[
'tuner'
].
get
(
'builtinTunerName'
):
if
experiment_config
.
get
(
'tuner'
)
and
experiment_config
[
'tuner'
].
get
(
'builtinTunerName'
):
package_name
=
experiment_config
[
'tuner'
][
'builtinTunerName'
]
package_name
=
experiment_config
[
'tuner'
][
'builtinTunerName'
]
module_name
=
ModuleName
.
get
(
package_name
)
module_name
,
_
=
get_builtin_module_class_name
(
'tuners'
,
package_name
)
elif
experiment_config
.
get
(
'advisor'
)
and
experiment_config
[
'advisor'
].
get
(
'builtinAdvisorName'
):
elif
experiment_config
.
get
(
'advisor'
)
and
experiment_config
[
'advisor'
].
get
(
'builtinAdvisorName'
):
package_name
=
experiment_config
[
'advisor'
][
'builtinAdvisorName'
]
package_name
=
experiment_config
[
'advisor'
][
'builtinAdvisorName'
]
module_name
=
AdvisorModuleName
.
get
(
package_name
)
module_name
,
_
=
get_builtin_module_class_name
(
'advisors'
,
package_name
)
if
package_name
and
module_name
:
if
package_name
and
module_name
:
try
:
try
:
stdout_full_path
,
stderr_full_path
=
get_log_path
(
config_file_name
)
stdout_full_path
,
stderr_full_path
=
get_log_path
(
config_file_name
)
...
@@ -402,7 +406,7 @@ def launch_experiment(args, experiment_config, mode, config_file_name, experimen
...
@@ -402,7 +406,7 @@ def launch_experiment(args, experiment_config, mode, config_file_name, experimen
except
CalledProcessError
:
except
CalledProcessError
:
print_error
(
'some errors happen when import package %s.'
%
(
package_name
))
print_error
(
'some errors happen when import package %s.'
%
(
package_name
))
print_log_content
(
config_file_name
)
print_log_content
(
config_file_name
)
if
package_name
in
PACKAGE_REQUIREMENTS
:
if
package_name
in
INSTALLABLE_PACKAGE_META
:
print_error
(
'If %s is not installed, it should be installed through '
\
print_error
(
'If %s is not installed, it should be installed through '
\
'
\'
nnictl package install --name %s
\'
'
%
(
package_name
,
package_name
))
'
\'
nnictl package install --name %s
\'
'
%
(
package_name
,
package_name
))
exit
(
1
)
exit
(
1
)
...
@@ -502,7 +506,11 @@ def create_experiment(args):
...
@@ -502,7 +506,11 @@ def create_experiment(args):
print_error
(
'Please set correct config path!'
)
print_error
(
'Please set correct config path!'
)
exit
(
1
)
exit
(
1
)
experiment_config
=
get_yml_content
(
config_path
)
experiment_config
=
get_yml_content
(
config_path
)
validate_all_content
(
experiment_config
,
config_path
)
try
:
validate_all_content
(
experiment_config
,
config_path
)
except
Exception
as
e
:
print_error
(
e
)
exit
(
1
)
nni_config
.
set_config
(
'experimentConfig'
,
experiment_config
)
nni_config
.
set_config
(
'experimentConfig'
,
experiment_config
)
nni_config
.
set_config
(
'restServerPort'
,
args
.
port
)
nni_config
.
set_config
(
'restServerPort'
,
args
.
port
)
...
...
tools/nni_cmd/launcher_utils.py
View file @
a5764016
...
@@ -2,14 +2,9 @@
...
@@ -2,14 +2,9 @@
# Licensed under the MIT license.
# Licensed under the MIT license.
import
os
import
os
import
json
import
netifaces
from
schema
import
SchemaError
from
schema
import
SchemaError
from
schema
import
Schema
from
.config_schema
import
NNIConfigSchema
from
.config_schema
import
LOCAL_CONFIG_SCHEMA
,
REMOTE_CONFIG_SCHEMA
,
PAI_CONFIG_SCHEMA
,
PAI_YARN_CONFIG_SCHEMA
,
\
from
.common_utils
import
print_normal
DLTS_CONFIG_SCHEMA
,
KUBEFLOW_CONFIG_SCHEMA
,
FRAMEWORKCONTROLLER_CONFIG_SCHEMA
,
\
tuner_schema_dict
,
advisor_schema_dict
,
assessor_schema_dict
from
.common_utils
import
print_error
,
print_warning
,
print_normal
,
get_yml_content
def
expand_path
(
experiment_config
,
key
):
def
expand_path
(
experiment_config
,
key
):
'''Change '~' to user home directory'''
'''Change '~' to user home directory'''
...
@@ -27,12 +22,10 @@ def parse_time(time):
...
@@ -27,12 +22,10 @@ def parse_time(time):
'''Change the time to seconds'''
'''Change the time to seconds'''
unit
=
time
[
-
1
]
unit
=
time
[
-
1
]
if
unit
not
in
[
's'
,
'm'
,
'h'
,
'd'
]:
if
unit
not
in
[
's'
,
'm'
,
'h'
,
'd'
]:
print_error
(
'the unit of time could only from {s, m, h, d}'
)
raise
SchemaError
(
'the unit of time could only from {s, m, h, d}'
)
exit
(
1
)
time
=
time
[:
-
1
]
time
=
time
[:
-
1
]
if
not
time
.
isdigit
():
if
not
time
.
isdigit
():
print_error
(
'time format error!'
)
raise
SchemaError
(
'time format error!'
)
exit
(
1
)
parse_dict
=
{
's'
:
1
,
'm'
:
60
,
'h'
:
3600
,
'd'
:
86400
}
parse_dict
=
{
's'
:
1
,
'm'
:
60
,
'h'
:
3600
,
'd'
:
86400
}
return
int
(
time
)
*
parse_dict
[
unit
]
return
int
(
time
)
*
parse_dict
[
unit
]
...
@@ -101,100 +94,7 @@ def parse_path(experiment_config, config_path):
...
@@ -101,100 +94,7 @@ def parse_path(experiment_config, config_path):
if
experiment_config
[
'trial'
].
get
(
'paiConfigPath'
):
if
experiment_config
[
'trial'
].
get
(
'paiConfigPath'
):
parse_relative_path
(
root_path
,
experiment_config
[
'trial'
],
'paiConfigPath'
)
parse_relative_path
(
root_path
,
experiment_config
[
'trial'
],
'paiConfigPath'
)
def
validate_search_space_content
(
experiment_config
):
def
set_default_values
(
experiment_config
):
'''Validate searchspace content,
if the searchspace file is not json format or its values does not contain _type and _value which must be specified,
it will not be a valid searchspace file'''
try
:
search_space_content
=
json
.
load
(
open
(
experiment_config
.
get
(
'searchSpacePath'
),
'r'
))
for
value
in
search_space_content
.
values
():
if
not
value
.
get
(
'_type'
)
or
not
value
.
get
(
'_value'
):
print_error
(
'please use _type and _value to specify searchspace!'
)
exit
(
1
)
except
:
print_error
(
'searchspace file is not a valid json format!'
)
exit
(
1
)
def
validate_kubeflow_operators
(
experiment_config
):
'''Validate whether the kubeflow operators are valid'''
if
experiment_config
.
get
(
'kubeflowConfig'
):
if
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'operator'
)
==
'tf-operator'
:
if
experiment_config
.
get
(
'trial'
).
get
(
'master'
)
is
not
None
:
print_error
(
'kubeflow with tf-operator can not set master'
)
exit
(
1
)
if
experiment_config
.
get
(
'trial'
).
get
(
'worker'
)
is
None
:
print_error
(
'kubeflow with tf-operator must set worker'
)
exit
(
1
)
elif
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'operator'
)
==
'pytorch-operator'
:
if
experiment_config
.
get
(
'trial'
).
get
(
'ps'
)
is
not
None
:
print_error
(
'kubeflow with pytorch-operator can not set ps'
)
exit
(
1
)
if
experiment_config
.
get
(
'trial'
).
get
(
'master'
)
is
None
:
print_error
(
'kubeflow with pytorch-operator must set master'
)
exit
(
1
)
if
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'storage'
)
==
'nfs'
:
if
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'nfs'
)
is
None
:
print_error
(
'please set nfs configuration!'
)
exit
(
1
)
elif
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'storage'
)
==
'azureStorage'
:
if
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'azureStorage'
)
is
None
:
print_error
(
'please set azureStorage configuration!'
)
exit
(
1
)
elif
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'storage'
)
is
None
:
if
experiment_config
.
get
(
'kubeflowConfig'
).
get
(
'azureStorage'
):
print_error
(
'please set storage type!'
)
exit
(
1
)
def
validate_common_content
(
experiment_config
):
'''Validate whether the common values in experiment_config is valid'''
if
not
experiment_config
.
get
(
'trainingServicePlatform'
)
or
\
experiment_config
.
get
(
'trainingServicePlatform'
)
not
in
[
'local'
,
'remote'
,
'pai'
,
'kubeflow'
,
'frameworkcontroller'
,
'paiYarn'
,
'dlts'
]:
print_error
(
'Please set correct trainingServicePlatform!'
)
exit
(
1
)
schema_dict
=
{
'local'
:
LOCAL_CONFIG_SCHEMA
,
'remote'
:
REMOTE_CONFIG_SCHEMA
,
'pai'
:
PAI_CONFIG_SCHEMA
,
'paiYarn'
:
PAI_YARN_CONFIG_SCHEMA
,
'kubeflow'
:
KUBEFLOW_CONFIG_SCHEMA
,
'frameworkcontroller'
:
FRAMEWORKCONTROLLER_CONFIG_SCHEMA
,
'dlts'
:
DLTS_CONFIG_SCHEMA
,
}
separate_schema_dict
=
{
'tuner'
:
tuner_schema_dict
,
'advisor'
:
advisor_schema_dict
,
'assessor'
:
assessor_schema_dict
}
separate_builtInName_dict
=
{
'tuner'
:
'builtinTunerName'
,
'advisor'
:
'builtinAdvisorName'
,
'assessor'
:
'builtinAssessorName'
}
try
:
schema_dict
.
get
(
experiment_config
[
'trainingServicePlatform'
]).
validate
(
experiment_config
)
for
separate_key
in
separate_schema_dict
.
keys
():
if
experiment_config
.
get
(
separate_key
):
if
experiment_config
[
separate_key
].
get
(
separate_builtInName_dict
[
separate_key
]):
validate
=
False
for
key
in
separate_schema_dict
[
separate_key
].
keys
():
if
key
.
__contains__
(
experiment_config
[
separate_key
][
separate_builtInName_dict
[
separate_key
]]):
Schema
({
**
separate_schema_dict
[
separate_key
][
key
]}).
validate
(
experiment_config
[
separate_key
])
validate
=
True
break
if
not
validate
:
print_error
(
'%s %s error!'
%
(
separate_key
,
separate_builtInName_dict
[
separate_key
]))
exit
(
1
)
else
:
Schema
({
**
separate_schema_dict
[
separate_key
][
'customized'
]}).
validate
(
experiment_config
[
separate_key
])
except
SchemaError
as
error
:
print_error
(
'Your config file is not correct, please check your config file content!'
)
print_error
(
error
.
code
)
exit
(
1
)
#set default value
if
experiment_config
.
get
(
'maxExecDuration'
)
is
None
:
if
experiment_config
.
get
(
'maxExecDuration'
)
is
None
:
experiment_config
[
'maxExecDuration'
]
=
'999d'
experiment_config
[
'maxExecDuration'
]
=
'999d'
if
experiment_config
.
get
(
'maxTrialNum'
)
is
None
:
if
experiment_config
.
get
(
'maxTrialNum'
)
is
None
:
...
@@ -204,124 +104,11 @@ def validate_common_content(experiment_config):
...
@@ -204,124 +104,11 @@ def validate_common_content(experiment_config):
if
experiment_config
[
'machineList'
][
index
].
get
(
'port'
)
is
None
:
if
experiment_config
[
'machineList'
][
index
].
get
(
'port'
)
is
None
:
experiment_config
[
'machineList'
][
index
][
'port'
]
=
22
experiment_config
[
'machineList'
][
index
][
'port'
]
=
22
def
validate_customized_file
(
experiment_config
,
spec_key
):
'''
check whether the file of customized tuner/assessor/advisor exists
spec_key: 'tuner', 'assessor', 'advisor'
'''
if
experiment_config
[
spec_key
].
get
(
'codeDir'
)
and
\
experiment_config
[
spec_key
].
get
(
'classFileName'
)
and
\
experiment_config
[
spec_key
].
get
(
'className'
):
if
not
os
.
path
.
exists
(
os
.
path
.
join
(
experiment_config
[
spec_key
][
'codeDir'
],
experiment_config
[
spec_key
][
'classFileName'
])):
print_error
(
'%s file directory is not valid!'
%
(
spec_key
))
exit
(
1
)
else
:
print_error
(
'%s file directory is not valid!'
%
(
spec_key
))
exit
(
1
)
def
parse_tuner_content
(
experiment_config
):
'''Validate whether tuner in experiment_config is valid'''
if
not
experiment_config
[
'tuner'
].
get
(
'builtinTunerName'
):
validate_customized_file
(
experiment_config
,
'tuner'
)
def
parse_assessor_content
(
experiment_config
):
'''Validate whether assessor in experiment_config is valid'''
if
experiment_config
.
get
(
'assessor'
):
if
not
experiment_config
[
'assessor'
].
get
(
'builtinAssessorName'
):
validate_customized_file
(
experiment_config
,
'assessor'
)
def
parse_advisor_content
(
experiment_config
):
'''Validate whether advisor in experiment_config is valid'''
if
not
experiment_config
[
'advisor'
].
get
(
'builtinAdvisorName'
):
validate_customized_file
(
experiment_config
,
'advisor'
)
def
validate_annotation_content
(
experiment_config
,
spec_key
,
builtin_name
):
'''
Valid whether useAnnotation and searchSpacePath is coexist
spec_key: 'advisor' or 'tuner'
builtin_name: 'builtinAdvisorName' or 'builtinTunerName'
'''
if
experiment_config
.
get
(
'useAnnotation'
):
if
experiment_config
.
get
(
'searchSpacePath'
):
print_error
(
'If you set useAnnotation=true, please leave searchSpacePath empty'
)
exit
(
1
)
else
:
# validate searchSpaceFile
if
experiment_config
[
spec_key
].
get
(
builtin_name
)
==
'NetworkMorphism'
:
return
if
experiment_config
[
spec_key
].
get
(
builtin_name
):
if
experiment_config
.
get
(
'searchSpacePath'
)
is
None
:
print_error
(
'Please set searchSpacePath!'
)
exit
(
1
)
validate_search_space_content
(
experiment_config
)
def
validate_machine_list
(
experiment_config
):
'''Validate machine list'''
if
experiment_config
.
get
(
'trainingServicePlatform'
)
==
'remote'
and
experiment_config
.
get
(
'machineList'
)
is
None
:
print_error
(
'Please set machineList!'
)
exit
(
1
)
def
validate_pai_config_path
(
experiment_config
):
'''validate paiConfigPath field'''
if
experiment_config
.
get
(
'trainingServicePlatform'
)
==
'pai'
:
if
experiment_config
.
get
(
'trial'
,
{}).
get
(
'paiConfigPath'
):
# validate commands
pai_config
=
get_yml_content
(
experiment_config
[
'trial'
][
'paiConfigPath'
])
taskRoles_dict
=
pai_config
.
get
(
'taskRoles'
)
if
not
taskRoles_dict
:
print_error
(
'Please set taskRoles in paiConfigPath config file!'
)
exit
(
1
)
else
:
pai_trial_fields_required_list
=
[
'image'
,
'gpuNum'
,
'cpuNum'
,
'memoryMB'
,
'paiStorageConfigName'
,
'command'
]
for
trial_field
in
pai_trial_fields_required_list
:
if
experiment_config
[
'trial'
].
get
(
trial_field
)
is
None
:
print_error
(
'Please set {0} in trial configuration,
\
or set additional pai configuration file path in paiConfigPath!'
.
format
(
trial_field
))
exit
(
1
)
def
validate_pai_trial_conifg
(
experiment_config
):
'''validate the trial config in pai platform'''
if
experiment_config
.
get
(
'trainingServicePlatform'
)
in
[
'pai'
,
'paiYarn'
]:
if
experiment_config
.
get
(
'trial'
).
get
(
'shmMB'
)
and
\
experiment_config
[
'trial'
][
'shmMB'
]
>
experiment_config
[
'trial'
][
'memoryMB'
]:
print_error
(
'shmMB should be no more than memoryMB!'
)
exit
(
1
)
#backward compatibility
warning_information
=
'{0} is not supported in NNI anymore, please remove the field in config file!
\
please refer https://github.com/microsoft/nni/blob/master/docs/en_US/TrainingService/PaiMode.md#run-an-experiment
\
for the practices of how to get data and output model in trial code'
if
experiment_config
.
get
(
'trial'
).
get
(
'dataDir'
):
print_warning
(
warning_information
.
format
(
'dataDir'
))
if
experiment_config
.
get
(
'trial'
).
get
(
'outputDir'
):
print_warning
(
warning_information
.
format
(
'outputDir'
))
validate_pai_config_path
(
experiment_config
)
def
validate_eth0_device
(
experiment_config
):
'''validate whether the machine has eth0 device'''
if
experiment_config
.
get
(
'trainingServicePlatform'
)
not
in
[
'local'
]
\
and
not
experiment_config
.
get
(
'nniManagerIp'
)
\
and
'eth0'
not
in
netifaces
.
interfaces
():
print_error
(
'This machine does not contain eth0 network device, please set nniManagerIp in config file!'
)
exit
(
1
)
def
validate_all_content
(
experiment_config
,
config_path
):
def
validate_all_content
(
experiment_config
,
config_path
):
'''Validate whether experiment_config is valid'''
'''Validate whether experiment_config is valid'''
parse_path
(
experiment_config
,
config_path
)
parse_path
(
experiment_config
,
config_path
)
validate_common_content
(
experiment_config
)
set_default_values
(
experiment_config
)
validate_eth0_device
(
experiment_config
)
validate_pai_trial_conifg
(
experiment_config
)
NNIConfigSchema
().
validate
(
experiment_config
)
experiment_config
[
'maxExecDuration'
]
=
parse_time
(
experiment_config
[
'maxExecDuration'
])
experiment_config
[
'maxExecDuration'
]
=
parse_time
(
experiment_config
[
'maxExecDuration'
])
if
experiment_config
.
get
(
'advisor'
):
if
experiment_config
.
get
(
'assessor'
)
or
experiment_config
.
get
(
'tuner'
):
print_error
(
'advisor could not be set with assessor or tuner simultaneously!'
)
exit
(
1
)
parse_advisor_content
(
experiment_config
)
validate_annotation_content
(
experiment_config
,
'advisor'
,
'builtinAdvisorName'
)
else
:
if
not
experiment_config
.
get
(
'tuner'
):
raise
Exception
(
'Please provide tuner spec!'
)
parse_tuner_content
(
experiment_config
)
parse_assessor_content
(
experiment_config
)
validate_annotation_content
(
experiment_config
,
'tuner'
,
'builtinTunerName'
)
tools/nni_cmd/nnictl.py
View file @
a5764016
...
@@ -12,7 +12,7 @@ from .nnictl_utils import stop_experiment, trial_ls, trial_kill, list_experiment
...
@@ -12,7 +12,7 @@ from .nnictl_utils import stop_experiment, trial_ls, trial_kill, list_experiment
log_trial
,
experiment_clean
,
platform_clean
,
experiment_list
,
\
log_trial
,
experiment_clean
,
platform_clean
,
experiment_list
,
\
monitor_experiment
,
export_trials_data
,
trial_codegen
,
webui_url
,
\
monitor_experiment
,
export_trials_data
,
trial_codegen
,
webui_url
,
\
get_config
,
log_stdout
,
log_stderr
,
search_space_auto_gen
,
webui_nas
get_config
,
log_stdout
,
log_stderr
,
search_space_auto_gen
,
webui_nas
from
.package_management
import
package_install
,
package_
show
from
.package_management
import
package_install
,
package_
uninstall
,
package_show
,
package_list
from
.constants
import
DEFAULT_REST_PORT
from
.constants
import
DEFAULT_REST_PORT
from
.tensorboard_utils
import
start_tensorboard
,
stop_tensorboard
from
.tensorboard_utils
import
start_tensorboard
,
stop_tensorboard
init
(
autoreset
=
True
)
init
(
autoreset
=
True
)
...
@@ -196,11 +196,22 @@ def parse_args():
...
@@ -196,11 +196,22 @@ def parse_args():
# add subparsers for parser_package
# add subparsers for parser_package
parser_package_subparsers
=
parser_package
.
add_subparsers
()
parser_package_subparsers
=
parser_package
.
add_subparsers
()
parser_package_install
=
parser_package_subparsers
.
add_parser
(
'install'
,
help
=
'install packages'
)
parser_package_install
=
parser_package_subparsers
.
add_parser
(
'install'
,
help
=
'install packages'
)
parser_package_install
.
add_argument
(
'--name'
,
'-n'
,
dest
=
'name'
,
help
=
'package name to be installed'
)
parser_package_install
.
add_argument
(
'source'
,
nargs
=
'?'
,
help
=
'installation source, can be a directory or whl file'
)
parser_package_install
.
add_argument
(
'--name'
,
'-n'
,
dest
=
'name'
,
help
=
'package name to be installed'
,
required
=
False
)
parser_package_install
.
set_defaults
(
func
=
package_install
)
parser_package_install
.
set_defaults
(
func
=
package_install
)
parser_package_uninstall
=
parser_package_subparsers
.
add_parser
(
'uninstall'
,
help
=
'uninstall packages'
)
parser_package_uninstall
.
add_argument
(
'name'
,
nargs
=
1
,
help
=
'package name to be uninstalled'
)
parser_package_uninstall
.
set_defaults
(
func
=
package_uninstall
)
parser_package_show
=
parser_package_subparsers
.
add_parser
(
'show'
,
help
=
'show the information of packages'
)
parser_package_show
=
parser_package_subparsers
.
add_parser
(
'show'
,
help
=
'show the information of packages'
)
parser_package_show
.
add_argument
(
'name'
,
nargs
=
1
,
help
=
'builtin name of the package'
)
parser_package_show
.
set_defaults
(
func
=
package_show
)
parser_package_show
.
set_defaults
(
func
=
package_show
)
parser_package_list
=
parser_package_subparsers
.
add_parser
(
'list'
,
help
=
'list installed packages'
)
parser_package_list
.
add_argument
(
'--all'
,
action
=
'store_true'
,
help
=
'list all builtin packages'
)
parser_package_list
.
set_defaults
(
func
=
package_list
)
#parse tensorboard command
#parse tensorboard command
parser_tensorboard
=
subparsers
.
add_parser
(
'tensorboard'
,
help
=
'manage tensorboard'
)
parser_tensorboard
=
subparsers
.
add_parser
(
'tensorboard'
,
help
=
'manage tensorboard'
)
parser_tensorboard_subparsers
=
parser_tensorboard
.
add_subparsers
()
parser_tensorboard_subparsers
=
parser_tensorboard
.
add_subparsers
()
...
...
tools/nni_cmd/nnictl_utils.py
View file @
a5764016
...
@@ -13,13 +13,14 @@ from datetime import datetime, timezone
...
@@ -13,13 +13,14 @@ from datetime import datetime, timezone
from
pathlib
import
Path
from
pathlib
import
Path
from
subprocess
import
Popen
from
subprocess
import
Popen
from
pyhdfs
import
HdfsClient
from
pyhdfs
import
HdfsClient
from
nni.package_utils
import
get_nni_installation_path
from
nni_annotation
import
expand_annotations
from
nni_annotation
import
expand_annotations
from
.rest_utils
import
rest_get
,
rest_delete
,
check_rest_server_quick
,
check_response
from
.rest_utils
import
rest_get
,
rest_delete
,
check_rest_server_quick
,
check_response
from
.url_utils
import
trial_jobs_url
,
experiment_url
,
trial_job_id_url
,
export_data_url
from
.url_utils
import
trial_jobs_url
,
experiment_url
,
trial_job_id_url
,
export_data_url
from
.config_utils
import
Config
,
Experiments
from
.config_utils
import
Config
,
Experiments
from
.constants
import
NNICTL_HOME_DIR
,
EXPERIMENT_INFORMATION_FORMAT
,
EXPERIMENT_DETAIL_FORMAT
,
\
from
.constants
import
NNICTL_HOME_DIR
,
EXPERIMENT_INFORMATION_FORMAT
,
EXPERIMENT_DETAIL_FORMAT
,
\
EXPERIMENT_MONITOR_INFO
,
TRIAL_MONITOR_HEAD
,
TRIAL_MONITOR_CONTENT
,
TRIAL_MONITOR_TAIL
,
REST_TIME_OUT
EXPERIMENT_MONITOR_INFO
,
TRIAL_MONITOR_HEAD
,
TRIAL_MONITOR_CONTENT
,
TRIAL_MONITOR_TAIL
,
REST_TIME_OUT
from
.common_utils
import
print_normal
,
print_error
,
print_warning
,
detect_process
,
get_yml_content
,
get_nni_installation_path
from
.common_utils
import
print_normal
,
print_error
,
print_warning
,
detect_process
,
get_yml_content
from
.command_utils
import
check_output_command
,
kill_command
from
.command_utils
import
check_output_command
,
kill_command
from
.ssh_utils
import
create_ssh_sftp_client
,
remove_remote_directory
from
.ssh_utils
import
create_ssh_sftp_client
,
remove_remote_directory
...
...
tools/nni_cmd/package_management.py
View file @
a5764016
...
@@ -2,23 +2,183 @@
...
@@ -2,23 +2,183 @@
# Licensed under the MIT license.
# Licensed under the MIT license.
import
os
import
os
from
collections
import
defaultdict
import
json
import
pkginfo
import
nni
import
nni
from
.constants
import
PACKAGE_REQUIREMENTS
from
nni.package_utils
import
read_installed_package_meta
,
get_installed_package_meta
,
\
from
.common_utils
import
print_error
write_package_meta
,
get_builtin_algo_meta
,
get_not_installable_builtin_names
,
ALGO_TYPES
from
.command_utils
import
install_requirements_command
def
process_install
(
package_name
):
from
.constants
import
INSTALLABLE_PACKAGE_META
if
PACKAGE_REQUIREMENTS
.
get
(
package_name
)
is
None
:
from
.common_utils
import
print_error
,
print_green
print_error
(
'{0} is not supported!'
%
package_name
)
from
.command_utils
import
install_requirements_command
,
call_pip_install
,
call_pip_uninstall
else
:
requirements_path
=
os
.
path
.
join
(
nni
.
__path__
[
0
],
PACKAGE_REQUIREMENTS
[
package_name
])
PACKAGE_TYPES
=
[
'tuner'
,
'assessor'
,
'advisor'
]
install_requirements_command
(
requirements_path
)
def
install_by_name
(
package_name
):
if
package_name
not
in
INSTALLABLE_PACKAGE_META
:
raise
RuntimeError
(
'{} is not found in installable packages!'
.
format
(
package_name
))
requirements_path
=
os
.
path
.
join
(
nni
.
__path__
[
0
],
INSTALLABLE_PACKAGE_META
[
package_name
][
'code_sub_dir'
],
'requirements.txt'
)
assert
os
.
path
.
exists
(
requirements_path
)
return
install_requirements_command
(
requirements_path
)
def
package_install
(
args
):
def
package_install
(
args
):
'''install packages'''
'''install packages'''
process_install
(
args
.
name
)
installed
=
False
try
:
if
args
.
name
:
if
install_by_name
(
args
.
name
)
==
0
:
package_meta
=
{}
package_meta
[
'type'
]
=
INSTALLABLE_PACKAGE_META
[
args
.
name
][
'type'
]
package_meta
[
'name'
]
=
args
.
name
package_meta
[
'class_name'
]
=
INSTALLABLE_PACKAGE_META
[
args
.
name
][
'class_name'
]
package_meta
[
'class_args_validator'
]
=
INSTALLABLE_PACKAGE_META
[
args
.
name
][
'class_args_validator'
]
save_package_meta_data
(
package_meta
)
print_green
(
'{} installed!'
.
format
(
args
.
name
))
installed
=
True
else
:
package_meta
=
get_nni_meta
(
args
.
source
)
if
package_meta
:
if
call_pip_install
(
args
.
source
)
==
0
:
save_package_meta_data
(
package_meta
)
print_green
(
'{} installed!'
.
format
(
package_meta
[
'name'
]))
installed
=
True
except
Exception
as
e
:
print_error
(
e
)
if
not
installed
:
print_error
(
'installation failed!'
)
def
package_uninstall
(
args
):
'''uninstall packages'''
name
=
args
.
name
[
0
]
if
name
in
get_not_installable_builtin_names
():
print_error
(
'{} can not be uninstalled!'
.
format
(
name
))
exit
(
1
)
meta
=
get_installed_package_meta
(
None
,
name
)
if
meta
is
None
:
print_error
(
'package {} not found!'
.
format
(
name
))
return
if
'installed_package'
in
meta
:
call_pip_uninstall
(
meta
[
'installed_package'
])
if
remove_package_meta_data
(
name
):
print_green
(
'{} uninstalled sucessfully!'
.
format
(
name
))
else
:
print_error
(
'Failed to uninstall {}!'
.
format
(
name
))
def
package_show
(
args
):
def
package_show
(
args
):
'''show all packages'''
'''show specified packages'''
print
(
' '
.
join
(
PACKAGE_REQUIREMENTS
.
keys
()))
builtin_name
=
args
.
name
[
0
]
meta
=
get_builtin_algo_meta
(
builtin_name
=
builtin_name
)
if
meta
:
print
(
json
.
dumps
(
meta
,
indent
=
4
))
else
:
print_error
(
'package {} not found'
.
format
(
builtin_name
))
def
print_package_list
(
meta
):
print
(
'+-----------------+------------+-----------+--------=-------------+------------------------------------------+'
)
print
(
'| Name | Type | Installed | Class Name | Module Name |'
)
print
(
'+-----------------+------------+-----------+----------------------+------------------------------------------+'
)
MAX_MODULE_NAME
=
38
for
t
in
[
'tuners'
,
'assessors'
,
'advisors'
]:
for
p
in
meta
[
t
]:
module_name
=
'.'
.
join
(
p
[
'class_name'
].
split
(
'.'
)[:
-
1
])
if
len
(
module_name
)
>
MAX_MODULE_NAME
:
module_name
=
module_name
[:
MAX_MODULE_NAME
-
3
]
+
'...'
class_name
=
p
[
'class_name'
].
split
(
'.'
)[
-
1
]
print
(
'| {:15s} | {:10s} | {:9s} | {:20s} | {:40s} |'
.
format
(
p
[
'name'
],
t
,
p
[
'installed'
],
class_name
,
module_name
[:
38
]))
print
(
'+-----------------+------------+-----------+----------------------+------------------------------------------+'
)
def
package_list
(
args
):
'''list all packages'''
if
args
.
all
:
meta
=
get_builtin_algo_meta
()
else
:
meta
=
read_installed_package_meta
()
installed_names
=
defaultdict
(
list
)
for
t
in
[
'tuners'
,
'assessors'
,
'advisors'
]:
for
p
in
meta
[
t
]:
p
[
'installed'
]
=
'Yes'
installed_names
[
t
].
append
(
p
[
'name'
])
for
k
,
v
in
INSTALLABLE_PACKAGE_META
.
items
():
t
=
v
[
'type'
]
+
's'
if
k
not
in
installed_names
[
t
]:
meta
[
t
].
append
({
'name'
:
k
,
'class_name'
:
v
[
'class_name'
],
'class_args_validator'
:
v
[
'class_args_validator'
],
'installed'
:
'No'
})
print_package_list
(
meta
)
def
save_package_meta_data
(
meta_data
):
assert
meta_data
[
'type'
]
in
PACKAGE_TYPES
assert
'name'
in
meta_data
assert
'class_name'
in
meta_data
config
=
read_installed_package_meta
()
if
meta_data
[
'name'
]
in
[
x
[
'name'
]
for
x
in
config
[
meta_data
[
'type'
]
+
's'
]]:
raise
ValueError
(
'name %s already installed'
%
meta_data
[
'name'
])
package_meta
=
{
k
:
meta_data
[
k
]
for
k
in
[
'name'
,
'class_name'
,
'class_args_validator'
]
if
k
in
meta_data
}
if
'package_name'
in
meta_data
:
package_meta
[
'installed_package'
]
=
meta_data
[
'package_name'
]
config
[
meta_data
[
'type'
]
+
's'
].
append
(
package_meta
)
write_package_meta
(
config
)
def
remove_package_meta_data
(
name
):
config
=
read_installed_package_meta
()
updated
=
False
for
t
in
ALGO_TYPES
:
for
meta
in
config
[
t
]:
if
meta
[
'name'
]
==
name
:
config
[
t
].
remove
(
meta
)
updated
=
True
if
updated
:
write_package_meta
(
config
)
return
True
return
False
def
get_nni_meta
(
source
):
if
not
os
.
path
.
exists
(
source
):
print_error
(
'{} does not exist'
.
format
(
source
))
return
None
if
os
.
path
.
isdir
(
source
):
if
not
os
.
path
.
exists
(
os
.
path
.
join
(
source
,
'setup.py'
)):
print_error
(
'setup.py not found'
)
return
None
pkg
=
pkginfo
.
Develop
(
source
)
else
:
if
not
source
.
endswith
(
'.whl'
):
print_error
(
'File name {} must ends with
\'
.whl
\'
'
.
format
(
source
))
return
False
pkg
=
pkginfo
.
Wheel
(
source
)
classifiers
=
pkg
.
classifiers
meta
=
parse_classifiers
(
classifiers
)
meta
[
'package_name'
]
=
pkg
.
name
return
meta
def
parse_classifiers
(
classifiers
):
parts
=
[]
for
c
in
classifiers
:
if
c
.
startswith
(
'NNI Package'
):
parts
=
[
x
.
strip
()
for
x
in
c
.
split
(
'::'
)]
break
if
len
(
parts
)
<
4
or
not
all
(
parts
):
raise
ValueError
(
'Can not find correct NNI meta data in package classifiers.'
)
meta
=
{
'type'
:
parts
[
1
],
'name'
:
parts
[
2
],
'class_name'
:
parts
[
3
]
}
if
len
(
parts
)
>=
5
:
meta
[
'class_args_validator'
]
=
parts
[
4
]
return
meta
Prev
1
2
3
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