MNIST数据集MLP网格搜索报错:1D数组/形状不兼容问题求解
解决MNIST数据集MLP网格搜索中的标签格式冲突问题
问题描述
在MNIST数据集上用MLP做网格搜索时,因为标签是0-9,输出层设了10个神经元,所以用了one-hot编码。但运行网格搜索时报错:y should be a 1d array, got an array of shape (54000, 10) instead;换成y.argmax(axis=1)转成一维标签后,又出现ValueError: Shapes (10, 1) and (10, 10) are incompatible的错误。
错误原因
- 第一个错误:Scikit-learn的搜索工具(包括
HalvingGridSearchCV)要求目标标签是一维数组,而to_categorical生成的是二维one-hot编码数组,两者不兼容。 - 第二个错误:模型使用的
categorical_crossentropy损失函数要求标签是one-hot格式的二维数组,和转成一维的整数标签形状不匹配,因此报错。
解决方案
核心思路是让模型损失函数与标签格式对应,同时满足Scikit-learn的输入要求,以下两种方案任选其一:
方案一:用一维整数标签,修改损失函数
sparse_categorical_crossentropy专门适配一维整数标签,无需one-hot编码,还能节省内存占用。
修改步骤:
- 不对标签做one-hot编码,保留原始一维整数数组(0-9)。
- 将模型的损失函数从
categorical_crossentropy改为sparse_categorical_crossentropy。
修正后的关键代码片段:
# 数据预处理:标签保留原始一维格式,不做to_categorical X_train = X_train.reshape((X_train.shape[0], 28 * 28)) / 255.0 # Y_train保持原始状态,无需to_categorical转换
# 模型编译部分修改损失函数 model.compile(loss="sparse_categorical_crossentropy", optimizer=o, metrics=metrics)
方案二:保留one-hot编码,关闭KerasClassifier的标签编码
Scikeras的KerasClassifier默认会将标签转为一维格式,通过设置y_encoder=None可以跳过这个处理,直接将二维one-hot标签传给Keras模型。
修改步骤:
- 保留
Y_train = to_categorical(Y_train)的one-hot编码。 - 初始化
KerasClassifier时添加y_encoder=None参数。
修正后的代码片段:
grid_model = KerasClassifier(model=create_MLP, epochs=30, verbose=4, y_encoder=None)
完整修正代码(方案一)
import tensorflow as tf from sklearn.experimental import enable_halving_search_cv from sklearn.model_selection import HalvingGridSearchCV from tensorflow.keras import Sequential from tensorflow.keras import optimizers from tensorflow.keras.layers import Dense from scikeras.wrappers import KerasClassifier from tensorflow.keras.datasets import mnist # 加载MNIST数据集 (X_train, Y_train), (X_test, Y_test) = mnist.load_data() # 数据预处理:仅归一化和reshape,标签保留一维整数格式 X_train = X_train.reshape((X_train.shape[0], 28 * 28)) / 255.0 def create_MLP(hlayer_count=1, hlayer_1_size=64, hlayer_2_size=64, activation="relu", optimizer="adam", learning_rate=0.01): model = Sequential() # 第一层隐藏层 model.add(Dense(hlayer_1_size, activation=activation, input_shape=(28 * 28,))) # 第二层隐藏层(可选) if hlayer_count == 2: model.add(Dense(hlayer_2_size, activation=activation)) # 输出层 model.add(Dense(10, activation="softmax")) # 编译模型:使用sparse_categorical_crossentropy适配一维标签 metrics = ["accuracy"] if optimizer == "adam": o = optimizers.Adam(learning_rate=learning_rate) elif optimizer == "sgd": o = optimizers.SGD(learning_rate=learning_rate, momentum=0.9) else: o = optimizers.RMSprop(learning_rate=learning_rate) model.compile(loss="sparse_categorical_crossentropy", optimizer=o, metrics=metrics) return model # 初始化Keras分类器 grid_model = KerasClassifier(model=create_MLP, epochs=30, verbose=4) # 网格搜索参数设置 batch_size = [10, 20, 40, 80] hlayer_size = [32, 64, 96, 128] activation = ["relu", "tanh", "sigmoid"] optimizer = ["adam", "sgd", "rmsprop"] learning_rate = [0.001, 0.01, 0.05, 0.1] # 单隐藏层参数组合 dict1 = dict(batch_size=batch_size, model__hlayer_count=[1], model__hlayer_1_size=hlayer_size, model__activation=activation, model__optimizer=optimizer, model__learning_rate=learning_rate) # 双隐藏层参数组合 dict2 = dict(batch_size=batch_size, model__hlayer_count=[2], model__hlayer_1_size=hlayer_size, model__hlayer_2_size=hlayer_size, model__activation=activation, model__optimizer=optimizer, model__learning_rate=learning_rate) # 执行网格搜索 grid = HalvingGridSearchCV(estimator=grid_model, param_grid=[dict1, dict2], n_jobs=-1, cv=3, error_score="raise") grid_results = grid.fit(X_train, Y_train)
内容的提问来源于stack exchange,提问作者Ardalan
相关产品推荐
相关产品推荐

