使用KerasClassifier时出现TypeError: NoneType无len()方法的问题
问题:Keras逻辑回归模型训练报错
TypeError: object of type 'NoneType' has no len() 我想用Keras构建逻辑回归模型,训练指定epoch后获取准确率和损失值,但代码抛出TypeError: object of type 'NoneType' has no len()错误,已确认X_train[cv_train]和y_train[cv_train]不是NoneType。
代码
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1) X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=1) def build_logistic_regression_model(): model = Sequential() model.add(Dense(units=1,kernel_initializer='glorot_uniform', activation='sigmoid',kernel_regularizer=l2(0.))) # Performance visualization callback performance_viz_cbk = PerformanceVisualizationCallback(model=model,validation_data=X_val,dat_dir='c:\\performance_charts') model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy']) return model lrscores = [] train_lrscores = [] for cv_train, cv_val in kfold.split(X_train, y_train): lr_model_logit = KerasClassifier(build_fn=build_logistic_regression_model, batch_size = 10) hist = lr_model_logit.fit(X_train[cv_train], y_train[cv_train], epochs=200).history_ losses = hist["mean_absolute_error"] train_lrscores.append(hist * 100) lr_score = hist.score(X_val, y_val) lrscores.append(lr_score * 100)
报错回溯
/opt/conda/lib/python3.7/site-packages/scikeras/wrappers.py:302: UserWarning: ``build_fn`` will be renamed to ``model`` in a future release, at which point use of ``build_fn`` will raise an Error instead. "``build_fn`` will be renamed to ``model`` in a future release," --------------------------------------------------------------------------- TypeError Traceback (most recent call last) /tmp/ipykernel_18384/2762271288.py in <module> 3 for cv_train, cv_val in kfold.split(X_train, y_train): 4 lr_model_logit = KerasClassifier(build_fn=build_logistic_regression_model, batch_size = 10) ----> 5 hist = lr_model_logit.fit(X_train[cv_train], y_train[cv_train], epochs=200).history_ 6 losses = hist["mean_absolute_error"] 7 train_lrscores.append(hist * 100) /opt/conda/lib/python3.7/site-packages/scikeras/wrappers.py in fit(self, X, y, sample_weight, **kwargs) 1492 sample_weight = 1 if sample_weight is None else sample_weight 1493 sample_weight *= compute_sample_weight(class_weight=self.class_weight, y=y) -> 1494 super().fit(X=X, y=y, sample_weight=sample_weight, **kwargs) 1495 return self 1496 /opt/conda/lib/python3.7/site-packages/scikeras/wrappers.py in fit(self, X, y, sample_weight, **kwargs) 765 sample_weight=sample_weight, 766 warm_start=self.warm_start, --> 767 **kwargs, 768 ) 769 /opt/conda/lib/python3.7/site-packages/scikeras/wrappers.py in _fit(self, X, y, sample_weight, warm_start, epochs, initial_epoch, **kwargs) 927 X = self.feature_encoder_.transform(X) 928 -> 929 self._check_model_compatibility(y) 930 931 self._fit_keras_model( /opt/conda/lib/python3.7/site-packages/scikeras/wrappers.py in _check_model_compatibility(self, y) 549 # we recognize the attribute but do not force it to be 550 # generated -> 551 if self.n_outputs_expected_ != len(self.model_.outputs): 552 raise ValueError( 553 "Detected a Keras model input of size" TypeError: object of type 'NoneType' has no len()
数据示例
X_train[cv_train]
array([[ 3.49907650e-01, 1.01934833e+00, 9.22962131e-01, ..., 4.65851423e-01, 5.85124577e-01, -2.30825406e-01], [-1.66145691e-01, -1.70198795e-01, 7.40812556e-01, ..., -1.25252966e-01, 6.11333541e-04, -1.85578709e+00], [-3.34532309e-01, 1.47744989e+00, -7.94889360e-01, ..., 1.10431254e+00, 5.00866647e-01, 5.75451553e-01], ..., [-1.21341832e+00, 8.56729999e-01, 1.87070578e-01, ..., -8.38769062e-01, -7.08780127e-02, -6.54645722e-01], [ 3.45711192e-01, 8.01029131e-01, 9.37260745e-01, ..., 6.35312010e-01, -1.77277404e-01, -1.05178867e+00], [ 1.65016194e+00, 1.34960903e+00, 1.17654404e+00, ..., 3.79284887e-01, 4.38081218e-01, -3.55481467e-01]])
y_train
array([1, 3, 2, 2, 3, 2, 3, 3, 1, 2, 1, 1, 3, 2, 1, 1, 2, 3, 2, 1, 1, 1, 1, 0, 1, 2, 3, 1, 1, 0, 0, 1, 1, 3, 1, 1, 2, 0, 1, 1, 2, 1, 0, 3, 3, 0, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 2, 3, 1, 1, 3, 2, 3, 1, 1, 2, 1, 2, 1, 1, 0, 2, 2, 3, 3, 2, 1, 1, 3, 1, 3, 1, 1, 3, 1, 2, 0, 1, 2, 0, 2, 2, 2, 3, 1, 1, 2, 1, 0, 2, 2, 1, 1, 0, 2, 3, 3, 3, 3, 1, 1, 1, 1, 2, 3, 2, 1, 1, 1, 2, 2, 0, 3, 2, 1, 2, 3, 3, 2, 0, 3, 0, 1, 1, 1, 1, 2, 3, 3, 3, 2, 0, 3, 2, 3, 1, 3, 1, 2, 1, 2, 3, 2, 2, 3, 3, 1, 0, 3, 1, 3, 2, 2, 2, 2, 3, 3, 1, 3, 2, 3, 1, 3, 1, 2, 2, 1, 2, 3, 3, 1, 1, 2, 0, 2, 1, 2, 1, 3, 3, 3, 1, 3, 1, 1, 2, 3, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 0, 2, 0, 3, 1, 2, 3, 1, 1, 3, 1, 3, 0, 3, 1, 3, 1, 1, 1, 1, 0, 3, 3, 2, 2, 3, 3, 1, 3, 1, 2, 1, 2, 2, 3, 2, 1, 2, 3, 3, 3, 3, 1, 2, 3, 1, 2, 1, 1, 1, 2, 1, 2, 3, 2, 1, 2, 1, 2, 1, 2, 3, 3, 1, 2, 0, 1, 2, 2, 2, 1, 1, 3, 3, 1, 3, 3, 2, 1, 3, 1, 3, 1, 1, 1, 3, 1, 3, 1, 2, 1, 0, 1, 2, 1, 2, 2, 1, 1, 2, 1, 2, 2, 2, 1, 3, 1, 2, 3, 2, 2, 3, 1, 2, 0, 0, 3, 2, 2, 2, 3, 2, 1, 1, 1, 1, 2, 2, 2, 1, 3, 1, 2, 1, 3, 2, 2, 1, 1, 1, 2, 3, 3, 2, 3, 2, 3, 1, 2, 2, 1, 2, 1, 1, 3, 3, 3, 2, 1, 1, 3, 2, 3, 3, 2, 1, 1, 1, 2, 3, 0, 1, 2, 1, 1, 2, 0, 2, 1, 0, 2, 0, 3, 2, 3, 2, 1, 1, 2, 3, 0, 0, 2, 2, 2, 1, 1, 1, 3, 1, 0, 1, 2, 2])
问题分析与修正方案
核心问题
- 任务类型不匹配:
y_train是0-3的多分类标签,但模型用了二元分类的配置(输出单元1个+binary_crossentropy),导致Scikeras无法正确初始化模型,出现model_为None的错误。 - 训练后逻辑错误:
hist是训练历史字典,不是模型对象,不能调用score();且编译时未指定mean_absolute_error指标,无法从历史中提取该值。 - 参数即将废弃:
build_fn参数将被Scikeras移除,应改用model参数。
修正后的代码
from sklearn.model_selection import train_test_split, KFold from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.regularizers import l2 from tensorflow.keras.utils import to_categorical from scikeras.wrappers import KerasClassifier # 数据划分 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1) X_train, X_val, y_train, y_val = train_test_split(X_train, y_train, test_size=0.25, random_state=1) # 多分类标签转独热编码 y_train_onehot = to_categorical(y_train) y_val_onehot = to_categorical(y_val) def build_logistic_regression_model(): model = Sequential() # 多分类输出单元数等于类别数,激活用softmax model.add(Dense(units=4, kernel_initializer='glorot_uniform', activation='softmax', kernel_regularizer=l2(0.))) model.compile(optimizer='sgd', loss='categorical_crossentropy', # 多分类用交叉熵损失 metrics=['accuracy']) return model lrscores = [] train_lrscores = [] kfold = KFold(n_splits=5, shuffle=True, random_state=1) for cv_train_idx, cv_val_idx in kfold.split(X_train, y_train): # 准备当前折叠的训练/验证数据 X_cv_train = X_train[cv_train_idx] y_cv_train_onehot = to_categorical(y_train[cv_train_idx]) lr_model_logit = KerasClassifier(model=build_logistic_regression_model, batch_size=10) hist = lr_model_logit.fit(X_cv_train, y_cv_train_onehot, epochs=200, validation_data=(X_val, y_val_onehot)).history_ # 记录训练集最后一轮准确率 train_acc = hist['accuracy'][-1] * 100 train_lrscores.append(train_acc) # 验证集评估 val_loss, val_acc = lr_model_logit.score(X_val, y_val_onehot, return_dict=False) lrscores.append(val_acc * 100) print(f"交叉验证训练准确率均值: {sum(train_lrscores)/len(train_lrscores):.2f}%") print(f"交叉验证验证准确率均值: {sum(lrscores)/len(lrscores):.2f}%")
关键修正点
- 适配多分类任务:输出单元改为4个,激活函数用
softmax,损失函数换为categorical_crossentropy,标签转为独热编码。 - 修正Scikeras参数:用
model参数替代即将废弃的build_fn。 - 修复训练后逻辑:从训练历史中提取最后一轮准确率,使用模型对象调用
score()获取验证集结果。 - 避免数据泄露:移除回调中硬编码的全局验证集,改为训练时传入独立验证数据。
内容的提问来源于stack exchange,提问作者melolilili
相关产品推荐
相关产品推荐

