我的基于 Pytorch 的 GAN 如何输出没有灰度的纯黑白?

数据挖掘 火炬 图片
2021-09-30 05:46:50

我的目标是用纯黑色和白色创建简单的几何线条图。我不需要灰色调。像这样的东西(训练图像的例子):

在此处输入图像描述

但是使用该 GAN 会产生灰色调的图像。例如,这里是生成图像的一些细节。

在此处输入图像描述

我使用这个基于 Pytorch 的 Vanilla GAN作为我正在尝试做的事情的基础。我怀疑我的 GAN 在计算所有这些浮点数时做的工作太多了。我很确定在 nn 中使用 -1 和 1 之间的数字是标准化的?我读过由于 tanh 激活层的问题,尝试使用 0 和 1 是个坏主意。那么还有其他想法吗?这是我的鉴别器和生成器的代码。

image_size=248
batch_size = 10
n_noise = 100
class Discriminator(nn.Module):
    """
        Simple Discriminator w/ MLP
    """
    def __init__(self, input_size=image_size ** 2, num_classes=1):
        super(Discriminator, self).__init__()
        self.layer = nn.Sequential(
            nn.Linear(input_size, 512),
            nn.LeakyReLU(0.2),
            nn.Linear(512, 256),
            nn.LeakyReLU(0.2),
            nn.Linear(256, num_classes),
            nn.Sigmoid(),
        )

    def forward(self, x):
        y_ = x.view(x.size(0), -1)
        y_ = self.layer(y_)
        return y_

发电机:

class Generator(nn.Module):
    """
        Simple Generator w/ MLP
    """
    def __init__(self, input_size=batch_size, num_classes=image_size ** 2):
        super(Generator, self).__init__()
        self.layer = nn.Sequential(
            nn.Linear(input_size, 128),
            nn.LeakyReLU(0.2),
            nn.Linear(128, 256),
            nn.BatchNorm1d(256),
            nn.LeakyReLU(0.2),
            nn.Linear(256, 512),
            nn.BatchNorm1d(512),
            nn.LeakyReLU(0.2),
            nn.Linear(512, 1024),
            nn.BatchNorm1d(1024),
            nn.LeakyReLU(0.2),
            nn.Linear(1024, num_classes),
            nn.Tanh()
        )

    def forward(self, x):
        y_ = self.layer(x)
        y_ = y_.view(x.size(0), 1, image_size, image_size)
        return y_

到目前为止,我所拥有的几乎消耗了我拥有的所有可用内存,因此简化它和/或加速它都是一个优点。我的输入图像是 248 像素 x 248 像素。如果我比这更小,它们就不再有用了。所以比创建原始 GAN 的 MNIST 数字 (28x28) 大得多。我对这一切也很陌生,因此也感谢任何其他建议。

编辑:到目前为止我已经尝试过什么。我尝试通过使用此类生成输出二进制(-1 或 1)来生成生成器 B&W 的最终输出:

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

    def forward(self, x):
        x2 = x.clone()
        x2 = x2.sign()
        x2[x2==0] = -1.
        x = x2
        return x

然后我nn.Tanh()Binary(). 它确实生成了黑白图像。但无论多少个 epoch,输出看起来仍然是随机的。使用灰度,nn.Tanh()我至少看到了不错的结果。

1个回答

如果您不将其用于“分类”,则输出将是“连续的”。

您可以在此处遵循几种方法:

  • 这将是最简单的方法,但您可能需要一些后处理来填补行中的漏洞:

    1. 定义一个阈值,使图像二值化;
    2. 重新定义最后一层以输出具有 2 个通道的图像,并通过获取每个像素的最大通道值的索引来定义最终图像(因为这是一个分类问题)
  • 您还可以重新定义您的问题:

PS:从现在开始每次提到“线”实际上是指线段。

鉴于您的图像是一组几何图形,它们都可以分解为线条,并且任何线条都可以用一组 4 个数字来描述,您可以使用 RNN 生成一组线条(点对),之后很容易画出来。

为此,您需要重写您的训练集:

  • 为图像定义线宽
  • 根据该线宽,您可以设置多个可能的线方向(例如,宽度为一个像素,您只能在 0、45、90 135 度的 4 个方向上绘制线)
  • 通过查找这些方向发生变化的点,使用它来查找定义线(起点和终点)的每个点
  • 要将这组点转换为一组线,您可以检查在该间隔内的那个方向上是否有黑色像素。

二进制层问题

你的二进制层实现了一个 Heaveside Step 函数,它将杀死梯度,因为它的导数对于除 x=0 之外的所有值都是 0。在 x=0 中,实际上没有定义导数(极限趋于无穷大)。

因此您的权重无法更新,因此每次前向传递都会过滤具有随机权重的数据,从而对输出造成随机影响。

检查这个答案以了解更多关于为什么我们不使用 Heaveside Step 函数作为神经网络上的激活函数