最近的神经网络所生成的图像存在棋盘状的失真问题,这种问题在色彩强烈的图像中尤为突出。
Deconvolution & Overlap
使用反卷积进行低分辨率到高分辨率的操作:当kernel size不能被stride整除的时候,使用反卷积容易出现不均匀重叠(uneven overlap)的问题。
从理论上来说,模型可以通过学习权重来避免这种情况的发生。
现在的网络通常使用多层反卷积来生成图像,虽然堆叠反卷积层可能会抵消失真问题,但是频繁组合会产生各种尺度的失真问题,会导致失真问题层层传递。
虽然把最后一层的stride设为1可以减少失真的问题,但是效果并不明显。
Overlap & Learning
从理论上来说,模型可以学习不均匀失真的位置的参数,使得输出是均匀平衡的。
而实际上,不仅仅是不均匀重叠的模型(kernel size没有被stride整除)没有解决这种平衡问题,就连均匀重叠的模型也没有解决这种平衡问题。应该对filters进行一些限制使其尽可能多保持输出是均匀平衡的。
影响这种失真的原因有很多,比如GANs中的鉴别器和梯度、反卷积,但是主要影响因素还是反卷积。
Better Upsampling
可以设计一个常规反卷积(常规反卷积默认产生失真图像)的替代方法。
(1)kernel size可以被stride整除
(2)从卷积中分离出更高分辨率的上采样来计算特征,比如先调整图像的大小(最近邻插值或者双线性插值),然后再执行卷积操作。
实验表明,最近邻插值的效果更好一些,可以修复一定的棋盘失真问题。
Code
Resize-convolution layers: tf.image.resize_images()
可以在做tf.nn.conv2d()之前使用tf.pad()来避免边界失真的问题
import mxnet as mx
batch_size = 1
in_channel = 1
height = 5
width = 5
data_shape = (batch_size, in_channel, height, width)
data = mx.nd.ones(data_shape)
out_channel = 1
kernel_size = 3
deconv_weight_shape = (in_channel, out_channel, kernel_size, kernel_size)
deconv_weight = mx.nd.ones(deconv_weight_shape)
stride = 2
up_scale = 2
data_deconv = mx.nd.Deconvolution(data=data, weight=deconv_weight,
target_shape=(height * up_scale, width * up_scale),
kernel=(kernel_size, kernel_size),
stride=(stride, stride),
num_filter=out_channel)
print(data_deconv)
data_upsample = mx.nd.contrib.BilinearResize2D(data=data, scale_height=up_scale, scale_width=up_scale)
conv_weight_shape = (out_channel, in_channel, kernel_size, kernel_size)
conv_weight = mx.nd.ones(conv_weight_shape)
pad = (kernel_size - 1) / 2
data_conv = mx.nd.Convolution(data=data_upsample, weight=conv_weight,
kernel=(kernel_size, kernel_size),
pad=(pad, pad), num_filter=out_channel, no_bias=True)
print(data_conv)
Image Generation Results
在GAN中,nearest-neighbor resize+convolution可以消除不同频率的失真情况。
下图表明,棋盘状失真情况并不是对抗训练造成的而是生成图像造成的。
下图表明,在艺术风格迁移的时候,将反卷积进行替换可以使棋盘状失真的现象消失。
Artifacts in Gradients
在计算卷积层梯度的时候,我们在反向传播中做反卷积操作,可能会在梯度中产生棋盘模式。
在特征可视化的过程中我们知道,图像模型梯度中存在高频噪声(作者认为这是max pool 引起的)。