使用Scikeras KerasRegressor构建CNN的输入维度错误解决
解决Scikeras KerasRegressor构建CNN回归模型的维度错误
第一个错误:输入维度不匹配(Expected min_ndim=4, found ndim=2)
你的输入X[i]初始形状是(600,99),属于2D张量(样本数,特征数),但Conv2D要求输入是4D张量(样本数,高度,宽度,通道数)。你在Input层指定了shape=(None,99,1),但实际输入未达到4维要求。
解决方法:
将输入扩展为4D张量,根据数据结构调整维度:
for i in range(len(X)): # 从(600,99) → (600, 1, 99, 1),对应(样本数, 高度, 宽度, 通道) X[i] = np.expand_dims(np.expand_dims(X[i], axis=1), axis=-1) X_test[i] = np.expand_dims(np.expand_dims(X_test[i], axis=1), axis=-1)
如果你的可变长度维度是宽度(比如每个样本宽度可变、高度固定为99),则调整Input层的shape为(99, None, 1),同时对应调整输入扩展方式。
第二个错误:MaxPooling2D导致负维度
当输入变成(?,99,1,4)时,默认的MaxPooling2D(pool_size=(2,2), padding="valid")会在宽度维度(大小为1)上尝试池化,计算后维度变为负数,引发报错。
解决方法(选其一即可):
- 调整池化窗口,仅在有效维度池化:
将所有MaxPooling2D的pool_size设为(2,1),仅在高度维度(99)做池化:model.add(keras.layers.MaxPooling2D(pool_size=(2,1))) - 设置padding为same,保持维度不变:
给MaxPooling2D添加padding="same"参数,避免维度缩小为负:model.add(keras.layers.MaxPooling2D(padding="same")) - 调换输入维度顺序:
将输入调整为(?,1,99,1),让宽度维度为99、高度为1,池化(2,2)时高度维度用padding="same"保持为1,避免出错。
模型代码的其他问题修正
除维度问题外,你的模型还有几个关键错误需要修复:
- 移除
Conv2D和MaxPooling2D语句末尾的逗号(会导致添加元组而非层); - 删除
Conv2D中的input_shape参数(Input层已指定,重复定义会冲突); - 回归任务需在模型末尾添加
Flatten()和Dense(1)层,将卷积特征映射为单个回归值;
修正后的完整模型代码
from typing import Dict, Any import numpy as np import keras from scikeras.wrappers import KerasRegressor from sklearn.datasets import make_regression class CNNRegressor(KerasRegressor): def __init__( self, optimizer="adam", optimizer__learning_rate=0.001, epochs=200, verbose=0, **kwargs, ): super().__init__(**kwargs) self.optimizer = optimizer self.epochs = epochs self.verbose = verbose def _keras_build_fn(self, compile_kwargs: Dict[str, Any]): model = keras.Sequential() # 输入形状对应(高度, 宽度, 通道),样本数自动添加 model.add(keras.layers.Input(shape=(1, 99, 1))) model.add(keras.layers.Conv2D(activation='relu', filters=4, kernel_size=(3,3), padding='same')) model.add(keras.layers.MaxPooling2D(pool_size=(2,1))) # 只在高度维度池化 model.add(keras.layers.Conv2D(activation='relu', filters=4, kernel_size=(3,3), padding='same')) model.add(keras.layers.MaxPooling2D(pool_size=(2,1))) model.add(keras.layers.Conv2D(activation='relu', filters=4, kernel_size=(3,3), padding='same')) model.add(keras.layers.MaxPooling2D(pool_size=(2,1))) model.add(keras.layers.Conv2D(activation='relu', filters=4, kernel_size=(3,3), padding='same')) model.add(keras.layers.MaxPooling2D(pool_size=(2,1))) model.add(keras.layers.Conv2D(activation='relu', filters=4, kernel_size=(3,3), padding='same')) # 展平特征图,添加全连接层输出回归值 model.add(keras.layers.Flatten()) model.add(keras.layers.Dense(1)) model.compile(loss="mse", optimizer=compile_kwargs["optimizer"]) return model # 示例数据生成(替换为你的真实数据) X, y = make_regression(n_samples=5, n_features=99, random_state=42) X = [x.reshape(600,99) for x in np.split(X,5)] # 模拟你的X结构 y = [y_i.reshape(-1,1) for y_i in np.split(y,5)] X_test, y_test = make_regression(n_samples=2, n_features=99, random_state=42) X_test = [x.reshape(600,99) for x in np.split(X_test,2)] # 扩展输入维度 for i in range(len(X)): X[i] = np.expand_dims(np.expand_dims(X[i], axis=1), axis=-1) for i in range(len(X_test)): X_test[i] = np.expand_dims(np.expand_dims(X_test[i], axis=1), axis=-1) # 训练与预测 reg = CNNRegressor(epochs=20, verbose=1) for i in range(len(X)): result_cnn = reg.fit(X[i], y[i]) print(result_cnn.model.summary()) for i in range(len(X_test)): pred_cnn = result_cnn.predict(X_test[i]) print(pred_cnn)
内容的提问来源于stack exchange,提问作者bree_geophys
相关产品推荐
相关产品推荐

