Skip to content
This repository was archived by the owner on Jul 10, 2021. It is now read-only.

Commit deb38ff

Browse files
committed
Adding more tests for grid search and randomized search, using both classifiers and regressors. Removed prefix from output layers. Adding example to advanced section of documentation.
1 parent 8e4ab8d commit deb38ff

File tree

4 files changed

+78
-27
lines changed

4 files changed

+78
-27
lines changed

docs/guide_advanced.rst

+22-4
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,15 @@ Here's how to setup such a pipeline with a multi-layer perceptron as a classifie
4444
You can then use the pipeline as you would the neural network, or any other standard API from scikit-learn.
4545

4646

47-
4847
Grid Search
4948
-----------
5049

51-
In scikit-learn, you can use a ``GridSearchCV`` to optimize your neural network's parameters automatically, both the top-level parameters and the parameters within the layers. For example, assuming you have your MLP constructed as in the :ref:`Regression` example in the local variable called ``nn``, the layers are named automatically so you can refer to them as follows:
50+
In scikit-learn, you can use a ``GridSearchCV`` to optimize your neural network's hyper-parameters automatically, both the top-level parameters and the parameters within the layers. For example, assuming you have your MLP constructed as in the :ref:`Regression` example in the local variable called ``nn``, the layers are named automatically so you can refer to them as follows:
5251

5352
* ``hidden0``
5453
* ``hidden1``
5554
* ...
56-
* ``output2``
55+
* ``output``
5756

5857
Keep in mind you can manually specify the ``name`` of any ``Layer`` in the constructor if you don't want the automatically assigned name. Then, you can use sklearn's hierarchical parameters to perform a grid search over those nested parameters too:
5958

@@ -67,4 +66,23 @@ Keep in mind you can manually specify the ``name`` of any ``Layer`` in the const
6766
'hidden0__type': ["Rectifier", "Sigmoid", "Tanh"]})
6867
gs.fit(a_in, a_out)
6968
70-
This will search through the listed ``learning_rate`` values, the number of hidden units and the activation type for that layer too, and find the best combination of parameters.
69+
This will search through the listed ``learning_rate`` values, the number of hidden units and the activation type for that layer too, and find the best combination of parameters.
70+
71+
72+
Randomized Search
73+
-----------------
74+
75+
In the cases when you have large numbers of hyper-parameters that you want to try automatically to find a good combination, you can use a randomized search as follows:
76+
77+
.. code:: python
78+
79+
from scipy import stats
80+
from sklearn.grid_search import RandomizedSearchCV
81+
82+
rs = RandomizedSearchCV(nn, param_grid={
83+
learning_rate: stats.uniform(0.001, 0.05),
84+
'hidden0__units': stats.randint(4, 12),
85+
'hidden0__type': ["Rectifier", "Sigmoid", "Tanh"]})
86+
rs.fit(a_in, a_out)
87+
88+
This works for both :class:`sknn.mlp.Classifier` and :class:`sknn.mlp.Regressor`.

