如何还原KerasClassfier?

时间:2019-01-27 10:31:56

标签: keras python-3.6

保存KerasClassifier模型https://github.com/keras-team/keras/blob/master/keras/wrappers/scikit_learn.py的权重和json配置后,我需要恢复它并验证结果。 但是,如果我恢复重量和模型,那么我就有一个序列对象,如何从中重建原始KerasClassifier?

2 个答案:

答案 0 :(得分:1)

如果您有两个文件model.json和weights.h5,则可以轻松加载模型并根据需要使用它。

from keras.models import model_from_json

json_file = open('model.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
loaded_model.load_weights("model.h5")

# evaluate loaded model on test data
loaded_model.compile(loss='binary_crossentropy', optimizer='rmsprop', metrics=['accuracy'])
score = loaded_model.evaluate(X, Y, verbose=0)
print("%s: %.2f%%" % (loaded_model.metrics_names[1], score[1]*100))

答案 1 :(得分:1)

我不确定我是否正确理解您,但请提出以下解决方案。 KerasClassifier继承自具有以下BaseWrapper签名的__init__

def __init__(self, build_fn=None, **sk_params):
    self.build_fn = build_fn
    self.sk_params = sk_params
    self.check_params(sk_params)

好的,什么是build_fn和sk_params?

  

build_fn应该构造,编译并返回Keras模型,该模型       然后将用于拟合/预测。以下之一       三个值可以传递给build_fn
      1.功能
      2.实现__call__方法的类的实例
      3.没有。这意味着您要实现一个继承自任一类的类
      KerasClassifierKerasRegressor。的__call__方法       当前类将被视为默认的build_fn
      ...
      sk_params同时使用模型参数和拟合参数。法律模式       参数是build_fn的参数。请注意,就像其他所有       scikit-learn build_fn中的估算器应为       它的参数,以便您可以创建估算器而无需传递任何       值sk_params
      ...
      省略了一些

您可以在thisthis链接上阅读完整的评论。
由于build_fn期望函数返回已编译的keras模型(无论是Sequential还是Model),您可以将其作为值函数传递,该函数返回已加载的模型。

编辑,您还应该使用一些参数调用fit,以使用该方法恢复模型。

将模型加载为build_fn

fit方法将调用build_fn,因此,每次尝试训练此类分类器时,都会加载然后适合已加载的clssifier。 例如:

from keras.models import load_model  # or another method - but this one is simpliest
from keras.wrappers.scikit_learn import KerasClassifier

def load_model(*args, **kwargs):
    """probably this function expects sk_params, so you can use it in theory"""
    path="my_model.hd5"
    model = load_model(path)
    return model

keras_classifier = KerasClassifier(load_model, sk_params)  # use your sk_params
keras_classifier.fit(X_tr, y_tr)  # I use slice (1, input_shape) to train

-它会起作用,因为已加载的模型几乎已经过训练和编译。但是,即使您以1的大小和1个时期的批处理来调用它,它也会给您的模型带来很小的变化。

通过build_fn闭包加载

此外,您可以先加载模型(如果您希望轻松提供路径并且硬编码路径不可接受),然后返回“ build_fn-可接受” 的函数:

def load_model_return_build_fn(path):
    model = load_model(path)
    def build_fn(*args, **kwars):
         """probably this function expects sk_params"""
         return model  # defined above
    return build_fn

build_fn = load_model_return_build_fn("model.hd5")

keras_classifier = KerasClassifier(build_fn, sk_params)  # use your sk_params
keras_classifier.fit(X_tr, y_tr)  # I use slice (1, input_shape) to train

为模型分配属性

如果您计划仅加载并使用预训练的模型,则可以使用any加载它,将其分配给model属性,然后不要调用fit

build_fn = load_model_return_build_fn("model.hd5")
# or the function which realy builds and fits a model
keras_classifier = KerasClassifier(build_fn, sk_params)  # use your sk_params
keras_classifier.model = model  # assign model here, don't call fit

-在这种情况下,您将模型明确设置为其属性。请注意,build_fn应该是一个正确的build_fn-否则它不会通过self.check_params(sk_params)测试。

从KerasClassifier继承(不是我想象的那么容易)
毕竟,我知道最好的解决方案是从KerasClassifier继承并添加load和/或from_file方法。

class KerasClassifierLoadable(KerasClassifier):
    @classmethod
    def from_file(cls, path, *args, **kwargs):
        keras_classifier = cls(*args, **kwargs)
        keras_classifier.model = load_model(path)
        outp_shape = keras_classifier.model.layers[-1].output_shape[-1]
        if outp_shape > 1:
            keras_classifier.classes_ = np.arange(outp_shape, dtype='int32')
        else:
            raise ValueError("Inconsistent output shape: outp_shape={}".format(outp_shape))
        keras_classifier.n_classes_ = len(keras_classifier.classes_)
        return keras_classifier

    def load(self, path):
        self.model = load_model(path)
        outp_shape = keras_classifier.model.layers[-1].output_shape[-1]
        if outp_shape > 1:
            keras_classifier.classes_ = np.arange(outp_shape, dtype='int32')
        else:
            raise ValueError("Inconsistent output shape: outp_shape={}".format(outp_shape))
        self.n_classes_ = len(self.classes_)

在这里,我们应该将self.classes_设置为正确的类标签-但我只使用来自range(0,n_classes)的整数值。

用法(build_fn可以是任何合适的build_fn):

keras_classifier = KerasClassifierLoadable.from_file("model.hd5", build_fn=build_fn)

keras_classifier = KerasClassifierLoadable(build_fn=build_fn)
keras_classifier.load("model.hd5")