使用 keras 的 sk-learn API 时出错
Posted
技术标签:
【中文标题】使用 keras 的 sk-learn API 时出错【英文标题】:error when using keras' sk-learn API 【发布时间】:2017-01-20 21:43:57 【问题描述】:这几天在学习 keras,在使用 scikit-learn API 时遇到了错误。这里有一些可能有用的东西:
环境:
python:3.5.2
keras:1.0.5
scikit-learn:0.17.1
代码
import pandas as pd
from keras.layers import Input, Dense
from keras.models import Model
from keras.models import Sequential
from keras.wrappers.scikit_learn import KerasRegressor
from sklearn.cross_validation import train_test_split
from sklearn.cross_validation import cross_val_score
from sqlalchemy import create_engine
from sklearn.cross_validation import KFold
def read_db():
"get prepared data from 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 data
def nn_model():
"create a 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 model
data = 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) #something wrong here!
错误
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 打包的情况下运行良好,但我想在此之后使用 sk_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):
'''Construct a new model with build_fn and fit the model according
to the given training data.
# Arguments
X : array-like, shape `(n_samples, n_features)`
Training samples where n_samples in the number of samples
and n_features is the number of features.
y : array-like, shape `(n_samples,)` or `(n_samples, n_outputs)`
True labels for X.
kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.fit`
# Returns
history : object
details about the training history at each 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 是什么意思以及如何解决这个错误? 谢谢!
【问题讨论】:
【参考方案1】:xiao,我遇到了同样的问题!希望这会有所帮助:
背景和问题
documentation for Keras 指出,在为 scikit-learn 实现 Wrappers 时,有两个参数。第一个是构建函数,它是一个“可调用函数或类实例”。具体来说,它指出:
build_fn
应该构造、编译并返回一个 Keras 模型,然后该模型将用于拟合/预测。可以将以下三个值之一传递给 build_fn:一个函数 实现call方法的类的实例 无。这意味着您实现了一个继承自
KerasClassifier
或KerasRegressor
的类。当前类的 call 方法将被视为默认的 build_fn。
在您的代码中,您创建模型,然后在创建 KerasRegressor
包装器时将模型作为参数 build_fn
的值传递:
model = nn_model()
model = KerasRegressor(build_fn=model, nb_epoch=2)
这就是问题所在。不是将 nn_model
function 作为 build_fn
传递,而是传递 Keras Sequential
模型的实际实例。为此,在调用fit()
时,找不到call
方法,因为在你返回的类中没有实现。
建议的解决方案
我所做的就是将函数作为build_fn
传递,而不是实际模型:
data = read_db()
y = data.pop('PRICE').as_matrix()
x = data.as_matrix()
# model = nn_model() # Don't do this!
# set build_fn equal to the nn_model function
model = KerasRegressor(build_fn=nn_model, nb_epoch=2) # note that you do not call the function!
model.fit(x,y) # fixed!
这不是唯一的解决方案(您可以将build_fn
设置为适当地实现call
方法的类),而是对我有用的解决方案。希望对你有帮助!
【讨论】:
@matsuninja 你知道如何将参数传递给函数吗?我想做一个更通用的nn_model
函数,具有不同的层大小和这样的参数...
@Luis,在上面的示例中,请记住 nn_model 函数内部的代码定义了模型参数(包括层大小等)。我提出的解决方案(同样,只是少数替代方案之一)将函数 nn_model 作为 build_fn 值传递。为了设置模型参数,修改 nn_model 函数中的代码;这实际上是 xiao 在定义 nn_model 函数时所做的。希望对您有所帮助。
@matsuninja 我通过将全局变量设置为节点数来解决它。我猜不可能使用 nn_model
函数在这种方法中需要参数...【参考方案2】:
用户定义的关键字参数传递给__init__()
,也就是说,所有给__init__()
的关键字参数将直接传递给model_build_fn
。例如,调用KerasClassifier(myparam=10)
将导致model_build_fn(my_param=10)
这是一个例子:
class MyMultiOutputKerasRegressor(KerasRegressor):
# initializing
def __init__(self, **kwargs):
KerasRegressor.__init__(self, **kwargs)
# simpler fit method
def fit(self, X, y, **kwargs):
KerasRegressor.fit(self, X, [y]*3, **kwargs)
(...)
def get_quantile_reg_rpf_nn(layers_shape=[50,100,200,100,50], inDim= 4, outDim=1, act='relu'):
# do model stuff...
(...) 初始化 Keras 回归器:
base_model = MyMultiOutputKerasRegressor(build_fn=get_quantile_reg_rpf_nn,
layers_shape=[50,100,200,100,50], inDim= 4,
outDim=1, act='relu', epochs=numEpochs,
batch_size=batch_size, verbose=0)
【讨论】:
以上是关于使用 keras 的 sk-learn API 时出错的主要内容,如果未能解决你的问题,请参考以下文章
使用 Tensorflow 2 的 Keras 功能 API 时传递 `training=true`
当我在 Tensorflow 上使用 Keras API 连接两个模型时,模型的输入张量必须来自 `tf.layers.Input`