TensorFlow去噪自编码器维度不匹配问题求助
修正TensorFlow自编码器维度不匹配问题
问题背景
输入数据形状为(339, 129, 32),构建自编码器时出现维度不匹配错误,原模型代码如下:
import tensorflow as tf from tensorflow import keras input_data = tf.keras.layers.Input(shape=train_sample.shape[1:]) masking = keras.layers.Masking(mask_value=-100.0)(input_data) conv = tf.keras.Sequential([ tf.keras.layers.Conv1D(128, 3, padding='same'), tf.keras.layers.AveragePooling1D(3), tf.keras.layers.ReLU(), tf.keras.layers.Conv1D(64, 3, padding='same'), tf.keras.layers.AveragePooling1D(2), tf.keras.layers.ReLU(), tf.keras.layers.Conv1D(32, 3, padding='same'), tf.keras.layers.ReLU(), tf.keras.layers.Conv1D(16, 3, padding='same'), tf.keras.layers.ReLU() ]) fc = tf.keras.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(256), tf.keras.layers.BatchNormalization(), tf.keras.layers.ReLU(), tf.keras.layers.Dense(32), ]) conv_out = conv(masking) fc_out = fc(conv_out) defc = tf.keras.Sequential([ tf.keras.layers.Dense(256), tf.keras.layers.BatchNormalization(), tf.keras.layers.ReLU(), tf.keras.layers.Dense(576), tf.keras.layers.ReLU(), tf.keras.layers.Dense(1024), tf.keras.layers.ReLU() ]) dconv = tf.keras.Sequential([ tf.keras.layers.Reshape((1024, 1)), tf.keras.layers.Conv1DTranspose(576, kernel_size=3, dilation_rate=2), tf.keras.layers.BatchNormalization(), tf.keras.layers.ReLU(), tf.keras.layers.Conv1DTranspose(384, kernel_size=4, strides=3, padding='same'), tf.keras.layers.BatchNormalization(), tf.keras.layers.ReLU(), tf.keras.layers.Conv1DTranspose(32, kernel_size=3, strides=3), tf.keras.layers.Activation("sigmoid") ]) defc_out = defc(fc_out) dconv_out = dconv(defc_out)
错误信息
ValueError: Dimensions must be equal, but are 9252 and 129 for '{{node mean_squared_error/SquaredDifference}} = SquaredDifference[T=DT_FLOAT](model_6/sequential_21/activation_3/Sigmoid, IteratorGetNext:1)' with input shapes: [?,9252,32], [?,129,32].
问题分析
错误源于编码器输出经解码后,序列长度(9252)与输入序列长度(129)不匹配。需重新计算编码器各层输出维度,对应调整解码器结构,确保输出维度与输入一致。
先计算编码器各层输出形状:
- 输入形状:
(129, 32) - 第一次Conv1D+AveragePooling1D后:
(43, 128)(129/3=43) - 第二次Conv1D+AveragePooling1D后:
(21, 64)(43//2=21) - 后续两次Conv1D(padding='same')后:形状保持
(21, 16)
所以conv_out形状为(21,16),解码器需先还原该形状,再通过转置卷积逐步恢复到输入的(129,32)。
修正后的模型代码
import tensorflow as tf from tensorflow import keras input_data = tf.keras.layers.Input(shape=(129, 32)) masking = keras.layers.Masking(mask_value=-100.0)(input_data) # 编码器部分 conv = tf.keras.Sequential([ tf.keras.layers.Conv1D(128, 3, padding='same'), tf.keras.layers.AveragePooling1D(3), # (129,128) → (43,128) tf.keras.layers.ReLU(), tf.keras.layers.Conv1D(64, 3, padding='same'), tf.keras.layers.AveragePooling1D(2), # (43,64) → (21,64) tf.keras.layers.ReLU(), tf.keras.layers.Conv1D(32, 3, padding='same'), tf.keras.layers.ReLU(), tf.keras.layers.Conv1D(16, 3, padding='same'), tf.keras.layers.ReLU() # 输出形状 (21,16) ]) fc = tf.keras.Sequential([ tf.keras.layers.Flatten(), # 21*16=336 → (336,) tf.keras.layers.Dense(256), tf.keras.layers.BatchNormalization(), tf.keras.layers.ReLU(), tf.keras.layers.Dense(32), # 编码向量 (32,) ]) conv_out = conv(masking) fc_out = fc(conv_out) # 解码器部分:先还原编码器卷积层输出的形状 defc = tf.keras.Sequential([ tf.keras.layers.Dense(256), tf.keras.layers.BatchNormalization(), tf.keras.layers.ReLU(), tf.keras.layers.Dense(21*16), # 还原为编码器卷积输出的展平长度 tf.keras.layers.ReLU(), tf.keras.layers.Reshape((21, 16)) # 恢复为(21,16),与conv_out形状一致 ]) # 转置卷积逐步恢复序列长度到129,通道数到32 dconv = tf.keras.Sequential([ tf.keras.layers.Conv1DTranspose(32, 3, padding='same'), # (21,16) → (21,32) tf.keras.layers.ReLU(), tf.keras.layers.Conv1DTranspose(64, 3, strides=2, padding='same'), # (21,32) → (42,64) tf.keras.layers.ReLU(), tf.keras.layers.ZeroPadding1D(padding=(0,1)), # 补1个元素到43,匹配编码器池化前长度 tf.keras.layers.Conv1DTranspose(128, 3, strides=3, padding='same'), # (43,64) → (129,128) tf.keras.layers.ReLU(), tf.keras.layers.Conv1DTranspose(32, 3, padding='same'), # (129,128) → (129,32) tf.keras.layers.Activation("sigmoid") ]) defc_out = defc(fc_out) dconv_out = dconv(defc_out) # 构建完整模型并验证输出形状 autoencoder = tf.keras.Model(inputs=input_data, outputs=dconv_out) autoencoder.compile(optimizer='adam', loss='mse') print(autoencoder.output_shape) # 输出应为 (None, 129, 32),与输入一致
关键调整说明
- 解码器全连接层:将原
Dense(1024)改为Dense(21*16),并添加Reshape((21,16)),还原编码器卷积层的输出形状,确保转置卷积的输入形状匹配。 - 转置卷积序列:
- 第一步转置卷积恢复通道数到32,保持序列长度21;
- 第二步用
strides=2将长度从21变为42,再通过ZeroPadding1D补1个元素到43,匹配编码器第一次池化前的长度; - 第三步用
strides=3将长度从43变为129(43*3=129); - 最后一步转置卷积将通道数恢复为输入的32,激活函数用sigmoid。
内容的提问来源于stack exchange,提问作者Md Hafizur Rahman
相关产品推荐
相关产品推荐

