【问题标题】:How to reshape multichannel image with a PyTorch encoder?如何使用 PyTorch 编码器重塑多通道图像?
【发布时间】:2021-07-06 23:45:29
【问题描述】:

我有一个尺寸为 [18, 512, 512] 的张量,表示 512x512 图像上最多 18 个特定对象的灰度热图。为了为我的条件 GAN 生成该图像的合适表示,我需要使用编码器将该张量重塑为 [512, 4, 4] 形状。但是,我无法理解这种转换是如何实现的,因为给定的维度对于直接线性或卷积转换来说似乎太不匹配了。

class HeatmapEncoder(torch.nn.Module):
  def __init__(self):
    # source = 18x512x512
    # target = 512x4x4
    self.encoder = torch.nn.Sequential(
        nn.Linear(),
        nn.ReLU(),
        nn.Linear()
    )

    def forward(self, x):
      pass

这里可以使用 start_dim=0 的 `nn.Flatten()',但结果将是一个简化的张量,不能用作线性层的输入。 解码器部分现在并不是特别重要,因为我只需要热图的低维表示来调节我的 GAN,而不是重新创建这些图像。

【问题讨论】:

    标签: python machine-learning computer-vision pytorch generative-adversarial-network


    【解决方案1】:

    您可以尝试几种不同的方法来解决您的问题,例如将其视为一个大向量,然后慢慢将其缩小到您的大小,或者置换尺寸并应用不同的操作等。因为没有完整的代码来测试它实际问题,我不能说哪个会更好,但我的第一直觉说基于卷积的降维非常适合这个问题。先写代码,再谈:

    class ReduceConv(torch.nn.Module):
      def __init__(self, nin, nout, activ=nn.ReLU):
        super(ReduceConv, self).__init__()
    
        # source = Batch x nin x H x W
        # target = Batch x nout x (H/2) x (W/2)
    
        self.conv = nn.Sequential(
            nn.Conv2d(
                nin, nout,
                kernel_size=3,
                stride=1,
                padding=1),
            nn.Conv2d(
                nout, nout,
                kernel_size=3,
                stride = 2,
                padding = 1),
            nn.BatchNorm2d(nout),
            activ()
        )
    
      def forward(self, x):
        return self.conv(x)
    
    class HeatmapEncoder(torch.nn.Module):
      def __init__(self):
        super(HeatmapEncoder, self).__init__()
    
        # source = 18x512x512
        # target = 512x4x4
        self.encoder = torch.nn.Sequential(
            ReduceConv(18, 32),       # out->  32 256 256 
            ReduceConv(32, 64),       # out->  64 128 128
            ReduceConv(64, 64),       # out->  64 64 64
            ReduceConv(64, 64),       # out->  64 32 32
            ReduceConv(64, 128),      # out-> 128 16 16
            ReduceConv(128, 256),     # out-> 256 8 8
            ReduceConv(256, 512)      # out-> 512 4 4
        )
    
      def forward(self, x):
        return self.encoder(x)
    
    # 10 is batch size
    inp = torch.rand(10, 18, 512, 512)
    enc = HeatmapEncoder()
    out = enc(inp)
    print(inp.shape)      # torch.Size([10, 18, 512, 512])
    print(out.shape)      # torch.Size([10, 512, 4, 4]) 
    

    它本质上只是一堆卷积层。请注意,在每个 ReduceConv 层中,输入维度通过使用 stride=2 卷积减半。从技术上讲,您不需要 ReduceConv 层中的第一个卷积,但现在是深度学习时代,越多越好 :) 我还在每次归约后添加了 BatchNorm 以及一个激活函数。当输入到第一个卷积时,18 被视为通道。这样通道最多可建立 512 个,而宽度和高度在每次操作后减半。此编码器模型可能不是最好或最有效的模型,但它应该足以解决您的问题。

    【讨论】:

    • 感谢您的代码,它确实按预期工作。但是,我的一个后台辅助函数在堆栈跟踪中引发了一个错误:assert (nan_to_num(tensor) == nan_to_num(other)).all(), fullname AssertionError: Generator.synthesis.heatmap_encoder.encoder.0.conv.2.running_mean。我不知道是什么原因导致了这个错误,因为这些卷积层本身不应该引入任何奇怪的 NaN 处理。
    • 辅助函数有什么用?从断言来看,在替换了在 Generator.synthesis.heatmap_encoder.encoder.0.conv.2.running_mean 上失败的 NaN 值之后,它看起来只是检查所有值的 tensor==other。 Running_mean 是批次标准化的一部分,它跟踪批次的运行平均值。如果您在训练模式下将输入转发到网络,running_mode 将被更新。如果您的辅助函数在转发后要求它相同,请尝试在 eval() 模式下运行网络。
    • 该函数应该检查DistributedDataParallel 跨进程的一致性,如果我在不使用 DDP 的情况下训练我的网络,则不会出现错误。但这在这个项目的范围内是不可行的。正如您所建议的,我将尝试手动将HeatmapEncoder 本身切换到 eval() 模式,尽管我认为这是默认设置。
    猜你喜欢
    • 2020-06-25
    • 2017-10-10
    • 2022-07-29
    • 2018-12-13
    • 2019-10-18
    • 2020-07-03
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    相关资源
    最近更新 更多