如何在自编码器中使用SparseCategoricalCrossentropy并修复维度不匹配报错
报错根本原因
- 损失函数与网络输出、标签形状不匹配:
SparseCategoricalCrossentropy是分类损失,要求logits最后一维为类别总数,标签形状比logits少一维(无需独热的类别维度)。你当前decoder输出维度等于输入序列长度32,相当于误把序列长度当成了类别数,和形状为(batch, 32)的标签完全不匹配。 - 数据流程冲突:生成器外层额外套了epoch循环,且
model.fit重复传入batch_size参数,导致数据被重复切分,出现报错里的异常维度。 - 网络结构错误:输入为int32类型的类别id时,直接传入Dense层会把整数当成数值特征处理,不符合分类任务的逻辑。
修复方案
分两种场景选择对应方案:
场景1:输入32维均为数值特征,仅做普通自编码器重建
不需要使用分类损失,直接替换损失函数即可,无需改动网络结构:
# 修改train函数里的compile逻辑即可 model.compile(loss='mse', # 数值重建用均方误差,特征归一化到0-1也可以用BinaryCrossentropy optimizer=RMSprop(learning_rate=0.01))
同时修正数据生成和fit逻辑:
def data_generator(numpy_dataset, steps_per_epoch, batch_size): while True: np.random.shuffle(numpy_dataset) for i in range(steps_per_epoch): batch = numpy_dataset[i*batch_size : (i+1)*batch_size] yield batch, batch def train(model, numpy_dataset): BATCH_SIZE = 128 EPOCHS = 10 steps_per_epoch = len(numpy_dataset) // BATCH_SIZE model.compile(loss='mse', optimizer=RMSprop(learning_rate=0.01)) # 生成器训练不需要传batch_size参数 model.fit(x=data_generator(numpy_dataset=numpy_dataset, steps_per_epoch=steps_per_epoch, batch_size=BATCH_SIZE), epochs=EPOCHS, steps_per_epoch=steps_per_epoch)
场景2:输入32维每个位置都是类别id,需逐位做分类重建
需要调整网络结构,适配分类损失的要求:
- 先确认你的类别总数
vocab_size(即你之前使用独热编码时的维度) - 调整自编码器结构,增加嵌入层处理类别id,输出层适配分类要求:
def create_autoencoder(sequence_length, latent_dim, vocab_size): encoder_input = Input(shape=(sequence_length,)) # 嵌入层将类别id转换为向量 x = Embedding(input_dim=vocab_size, output_dim=64, input_length=sequence_length)(encoder_input) x = Flatten()(x) encoded = Dense(latent_dim, activation='tanh')(x) latent = Input(shape=(latent_dim,)) x = Dense(sequence_length * 64, activation='relu')(latent) x = Reshape((sequence_length, 64))(x) # 逐位输出类别概率 decoded = TimeDistributed(Dense(vocab_size, activation='softmax'))(x) encoder = Model(inputs=encoder_input, outputs=encoded, name="encoder") decoder = Model(inputs=latent, outputs=decoded, name="decoder") autoencoder = Model(inputs=encoder_input, outputs=decoder(encoded), name="autoencoder") return autoencoder
- 训练逻辑调整:
def data_generator(numpy_dataset, steps_per_epoch, batch_size): while True: np.random.shuffle(numpy_dataset) for i in range(steps_per_epoch): batch = numpy_dataset[i*batch_size : (i+1)*batch_size] yield batch, batch def train(model, numpy_dataset): BATCH_SIZE = 128 EPOCHS = 10 steps_per_epoch = len(numpy_dataset) // BATCH_SIZE model.compile(loss=SparseCategoricalCrossentropy(), optimizer=RMSprop(learning_rate=0.01), metrics=[SparseCategoricalAccuracy()]) model.fit(x=data_generator(numpy_dataset=numpy_dataset, steps_per_epoch=steps_per_epoch, batch_size=BATCH_SIZE), epochs=EPOCHS, steps_per_epoch=steps_per_epoch) # 初始化模型时传入vocab_size vocab_size = 你的类别总数 # 替换为实际值 autoencoder = create_autoencoder(32, 2, vocab_size) train(autoencoder, numpy_dataset)
内容的提问来源于stack exchange,提问作者Nexon
相关产品推荐
相关产品推荐

