我试图使用KerasClassifier
包装器来使我的工作流程与scikit兼容。然而,当我尝试使用以下函数时,它会报错;使用原生Keras模型的fit()
方法训练模型是可以的。(这是Tensorflow 2.2.0,在conda环境中运行)
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
以下代码可以正常工作:
X = np.random.random((100,3))y = np.random.random((100,)) # 'y'在实际中是一个二进制向量clf = model_arch(3)clf.fit(X, y, epochs=10)
然而,当我尝试使用KerasClassifier
包装器时,会出现错误:
clf = KerasClassifier(model_arch(3), epochs=10)clf.fit(X, y)# ValueError: The first argument to `Layer.call` must always be passed.
我在网上看到的所有例子似乎都和我做的一样:定义一个返回编译后的Keras模型的函数,然后将其传递给包装器,并进行拟合或在管道中使用。我注意到唯一的区别是,大多数(如果不是全部的话)例子使用的是Sequential
API而不是函数式API,但据我所知,这不应该是问题,对吗?
Tensorflow文档似乎没有给出我们应该传递给包装器的函数类型示例,但由于每个示例都使用类似于我的函数,我认为这是正确的。
谁能提供一些见解?谢谢。
编辑(评论后):
我这样导入KerasClassifier:
from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
错误日志:
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.
回答:
KerasClassifer
期望一个构建函数,而不是模型实例本身,该函数在调用时返回一个编译后的Keras模型实例。因此,要以最小的更改解决这个问题,您必须将其包装在一个函数中:
clf = KerasClassifier(lambda: model_arch(3), epochs=10)
或者,更好的方法是将模型的参数作为关键字参数传递:
clf = KerasClassifier(model_arch, n_features=3, epochs=10)