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

Commit b0aef47

Browse files
committed
Merge pull request #62 from aigamedev/digits
Converting input array shapes internally when they don't match
2 parents 8341b72 + b414d3c commit b0aef47

File tree

6 files changed

+115
-24
lines changed

6 files changed

+115
-24
lines changed

examples/plot_digits.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import (absolute_import, unicode_literals, print_function)
3+
4+
from sklearn import datasets, cross_validation
5+
from sknn.mlp import Classifier, Layer, Convolution
6+
7+
8+
# Load the data and split it into subsets for training and testing.
9+
digits = datasets.load_digits()
10+
X = digits.images
11+
y = digits.target
12+
13+
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X, y, test_size=0.2)
14+
15+
16+
# Create a neural network that uses convolution to scan the input images.
17+
nn = Classifier(
18+
layers=[
19+
Convolution('Rectifier', channels=12, kernel_shape=(3, 3), border_mode='full'),
20+
Convolution('Rectifier', channels=8, kernel_shape=(3, 3), border_mode='valid'),
21+
Layer('Rectifier', units=64),
22+
Layer('Softmax')],
23+
learning_rate=0.002,
24+
valid_size=0.2,
25+
n_stable=10,
26+
verbose=True)
27+
28+
nn.fit(X_train, y_train)
29+
30+
31+
# Determine how well it does on training data and unseen test data.
32+
print('\nTRAIN SCORE', nn.score(X_train, y_train))
33+
print('TEST SCORE', nn.score(X_test, y_test))
34+
35+
y_pred = nn.predict(X_test)
36+
37+
38+
# Show some training images and some test images too.
39+
import pylab
40+
41+
for index, (image, label) in enumerate(zip(digits.images, digits.target)[:6]):
42+
pylab.subplot(2, 6, index + 1)
43+
pylab.axis('off')
44+
pylab.imshow(image, cmap=pylab.cm.gray_r, interpolation='nearest')
45+
pylab.title('Training: %i' % label)
46+
47+
for index, (image, prediction) in enumerate(zip(X_test, y_pred)[:6]):
48+
pylab.subplot(2, 6, index + 7)
49+
pylab.axis('off')
50+
pylab.imshow(image.reshape((8,8)), cmap=pylab.cm.gray_r, interpolation='nearest')
51+
pylab.title('Predicts: %i' % prediction)
52+
53+
pylab.show()

