Issue
I'm trying to use a KerasClassifier
wrapper in order to make my workflow
scikit-friendly. However, when I try to use it with the following function, it
gives an error; training the model using native Keras model fit()
works.
(this is Tensorflow 2.2.0, running in a conda environment)
def model_arch(n_features: int):
i = tf.keras.layers.Input(shape=(n_features,))
hidden_dense = tf.keras.layers.Dense(64)(i)
hidden_dense = tf.keras.layers.BatchNormalization()(hidden_dense)
hidden_dense = tf.keras.layers.Activation(tf.nn.tanh)(hidden_dense)
o = tf.keras.layers.Dense(1)(hidden_dense)
o = tf.keras.layers.BatchNormalization()(o)
o = tf.keras.layers.Activation("sigmoid")(o)
classifier = tf.keras.models.Model(inputs=i, outputs=o)
opt = tf.keras.optimizers.SGD(lr=1e-3, decay=1e-6, momentum=0.9, nesterov=True)
classifier.compile(
loss="binary_crossentropy",
optimizer=opt,
metrics=["accuracy"],
)
return classifier
The following works:
X = np.random.random((100,3))
y = np.random.random((100,)) # 'y' is a binary vector in reality
clf = model_arch(3)
clf.fit(X, y, epochs=10)
However, when I try to use KerasClassifier
wrapper, I get an error:
clf = KerasClassifier(model_arch(3), epochs=10)
clf.fit(X, y)
# ValueError: The first argument to `Layer.call` must always be passed.
Every example I have seen on the internet seems to do the same as I: define a
function that returns a compiled keras model, then pass it to the wrapper, and
fit it or use in a pipeline. The only difference I notice is that most (if not
all) examples use the Sequential
API instead of the functional API, but afaik
that should not be a problem, right?
Tensorflow documentation doesn't seem to give any example of what kind of function we should pass to the wrapper, but since every example uses one similar to mine, I think that's correct.
Can anyone shed some light? Thanks.
EDIT (after comments):
I import the KerasClassifier like this:
from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
Error log:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/adrian/miniconda3/envs/kaggle/lib/python3.8/site-packages/tensorflow/python/keras/wrappers/scikit_learn.py", line 223, in fit
return super(KerasClassifier, self).fit(x, y, **kwargs)
File "/home/adrian/miniconda3/envs/kaggle/lib/python3.8/site-packages/tensorflow/python/keras/wrappers/scikit_learn.py", line 154, in fit
self.model = self.build_fn(
File "/home/adrian/miniconda3/envs/kaggle/lib/python3.8/site-packages/tensorflow/python/keras/engine/base_layer.py", line 799, in __call__
raise ValueError(
ValueError: The first argument to `Layer.call` must always be passed.
Solution
KerasClassifer
expects a build function, not the model instance itself, which upon its call returns a compiled instance of a Keras model. Therefore, to resolve this with minimal changes, you must wrap it inside a function:
clf = KerasClassifier(lambda: model_arch(3), epochs=10)
Alternatively, a much better way is to pass the model's argument as a keyword argument:
clf = KerasClassifier(model_arch, n_features=3, epochs=10)
Answered By - today
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.