Skip to content

Commit 66c8d7b

Browse files
committed
2 parents 9f92999 + 24f9626 commit 66c8d7b

File tree

3 files changed

+103
-1
lines changed

3 files changed

+103
-1
lines changed

examples/mnist_sklearn_wrapper.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'''Example of how to use sklearn wrapper
2+
3+
Builds simple CNN models on MNIST and uses sklearn's GridSearchCV to find best model
4+
'''
5+
6+
from __future__ import print_function
7+
import numpy as np
8+
np.random.seed(1337) # for reproducibility
9+
10+
from keras.datasets import mnist
11+
from keras.models import Sequential
12+
from keras.layers.core import Dense, Dropout, Activation, Flatten
13+
from keras.layers.convolutional import Convolution2D, MaxPooling2D
14+
from keras.utils import np_utils
15+
from keras.wrappers.scikit_learn import KerasClassifier
16+
from sklearn.grid_search import GridSearchCV
17+
18+
19+
nb_classes = 10
20+
21+
# input image dimensions
22+
img_rows, img_cols = 28, 28
23+
24+
# load training data and do basic data normalization
25+
(X_train, y_train), (X_test, y_test) = mnist.load_data()
26+
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
27+
X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
28+
X_train = X_train.astype('float32')
29+
X_test = X_test.astype('float32')
30+
X_train /= 255
31+
X_test /= 255
32+
33+
# convert class vectors to binary class matrices
34+
y_train = np_utils.to_categorical(y_train, nb_classes)
35+
y_test = np_utils.to_categorical(y_test, nb_classes)
36+
37+
def make_model(dense_layer_sizes, nb_filters, nb_conv, nb_pool):
38+
'''Creates model comprised of 2 convolutional layers followed by dense layers
39+
40+
dense_layer_sizes: List of layer sizes. This list has one number for each layer
41+
nb_filters: Number of convolutional filters in each convolutional layer
42+
nb_conv: Convolutional kernel size
43+
nb_pool: Size of pooling area for max pooling
44+
'''
45+
46+
model = Sequential()
47+
48+
model.add(Convolution2D(nb_filters, nb_conv, nb_conv,
49+
border_mode='valid',
50+
input_shape=(1, img_rows, img_cols)))
51+
model.add(Activation('relu'))
52+
model.add(Convolution2D(nb_filters, nb_conv, nb_conv))
53+
model.add(Activation('relu'))
54+
model.add(MaxPooling2D(pool_size=(nb_pool, nb_pool)))
55+
model.add(Dropout(0.25))
56+
57+
model.add(Flatten())
58+
for layer_size in dense_layer_sizes:
59+
model.add(Dense(layer_size))
60+
model.add(Activation('relu'))
61+
model.add(Dropout(0.5))
62+
model.add(Dense(nb_classes))
63+
model.add(Activation('softmax'))
64+
65+
model.compile(loss='categorical_crossentropy',
66+
optimizer='adadelta',
67+
metrics=['accuracy'])
68+
69+
return model
70+
71+
dense_size_candidates = [[32], [64], [32, 32], [64, 64]]
72+
my_classifier = KerasClassifier(make_model, batch_size=32)
73+
validator = GridSearchCV(my_classifier,
74+
param_grid={'dense_layer_sizes': dense_size_candidates,
75+
# nb_epoch is avail for tuning even when not
76+
# an argument to model building function
77+
'nb_epoch': [3, 6],
78+
'nb_filters': [8],
79+
'nb_conv': [3],
80+
'nb_pool': [2]},
81+
scoring='log_loss',
82+
n_jobs=1)
83+
validator.fit(X_train, y_train)
84+
85+
print('The parameters of the best model are: ')
86+
print(validator.best_params_)
87+
88+
# validator.best_estimator_ returns sklearn-wrapped version of best model.
89+
# validator.best_estimator_.model returns the (unwrapped) keras model
90+
best_model = validator.best_estimator_.model
91+
metric_names = best_model.metrics_names
92+
metric_values = best_model.evaluate(X_test, y_test)
93+
for metric, value in zip(metric_names, metric_values):
94+
print(metric, ': ', value)

keras/engine/training.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ def standardize_input_data(data, names, shapes=None, check_batch_dim=True,
6666
': data should be a Numpy array, '
6767
'or list/dict of Numpy arrays. '
6868
'Found: ' + str(data)[:200] + '...')
69+
if len(names) != 1:
70+
# case: model expects multiple inputs but only received
71+
# a single Numpy array
72+
raise Exception('The model expects ' + str(len(names)) +
73+
' input arrays, but only received one array. '
74+
'Found: array with shape ' + str(data.shape))
6975
arrays = [data]
7076

7177
# make arrays at least 2D

keras/layers/wrappers.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ def build(self, input_shape):
9898
'an "input_shape" or "batch_input_shape" '
9999
'argument, including the time axis.')
100100
child_input_shape = (input_shape[0],) + input_shape[2:]
101-
self.layer.build(child_input_shape)
101+
if not self.layer.built:
102+
self.layer.build(child_input_shape)
103+
self.layer.built = True
102104
super(TimeDistributed, self).build()
103105

104106
def get_output_shape_for(self, input_shape):

0 commit comments

Comments
 (0)