examples/plot_mlp.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import (absolute_import, unicode_literals, print_function)
3+
14
"""\
25
Visualizing Parameters in a Modern Neural Network
36
=================================================

sknn/mlp.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ def _array_to_mlp(self, array, nn):
330330
assert layer.get_biases().shape == biases.shape
331331
layer.set_biases(biases)
332332

333+
def _reshape(self, X, y=None):
334+
if y is not None and y.ndim == 1:
335+
y = y.reshape((y.shape[0], 1))
336+
if self.is_convolution and X.ndim == 3:
337+
X = X.reshape((X.shape[0], X.shape[1], X.shape[2], 1))
338+
if not self.is_convolution and X.ndim > 2:
339+
X = X.reshape((X.shape[0], numpy.product(X.shape[1:])))
340+
return X, y
341+
333342
def _fit(self, *data, **extra):
334343
try:
335344
return self._train(*data, **extra)
@@ -346,22 +355,19 @@ def _fit(self, *data, **extra):
346355
def _train(self, X, y, test=None):
347356
assert X.shape[0] == y.shape[0],\
348357
"Expecting same number of input and output samples."
349-
num_samples, data_size = X.shape[0], X.size+y.size
350-
351-
if y.ndim == 1:
352-
y = y.reshape((y.shape[0], 1))
358+
data_shape, data_size = X.shape, X.size+y.size
359+
X, y = self._reshape(X, y)
353360

354361
if not self.is_initialized:
355362
self._initialize(X, y)
356363
X, y = self.train_set
357364
else:
358365
self.train_set = X, y
366+
assert self.ds is not None, "Training after serialization is not (yet) supported."
359367

360-
if self.is_convolution:
361-
X = self.ds.view_converter.topo_view_to_design_mat(X)
362-
self.ds.X, self.ds.y = X, y
363-
364-
log.info("Training on dataset of {:,} samples with {:,} total size.".format(num_samples, data_size))
368+
log.info("Training on dataset of {:,} samples with {:,} total size.".format(data_shape[0], data_size))
369+
if data_shape[1:] != X.shape[1:]:
370+
log.warning(" - Reshaping input array from {} to {}.".format(data_shape, X.shape))
365371
if self.valid_set:
366372
X_v, _ = self.valid_set
367373
log.debug(" - Train: {: <9,} Valid: {: <4,}".format(X.shape[0], X_v.shape[0]))
@@ -370,6 +376,10 @@ def _train(self, X, y, test=None):
370376
if self.n_stable:
371377
log.debug(" - Early termination after {} stable iterations.".format(self.n_stable))
372378

379+
if self.is_convolution:
380+
X = self.ds.view_converter.topo_view_to_design_mat(X)
381+
self.ds.X, self.ds.y = X, y
382+
373383
if self.verbose:
374384
log.debug("\nEpoch Validation Error Time"
375385
"\n---------------------------------")
@@ -382,15 +392,14 @@ def _predict(self, X):
382392
assert self.layers[-1].units is not None,\
383393
"You must specify the number of units to predict without fitting."
384394
log.warning("Computing estimates with an untrained network.")
385-
386395
self._create_specs(X)
387396
self._create_mlp()
388397

398+
X, _ = self._reshape(X)
389399
if X.dtype != numpy.float32:
390400
X = X.astype(numpy.float32)
391401
if not isinstance(X, numpy.ndarray):
392402
X = X.toarray()
393-
394403
return self.f(X)
395404

396405
def get_params(self, deep=True):

sknn/nn.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
class ansi:
2929
BOLD = '\033[1;97m'
3030
WHITE = '\033[0;97m'
31+
YELLOW = '\033[0;33m'
3132
RED = '\033[0;31m'
3233
GREEN = '\033[0;32m'
3334
BLUE = '\033[0;94m'
@@ -457,6 +458,7 @@ def _create_logger(self):
457458
hnd.setFormatter(fmt)
458459
hnd.setLevel(lvl)
459460
log.addHandler(hnd)
461+
log.setLevel(lvl)
460462

461463
def _create_matrix_input(self, X, y=None):
462464
if self.is_convolution:
@@ -479,7 +481,7 @@ def _create_trainer(self, dataset, cost):
479481
if dataset is not None:
480482
termination_criterion = tc.MonitorBased(
481483
channel_name='objective',
482-
N=self.n_stable,
484+
N=self.n_stable-1,
483485
prop_decrease=self.f_stable)
484486
else:
485487
termination_criterion = None

sknn/tests/test_conv.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,22 @@
99

1010
class TestConvolution(unittest.TestCase):
1111

12-
def _run(self, nn):
13-
a_in, a_out = numpy.zeros((8,32,16,1)), numpy.zeros((8,4))
12+
def _run(self, nn, a_in=None):
13+
if a_in is None:
14+
a_in = numpy.zeros((8,32,16,1))
15+
a_out = numpy.zeros((8,4))
1416
nn.fit(a_in, a_out)
1517
a_test = nn.predict(a_in)
1618
assert_equal(type(a_out), type(a_in))
1719

20+
def test_MissingLastDim(self):
21+
self._run(MLPR(
22+
layers=[
23+
C("Tanh", channels=4, kernel_shape=(3,3)),
24+
L("Linear")],
25+
n_iter=1),
26+
a_in=numpy.zeros((8,32,16)))
27+
1828
def test_SquareKernel(self):
1929
self._run(MLPR(
2030
layers=[
@@ -39,7 +49,7 @@ def test_VerticalKernel(self):
3949
def test_VerticalVerbose(self):
4050
self._run(MLPR(
4151
layers=[
42-
C("Rectifier", channels=4, kernel_shape=(16,1)),
52+
C("Sigmoid", channels=4, kernel_shape=(16,1)),
4353
L("Linear")],
4454
n_iter=1, verbose=1, valid_size=0.1))
4555

@@ -53,7 +63,7 @@ def test_HorizontalKernel(self):
5363
def test_ValidationSet(self):
5464
self._run(MLPR(
5565
layers=[
56-
C("Rectifier", channels=4, kernel_shape=(3,3)),
66+
C("Tanh", channels=4, kernel_shape=(3,3)),
5767
L("Linear")],
5868
n_iter=1,
5969
valid_size=0.5))
@@ -62,8 +72,8 @@ def test_MultipleLayers(self):
6272
self._run(MLPR(
6373
layers=[
6474
C("Rectifier", channels=6, kernel_shape=(3,3)),
65-
C("Rectifier", channels=4, kernel_shape=(5,5)),
66-
C("Rectifier", channels=8, kernel_shape=(3,3)),
75+
C("Sigmoid", channels=4, kernel_shape=(5,5)),
76+
C("Tanh", channels=8, kernel_shape=(3,3)),
6777
L("Linear")],
6878
n_iter=1))
6979

@@ -187,8 +197,11 @@ def test_UnknownConv(self):
187197

188198
class TestConvolutionRGB(TestConvolution):
189199

190-
def _run(self, nn):
191-
a_in, a_out = numpy.zeros((8,32,16,3)), numpy.zeros((8,4))
200+
def _run(self, nn, a_in=None):
201+
if a_in is None:
202+
a_in = numpy.zeros((8,32,16,1))
203+
a_out = numpy.zeros((8,4))
204+
192205
nn.fit(a_in, a_out)
193206
a_test = nn.predict(a_in)
194207
assert_equal(type(a_out), type(a_in))

sknn/tests/test_linear.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ def test_FitAutoInitialize(self):
3232
self.nn.fit(a_in, a_out)
3333
assert_true(self.nn.is_initialized)
3434

35+
def test_ResizeInputFrom4D(self):
36+
a_in, a_out = numpy.zeros((8,4,4,1)), numpy.zeros((8,4))
37+
self.nn.fit(a_in, a_out)
38+
assert_true(self.nn.is_initialized)
39+
40+
def test_ResizeInputFrom3D(self):
41+
a_in, a_out = numpy.zeros((8,4,4)), numpy.zeros((8,4))
42+
self.nn.fit(a_in, a_out)
43+
assert_true(self.nn.is_initialized)
44+
3545
def test_FitWrongSize(self):
3646
a_in, a_out = numpy.zeros((7,16)), numpy.zeros((9,4))
3747
assert_raises(AssertionError, self.nn.fit, a_in, a_out)
@@ -87,10 +97,11 @@ def test_TypeOfWeightsArray(self):
8797
assert_equal(type(w), numpy.ndarray)
8898
assert_equal(type(b), numpy.ndarray)
8999

90-
def test_FitAutoInitialize(self):
91-
# Override base class test, you currently can't re-train a network that
92-
# was serialized and deserialized.
93-
pass
100+
# Override base class test, you currently can't re-train a network that
101+
# was serialized and deserialized.
102+
def test_FitAutoInitialize(self): pass
103+
def test_ResizeInputFrom4D(self): pass
104+
def test_ResizeInputFrom3D(self): pass
94105

95106
def test_PredictNoOutputUnitsAssertion(self):
96107
# Override base class test, this is not initialized but it

0 commit comments

Comments
 (0)