使用KerasClassifier拟合含字符串X的Keras模型时出现2D/1D数组错误
问题:KerasClassifier结合TextVectorization层模型时触发ValueError: Expected 2D array, got 1D array
问题描述
直接拟合含TextVectorization层的自定义Keras模型时正常,但用KerasClassifier包装后拟合,传入字符串列表作为训练数据X时触发该错误。已使用官方推荐的TextVectorization层(拒绝使用已废弃的Tokenizer类),且该层已适配训练数据,核心需求是将output_sequence_length设为超参数。
相关代码
def Build_Model(X_train, nodes=10, nLayers=1, epochs=10, batch_size=32, dropout=0.5, act_h='relu', act_o='sigmoid', optimizer='adam', verbose=2, emb_matrix=None, vocab=None, sequence_length=200): vectorize_layer = TextVec_Layer(vocab, sequence_length) embedding_layer = Emb_Layer(emb_matrix, sequence_length) model.add(InputLayer(input_shape=(1,), dtype=tf.string)) # 注意:原代码未初始化model vectorize_layer.adapt(X_train) model.add(vectorize_layer) model.add(embedding_layer) model.add(Flatten()) model.add(Dense(nodes, activation=act_h)) model.add(Dropout(dropout)) model.add(Dense(nClasses, activation=act_o)) model.compile(optimizer=optimizer, loss= 'binary_crossentropy', metrics=['accuracy']) return model emb_model = KerasClassifier(build_fn=Build_Model, X_train=X_train, nodes=10, nLayers=1, epochs=10, batch_size=100, dropout=0.5, act_h='relu', act_o='sigmoid', optimizer='adam', emb_matrix=emb_matrix, vocab=vocab, sequence_length=100,verbose=2, random_state=42) model = emb_model.fit(X_train, y_train)
报错栈信息
ValueError Traceback (most recent call last) ...\Temp/ipykernel_18552/393945425.py in <module> ----> 1 emb_model.fit(X_train, y_train)#, , validation_data=(X_test_t, y_test) ...\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 ...\wrappers.py in fit(self, X, y, sample_weight, **kwargs) 760 kwargs["initial_epoch"] = kwargs.get("initial_epoch", 0) 761 -> 762 self._fit( 763 X=X, 764 y=y, ...\wrappers.py in _fit(self, X, y, sample_weight, warm_start, epochs, initial_epoch, **kwargs) 916 # Data checks 917 if not ((self.warm_start or warm_start) and self.initialized_): -> 918 X, y = self._initialize(X, y) 919 else: 920 X, y = self._validate_data(X, y)
解决方案
原因分析
KerasClassifier继承自scikit-learn的Estimator接口,默认会对输入数据执行scikit-learn风格的维度验证,它期望输入是2D数组,但你的X是1D字符串列表,触发了维度检查错误。而直接使用Keras模型时,模型的InputLayer明确接受(1,)形状的字符串输入,因此不会有该问题。
修复方案1:跳过KerasClassifier的数据验证
在初始化KerasClassifier时添加validate_data=False参数,跳过scikit-learn风格的数据验证,让数据直接传入Keras模型处理:
emb_model = KerasClassifier( build_fn=Build_Model, X_train=X_train, nodes=10, nLayers=1, epochs=10, batch_size=100, dropout=0.5, act_h='relu', act_o='sigmoid', optimizer='adam', emb_matrix=emb_matrix, vocab=vocab, sequence_length=100, verbose=2, random_state=42, validate_data=False # 新增:关闭数据验证 )
修复方案2:规范模型构建逻辑(推荐)
- 补全模型初始化:原
Build_Model函数未初始化model对象,需添加model = tf.keras.Sequential()。 - 提前适配TextVectorization层:不要在模型构建函数内调用
vectorize_layer.adapt(X_train),避免KerasClassifier重复构建模型时重复适配(比如交叉验证场景)。 - 传递已适配的向量层:将提前适配好的vectorize_layer作为参数传入模型构建函数。
修改后代码示例:
# 定义TextVectorization层封装函数 def TextVec_Layer(vocab, sequence_length): return tf.keras.layers.TextVectorization( vocabulary=vocab, output_sequence_length=sequence_length, output_mode='int' ) # 提前适配向量层 sequence_length = 100 vectorize_layer = TextVec_Layer(vocab, sequence_length) vectorize_layer.adapt(X_train) # 修改模型构建函数,移除X_train参数和内部adapt逻辑 def Build_Model(nodes=10, nLayers=1, epochs=10, batch_size=32, dropout=0.5, act_h='relu', act_o='sigmoid', optimizer='adam', verbose=2, emb_matrix=None, vectorize_layer=None, sequence_length=200): # 补全模型初始化 model = tf.keras.Sequential() model.add(tf.keras.layers.InputLayer(input_shape=(1,), dtype=tf.string)) model.add(vectorize_layer) embedding_layer = Emb_Layer(emb_matrix, sequence_length) model.add(embedding_layer) model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(nodes, activation=act_h)) model.add(tf.keras.layers.Dropout(dropout)) model.add(tf.keras.layers.Dense(nClasses, activation=act_o)) model.compile(optimizer=optimizer, loss= 'binary_crossentropy', metrics=['accuracy']) return model # 初始化KerasClassifier,传入已适配的vectorize_layer emb_model = KerasClassifier( build_fn=Build_Model, nodes=10, nLayers=1, epochs=10, batch_size=100, dropout=0.5, act_h='relu', act_o='sigmoid', optimizer='adam', emb_matrix=emb_matrix, vectorize_layer=vectorize_layer, sequence_length=sequence_length, verbose=2, random_state=42, validate_data=False )
额外提示
如果使用新版scikeras(替代旧版keras.wrappers.scikit_learn),建议使用scikeras.wrappers.KerasClassifier,并通过model__前缀传递模型参数,更符合scikit-learn的参数传递规范。
内容的提问来源于stack exchange,提问作者Dython
相关产品推荐
相关产品推荐

