Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grid Search for Keras with multiple inputs

I am trying to do a grid search over my hyperparameters for tuning a deep learning architecture. I have multiple input options to the model and I am trying to use sklearn's grid search api. The problem is, grid search api only takes single array as input and the code fails while it checks for the data size dimension.(My input dimension is 5*number of data points while according to sklearn api, it should be number of data points*feature dimension). My code looks something like this:

from keras.layers import Concatenate, Reshape, Input, Embedding, Dense, Dropout
from keras.models import Model
from keras.wrappers.scikit_learn import KerasClassifier

def model(hyparameters):
    a = Input(shape=(1,))
    b = Input(shape=(1,))
    c = Input(shape=(1,))
    d = Input(shape=(1,))
    e = Input(shape=(1,))

    //Some operations and I get a single output -->out
    model = Model([a, b, c, d, e], out)
    model.compile(optimizer='rmsprop',
                               loss='categorical_crossentropy',
                               metrics=['accuracy'])
    return model

k_model = KerasClassifier(build_fn=model, epochs=150, batch_size=512, verbose=2)
# define the grid search parameters
param_grid = hyperparameter options dict
grid = GridSearchCV(estimator=k_model, param_grid=param_grid, n_jobs=-1)
grid_result = grid.fit([a_input, b_input, c_input, d_input, e_input], encoded_outputs)
like image 401
Biswadip Mandal Avatar asked Jun 30 '19 12:06

Biswadip Mandal


1 Answers

this is workaround to use GridSearch and Keras model with multiple inputs. the trick consists in merge all the inputs in a single array. I create a dummy model that receives a SINGLE input and then split it into the desired parts using Lambda layers. the procedure can be easily modified according to your own data structure

def createMod(optimizer='Adam'):
    
    combi_input = Input((3,)) # (None, 3)
    a_input = Lambda(lambda x: tf.expand_dims(x[:,0],-1))(combi_input) # (None, 1) 
    b_input = Lambda(lambda x: tf.expand_dims(x[:,1],-1))(combi_input) # (None, 1)
    c_input = Lambda(lambda x: tf.expand_dims(x[:,2],-1))(combi_input) # (None, 1)
    
    ## do something
    c = Concatenate()([a_input, b_input, c_input])
    x = Dense(32)(c)

    out = Dense(1,activation='sigmoid')(x)
    model = Model(combi_input, out)

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

    return model


## recreate multiple inputs
n_sample = 1000
a_input, b_input, c_input = [np.random.uniform(0,1, n_sample) for _ in range(3)]
y = np.random.randint(0,2, n_sample)

## merge inputs
combi_input = np.stack([a_input, b_input, c_input], axis=-1)


model = tf.keras.wrappers.scikit_learn.KerasClassifier(build_fn=createMod, verbose=0)
batch_size = [10, 20]
epochs = [10, 5]
optimizer = ['adam','SGD']
param_grid = dict(batch_size=batch_size, epochs=epochs)
grid = GridSearchCV(estimator=model, param_grid=param_grid, n_jobs=-1, cv=3)
grid_result = grid.fit(combi_input, y)

Another simple and valuable solution

like image 54
Marco Cerliani Avatar answered Sep 27 '22 19:09

Marco Cerliani