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

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编码,还能节省内存占用。

修改步骤:

  1. 不对标签做one-hot编码,保留原始一维整数数组(0-9)。
  2. 将模型的损失函数从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模型。

修改步骤:

  1. 保留Y_train = to_categorical(Y_train)的one-hot编码。
  2. 初始化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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 11:59:59