PyTorch 中的图像梯度 - 用于 WGAN 中的梯度惩罚计算

Gradient of Image in PyTorch - for Gradient Penalty calculation in WGAN

我正在关注此 Github Repo 以了解带有梯度惩罚的 WGAN 实现。

我正在尝试理解以下方法,该方法对梯度惩罚计算进行单元测试。

def test_gradient_penalty(image_shape):
    bad_gradient = torch.zeros(*image_shape)
    bad_gradient_penalty = gradient_penalty(bad_gradient)
    assert torch.isclose(bad_gradient_penalty, torch.tensor(1.))

    image_size = torch.prod(torch.Tensor(image_shape[1:]))
    good_gradient = torch.ones(*image_shape) / torch.sqrt(image_size)
    good_gradient_penalty = gradient_penalty(good_gradient)
    assert torch.isclose(good_gradient_penalty, torch.tensor(0.))

    random_gradient = test_get_gradient(image_shape)
    random_gradient_penalty = gradient_penalty(random_gradient)
    assert torch.abs(random_gradient_penalty - 1) < 0.1

# Now pass tuple argument for image dimenstion of 
# (batch_size, channel, height, width)
test_gradient_penalty((256, 1, 28, 28))

我不明白下面这行

good_gradient = torch.ones(*image_shape) / torch.sqrt(image_size)

在上面的 torch.ones(*image_shape) 只是填充一个 4-D Tensor 填充 1 然后 torch.sqrt(image_size) 只是表示 tensor(28.)

的值

所以,我想了解为什么我需要将 4-D 张量除以 tensor(28.) 以获得 good_gradient

如果我打印 bad_gradient,它将是一个 4-D 张量,如下所示

tensor([[[[0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          ...,
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.],
          [0., 0., 0.,  ..., 0., 0., 0.]]],

          ---
          ---

如果我打印good_gradient,输出将是

tensor([[[[0.0357, 0.0357, 0.0357,  ..., 0.0357, 0.0357, 0.0357],
          [0.0357, 0.0357, 0.0357,  ..., 0.0357, 0.0357, 0.0357],
          [0.0357, 0.0357, 0.0357,  ..., 0.0357, 0.0357, 0.0357],
          ...,
          [0.0357, 0.0357, 0.0357,  ..., 0.0357, 0.0357, 0.0357],
          [0.0357, 0.0357, 0.0357,  ..., 0.0357, 0.0357, 0.0357],
          [0.0357, 0.0357, 0.0357,  ..., 0.0357, 0.0357, 0.0357]]],

          ---
          ---

换行

good_gradient = torch.ones(*image_shape) / torch.sqrt(image_size)

首先,注意 WGAN 中的梯度惩罚项是 =>

(norm(gradient(interpolated)) - 1)^2

对于理想梯度(即良好梯度),该惩罚项将为 0。即良好梯度是其 gradient_penalty 尽可能接近 0 的梯度

这意味着在考虑了梯度的 L2-Norm 之后应该满足以下条件

(norm(gradient(x')) -1)^2 = 0

norm(gradient(x')) = 1

sqrt(Sum(gradient_i^2) ) = 1

现在如果你继续简化上面的(考虑 norm 是如何计算的,见我下面的注释)数学表达式,你最终会得到

good_gradient = torch.ones(*image_shape) / torch.sqrt(image_size)

由于您将 image_shape 作为 (256, 1, 28, 28) 传递 - 所以 torch.sqrt(image_size) 在您的情况下是张量 (28.)

有效地,上面的行将 4-D 张量的每个元素分开,如 [[[[1., 1. ... ]]]] 与缩放张量 (28.)


另外,注意 norm 是如何计算的

torch.norm 在没有额外参数的情况下执行所谓的 Frobenius 范数,它有效地将矩阵重塑为一个长向量并返回其 2 范数。

给定一个 M * N 矩阵,矩阵的 Frobenius 范数定义为矩阵元素平方和的平方根。

Input: mat[][] = [[1, 2], [3, 4]] 
Output: 5.47723 
sqrt(1^2 + 2^2 + 3^2 + 4^2) = sqrt(30) = 5.47723