sknn/mlp.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@ class Layer(object):
4848
4949
name: str, optional
5050
You optionally can specify a name for this layer, and its parameters
51-
will then be accessible to `scikit-learn` via a nested sub-object. For example,
52-
if name is set to `hidden1`, then the parameter `hidden1__units` from the network
53-
is bound to this layer's `units` variable.
51+
will then be accessible to scikit-learn via a nested sub-object. For example,
52+
if name is set to ``layer1``, then the parameter ``layer1__units`` from the network
53+
is bound to this layer's ``units`` variable.
54+
55+
The name defaults to ``hiddenN`` where N is the integer index of that layer, and the
56+
final layer is always ``output`` without an index.
5457
5558
units: int
5659
The number of units (also known as neurons) in this layer. This applies to all
@@ -353,8 +356,7 @@ def __init__(
353356

354357
# Layer names are optional, if not specified then generate one.
355358
if layer.name is None:
356-
label = "hidden" if i < len(layers)-1 else "output"
357-
layer.name = "%s%i" % (label, i)
359+
layer.name = ("hidden%i" % i) if i < len(layers)-1 else "output"
358360

359361
# sklearn may pass layers in as additional named parameters, remove them.
360362
if layer.name in params:

sknn/tests/test_layers.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class TestNestedParameters(unittest.TestCase):
1010
def test_GetParamsIncludesLayers(self):
1111
nn = MLPR(layers=[L("Linear", units=123)])
1212
p = nn.get_params()
13-
assert_in('output0', p)
13+
assert_in('output', p)
1414

1515
def test_GetParamsMissingLayer(self):
1616
nn = MLPR(layers=[L("Linear", units=123)])
@@ -19,9 +19,9 @@ def test_GetParamsMissingLayer(self):
1919

2020
def test_SetParamsDoubleUnderscore(self):
2121
nn = MLPR(layers=[L("Linear", units=123)])
22-
nn.set_params(output0__units=456)
22+
nn.set_params(output__units=456)
2323
assert_equal(nn.layers[0].units, 456)
2424

2525
def test_SetParamsValueError(self):
2626
nn = MLPR(layers=[L("Linear")])
27-
assert_raises(ValueError, nn.set_params, output0__range=1.0)
27+
assert_raises(ValueError, nn.set_params, output__range=1.0)

sknn/tests/test_sklearn.py

+46-15
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,57 @@
22
from nose.tools import (assert_equal, assert_raises, assert_in, assert_not_in)
33

44
import numpy
5-
from sklearn.grid_search import GridSearchCV
5+
from scipy.stats import randint, uniform
6+
7+
from sklearn.grid_search import GridSearchCV, RandomizedSearchCV
68
from sklearn.cross_validation import cross_val_score
79

8-
from sknn.mlp import Regressor as MLPR
10+
from sknn.mlp import Regressor as MLPR, Classifier as MLPC
911
from sknn.mlp import Layer as L
1012

1113

12-
class TestGridSearch(unittest.TestCase):
13-
14-
def test_RegressorGlobalParams(self):
15-
a_in = numpy.random.uniform(0.0, 1.0, (64,16))
16-
a_out = numpy.zeros((64,1))
14+
class TestGridSearchRegressor(unittest.TestCase):
15+
16+
__estimator__ = MLPR
17+
18+
def setUp(self):
19+
self.a_in = numpy.random.uniform(0.0, 1.0, (64,16))
20+
self.a_out = numpy.zeros((64,1))
1721

22+
def test_GridGlobalParams(self):
1823
clf = GridSearchCV(
19-
MLPR(layers=[L("Linear")], n_iter=1),
24+
self.__estimator__(layers=[L("Linear")], n_iter=1),
2025
param_grid={'learning_rate': [0.01, 0.001]})
21-
clf.fit(a_in, a_out)
22-
23-
def test_RegressorLayerParams(self):
24-
a_in = numpy.random.uniform(0.0, 1.0, (64,16))
25-
a_out = numpy.zeros((64,1))
26+
clf.fit(self.a_in, self.a_out)
2627

28+
def test_GridLayerParams(self):
2729
clf = GridSearchCV(
28-
MLPR(layers=[L("Rectifier", units=12), L("Linear")], n_iter=1),
30+
self.__estimator__(layers=[L("Rectifier", units=12), L("Linear")], n_iter=1),
2931
param_grid={'hidden0__units': [4, 8, 12]})
30-
clf.fit(a_in, a_out)
32+
clf.fit(self.a_in, self.a_out)
33+
34+
def test_RandomGlobalParams(self):
35+
clf = RandomizedSearchCV(
36+
self.__estimator__(layers=[L("Softmax")], n_iter=1),
37+
param_distributions={'learning_rate': uniform(0.001, 0.01)},
38+
n_iter=2)
39+
clf.fit(self.a_in, self.a_out)
40+
41+
def test_RandomLayerParams(self):
42+
clf = RandomizedSearchCV(
43+
self.__estimator__(layers=[L("Softmax", units=12), L("Linear")], n_iter=1),
44+
param_distributions={'hidden0__units': randint(4, 12)},
45+
n_iter=2)
46+
clf.fit(self.a_in, self.a_out)
47+
48+
49+
class TestGridSearchClassifier(TestGridSearchRegressor):
50+
51+
__estimator__ = MLPC
52+
53+
def setUp(self):
54+
self.a_in = numpy.random.uniform(0.0, 1.0, (64,16))
55+
self.a_out = numpy.random.randint(0, 4, (64,))
3156

3257

3358
class TestCrossValidation(unittest.TestCase):
@@ -37,3 +62,9 @@ def test_Regressor(self):
3762
a_out = numpy.zeros((64,1))
3863

3964
cross_val_score(MLPR(layers=[L("Linear")], n_iter=1), a_in, a_out, cv=5)
65+
66+
def test_Classifier(self):
67+
a_in = numpy.random.uniform(0.0, 1.0, (64,16))
68+
a_out = numpy.random.randint(0, 4, (64,))
69+
70+
cross_val_score(MLPC(layers=[L("Linear")], n_iter=1), a_in, a_out, cv=5)

0 commit comments

Comments
 (0)