使用cross_val_predict时Keras模型无法克隆的报错原因排查
自定义损失函数的MLP回归任务中cross_val_predict报错原因
问题背景
正在实现一个MLP对数据集执行回归任务,在model.compile()中使用了自定义损失函数,相关代码如下:
input_dim = 24 output_dim = 1 # 定义Spearman秩相关系数作为自定义损失函数 def spearman_rank_correlation(y_true, y_pred): corr = tfp.stats.correlation(y_true, y_pred) return -corr def rank_loss(y_true, y_pred): true_ranks = tf.argsort(tf.argsort(y_true, axis=1), axis=1) pred_ranks = tf.argsort(tf.argsort(y_pred, axis=1), axis=1) return tf.keras.losses.mean_squared_error(true_ranks, pred_ranks) model = tf.keras.models.Sequential([ tf.keras.layers.Dense(64, activation='relu', input_dim=input_dim), tf.keras.layers.Dense(64, activation='relu'), tf.keras.layers.Dense(output_dim, activation='linear') ]) model.compile(optimizer='adam', loss=tfp.stats.correlation) model.fit(X_train_fr, Y_train, epochs=100, batch_size=32) pred_train = cross_val_predict(model, X_train_fr, Y_train, cv=5)
调用cross_val_predict()时出现如下报错:
Cannot clone object '<keras.engine.sequential.Sequential object at 0x0000021DFE729190>' (type <class 'keras.engine.sequential.Sequential'>): it does not seem to be a scikit-learn estimator as it does not implement a 'get_params' method.
报错原因
- scikit-learn的
cross_val_predict()函数要求传入的模型必须符合scikit-learn estimator接口规范,核心要求是模型必须实现get_params()和set_params()方法——交叉验证过程中需要为每个fold克隆独立的模型实例,这两个方法是克隆操作的基础。 - 原生的Keras Sequential模型并没有实现scikit-learn的estimator接口,因此无法被scikit-learn的交叉验证函数识别和处理,从而抛出该错误。
- 额外提示:你直接使用
tfp.stats.correlation作为损失函数的写法存在问题,该函数返回的是相关系数,损失函数需要是可微分的优化目标,应该使用你定义的spearman_rank_correlation(取负后让优化器最大化相关系数),不过这不是当前报错的直接原因。
快速解决方向
要在Keras模型上使用scikit-learn的交叉验证工具,需要用tf.keras.wrappers.scikit_learn.KerasRegressor将Keras模型包装成符合scikit-learn接口的estimator,示例代码如下:
from tensorflow.keras.wrappers.scikit_learn import KerasRegressor def build_model(): model = tf.keras.models.Sequential([ tf.keras.layers.Dense(64, activation='relu', input_dim=input_dim), tf.keras.layers.Dense(64, activation='relu'), tf.keras.layers.Dense(output_dim, activation='linear') ]) model.compile(optimizer='adam', loss=spearman_rank_correlation) return model # 包装Keras模型 sk_model = KerasRegressor(build_fn=build_model, epochs=100, batch_size=32) # 现在可以正常调用cross_val_predict pred_train = cross_val_predict(sk_model, X_train_fr, Y_train, cv=5)
内容的提问来源于stack exchange,提问作者Virgile BRIAN
相关产品推荐
相关产品推荐

