我最近在学习 Keras,使用 scikit-learn API 时遇到了一个错误。以下是一些可能有用的信息:
环境:
python:3.5.2 keras:1.0.5 scikit-learn:0.17.1
代码
import pandas as pdfrom keras.layers import Input, Densefrom keras.models import Modelfrom keras.models import Sequentialfrom keras.wrappers.scikit_learn import KerasRegressorfrom sklearn.cross_validation import train_test_splitfrom sklearn.cross_validation import cross_val_scorefrom sqlalchemy import create_enginefrom sklearn.cross_validation import KFolddef read_db(): "从 MySQL 获取准备好的数据。" con_str = "mysql+mysqldb://root:0000@localhost/nbse?charset=utf8" engine = create_engine(con_str) data = pd.read_sql_table('data_ml', engine) return datadef nn_model(): "创建模型。" model = Sequential() model.add(Dense(output_dim=100, input_dim=105, activation='softplus')) model.add(Dense(output_dim=1, input_dim=100, activation='softplus')) model.compile(loss='mean_squared_error', optimizer='adam') return modeldata = read_db()y = data.pop('PRICE').as_matrix()x = data.as_matrix()model = nn_model()model = KerasRegressor(build_fn=model, nb_epoch=2)model.fit(x,y) #这里出错了!
错误
Traceback (most recent call last): File "C:/Users/Administrator/PycharmProjects/forecast/gridsearch.py", line 43, in <module> model.fit(x,y) File "D:\Program Files\Python35\lib\site-packages\keras\wrappers\scikit_learn.py", line 135, in fit **self.filter_sk_params(self.build_fn.__call__))TypeError: __call__() missing 1 required positional argument: 'x'Process finished with exit code 1
模型在没有使用 KerasRegressor 封装时运行良好,但我希望在之后使用 scikit-learn 的 GridSearch,所以我来这里寻求帮助。我尝试过但仍然没有头绪。
可能有帮助的信息:
keras.warappers.scikit_learn.py class BaseWrapper(object): def __init__(self, build_fn=None, **sk_params): self.build_fn = build_fn self.sk_params = sk_params self.check_params(sk_params) def fit(self, X, y, **kwargs): '''根据给定的训练数据构建并拟合新模型。 # 参数 X : array-like, shape `(n_samples, n_features)` 训练样本,其中 n_samples 为样本数,n_features 为特征数。 y : array-like, shape `(n_samples,)` or `(n_samples, n_outputs)` X 的真实标签。 kwargs: 字典参数 合法的参数是 `Sequential.fit` 的参数。 # 返回 history : object 关于每个 epoch 的训练历史的详细信息。 ''' if self.build_fn is None: self.model = self.__call__(**self.filter_sk_params(self.__call__)) elif not isinstance(self.build_fn, types.FunctionType): self.model = self.build_fn( **self.filter_sk_params(self.build_fn.__call__)) else: self.model = self.build_fn(**self.filter_sk_params(self.build_fn)) loss_name = self.model.loss if hasattr(loss_name, '__name__'): loss_name = loss_name.__name__ if loss_name == 'categorical_crossentropy' and len(y.shape) != 2: y = to_categorical(y) fit_args = copy.deepcopy(self.filter_sk_params(Sequential.fit)) fit_args.update(kwargs) history = self.model.fit(X, y, **fit_args) return history
错误发生在这行:
self.model = self.build_fn( **self.filter_sk_params(self.build_fn.__call__))
这里的 self.build_fn 是 keras.models.Sequential
models.py class Sequential(Model): def call(self, x, mask=None): if not self.built: self.build() return self.model.call(x, mask)
那么,这个 x 是什么意思,如何修复这个错误?
谢谢!
回答:
xiao,我也遇到了同样的问题!希望这对你有帮助:
背景与问题
Keras 的文档指出,在实现 scikit-learn 的包装器时,有两个参数。第一个是构建函数,它是一个“可调用的函数或类实例”。具体来说,它指出:
build_fn
应该构建、编译并返回一个 Keras 模型,该模型随后将用于拟合/预测。可以传递给 build_fn 的三种值之一是:
- 一个函数
- 实现 call 方法的类的实例
- None。这意味着你实现了一个从
KerasClassifier
或KerasRegressor
继承的类。当前类的 call 方法将被视为默认的 build_fn。
在你的代码中,你创建了模型,然后在创建 KerasRegressor
包装器时将模型作为参数 build_fn
的值传递:
model = nn_model()model = KerasRegressor(build_fn=model, nb_epoch=2)
问题就出在这里。你没有将 nn_model
函数 作为 build_fn
传递,而是传递了一个实际的 Keras Sequential
模型的实例。因此,当调用 fit()
时,它找不到 call
方法,因为你返回的类中没有实现它。
提议的解决方案
我为了使事情正常工作,是将函数作为 build_fn
传递,而不是一个实际的模型:
data = read_db()y = data.pop('PRICE').as_matrix()x = data.as_matrix()# model = nn_model() # 不要这样做!# 将 build_fn 设置为 nn_model 函数model = KerasRegressor(build_fn=nn_model, nb_epoch=2) # 注意你不调用该函数!model.fit(x,y) # 修复了!
这不是唯一的解决方案(你可以将 build_fn
设置为一个适当实现 call
方法的类),但这是对我有效的方法。希望它能帮到你!