Unverified Commit 40391ec2 authored by SparkSnail's avatar SparkSnail Committed by GitHub
Browse files

Merge pull request #125 from Microsoft/master

merge master
parents 8422992c 0da6f470
<p align="center">
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/nni_logo.png" width="300"/>
<img src="docs/img/nni_logo.png" width="300"/>
</p>
-----------
[![MIT licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://github.com/Microsoft/nni/blob/master/LICENSE)
[![MIT licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE)
[![Build Status](https://msrasrg.visualstudio.com/NNIOpenSource/_apis/build/status/Microsoft.nni)](https://msrasrg.visualstudio.com/NNIOpenSource/_build/latest?definitionId=6)
[![Issues](https://img.shields.io/github/issues-raw/Microsoft/nni.svg)](https://github.com/Microsoft/nni/issues?q=is%3Aissue+is%3Aopen)
[![Bugs](https://img.shields.io/github/issues/Microsoft/nni/bug.svg)](https://github.com/Microsoft/nni/issues?q=is%3Aissue+is%3Aopen+label%3Abug)
......@@ -18,22 +18,22 @@ The tool dispatches and runs trial jobs generated by tuning algorithms to search
### **NNI [v0.5.1](https://github.com/Microsoft/nni/releases) has been released!**
<p align="center">
<a href="#nni-v05-has-been-released"><img src="https://github.com/Microsoft/nni/blob/master/docs/img/overview.svg" /></a>
<a href="#nni-v05-has-been-released"><img src="docs/img/overview.svg" /></a>
</p>
<table>
<tbody>
<tr align="center" valign="bottom">
<td>
<b>Supported Frameworks</b>
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/bar.png"/>
<img src="docs/img/bar.png"/>
</td>
<td>
<b>Tuning Algorithms</b>
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/bar.png"/>
<img src="docs/img/bar.png"/>
</td>
<td>
<b>Training Services</b>
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/bar.png"/>
<img src="docs/img/bar.png"/>
</td>
</tr>
<tr/>
......@@ -204,4 +204,4 @@ Before start coding, review and get familiar with the NNI Code Contribution Guid
We are in construction of the instruction for [How to Debug](docs/HowToDebug.md), you are also welcome to contribute questions or suggestions on this area.
## **License**
The entire codebase is under [MIT license](https://github.com/Microsoft/nni/blob/master/LICENSE)
The entire codebase is under [MIT license](LICENSE)
......@@ -48,11 +48,12 @@ setuptools.setup(
long_description_content_type = 'text/markdown',
license = 'MIT',
url = 'https://github.com/Microsoft/nni',
packages = setuptools.find_packages('../../tools') + setuptools.find_packages('../../src/sdk/pynni')
packages = setuptools.find_packages('../../tools') + setuptools.find_packages('../../src/sdk/pynni', exclude=['tests']),
package_dir = {
'nni_annotation': '../../tools/nni_annotation',
'nni_cmd': '../../tools/nni_cmd',
'nni_trial_tool': '../../tools/nni_trial_tool',
'nni_gpu_tool': '../../tools/nni_gpu_tool',
'nni': '../../src/sdk/pynni/nni'
},
python_requires = '>=3.5',
......
......@@ -49,7 +49,7 @@
#### Training Service improvements
* Migrate [Kubeflow training service](https://github.com/Microsoft/nni/blob/master/docs/KubeflowMode.md)'s dependency from kubectl CLI to [Kubernetes API](https://kubernetes.io/docs/concepts/overview/kubernetes-api/) client
* Migrate [Kubeflow training service](KubeflowMode.md)'s dependency from kubectl CLI to [Kubernetes API](https://kubernetes.io/docs/concepts/overview/kubernetes-api/) client
* [Pytorch-operator](https://github.com/kubeflow/pytorch-operator) support for Kubeflow training service
* Improvement on local code files uploading to OpenPAI HDFS
* Fixed OpenPAI integration WebUI bug: WebUI doesn't show latest trial job status, which is caused by OpenPAI token expiration
......@@ -115,7 +115,7 @@
```
* Support updating max trial number.
use `nnictl update --help` to learn more. Or refer to [NNICTL Spec](https://github.com/Microsoft/nni/blob/master/docs/NNICTLDOC.md) for the fully usage of NNICTL.
use `nnictl update --help` to learn more. Or refer to [NNICTL Spec](NNICTLDOC.md) for the fully usage of NNICTL.
### API new features and updates
......
......@@ -77,7 +77,7 @@ nnictl create --config nni/examples/trials/cifar10_pytorch/config.yml
[2]: https://pytorch.org/
[3]: https://www.cs.toronto.edu/~kriz/cifar.html
[4]: https://github.com/Microsoft/nni/tree/master/examples/trials/cifar10_pytorch
[5]: https://github.com/Microsoft/nni/blob/master/docs/Trials.md
[5]: Trials.md
[6]: https://github.com/Microsoft/nni/blob/master/examples/trials/cifar10_pytorch/config.yml
[7]: https://github.com/Microsoft/nni/blob/master/examples/trials/cifar10_pytorch/config_pai.yml
[8]: https://github.com/Microsoft/nni/blob/master/examples/trials/cifar10_pytorch/search_space.json
......
......@@ -98,7 +98,7 @@ If you like to tune `num_leaves`, `learning_rate`, `bagging_fraction` and `baggi
}
```
More support variable type you could reference [here](https://github.com/Microsoft/nni/blob/master/docs/SearchSpaceSpec.md).
More support variable type you could reference [here](SearchSpaceSpec.md).
### 3.3 Add SDK of nni into your code.
......
......@@ -48,7 +48,8 @@ setup(
'nni': 'src/sdk/pynni/nni',
'nni_annotation': 'tools/nni_annotation',
'nni_cmd': 'tools/nni_cmd',
'nni_trial_tool':'tools/nni_trial_tool'
'nni_trial_tool':'tools/nni_trial_tool',
'nni_gpu_tool':'tools/nni_gpu_tool'
},
package_data = {'nni': ['**/requirements.txt']},
python_requires = '>=3.5',
......
......@@ -17,10 +17,10 @@
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''
"""
batch_tuner.py including:
class BatchTuner
'''
"""
import copy
from enum import Enum, unique
......@@ -37,7 +37,7 @@ VALUE = '_value'
class BatchTuner(Tuner):
'''
"""
BatchTuner is tuner will running all the configure that user want to run batchly.
The search space only be accepted like:
{
......@@ -45,16 +45,20 @@ class BatchTuner(Tuner):
'_value': '[{...}, {...}, {...}]',
}
}
'''
"""
def __init__(self):
self.count = -1
self.values = []
def is_valid(self, search_space):
'''
"""
Check the search space is valid: only contains 'choice' type
'''
Parameters
----------
search_space : dict
"""
if not len(search_space) == 1:
raise RuntimeError('BatchTuner only supprt one combined-paramreters key.')
......@@ -69,9 +73,21 @@ class BatchTuner(Tuner):
return None
def update_search_space(self, search_space):
"""Update the search space
Parameters
----------
search_space : dict
"""
self.values = self.is_valid(search_space)
def generate_parameters(self, parameter_id):
"""Returns a dict of trial (hyper-)parameters, as a serializable object.
Parameters
----------
parameter_id : int
"""
self.count +=1
if self.count>len(self.values)-1:
raise nni.NoMoreTrialError('no more parameters now.')
......
......@@ -17,16 +17,12 @@
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
'''
"""
evolution_tuner.py including:
class OptimizeMode
class Individual
class EvolutionTuner
if OptimizeMode is 'minimize', it means the tuner need to minimize the reward
that received from Trial.
if OptimizeMode is 'maximize', it means the tuner need to maximize the reward
that received from Trial.
'''
"""
import copy
from enum import Enum, unique
......@@ -40,18 +36,22 @@ from .. import parameter_expressions
@unique
class OptimizeMode(Enum):
'''
Optimize Mode class
'''
"""Optimize Mode class
if OptimizeMode is 'minimize', it means the tuner need to minimize the reward
that received from Trial.
if OptimizeMode is 'maximize', it means the tuner need to maximize the reward
that received from Trial.
"""
Minimize = 'minimize'
Maximize = 'maximize'
@unique
class NodeType(Enum):
'''
Node Type class
'''
"""Node Type class
"""
Root = 'root'
Type = '_type'
Value = '_value'
......@@ -59,9 +59,8 @@ class NodeType(Enum):
def json2space(x, oldy=None, name=NodeType.Root.value):
'''
Change search space from json format to hyperopt format
'''
"""Change search space from json format to hyperopt format
"""
y = list()
if isinstance(x, dict):
if NodeType.Type.value in x.keys():
......@@ -89,9 +88,8 @@ def json2space(x, oldy=None, name=NodeType.Root.value):
def json2paramater(x, is_rand, random_state, oldy=None, Rand=False, name=NodeType.Root.value):
'''
Json to pramaters.
'''
"""Json to pramaters.
"""
if isinstance(x, dict):
if NodeType.Type.value in x.keys():
_type = x[NodeType.Type.value]
......@@ -131,6 +129,16 @@ def json2paramater(x, is_rand, random_state, oldy=None, Rand=False, name=NodeTyp
def _split_index(params):
"""Delete index information from params
Parameters
----------
params : dict
Returns
-------
result : dict
"""
result = {}
for key in params:
if isinstance(params[key], dict):
......@@ -142,10 +150,19 @@ def _split_index(params):
class Individual(object):
'''
"""
Indicidual class to store the indv info.
'''
"""
def __init__(self, config=None, info=None, result=None, save_dir=None):
"""
Parameters
----------
config : str
info : str
result : float
save_dir : str
"""
self.config = config
self.result = result
self.info = info
......@@ -157,6 +174,13 @@ class Individual(object):
", config :" + str(self.config) + ", result: " + str(self.result)
def mutation(self, config=None, info=None, save_dir=None):
"""
Parameters
----------
config : str
info : str
save_dir : str
"""
self.result = None
self.config = config
self.restore_dir = self.save_dir
......@@ -165,13 +189,22 @@ class Individual(object):
class EvolutionTuner(Tuner):
'''
EvolutionTuner is tuner using evolution algorithm.
'''
"""
EvolutionTuner is tuner using navie evolution algorithm.
"""
def __init__(self, optimize_mode, population_size=32):
"""
Parameters
----------
optimize_mode : str
population_size : int
initial population size. The larger population size,
the better evolution performance.
"""
self.optimize_mode = OptimizeMode(optimize_mode)
self.population_size = population_size
self.trial_result = []
self.searchspace_json = None
self.total_data = {}
......@@ -180,10 +213,13 @@ class EvolutionTuner(Tuner):
self.space = None
def update_search_space(self, search_space):
'''
Update search space
search_space: search_space the json file that user pre-defined.
'''
"""Update search space.
Search_space contains the information that user pre-defined.
Parameters
----------
search_space : dict
"""
self.searchspace_json = search_space
self.space = json2space(self.searchspace_json)
......@@ -198,8 +234,15 @@ class EvolutionTuner(Tuner):
self.population.append(Individual(config=config))
def generate_parameters(self, parameter_id):
"""Returns a set of trial (hyper-)parameters, as a serializable object.
"""Returns a dict of trial (hyper-)parameters, as a serializable object.
Parameters
----------
parameter_id : int
Returns
-------
config : dict
"""
if not self.population:
raise RuntimeError('The population is empty')
......@@ -235,10 +278,14 @@ class EvolutionTuner(Tuner):
return config
def receive_trial_result(self, parameter_id, parameters, value):
'''
Record an observation of the objective function
parameters: dict of parameters
value: final metrics of the trial, including reward
'''Record the result from a trial
Parameters
----------
parameters: dict
value : dict/float
if value is dict, it should have "default" key.
value is final metrics of the trial.
'''
reward = self.extract_scalar_reward(value)
if parameter_id not in self.total_data:
......
......@@ -35,9 +35,9 @@ logger = logging.getLogger('hyperopt_AutoML')
@unique
class OptimizeMode(Enum):
'''
Oprimize Mode class
'''
"""
Optimize Mode including Minimize and Maximize
"""
Minimize = 'minimize'
Maximize = 'maximize'
......@@ -49,9 +49,16 @@ INDEX = '_index'
def json2space(in_x, name=ROOT):
'''
"""
Change json to search space in hyperopt.
'''
Parameters
----------
in_x : dict/list/str/int/float
The part of json.
name : str
name could be ROOT, TYPE, VALUE or INDEX.
"""
out_y = copy.deepcopy(in_x)
if isinstance(in_x, dict):
if TYPE in in_x.keys():
......@@ -78,9 +85,9 @@ def json2space(in_x, name=ROOT):
def json2parameter(in_x, parameter, name=ROOT):
'''
"""
Change json to parameters.
'''
"""
out_y = copy.deepcopy(in_x)
if isinstance(in_x, dict):
if TYPE in in_x.keys():
......@@ -133,6 +140,9 @@ def json2vals(in_x, vals, out_y, name=ROOT):
def _split_index(params):
"""
Delete index infromation from params
"""
result = {}
for key in params:
if isinstance(params[key], dict):
......@@ -144,11 +154,18 @@ def _split_index(params):
class HyperoptTuner(Tuner):
'''
"""
HyperoptTuner is a tuner which using hyperopt algorithm.
'''
"""
def __init__(self, algorithm_name, optimize_mode):
"""
Parameters
----------
algorithm_name : str
algorithm_name includes "tpe", "random_search" and anneal".
optimize_mode : str
"""
self.algorithm_name = algorithm_name
self.optimize_mode = OptimizeMode(optimize_mode)
self.json = None
......@@ -156,6 +173,12 @@ class HyperoptTuner(Tuner):
self.rval = None
def _choose_tuner(self, algorithm_name):
"""
Parameters
----------
algorithm_name : str
algorithm_name includes "tpe", "random_search" and anneal"
"""
if algorithm_name == 'tpe':
return hp.tpe.suggest
if algorithm_name == 'random_search':
......@@ -165,11 +188,15 @@ class HyperoptTuner(Tuner):
raise RuntimeError('Not support tuner algorithm in hyperopt.')
def update_search_space(self, search_space):
'''
"""
Update search space definition in tuner by search_space in parameters.
'''
#assert self.json is None
Will called when first setup experiemnt or update search space in WebUI.
Parameters
----------
search_space : dict
"""
self.json = search_space
search_space_instance = json2space(self.json)
rstate = np.random.RandomState()
......@@ -182,39 +209,38 @@ class HyperoptTuner(Tuner):
self.rval.catch_eval_exceptions = False
def generate_parameters(self, parameter_id):
'''
"""
Returns a set of trial (hyper-)parameters, as a serializable object.
Parameters
----------
parameter_id : int
'''
rval = self.rval
trials = rval.trials
algorithm = rval.algo
new_ids = rval.trials.new_trial_ids(1)
rval.trials.refresh()
random_state = rval.rstate.randint(2**31-1)
new_trials = algorithm(new_ids, rval.domain, trials, random_state)
rval.trials.refresh()
vals = new_trials[0]['misc']['vals']
parameter = dict()
for key in vals:
try:
parameter[key] = vals[key][0].item()
except Exception:
parameter[key] = None
# remove '_index' from json2parameter and save params-id
total_params = json2parameter(self.json, parameter)
Returns
-------
params : dict
"""
total_params = self.get_suggestion(random_search=False)
# avoid generating same parameter with concurrent trials because hyperopt doesn't support parallel mode
if total_params in self.total_data.values():
# but it can cause deplicate parameter rarely
total_params = self.get_suggestion(random_search=True)
self.total_data[parameter_id] = total_params
params = _split_index(total_params)
return params
def receive_trial_result(self, parameter_id, parameters, value):
'''
"""
Record an observation of the objective function
Parameters
----------
parameter_id : int
parameters : dict of parameters
value: final metrics of the trial, including reward
'''
parameters : dict
value : dict/float
if value is dict, it should have "default" key.
value is final metrics of the trial.
"""
reward = self.extract_scalar_reward(value)
# restore the paramsters contains '_index'
if parameter_id not in self.total_data:
......@@ -262,13 +288,16 @@ class HyperoptTuner(Tuner):
def miscs_update_idxs_vals(self, miscs, idxs, vals,
assert_all_vals_used=True,
idxs_map=None):
'''
"""
Unpack the idxs-vals format into the list of dictionaries that is
`misc`.
idxs_map: a dictionary of id->id mappings so that the misc['idxs'] can
contain different numbers than the idxs argument. XXX CLARIFY
'''
Parameters
----------
idxs_map : dict
idxs_map is a dictionary of id->id mappings so that the misc['idxs'] can
contain different numbers than the idxs argument.
"""
if idxs_map is None:
idxs_map = {}
......@@ -286,3 +315,40 @@ class HyperoptTuner(Tuner):
if assert_all_vals_used or tid in misc_by_id:
misc_by_id[tid]['idxs'][key] = [tid]
misc_by_id[tid]['vals'][key] = [val]
def get_suggestion(self, random_search=False):
"""get suggestion from hyperopt
Parameters
----------
random_search : bool
flag to indicate random search or not (default: {False})
Returns
----------
total_params : dict
parameter suggestion
"""
rval = self.rval
trials = rval.trials
algorithm = rval.algo
new_ids = rval.trials.new_trial_ids(1)
rval.trials.refresh()
random_state = rval.rstate.randint(2**31-1)
if random_search:
new_trials = hp.rand.suggest(new_ids, rval.domain, trials, random_state)
else:
new_trials = algorithm(new_ids, rval.domain, trials, random_state)
rval.trials.refresh()
vals = new_trials[0]['misc']['vals']
parameter = dict()
for key in vals:
try:
parameter[key] = vals[key][0].item()
except KeyError:
parameter[key] = None
# remove '_index' from json2parameter and save params-id
total_params = json2parameter(self.json, parameter)
return total_params
......@@ -25,6 +25,8 @@ import random
import statistics
import sys
import numpy as np
from enum import Enum, unique
from multiprocessing.dummy import Pool as ThreadPool
......@@ -43,9 +45,9 @@ logger = logging.getLogger("Metis_Tuner_AutoML")
@unique
class OptimizeMode(Enum):
'''
"""
Optimize Mode class
'''
"""
Minimize = 'minimize'
Maximize = 'maximize'
......@@ -57,27 +59,38 @@ CONSTRAINT_PARAMS_IDX = []
class MetisTuner(Tuner):
'''
"""
Metis Tuner
'''
More algorithm information you could reference here:
https://www.microsoft.com/en-us/research/publication/metis-robustly-tuning-tail-latencies-cloud-systems/
"""
def __init__(self, optimize_mode="maximize", no_resampling=True, no_candidates=True,
selection_num_starting_points=10, cold_start_num=10):
'''
optimize_mode: is a string that including two mode "maximize" and "minimize"
no_resampling: True or False. Should Metis consider re-sampling as part of the search strategy?
"""
Parameters
----------
optimize_mode : str
optimize_mode is a string that including two mode "maximize" and "minimize"
no_resampling : bool
True or False. Should Metis consider re-sampling as part of the search strategy?
If you are confident that the training dataset is noise-free, then you do not need re-sampling.
no_candidates: True or False. Should Metis suggest parameters for the next benchmark?
no_candidates: bool
True or False. Should Metis suggest parameters for the next benchmark?
If you do not plan to do more benchmarks, Metis can skip this step.
selection_num_starting_points: how many times Metis should try to find the global optimal in the search space?
selection_num_starting_points: int
how many times Metis should try to find the global optimal in the search space?
The higher the number, the longer it takes to output the solution.
cold_start_num: Metis need some trial result to get cold start. when the number of trial result is less than
cold_start_num: int
Metis need some trial result to get cold start. when the number of trial result is less than
cold_start_num, Metis will randomly sample hyper-parameter for trial.
'''
"""
self.samples_x = []
self.samples_y = []
self.samples_y_aggregation = []
......@@ -93,9 +106,12 @@ class MetisTuner(Tuner):
def update_search_space(self, search_space):
'''
Update the self.x_bounds and self.x_types by the search_space.json
'''
"""Update the self.x_bounds and self.x_types by the search_space.json
Parameters
----------
search_space : dict
"""
self.x_bounds = [[] for i in range(len(search_space))]
self.x_types = [NONE_TYPE for i in range(len(search_space))]
......@@ -120,7 +136,7 @@ class MetisTuner(Tuner):
self.x_types[idx] = 'range_int'
else:
bounds = []
for value in range(key_range[0], key_range[1], key_range[2]):
for value in np.arange(key_range[0], key_range[1], key_range[2]):
bounds.append(value)
self.x_bounds[idx] = bounds
self.x_types[idx] = 'discrete_int'
......@@ -150,9 +166,16 @@ class MetisTuner(Tuner):
def _pack_output(self, init_parameter):
'''
Pack the output
'''
"""Pack the output
Parameters
----------
init_parameter : dict
Returns
-------
output : dict
"""
output = {}
for i, param in enumerate(init_parameter):
output[self.key_order[i]] = param
......@@ -160,12 +183,19 @@ class MetisTuner(Tuner):
def generate_parameters(self, parameter_id):
'''
This function is for generate parameters to trial.
"""Generate next parameter for trial
If the number of trial result is lower than cold start number,
metis will first random generate some parameters.
Otherwise, metis will choose the parameters by the Gussian Process Model and the Gussian Mixture Model.
'''
Parameters
----------
parameter_id : int
Returns
-------
result : dict
"""
if self.samples_x or len(self.samples_x) < self.cold_start_num:
init_parameter = _rand_init(self.x_bounds, self.x_types, 1)[0]
results = self._pack_output(init_parameter)
......@@ -177,23 +207,27 @@ class MetisTuner(Tuner):
minimize_starting_points=self.minimize_starting_points,
minimize_constraints_fun=self.minimize_constraints_fun)
logger.info("Generate paramageters:\n", str(results))
logger.info("Generate paramageters:\n%s", str(results))
return results
def receive_trial_result(self, parameter_id, parameters, value):
'''
Tuner receive result from trial.
An value example as follow:
value: 99.5%
'''
"""Tuner receive result from trial.
Parameters
----------
parameter_id : int
parameters : dict
value : dict/float
if value is dict, it should have "default" key.
"""
value = self.extract_scalar_reward(value)
if self.optimize_mode == OptimizeMode.Maximize:
value = -value
logger.info("Received trial result.")
logger.info("value is :", str(value))
logger.info("parameter is : ", str(parameters))
logger.info("value is :\t%f", value)
logger.info("parameter is :\t%s", str(parameters))
# parse parameter to sample_x
sample_x = [0 for i in range(len(self.key_order))]
......@@ -432,9 +466,8 @@ def _rand_init(x_bounds, x_types, selection_num_starting_points):
def get_median(temp_list):
'''
Return median
'''
"""Return median
"""
num = len(temp_list)
temp_list.sort()
print(temp_list)
......
......@@ -52,20 +52,35 @@ class NetworkMorphismTuner(Tuner):
default_model_width=Constant.MODEL_WIDTH,
):
""" initilizer of the NetworkMorphismTuner.
Keyword Arguments:
task {str} -- [task mode, such as "cv","common" etc.] (default: {"cv"})
input_width {int} -- [input sample shape] (default: {32})
input_channel {int} -- [input sample shape] (default: {3})
n_output_node {int} -- [output node number] (default: {10})
algorithm_name {str} -- [algorithm name used in the network morphism] (default: {"Bayesian"})
optimize_mode {str} -- [optimize mode "minimize" or "maximize"] (default: {"minimize"})
path {str} -- [default mode path to save the model file] (default: {"model_path"})
verbose {bool} -- [verbose to print the log] (default: {True})
beta {float} -- [The beta in acquisition function. (refer to our paper)] (default: {Constant.BETA})
t_min {float} -- [The minimum temperature for simulated annealing.] (default: {Constant.T_MIN})
max_model_size {int} -- [max model size to the graph] (default: {Constant.MAX_MODEL_SIZE})
default_model_len {int} -- [default model length] (default: {Constant.MODEL_LEN})
default_model_width {int} -- [default model width] (default: {Constant.MODEL_WIDTH})
Parameters
----------
task : str
task mode, such as "cv","common" etc. (default: {"cv"})
input_width : int
input sample shape (default: {32})
input_channel : int
input sample shape (default: {3})
n_output_node : int
output node number (default: {10})
algorithm_name : str
algorithm name used in the network morphism (default: {"Bayesian"})
optimize_mode : str
optimize mode "minimize" or "maximize" (default: {"minimize"})
path : str
default mode path to save the model file (default: {"model_path"})
verbose : bool
verbose to print the log (default: {True})
beta : float
The beta in acquisition function. (default: {Constant.BETA})
t_min : float
The minimum temperature for simulated annealing. (default: {Constant.T_MIN})
max_model_size : int
max model size to the graph (default: {Constant.MAX_MODEL_SIZE})
default_model_len : int
default model length (default: {Constant.MODEL_LEN})
default_model_width : int
default model width (default: {Constant.MODEL_WIDTH})
"""
if not os.path.exists(path):
......@@ -92,8 +107,6 @@ class NetworkMorphismTuner(Tuner):
self.bo = BayesianOptimizer(self, self.t_min, self.optimize_mode, self.beta)
self.training_queue = []
# self.x_queue = []
# self.y_queue = []
self.descriptors = []
self.history = []
......@@ -112,6 +125,9 @@ class NetworkMorphismTuner(Tuner):
def generate_parameters(self, parameter_id):
"""
Returns a set of trial neural architecture, as a serializable object.
Parameters
----------
parameter_id : int
"""
if not self.history:
......@@ -137,14 +153,14 @@ class NetworkMorphismTuner(Tuner):
def receive_trial_result(self, parameter_id, parameters, value):
""" Record an observation of the objective function.
Arguments:
Parameters
----------
parameter_id : int
parameters : dict of parameters
value: final metrics of the trial, including reward
Raises:
RuntimeError -- Received parameter_id not in total_data.
parameters : dict
value : dict/float
if value is dict, it should have "default" key.
"""
reward = self.extract_scalar_reward(value)
if parameter_id not in self.total_data:
......@@ -176,9 +192,13 @@ class NetworkMorphismTuner(Tuner):
def generate(self):
"""Generate the next neural architecture.
Returns:
other_info: Anything to be saved in the training queue together with the architecture.
generated_graph: An instance of Graph.
Returns
-------
other_info: any object
Anything to be saved in the training queue together with the architecture.
generated_graph: Graph
An instance of Graph.
"""
generated_graph, new_father_id = self.bo.generate(self.descriptors)
if new_father_id is None:
......@@ -191,11 +211,16 @@ class NetworkMorphismTuner(Tuner):
def update(self, other_info, graph, metric_value, model_id):
""" Update the controller with evaluation result of a neural architecture.
Args:
other_info: Anything. In our case it is the father ID in the search tree.
graph: An instance of Graph. The trained neural architecture.
metric_value: The final evaluated metric value.
model_id: An integer.
Parameters
----------
other_info: any object
In our case it is the father ID in the search tree.
graph: Graph
An instance of Graph. The trained neural architecture.
metric_value: float
The final evaluated metric value.
model_id: int
"""
father_id = other_info
self.bo.fit([graph.extract_descriptor()], [metric_value])
......@@ -204,15 +229,16 @@ class NetworkMorphismTuner(Tuner):
def add_model(self, metric_value, model_id):
""" Add model to the history, x_queue and y_queue
Arguments:
metric_value: int --metric_value
graph: dict -- graph
model_id: int -- model_id
Parameters
----------
metric_value : float
graph : dict
model_id : int
Returns:
model dict
Returns
-------
model : dict
"""
if self.verbose:
logger.info("Saving model.")
......@@ -223,16 +249,10 @@ class NetworkMorphismTuner(Tuner):
file = open(os.path.join(self.path, "best_model.txt"), "w")
file.write("best model: " + str(model_id))
file.close()
# descriptor = graph.extract_descriptor()
# self.x_queue.append(descriptor)
# self.y_queue.append(metric_value)
return ret
def get_best_model_id(self):
""" Get the best model_id from history using the metric value
Returns:
int -- the best model_id
"""
if self.optimize_mode is OptimizeMode.Maximize:
......@@ -241,10 +261,16 @@ class NetworkMorphismTuner(Tuner):
def load_model_by_id(self, model_id):
"""Get the model by model_id
Arguments:
model_id {int} -- model index
Returns:
Graph -- the model graph representation
Parameters
----------
model_id : int
model index
Returns
-------
load_model : Graph
the model graph representation
"""
with open(os.path.join(self.path, str(model_id) + ".json")) as fin:
......@@ -255,17 +281,26 @@ class NetworkMorphismTuner(Tuner):
def load_best_model(self):
""" Get the best model by model id
Returns:
Graph -- the best model graph representation
Returns
-------
load_model : Graph
the model graph representation
"""
return self.load_model_by_id(self.get_best_model_id())
def get_metric_value_by_id(self, model_id):
""" Get the model metric valud by its model_id
Arguments:
model_id {int} -- model index
Returns:
float -- the model metric
Parameters
----------
model_id : int
model index
Returns
-------
float
the model metric
"""
for item in self.history:
if item["model_id"] == model_id:
......
# Makefile 文件和安装配置
NNI 使用 GNU 来生成和安装。
NNI 使用 GNU Make 来生成和安装。
`Makefile` 提供标准的目标 `生成``安装``卸载`, 以及不同设置的安装对象:
* `easy-install`: 针对非专家用户,自动处理所有内容;
* `dev-easy-install`: 针对专家用户,自动处理所有内容;
* `easy-install`: 针对非专家用户,自动安装所有内容;
* `dev-easy-install`: 针对专家用户,自动安装所有内容;
* `install`: 针对 NNI 普通用户,通过复制文件来安装 NNI;
* `dev-install`: 针对 NNI 贡献者,通过创建 symlinks 而不是复制文件来安装 NNI;
* `dev-install`: 针对 NNI 开发人员,通过创建符号链接而不是复制文件来安装 NNI;
* `pip-install`: 针对使用 `setup.py` 安装的情况;
下文会有更详细的介绍。
## 依赖项
NNI 依赖于 Node.js, Yarn, 和 pip 来生成,推荐安装 TypeScript。
NNI 依赖于 Node.js, Yarn, 和 PIP 来生成,推荐安装 TypeScript。
NNI 需要 Node.js 以及运行所需要的所有库。 需要的 Node.js 库 (包括 TypeScript) 可以通过 Yarn 来安装, 需要的 Python 库可以通过 setuptools 或者 PIP 来安装。
运行 NNI 需要 Node.js 以及依赖库。 Node.js 依赖库 (包括 TypeScript) 可以通过 Yarn 来安装, Python 依赖库可以通过 setuptools 或者 PIP 来安装。
NNI *用户*可以用 `make install-dependencies` 来安装 Node.js 和 Yarn。 Node.js 会被安装到 NNI 的安装目录,Yarn 会被安装到 `/tmp/nni-yarn`。 安装过程需要 wget。
NNI *普通用户*可以用 `make install-dependencies` 来安装 Node.js 和 Yarn。 Node.js 会被安装到 NNI 的安装目录,Yarn 会被安装到 `/tmp/nni-yarn`。 安装过程需要 wget。
NNI *开发人员*推荐手工安装 Node.js 和 Yarn。 可浏览相应的官方文档了解安装过程。
......@@ -32,15 +32,15 @@ NNI *开发人员*推荐手工安装 Node.js 和 Yarn。 可浏览相应的官
NNI 项目主要由两个 Node.js 模块 (`nni_manager`, `webui`) 以及两个 Python 包 (`nni`, `nnictl`) 所组成。
默认情况下,Node.js 模块可以为所有用户安装在 `/usr/share/nni` 目录下,也可为只安装在当前用户 `~/.local/nni` 目录下。
默认情况下,Node.js 模块为所有用户安装在 `/usr/share/nni` 目录下,也可以只为当前用户安装在 `~/.local/nni` 目录下。
Python 包使用 setuptools 安装,所以安装路径依赖于 Python 配置。 如果为没有权限的用户安装,并且没有虚拟环境的时候,要加上 `--user` 参数。
Python 包使用 setuptools 安装,所以安装路径依赖于 Python 配置。 如果以非管理员身份安装 ,并且没有虚拟环境的时候,要加上 `--user` 参数。
此外,`nnictl` 是一个 bash 脚本,会被安装在 `/usr/share/bash-completion/completions``~/.bash_completion.d` 目录下。
此外,`nnictl` 提供一个自动完成脚本,会被安装在 `/usr/share/bash-completion/completions``~/.bash_completion.d` 目录下。
在某些配置情况下,NNI 也会将 Node.js 安装到 `/usr/share/nni` 目录下。
以上所有目录都可配置。 可参考下一章节。
以上所有目录都可配置。 可参考下一章节。
### 配置
......@@ -59,18 +59,18 @@ Python 包使用 setuptools 安装,所以安装路径依赖于 Python 配置
| `NODE` | Node.js 命令 | 参考源代码 | 参考源代码 |
| `YARN` | Yarn 命令 | 参考源代码 | 参考源代码 |
注意,这些变量不仅会影响安装路径,也会影响生成的 `nnictl` `nnimanager` 脚本。 如果复制文件的路径和运行时的不一样(例如,创建发行版本包时),需要手工编辑 `nnictl``nnimanager`
注意,这些变量不仅会影响安装路径,也会影响生成的 `nnictl` 脚本。 如果复制文件的路径和运行时的不一样(例如,创建发行版本包时),需要手工编辑 `nnictl``nnimanager`
### 目标
安装目标的流程如下:
| 目标 | 流程 |
| ------------------ | ------------------------------------------------ |
| ------------------ | ------------------------------------------ |
| `easy-install` | 安装依赖项,生成,安装 NNI,并编辑 `~/.bashrc` |
| `dev-easy-install` | 安装依赖项,生成,将 NNI 作为 symlinks 来安装,并编辑 `~/.bashrc` |
| `dev-easy-install` | 安装依赖项,生成,将 NNI 作为符号链接来安装,并编辑 `~/.bashrc` |
| `install` | 安装 Python 包,Node.js 模块,NNI 脚本和样例 |
| `dev-install` | 将 Python 和 Node.js 模块作为 symlinks 安装,然后安装 scripts |
| `dev-install` | 将 Python 和 Node.js 模块作为符号链接安装,然后安装 scripts |
| `pip-install` | 安装依赖项,生成,安装 NNI,但不安装 Python 包 |
## TODO
......
<p align="center">
<img src="https://microsoft.github.io/nni/docs/img/nni_logo.png" width="300"/>
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/nni_logo.png" width="300"/>
</p>
* * *
......@@ -13,7 +13,7 @@ NNI (Neural Network Intelligence) 是自动机器学习(AutoML)的工具包
### **NNI [v0.5.1](https://github.com/Microsoft/nni/releases) 已发布!**
<p align="center">
<a href="#nni-v05-has-been-released"><img src="https://microsoft.github.io/nni/docs/img/overview.svg" /></a>
<a href="#nni-v05-has-been-released"><img src="https://github.com/Microsoft/nni/blob/master/docs/img/overview.svg" /></a>
</p>
<table>
......@@ -21,15 +21,15 @@ NNI (Neural Network Intelligence) 是自动机器学习(AutoML)的工具包
<tr align="center" valign="bottom">
<td>
<b>支持的框架</b>
<img src="https://user-images.githubusercontent.com/44491713/51381727-e3d0f780-1b4f-11e9-96ab-d26b9198ba65.png"/>
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/bar.png"/>
</td>
<td>
<b>调优算法</b>
<img src="https://user-images.githubusercontent.com/44491713/51381727-e3d0f780-1b4f-11e9-96ab-d26b9198ba65.png"/>
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/bar.png"/>
</td>
<td>
<b>训练服务</b>
<img src="https://user-images.githubusercontent.com/44491713/51381727-e3d0f780-1b4f-11e9-96ab-d26b9198ba65.png"/>
<img src="https://github.com/Microsoft/nni/blob/master/docs/img/bar.png"/>
</td>
</tr>
<tr/>
......
......@@ -2,10 +2,12 @@
NNI 提供了先进的调优算法,使用上也很简单。 下面是内置 Assessor 的介绍:
注意:点击 **Assessor 的名称**可跳转到算法的详细描述,点击**用法**可看到 Assessor 的安装要求、建议场景和使用样例等等。
| Assessor | 算法简介 |
| ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Medianstop** [(用法)](#MedianStop) | Medianstop 是一简单的提前终止策略,可参考[论文](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/46180.pdf)。 如果 Trial X 的在步骤 S 的最好目标值比所有已完成 Trial 的步骤 S 的中位数值明显要低,就会停止运行 Trial X。 |
| [Curvefitting](../src/sdk/pynni/nni/curvefitting_assessor/README.md) [(用法)](#Curvefitting) | Curve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学习、预测、评估) 的算法。 如果预测的 Trial X 在 step S 比性能最好的 Trial要差,就会提前终止它。 此算法中采用了 12 种曲线来拟合精度 |
| ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Medianstop](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/medianstop_assessor/README.md) [(用法)](#MedianStop) | Medianstop 是一简单的提前终止算法。 如果 Trial X 的在步骤 S 的最好目标值比所有已完成 Trial 的步骤 S 的中位数值明显要低,就会停止运行 Trial X。 [参考论文](https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/46180.pdf) |
| [Curvefitting](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/curvefitting_assessor/README.md) [(用法)](#Curvefitting) | Curve Fitting Assessor 是一个 LPA (learning, predicting, assessing,即学习、预测、评估) 的算法。 如果预测的 Trial X 在 step S 比性能最好的 Trial要差,就会提前终止它。 此算法中采用了 12 种曲线来拟合精度曲线。 [参考论文](http://aad.informatik.uni-freiburg.de/papers/15-IJCAI-Extrapolation_of_Learning_Curves.pdf) |
## 用法
......@@ -49,7 +51,7 @@ assessor:
**建议场景**
适用于各种性能曲线,可用到各种场景中来加速优化过程。 更好的是,它能处理并评估性能类似的曲线。
适用于各种性能曲线,可用到各种场景中来加速优化过程。 更好的地方是,它能处理并评估性能类似的曲线。
**参数**
......
......@@ -2,18 +2,20 @@
NNI 提供了先进的调优算法,使用上也很简单。 下面是内置 Tuner 的简单介绍:
注意:点击 **Tuner 的名称**可跳转到算法的详细描述,点击**用法**可看到 Tuner 的安装要求、建议场景和使用样例等等。
| Tuner | 算法简介 |
| ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **TPE** [(用法)](#TPE) | Tree-structured Parzen Estimator (TPE) 是一种 sequential model-based optimization(SMBO,即基于序列模型优化)的方法。 SMBO 方法根据历史指标数据来按顺序构造模型,来估算超参的性能,随后基于此模型来选择新的超参。 |
| **Random Search** [(用法)](#Random) | 在超参优化时,随机搜索算法展示了其惊人的简单和效果。 建议当不清楚超参的先验分布时,采用随机搜索作为基准。 |
| **Anneal** [(用法)](#Anneal) | 这种简单的退火算法从先前的采样开始,会越来越靠近发现的最佳点取样。 此算法是随机搜索的简单变体,利用了反应曲面的平滑性。 退火率不是自适应的。 |
| **Naive Evolution** [(用法)](#Evolution) | 朴素进化算法来自于大规模图像分类进化。 它会基于搜索空间随机生成一个种群。 在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层)。 进化算法需要很多次 Trial 才能有效,但它也非常简单,也很容易扩展新功能。 |
| **SMAC** [(用法)](#SMAC) | SMAC 基于 Sequential Model-Based Optimization (SMBO,即序列的基于模型优化方法)。 它会利用使用过的结果好的模型(高斯随机过程模型),并将随机森林引入到 SMBO 中,来处理分类参数。 SMAC 算法包装了 Github 的 SMAC3。 注意:SMAC 需要通过 `nnictl package` 命令来安装。 |
| **Batch tuner** [(用法)](#Batch) | Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。 当所有配置都执行完后,Experiment 即结束。 Batch Tuner 仅支持 choice 类型。 |
| **Grid Search** [(用法)](#GridSearch) | 网格搜索会穷举定义在搜索空间文件中的所有超参组合。 网格搜索可以使用的类型有 choice, quniform, qloguniform。 quniform 和 qloguniform 中的数值 q 具有特别的含义(不同于搜索空间文档中的说明)。 它表示了在最高值与最低值之间采样的值的数量。 |
| [Hyperband](https://github.com/Microsoft/nni/tree/master/src/sdk/pynni/nni/hyperband_advisor) [(用法)](#Hyperband) | Hyperband 试图用有限的资源来探索尽可能多的组合,并发现最好的结果。 它的基本思路是生成大量的配置,并运行少量的步骤来找到有可能好的配置,然后继续训练找到其中更好的配置。 |
| [Network Morphism](../src/sdk/pynni/nni/networkmorphism_tuner/README.md) [(用法)](#NetworkMorphism) | Network Morphism 提供了深度学习模型的自动架构搜索功能。 每个子网络都继承于父网络的知识和形态,并变换网络的不同形态,包括深度,宽度,跨层连接(skip-connection)。 然后使用历史的架构和指标,来估计子网络的值。 最后会选择最有希望的模型进行训练。 |
| **Metis Tuner** [(用法)](#MetisTuner) | 大多数调参工具仅仅预测最优配置,而 Metis 的优势在于有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 Trial 的建议。 它不进行随机取样。 大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。 |
| ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [TPE](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/hyperopt_tuner/README.md) [(用法)](#TPE) | Tree-structured Parzen Estimator (TPE) 是一种 sequential model-based optimization(SMBO,即基于序列模型优化)的方法。 SMBO 方法根据历史指标数据来按顺序构造模型,来估算超参的性能,随后基于此模型来选择新的超参。 [参考论文](https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf) |
| [Random Search](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/hyperopt_tuner/README.md) [(用法)](#Random) | 在超参优化时,随机搜索算法展示了其惊人的简单和效果。 建议当不清楚超参的先验分布时,采用随机搜索作为基准。 [参考论文](http://www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf) |
| [Anneal](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/hyperopt_tuner/README.md) [(用法)](#Anneal) | 这种简单的退火算法从先前的采样开始,会越来越靠近发现的最佳点取样。 此算法是随机搜索的简单变体,利用了反应曲面的平滑性。 退火率不是自适应的。 |
| [Naive Evolution](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/evolution_tuner/README.md) [(Usage)](#Evolution) | 朴素进化算法来自于大规模图像分类进化。 它会基于搜索空间随机生成一个种群。 在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层)。 进化算法需要很多次 Trial 才能有效,但它也非常简单,也很容易扩展新功能。 [参考论文](https://arxiv.org/pdf/1703.01041.pdf) |
| [SMAC](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/smac_tuner/README.md) [(用法)](#SMAC) | SMAC 基于 Sequential Model-Based Optimization (SMBO,即序列的基于模型优化方法)。 它会利用使用过的结果好的模型(高斯随机过程模型),并将随机森林引入到 SMBO 中,来处理分类参数。 SMAC 算法包装了 Github 的 SMAC3。 注意:SMAC 需要通过 `nnictl package` 命令来安装。 [参考论文,](https://www.cs.ubc.ca/~hutter/papers/10-TR-SMAC.pdf) [Github 代码库](https://github.com/automl/SMAC3) |
| [Batch tuner](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/batch_tuner/README.md) [(用法)](#Batch) | Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。 当所有配置都执行完后,Experiment 即结束。 Batch Tuner 仅支持 choice 类型。 |
| [Grid Search](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/gridsearch_tuner/README.md) [(用法)](#GridSearch) | 网格搜索会穷举定义在搜索空间文件中的所有超参组合。 网格搜索可以使用的类型有 choice, quniform, qloguniform。 quniform 和 qloguniform 中的数值 q 具有特别的含义(不同于搜索空间文档中的说明)。 它表示了在最高值与最低值之间采样的值的数量。 |
| [Hyperband](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/hyperband_advisor/README.md) [(用法)](#Hyperband) | Hyperband 试图用有限的资源来探索尽可能多的组合,并发现最好的结果。 它的基本思路是生成大量的配置,并运行少量的步骤来找到有可能好的配置,然后继续训练找到其中更好的配置。 [参考论文](https://arxiv.org/pdf/1603.06560.pdf) |
| [Network Morphism](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/networkmorphism_tuner/README.md) [(用法)](#NetworkMorphism) | Network Morphism 提供了深度学习模型的自动架构搜索功能。 每个子网络都继承于父网络的知识和形态,并变换网络的不同形态,包括深度,宽度,跨层连接(skip-connection)。 然后使用历史的架构和指标,来估计子网络的值。 最后会选择最有希望的模型进行训练。 [参考论文](https://arxiv.org/abs/1806.10282) |
| [Metis Tuner](https://github.com/Microsoft/nni/blob/master/zh_CN/src/sdk/pynni/nni/metis_tuner/README.md) [(用法)](#MetisTuner) | 大多数调参工具仅仅预测最优配置,而 Metis 的优势在于有两个输出:(a) 最优配置的当前预测结果, 以及 (b) 下一次 Trial 的建议。 它不进行随机取样。 大多数工具假设训练集没有噪声数据,但 Metis 会知道是否需要对某个超参重新采样。 [参考论文](https://www.microsoft.com/en-us/research/publication/metis-robustly-tuning-tail-latencies-cloud-systems/) |
<br />
......@@ -109,7 +111,7 @@ tuner:
**建议场景**
此算法对计算资源的需求相对较高。 需要非常大的初始种群,以免落入局部最优中。 如果 Trial 时间很短,或者用了 Assessor,就非常适合此算法。 如果 Trial 代码支持权重迁移,即每次 Trial 会从上一轮继承已经收敛的权重,建议使用此算法。 这会大大提高训练速度。
此算法对计算资源的需求相对较高。 需要非常大的初始种群,以免落入局部最优中。 如果 Trial 时间很短,或者使用了 Assessor,就非常适合此算法。 如果 Trial 代码支持权重迁移,即每次 Trial 会从上一轮继承已经收敛的权重,建议使用此算法。 这会大大提高训练速度。
**参数**
......@@ -169,7 +171,7 @@ tuner:
**建议场景**
如果 Experiment 配置已确定,可通过 Batch Tuner 将它们罗列到搜索空间中运行即可。
如果 Experiment 配置已确定,可通过 `choice` 将它们罗列到搜索空间文件中运行即可。
**使用样例:**
......
# Batch Tuner
## Batch Tuner(批处理调参器)
Batch Tuner 能让用户简单的提供几组配置(如,超参选项的组合)。 当所有配置都执行完后,Experiment 即结束。 Batch Tuner 仅支持[搜索空间](../../../../../docs/SearchSpaceSpec.md)中的 choice。
建议场景:如果 Experiment 配置已确定,可通过 choice 将它们罗列到搜索空间文件中运行即可。
\ No newline at end of file
# Naive Evolution Tuner
## Naive Evolution(进化算法)
进化算法来自于 [Large-Scale Evolution of Image Classifiers](https://arxiv.org/pdf/1703.01041.pdf)。 它会基于搜索空间随机生成一个种群。 在每一代中,会选择较好的结果,并对其下一代进行一些变异(例如,改动一个超参,增加或减少一层)。 进化算法需要很多次 Trial 才能有效,但它也非常简单,也很容易扩展新功能。
\ No newline at end of file
# Grid Search
## Grid Search(遍历搜索)
Grid Search 会穷举定义在搜索空间文件中的所有超参组合。 注意,搜索空间仅支持 `choice`, `quniform`, `qloguniform``quniform``qloguniform` 中的 **数字 `q` 有不同的含义(与[搜索空间](../../../../../docs/SearchSpaceSpec.md)说明不同)。 这里的意义是在 `low``high` 之间均匀取值的数量。</p>
\ No newline at end of file
# TPE, Random Search, Anneal Tuners
## TPE
Tree-structured Parzen Estimator (TPE) 是一种 sequential model-based optimization(SMBO,即基于序列模型优化)的方法。 SMBO 方法根据历史指标数据来按顺序构造模型,来估算超参的性能,随后基于此模型来选择新的超参。 TPE 方法对 P(x|y) 和 P(y) 建模,其中 x 表示超参,y 表示相关的评估指标。 P(x|y) 通过变换超参的生成过程来建模,用非参数密度(non-parametric densities)代替配置的先验分布。 细节可参考 [Algorithms for Hyper-Parameter Optimization](https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf)。 ​
## Random Search(随机搜索)
[Random Search for Hyper-Parameter Optimization](http://www.jmlr.org/papers/volume13/bergstra12a/bergstra12a.pdf) 中介绍了随机搜索惊人的简单和效果。 建议当不清楚超参的先验分布时,采用随机搜索作为基准。
## Anneal(退火算法)
这种简单的退火算法从先前的采样开始,会越来越靠近发现的最佳点取样。 此算法是随机搜索的简单变体,利用了响应面的平滑性。 退火率不是自适应的。
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment