【问题标题】:Why is my Fully Convolutional Autoencoder not symmetric?为什么我的全卷积自动编码器不对称?
【发布时间】:2020-01-31 13:02:43
【问题描述】:

我正在开发一个全卷积自动编码器,它以 3 个通道作为输入并输出 2 个通道(输入:LAB,输出:AB)。因为输出应该和输入一样大,所以我使用全卷积。

代码:

import torch.nn as nn


class AE(nn.Module):
   def __init__(self):
       super(AE, self).__init__()

        self.encoder = nn.Sequential(
           # conv 1
           nn.Conv2d(in_channels=3, out_channels=64, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(64),
           nn.ReLU(),
           nn.MaxPool2d(kernel_size=2, stride=2),

           # conv 2
           nn.Conv2d(in_channels=64, out_channels=128, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(128),
           nn.ReLU(),
           nn.MaxPool2d(kernel_size=2, stride=2),

           # conv 3
           nn.Conv2d(in_channels=128, out_channels=256, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(256),
           nn.ReLU(),
           nn.MaxPool2d(kernel_size=2, stride=2),

           # conv 4
           nn.Conv2d(in_channels=256, out_channels=512, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(512),
           nn.ReLU(),
           nn.MaxPool2d(kernel_size=2, stride=2),

           # conv 5
           nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(1024),
           nn.ReLU()

       )

       self.decoder = nn.Sequential(
           # conv 6
           nn.ConvTranspose2d(in_channels=1024, out_channels=512, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(512),
           nn.ReLU(),

           # conv 7
           nn.Upsample(scale_factor=2, mode='bilinear'),
           nn.ConvTranspose2d(in_channels=512, out_channels=256, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(256),
           nn.ReLU(),

           # conv 8
           nn.Upsample(scale_factor=2, mode='bilinear'),
           nn.ConvTranspose2d(in_channels=256, out_channels=128, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(128),
           nn.ReLU(),

           # conv 9
           nn.Upsample(scale_factor=2, mode='bilinear'),
           nn.ConvTranspose2d(in_channels=128, out_channels=64, kernel_size=5, stride=1, padding=1),
           nn.BatchNorm2d(64),
           nn.ReLU(),

           # conv 10 out
           nn.Upsample(scale_factor=2, mode='bilinear'),
           nn.ConvTranspose2d(in_channels=64, out_channels=2, kernel_size=5, stride=1, padding=1),
           nn.Softmax()    # multi-class classification

           # TODO softmax deprecated
       )

   def forward(self, x):
       x = self.encoder(x)
       x = self.decoder(x)
       return x

输出张量的大小应该为:torch.Size([1, 2, 199, 253])

输出张量真正的大小:torch.Size([1, 2, 190, 238])

我的主要问题是结合 Conv2d 和 MaxPool2d 并在 ConvTranspose2d 中设置正确的参数值。因此,我分别对 MaxPool2d 和 ConvTranspose2d 使用 Upsample 函数对 Conv2d 进行处理。但我仍然有点不对称,我真的不知道为什么。

感谢您的帮助!

【问题讨论】:

  • 只是提示,因为我在移动 ATM 上:您也可以在解码器中使用标准 Conv2d。当您想要上采样图像时,您创建至少具有in_channel * r^2 通道的Conv2d 层,然后使用torch.nn.PixelShuffle。这将创建一个形状为(batch, in_channels, width * r, height * r) 的图像。调整 conv 的 rout_channels,但适合您。这类似于 fastai 为他们的 UNet 所做的事情。这样你可能会得到更好的分数(上采样期间的亚像素伪影更少),而且 IMO 的过程也更容易。
  • @SzymonMaszke,r 到底是什么?并感谢您的回复
  • 步幅和填充参数是否会缩小张量?

标签: python machine-learning deep-learning pytorch autoencoder


【解决方案1】:

有两个问题。

首先是填充不足:使用kernel_size=5,您的卷积每次应用时都会将图像缩小 4(每边 2 个像素),因此在所有地方都需要padding=2,而不仅仅是 1。

其次是“不均匀”的输入大小。我的意思是,一旦你的卷积被正确填充,你就会留下下采样操作,在每一点尝试将你的图像分辨率分成两半。当它们失败时,它们只返回一个较小的结果(整数除法丢弃余数)。由于您的网络有 4 个连续的 2x 下采样操作,因此您需要输入具有 H, W 维度,这是 2^4=16 的倍数。然后你实际上会得到同样形状的输出。下面是一个例子

import torch
import torch.nn as nn

class AE(nn.Module):
    def __init__(self):
        super(AE, self).__init__()

        self.encoder = nn.Sequential(
            # conv 1
            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),

            # conv 2
            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(128),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),

            # conv 3
            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(256),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),

            # conv 4
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(512),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),

            # conv 5
            nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(1024),
            nn.ReLU()
        )

        self.decoder = nn.Sequential(
            # conv 6
            nn.ConvTranspose2d(in_channels=1024, out_channels=512, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(512),
            nn.ReLU(),

            # conv 7
            nn.Upsample(scale_factor=2, mode='bilinear'),
            nn.ConvTranspose2d(in_channels=512, out_channels=256, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(256),
            nn.ReLU(),

            # conv 8
            nn.Upsample(scale_factor=2, mode='bilinear'),
            nn.ConvTranspose2d(in_channels=256, out_channels=128, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(128),
            nn.ReLU(),

            # conv 9
            nn.Upsample(scale_factor=2, mode='bilinear'),
            nn.ConvTranspose2d(in_channels=128, out_channels=64, kernel_size=5, stride=1, padding=2),
            nn.BatchNorm2d(64),
            nn.ReLU(),

            # conv 10 out
            nn.Upsample(scale_factor=2, mode='bilinear'),
            nn.ConvTranspose2d(in_channels=64, out_channels=2, kernel_size=5, stride=1, padding=2),
            nn.Softmax()    # multi-class classification
        )

    def forward(self, x):
        x = self.encoder(x)
        x = self.decoder(x)
        return x

input = torch.randn(1, 3, 6*16, 7*16)
output = AE()(input)
print(input.shape)
print(output.shape)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-20
    • 2018-11-12
    • 2019-12-01
    • 2017-11-11
    • 1970-01-01
    • 2019-11-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多