Commit c550bbce authored by Zejun Lin's avatar Zejun Lin Committed by QuanluZhang
Browse files

modify loguniform and lognormal (#395)

* modify loguniform and lognormal

* fix bug

* fix bug

* update doc

* update doc

* fix

* update tpe for loguniform

* update tpe for loguniform

* update for loguniform

* update for loguniform

* update loguniform and qloguniform

* update doc

* update

* revert

* revert

* revert

* revert
parent a3872505
......@@ -40,12 +40,12 @@ The candidate type and value for variable is here:
<br/>
* {"_type":"loguniform","_value":[low, high]}
* Which means the variable value is a value drawn according to exp(uniform(low, high)) so that the logarithm of the return value is uniformly distributed.
* When optimizing, this variable is constrained to the interval [exp(low), exp(high)].
* Which means the variable value is a value drawn from a range [low, high] according to a loguniform distribution like exp(uniform(log(low), log(high))), so that the logarithm of the return value is uniformly distributed.
* When optimizing, this variable is constrained to be positive.
<br/>
* {"_type":"qloguniform","_value":[low, high, q]}
* Which means the variable value is a value like round(exp(uniform(low, high)) / q) * q
* Which means the variable value is a value like round(loguniform(low, high)) / q) * q
* Suitable for a discrete variable with respect to which the objective is "smooth" and gets smoother with the size of the value, but which should be bounded both above and below.
<br/>
......@@ -67,4 +67,8 @@ The candidate type and value for variable is here:
* Suitable for a discrete variable with respect to which the objective is smooth and gets smoother with the size of the variable, which is bounded from one side.
<br/>
Note that SMAC only supports a subset of the types above, including `choice`, `randint`, `uniform`, `loguniform`, `quniform(q=1)`. In the current version, SMAC does not support cascaded search space (i.e., conditional variable in SMAC).
\ No newline at end of file
Note that SMAC only supports a subset of the types above, including `choice`, `randint`, `uniform`, `loguniform`, `quniform(q=1)`. In the current version, SMAC does not support cascaded search space (i.e., conditional variable in SMAC).
Note that GridSearch Tuner only supports a subset of the types above, including `choic`, `quniform` and `qloguniform`, where q here specifies the number of values that will be sampled. Details about the last two type as follows
* Type 'quniform' will receive three values [low, high, q], where [low, high] specifies a range and 'q' specifies the number of values that will be sampled evenly. Note that q should be at least 2. It will be sampled in a way that the first sampled value is 'low', and each of the following values is (high-low)/q larger that the value in front of it.
* Type 'qloguniform' behaves like 'quniform' except that it will first change the range to [log(low), log(high)] and sample and then change the sampled value back.
\ No newline at end of file
......@@ -35,7 +35,7 @@ import random
import numpy as np
from nni.tuner import Tuner
from . import parameter_expressions
from .. import parameter_expressions
@unique
......
......@@ -44,7 +44,7 @@ class GridSearchTuner(Tuner):
Note that q should be at least 2.
It will be sampled in a way that the first sampled value is 'low', and each of the following values is (high-low)/q larger that the value in front of it.
Type 'qloguniform' behaves like 'quniform' except that it will first change the range to [log10(low), log10(high)]
Type 'qloguniform' behaves like 'quniform' except that it will first change the range to [log(low), log(high)]
and sample and then change the sampled value back.
'''
......@@ -102,8 +102,8 @@ class GridSearchTuner(Tuner):
if param_type == 'quniform':
return self._parse_quniform(param_value)
if param_type == 'qloguniform':
param_value[:2] = np.log10(param_value[:2])
return list(np.power(10, self._parse_quniform(param_value)))
param_value[:2] = np.log(param_value[:2])
return list(np.exp(self._parse_quniform(param_value)))
raise RuntimeError("Not supported type: %s" % param_type)
......
......@@ -61,6 +61,8 @@ def json2space(in_x, name=ROOT):
if _type == 'choice':
out_y = eval('hp.hp.'+_type)(name, _value)
else:
if _type in ['loguniform', 'qloguniform']:
_value[:2] = np.log(_value[:2])
out_y = eval('hp.hp.' + _type)(name, *_value)
else:
out_y = dict()
......@@ -75,7 +77,7 @@ def json2space(in_x, name=ROOT):
return out_y
def json2paramater(in_x, paramater, name=ROOT):
def json2parameter(in_x, parameter, name=ROOT):
'''
Change json to parameters.
'''
......@@ -85,22 +87,22 @@ def json2paramater(in_x, paramater, name=ROOT):
_type = in_x[TYPE]
name = name + '-' + _type
if _type == 'choice':
_index = paramater[name]
_index = parameter[name]
out_y = {
INDEX: _index,
VALUE: json2paramater(in_x[VALUE][_index], paramater, name=name+'[%d]' % _index)
VALUE: json2parameter(in_x[VALUE][_index], parameter, name=name+'[%d]' % _index)
}
else:
out_y = paramater[name]
out_y = parameter[name]
else:
out_y = dict()
for key in in_x.keys():
out_y[key] = json2paramater(
in_x[key], paramater, name + '[%s]' % str(key))
out_y[key] = json2parameter(
in_x[key], parameter, name + '[%s]' % str(key))
elif isinstance(in_x, list):
out_y = list()
for i, x_i in enumerate(in_x):
out_y.append(json2paramater(x_i, paramater, name + '[%d]' % i))
out_y.append(json2parameter(x_i, parameter, name + '[%d]' % i))
else:
logger.info('in_x is not a dict or a list in json2space fuinction %s', str(in_x))
return out_y
......@@ -201,7 +203,7 @@ class HyperoptTuner(Tuner):
parameter[key] = None
# remove '_index' from json2parameter and save params-id
total_params = json2paramater(self.json, parameter)
total_params = json2parameter(self.json, parameter)
self.total_data[parameter_id] = total_params
params = _split_index(total_params)
return params
......
......@@ -46,6 +46,7 @@ def uniform(low, high, random_state):
high: an float that represent an upper bound
random_state: an object of numpy.random.RandomState
'''
assert high > low, 'Upper bound must be larger than lower bound'
return random_state.uniform(low, high)
......@@ -65,7 +66,8 @@ def loguniform(low, high, random_state):
high: an float that represent an upper bound
random_state: an object of numpy.random.RandomState
'''
return np.exp(uniform(low, high, random_state))
assert low > 0, 'Lower bound must be positive'
return np.exp(uniform(np.log(low), np.log(high), random_state))
def qloguniform(low, high, q, random_state):
......
......@@ -55,10 +55,12 @@ if env_args.platform is None:
return random.uniform(low, high)
def quniform(low, high, q, name=None):
assert high > low, 'Upper bound must be larger than lower bound'
return round(random.uniform(low, high) / q) * q
def loguniform(low, high, name=None):
return math.exp(random.uniform(low, high))
assert low > 0, 'Lower bound must be positive'
return np.exp(random.uniform(np.log(low), np.log(high)))
def qloguniform(low, high, q, name=None):
return round(loguniform(low, high) / q) * q
......@@ -70,7 +72,7 @@ if env_args.platform is None:
return round(random.gauss(mu, sigma) / q) * q
def lognormal(mu, sigma, name=None):
return math.exp(random.gauss(mu, sigma))
return np.exp(random.gauss(mu, sigma))
def qlognormal(mu, sigma, q, name=None):
return round(lognormal(mu, sigma) / q) * q
......
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