𝛑
𝛑
Posts List
  1. Create Keras Model
  2. Pipeline
  3. GridSearch CV

Plugging Keras Models into Sklearn's Pipeline

This post was written in 2018. Tools and versions mentioned may be outdated, though the underlying ideas still hold.

Create Keras Model

from keras.wrappers.scikit_learn import KerasClassifier
def create_model(kernel_initializer='he_normal', optimizer='adam', activation='relu', dropout=0.5):
inputs = Input(shape=(sequence_length,), dtype='int32')
embedding = Embedding(input_dim=vocabulary_size,
output_dim=embedding_dim, input_length=sequence_length)(inputs)
reshape = Reshape((sequence_length, embedding_dim, 1))(embedding)

conv_0 = Conv2D(num_filters, kernel_size=(
filter_sizes[0], embedding_dim), padding='valid', kernel_initializer=kernel_initializer, activation=activation)(reshape)
conv_1 = Conv2D(num_filters, kernel_size=(
filter_sizes[1], embedding_dim), padding='valid', kernel_initializer=kernel_initializer, activation=activation)(reshape)
conv_2 = Conv2D(num_filters, kernel_size=(
filter_sizes[2], embedding_dim), padding='valid', kernel_initializer=kernel_initializer, activation=activation)(reshape)

maxpool_0 = MaxPool2D(pool_size=(
sequence_length - filter_sizes[0] + 1, 1), strides=(1, 1), padding='valid')(conv_0)
maxpool_1 = MaxPool2D(pool_size=(
sequence_length - filter_sizes[1] + 1, 1), strides=(1, 1), padding='valid')(conv_1)
maxpool_2 = MaxPool2D(pool_size=(
sequence_length - filter_sizes[2] + 1, 1), strides=(1, 1), padding='valid')(conv_2)

concatenated_tensor = Concatenate(axis=1)(
[maxpool_0, maxpool_1, maxpool_2])
flatten = Flatten()(concatenated_tensor)
dropout = Dropout(dropout)(flatten)
output = Dense(units=2, activation='softmax')(dropout)

# this creates a model that includes
model = Model(inputs=inputs, outputs=output)

model.compile(optimizer=optimizer, loss='binary_crossentropy',
metrics=['accuracy'])
return model

keras_clf = KerasClassifier(build_fn=create_model)

If you’re building a regression model instead, just swap in from keras.wrappers.scikit_learn import KerasRegressor. The idea is simple — wrap your existing model definition as a function, then pass it into KerasRegressor or KerasClassifier via build_fn.

Pipeline

from sklearn.pipeline import Pipeline
pipline = Pipeline([
# ('preprocess_step1',None),
# ('preprocess_step2',None),
# ('preprocess_step3',None)
('clf', keras_clf)
])

Pipeline is sklearn’s way of chaining an entire training workflow together: preprocessing, feature selection, and model training as sequential steps. Add each step in order.

GridSearch CV

from sklearn.model_selection import GridSearchCV
param_grid = {
'clf__optimizer': ['rmsprop', 'adam', 'adagrad'],
'clf__epochs': [200, 300, 400, 700, 1000],
'clf__batch_size': [32, 64, 128],
'clf__dropout': [0.1, 0.2, 0.3, 0.4, 0.5],
'clf__kernel_initializer': ['he_normal', 'glorot_uniform', 'normal', 'uniform']
}
grid = GridSearchCV(pipline, cv=3, param_grid=param_grid)
grid.fit(X_train, y_train)

GridSearchCV is automated hyperparameter tuning through brute-force search. It works well on small datasets, but becomes expensive as the data grows.

print(" Best {} using {}".format(grid.best_score_, grid.best_params_))
means = grid.cv_results_['mean_test_score']
stds = grid.cv_results_['std_test_score']
params = grid.cv_results_['params']

for mean, stdev, param in zip(means, stds, params):
print('{} {} with {}'.format(mean, stdev, param))

After training, grab grid.best_score_ and grid.best_params_ to get the best accuracy and the params that got you there. Full code is here.

Brute-force search can help, but it is often more efficient to review hyperparameters used in relevant papers, choose a reasonable subset, and compare those values. There is no need to rediscover a range that others have already established.