使用中间层输出作为标签训练自编码器遇AttributeError问题求助
解决Keras自编码器训练时
'Tensor' object has no attribute 'ndim'错误 你遇到的问题核心很明确:你把计算图中的Keras Tensor对象(ae_input)直接传给了model.fit()的y参数,但这个方法需要的是实际的numpy数组格式的训练数据,而非计算图里的张量节点。Tensor是Keras用来构建模型计算流程的元素,它本身不包含真实的训练数据,自然没有ndim这个numpy数组特有的属性。
下面是两种可行的解决思路,帮你正确完成自编码器的训练:
方法1:提前准备好拼接后的目标数据(最直接)
自编码器的训练目标是重构输入,也就是你拼接后的ae_input对应的真实数据。我们可以先在numpy层面把稠密特征和嵌入层处理后的特征拼接好,作为训练的目标值:
import numpy as np from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Embedding, Flatten, Dense, concatenate # 先定义嵌入层相关的小模型,用来转换训练数据中的序列特征 sequences = Input(shape=(train_embed.shape[1],)) embed = Embedding(vocab_size, 20, input_length=num_embed_cols)(sequences) flatten = Flatten()(embed) embed_process_model = Model(inputs=sequences, outputs=flatten) # 得到训练数据中序列特征经过嵌入+Flatten后的结果 train_flattened_embed = embed_process_model.predict(train_embed) # 拼接稠密特征和处理后的嵌入特征,得到自编码器的目标数据y_train y_train = np.concatenate([train_dense_scaled, train_flattened_embed], axis=1) # 重新构建完整的自编码器模型 dense = Input(shape=(train_dense_scaled.shape[1],)) sequences_input = Input(shape=(train_embed.shape[1],)) embed_layer = Embedding(vocab_size, 20, input_length=num_embed_cols)(sequences_input) flatten_layer = Flatten()(embed_layer) ae_input = concatenate([dense, flatten_layer]) # 编码器部分 e_128 = Dense(units=128, activation='relu', kernel_initializer=initializer)(ae_input) e_64 = Dense(units=64, activation='relu', kernel_initializer=initializer)(e_128) # 解码器部分:输出维度要和ae_input一致,才能完成重构 decoded = Dense(units=ae_input.shape[1], activation='relu', kernel_initializer=initializer)(e_64) model = Model(inputs=[sequences_input, dense], outputs=decoded) model.compile(loss='mse', optimizer='adam') # 现在传入正确的numpy数组作为y model.fit(x=[train_embed, train_dense_scaled], y=y_train, epochs=200, batch_size=128)
方法2:用函数式API构建包含输入目标的模型(更优雅,适合复杂场景)
如果你不想提前处理数据,可以直接构建一个多输出模型,让模型自动关联输入和目标的映射关系:
from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Embedding, Flatten, Dense, concatenate from tensorflow.keras.losses import MeanSquaredError dense = Input(shape=(train_dense_scaled.shape[1],)) sequences = Input(shape=(train_embed.shape[1],)) embed = Embedding(vocab_size, 20, input_length=num_embed_cols)(sequences) flatten = Flatten()(embed) ae_input = concatenate([dense, flatten]) # 编码器 e_128 = Dense(units=128, activation='relu', kernel_initializer=initializer)(ae_input) e_64 = Dense(units=64, activation='relu', kernel_initializer=initializer)(e_128) # 解码器:输出维度匹配ae_input decoded = Dense(units=ae_input.shape[1], activation='relu', kernel_initializer=initializer)(e_64) # 自定义损失:直接计算重构结果和原始拼接输入的MSE def recon_loss(y_true, y_pred): return MeanSquaredError()(ae_input, y_pred) # 构建模型,只输出重构结果,用自定义损失关联原始输入 model = Model(inputs=[sequences, dense], outputs=decoded) model.compile(loss=recon_loss, optimizer='adam') # 训练时无需额外传入y,因为损失函数已经关联了ae_input model.fit(x=[train_embed, train_dense_scaled], epochs=200, batch_size=128)
关键注意点
- 解码器的输出层维度必须和
ae_input的维度完全一致,否则会出现维度不匹配的错误。 model.fit()的x和y参数都必须是numpy数组(或TensorFlow Dataset对象),不能是Keras的Tensor节点——Tensor只是计算图的一部分,本身不携带训练数据。
内容的提问来源于stack exchange,提问作者liamhawkins
相关产品推荐
相关产品推荐

