如何实现池化与上采样后输出尺寸与原输入一致?——Keras未知尺寸输入的处理方案
解决动态尺寸输入下上采样后与原输入尺寸匹配的问题
嗨,这个场景我太熟悉了——当输入是动态尺寸(比如(None, None, 64)),用MaxPooling2D加UpSampling2D很容易因为尺寸不能被池化倍数整除,导致上采样后的特征图比原输入大,没法直接拼接。下面给你几个实用的解决办法:
方法1:用Lambda层+Cropping2D手动裁剪
这是最直接的方案,通过获取原输入的动态尺寸,把上采样后的特征图裁剪到完全匹配的大小:
from tensorflow import keras from tensorflow.keras import layers def crop_to_match(inputs): # 传入的是[上采样特征图, 原输入] upsampled, original = inputs # 获取原输入的动态高度和宽度 orig_h, orig_w = keras.backend.shape(original)[1], keras.backend.shape(original)[2] # 计算需要裁剪的上下、左右边距(只裁剪右边和下边的多余部分) crop_h = keras.backend.shape(upsampled)[1] - orig_h crop_w = keras.backend.shape(upsampled)[2] - orig_w # 执行裁剪 return layers.Cropping2D(cropping=((0, crop_h), (0, crop_w)))(upsampled) # 构建模型 inp = layers.Input(shape=(None, None, 64)) P = layers.MaxPooling2D(4, padding='same')(inp) U = layers.UpSampling2D(4)(P) # 裁剪到原输入尺寸 U_cropped = layers.Lambda(crop_to_match)([U, inp]) # 现在可以放心拼接了 concat = layers.Concatenate(axis=-1)([inp, U_cropped])
方法2:改用Conv2DTranspose替代UpSampling2D
如果你不需要单纯的“重复元素”上采样,而是想让上采样过程学习到权重,同时自动匹配尺寸,Conv2DTranspose是更好的选择:
inp = layers.Input(shape=(None, None, 64)) P = layers.MaxPooling2D(4, padding='same')(inp) # 用Conv2DTranspose实现带卷积的上采样,输出尺寸自动匹配原输入 U = layers.Conv2DTranspose( filters=64, # 和原输入通道数一致,方便拼接 kernel_size=4, strides=4, padding='same' )(P) # 直接拼接,不需要额外裁剪 concat = layers.Concatenate(axis=-1)([inp, U])
这里的关键是strides=4和padding='same',和池化层的参数对应,能让输出尺寸精确还原到原输入的大小,不需要手动处理。
方法3:用TensorFlow切片快速裁剪
如果觉得Cropping2D有点繁琐,也可以直接用TensorFlow的切片操作,在Lambda层里一步完成:
import tensorflow as tf from tensorflow.keras import layers inp = layers.Input(shape=(None, None, 64)) P = layers.MaxPooling2D(4, padding='same')(inp) U = layers.UpSampling2D(4)(P) # 直接切片取原输入尺寸的部分 U_cropped = layers.Lambda( lambda x: x[0][:, :tf.shape(x[1])[1], :tf.shape(x[1])[2], :] )([U, inp]) concat = layers.Concatenate(axis=-1)([inp, U_cropped])
这个方法更简洁,利用动态形状获取原输入的高宽,直接截断上采样特征图的多余部分,效果和方法1完全一致。
内容的提问来源于stack exchange,提问作者Mastiff
相关产品推荐
相关产品推荐

