我正在使用全卷积自编码器为黑白图像上色,然而,输出结果出现了棋盘格图案,我想消除它。我之前看到的棋盘格伪影都比我的要小很多,通常的解决方法是用双线性上采样替换所有非池化操作(有人告诉我这样做)。
但是我不能简单地替换非池化操作,因为我处理的是不同尺寸的图像,因此需要非池化操作,否则输出张量的大小可能与原始图像不同。
TLDR:
如何在不替换非池化操作的情况下消除这些棋盘格伪影?
class AE(nn.Module): def __init__(self): super(AE, self).__init__() self.leaky_reLU = nn.LeakyReLU(0.2) self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=1, return_indices=True) self.unpool = nn.MaxUnpool2d(kernel_size=2, stride=2, padding=1) self.softmax = nn.Softmax2d() self.conv1 = nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1) self.conv2 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1) self.conv3 = nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1) self.conv4 = nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=1) self.conv5 = nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=3, stride=1, padding=1) self.conv6 = nn.ConvTranspose2d(in_channels=1024, out_channels=512, kernel_size=3, stride=1, padding=1) self.conv7 = nn.ConvTranspose2d(in_channels=512, out_channels=256, kernel_size=3, stride=1, padding=1) self.conv8 = nn.ConvTranspose2d(in_channels=256, out_channels=128, kernel_size=3, stride=1, padding=1) self.conv9 = nn.ConvTranspose2d(in_channels=128, out_channels=64, kernel_size=3, stride=1, padding=1) self.conv10 = nn.ConvTranspose2d(in_channels=64, out_channels=2, kernel_size=3, stride=1, padding=1) def forward(self, x): # 编码器 x = self.conv1(x) x = self.leaky_reLU(x) size1 = x.size() x, indices1 = self.pool(x) x = self.conv2(x) x = self.leaky_reLU(x) size2 = x.size() x, indices2 = self.pool(x) x = self.conv3(x) x = self.leaky_reLU(x) size3 = x.size() x, indices3 = self.pool(x) x = self.conv4(x) x = self.leaky_reLU(x) size4 = x.size() x, indices4 = self.pool(x) ###################### x = self.conv5(x) x = self.leaky_reLU(x) x = self.conv6(x) x = self.leaky_reLU(x) ###################### # 解码器 x = self.unpool(x, indices4, output_size=size4) x = self.conv7(x) x = self.leaky_reLU(x) x = self.unpool(x, indices3, output_size=size3) x = self.conv8(x) x = self.leaky_reLU(x) x = self.unpool(x, indices2, output_size=size2) x = self.conv9(x) x = self.leaky_reLU(x) x = self.unpool(x, indices1, output_size=size1) x = self.conv10(x) x = self.softmax(x) return x
回答:
跳跃连接通常用于编码器-解码器架构中,它通过从编码器(判别器)的浅层传递外观信息到解码器(生成器)的相应深层,帮助产生更准确的结果。Unet是广泛使用的编码器-解码器类型架构。Linknet也非常流行,它与Unet的区别在于融合编码器层和解码器层的外观信息的方式。在Unet中,来自编码器的输入特征在对应的解码器层中被拼接。而另一方面,Linknet执行加法操作,因此Linknet在单次前向传递中需要更少的操作,并且显著快于Unet。
此外,我附上了一张图,展示了Unet和LinkNet的架构。希望使用跳跃连接会有所帮助。