You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用K折交叉验证训练DenseNet121预训练模型时遭遇TypeError问题求助

K折交叉验证训练DenseNet121预训练模型时遭遇TypeError问题求助

我最近在做乳腺癌图像分类任务,用预训练的DenseNet121搭建了模型,数据集也分成了训练、测试和验证集。现在想加入K折交叉验证提升模型可靠性,用了sklearn的cross_validation工具,但运行代码时碰到了下面这个TypeError,试了好几种方法都没解决,有没有大佬能指点一下?

我的模型代码:

import tensorflow as tf
from tensorflow.keras.layers import Flatten, Dense, Input
from tensorflow.keras.models import Model
from sklearn import cross_validation

# 构建预训练模型
in_model = tf.keras.applications.DenseNet121(
    input_shape=(224,224,3),
    include_top=False,
    weights='imagenet',
    classes = 2
)
in_model.trainable = False

# 搭建自定义头部
inputs = tf.keras.Input(shape=(224,224,3))
x = in_model(inputs)
flat = Flatten()(x)
dense_1 = Dense(1024,activation = 'relu')(flat)
dense_2 = Dense(1024,activation = 'relu')(dense_1)
prediction = Dense(2,activation = 'softmax')(dense_2)

in_pred = Model(inputs = inputs,outputs = prediction)

# 编译模型
in_pred.compile(
    optimizer = tf.keras.optimizers.Adagrad(learning_rate=0.0002), 
    loss=tf.keras.losses.CategoricalCrossentropy(from_logits = False), 
    metrics=['accuracy']
)

# 尝试K折交叉验证
model_result=cross_validation(in_pred, train_data, train_labels, 5)

报错信息:

TypeError: Cannot clone object '<keras.engine.functional.Functional object at 0x000001F82E17E3A0>'
(type <class 'keras.engine.functional.Functional'>):
it does not seem to be a scikit-learn estimator as it does not implement a 'get_params' method.


问题原因

sklearn的交叉验证工具是为sklearn自身的estimator类设计的,而我们用Keras搭建的模型属于Keras的Functional模型,并没有实现sklearn要求的get_params()和set_params()方法,所以直接传入会报错。

解决办法

这里有两种常用的解决思路:

方法一:用KerasClassifier包装Keras模型

tensorflow提供了tf.keras.wrappers.scikit_learn.KerasClassifier(回归任务用KerasRegressor),可以把Keras模型包装成sklearn兼容的estimator,这样就能直接用sklearn的交叉验证工具了。

修改后的代码示例:

from tensorflow.keras.wrappers.scikit_learn import KerasClassifier
from sklearn.model_selection import cross_val_score

# 先把模型构建逻辑封装成函数
def build_model():
    in_model = tf.keras.applications.DenseNet121(
        input_shape=(224,224,3),
        include_top=False,
        weights='imagenet',
        classes = 2
    )
    in_model.trainable = False

    inputs = tf.keras.Input(shape=(224,224,3))
    x = in_model(inputs)
    flat = Flatten()(x)
    dense_1 = Dense(1024,activation = 'relu')(flat)
    dense_2 = Dense(1024,activation = 'relu')(dense_1)
    prediction = Dense(2,activation = 'softmax')(dense_2)

    model = Model(inputs = inputs,outputs = prediction)
    model.compile(
        optimizer = tf.keras.optimizers.Adagrad(learning_rate=0.0002), 
        loss=tf.keras.losses.CategoricalCrossentropy(from_logits = False), 
        metrics=['accuracy']
    )
    return model

# 包装成sklearn estimator
estimator = KerasClassifier(build_fn=build_model, epochs=3, batch_size=32)

# 执行K折交叉验证
model_result = cross_val_score(estimator, train_data, train_labels, cv=5)
print(f"5折交叉验证准确率结果: {model_result}")
print(f"平均准确率: {model_result.mean():.4f}")

方法二:手动实现K折交叉验证

如果不想依赖sklearn的包装器,也可以手动拆分数据集,循环训练每一轮的模型,这种方式更灵活,适合自定义训练流程(比如加入早停、模型保存等)。

示例代码:

from sklearn.model_selection import KFold
import numpy as np

# 初始化K折拆分器(shuffle=True保证数据打乱)
kf = KFold(n_splits=5, shuffle=True, random_state=42)
fold_scores = []

# 循环每一轮折
for fold, (train_idx, val_idx) in enumerate(kf.split(train_data)):
    print(f"===== 第 {fold+1} 折训练 =====")
    # 拆分当前折的训练和验证数据
    X_train_fold, X_val_fold = train_data[train_idx], train_data[val_idx]
    y_train_fold, y_val_fold = train_labels[train_idx], train_labels[val_idx]
    
    # 每折都重新构建模型,避免参数复用
    def build_model():
        in_model = tf.keras.applications.DenseNet121(
            input_shape=(224,224,3),
            include_top=False,
            weights='imagenet',
            classes = 2
        )
        in_model.trainable = False

        inputs = tf.keras.Input(shape=(224,224,3))
        x = in_model(inputs)
        flat = Flatten()(x)
        dense_1 = Dense(1024,activation = 'relu')(flat)
        dense_2 = Dense(1024,activation = 'relu')(dense_1)
        prediction = Dense(2,activation = 'softmax')(dense_2)

        model = Model(inputs = inputs,outputs = prediction)
        model.compile(
            optimizer = tf.keras.optimizers.Adagrad(learning_rate=0.0002), 
            loss=tf.keras.losses.CategoricalCrossentropy(from_logits = False), 
            metrics=['accuracy']
        )
        return model
    
    model = build_model()
    # 训练当前折的模型
    history = model.fit(
        X_train_fold, y_train_fold,
        epochs=3,
        batch_size=32,
        validation_data=(X_val_fold, y_val_fold),
        verbose=1
    )
    # 记录当前折的最终验证准确率
    fold_scores.append(history.history['val_accuracy'][-1])

# 输出所有折的准确率统计
print(f"\n5折交叉验证结果: {[round(score,4) for score in fold_scores]}")
print(f"平均准确率: {np.mean(fold_scores):.4f} ± {np.std(fold_scores):.4f}")

备注:内容来源于stack exchange,提问作者Eda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 10:45:30