tf.image.resize与pytorch中的nn.Upsampling的爱恨情愁
一直在使用tensorflow2搭建网络,之前没有涉及过Unet这种结构,或是即使涉及也没有仔细研究,最近恰好在做Unet网络的改进才发现,要想对于Unet输入任意尺寸的图像,还是存在一定问题的,就是下采样后的特征能否通过上采样恢复到原始分辨率,这里试举一个例子,原始输入是8x8的图像块,通过一个kernel size为3,stride为2的卷积层,same padding,这时的输出尺寸为H_new = [(H-kernel_size + 2*padding)/s]+1,其中"[]"表示向下取整,即4x4的输出块,使用一个相同配置的反卷积层对这个4x4的块进行操作,输出H_new = (H-1)s-kernel_size+2padding,即7x7的块,这样是无法恢复到原始分辨率的。这是在我看到一篇Unet的pytorch的代码才意识到这个问题的,那篇代码中在2倍反卷积之后加了一个Upsampling,pytorch中的Upsampling是可以上采样到某个图像的分辨率的,但tensorflow中的Upsampling就只能按照指定倍数的上采样,是没办法解决这个问题的,当时一直在抱怨tensorflow不如pytorch智能,其实还是人太笨,tensorflow中有一个tf.image.resize函数,之前一直觉得这个函数只能用于数据处理部分,其实我忽略了这个就是tensorflow中的一个双线性插值函数,我们完全可以将这个函数放在反卷积之后,这样就能够起到与pytorch中Upsampling同样的效果。
tf.image.resize与tf.keras的不兼容
在使用tf.image.resize双线性插值反卷积后的特征图时需要指定插值后的特征图的尺寸,这里你自然会想到直接使用tensorflow2中比较方便的tensor.shape来指定,但实际上直接这样做不可行的,在这里需要使用tf.shape(tensor)来指定,具体为什么我也难以说清楚,我只有一个比较模糊的经验性的认识,这里举一个不太像例子的例子来帮助大家进一步理解tensorflow2中不同函数如何使用tensor的尺寸的。
inputs = tf.keras.layers.Input(shape=[256, 256, 3],name = name+'input')
x = tf.keras.layers.Conv2D(64, 3, strides=2, padding='same', activation='relu')(inputs)
x = tf.keras.layers.Conv2DTranspose(inputs.shape[-1], 3, strides=2, padding='same')(x)
x = tf.image.resize(x,size = [tf.shape(inputs)[1],tf.shape(inputs)[2]])