PyTorch 中的权重标准化

Moh*_*mba 6 python pytorch

本文介绍了一种重要的权重归一化技术,并且很早就被包含在 PyTorch 中,如下:

    from torch.nn.utils import weight_norm
    weight_norm(nn.Conv2d(in_channles, out_channels))
Run Code Online (Sandbox Code Playgroud)

从我了解到的文档weight_norm中,每次传递之前都会重新参数化forward()。但我不确定当所有内容都在内部运行with torch.no_grad()并且模型设置为eval()模式时,这种重新参数化是否也会在推理过程中发生。

有人可以帮我知道是否weight_norm仅在训练期间或在上述推理模式期间有效吗?

谢谢

Moh*_*mba 10

我终于弄清楚了问题所在。

批量归一化在训练期间学习两个参数并使用它们进行推理。因此,有必要使用eval()告诉不要进一步修改它们来改变其行为。

然后我仔细检查了权重归一化纸,发现它是“本质上确定性的”。它只是将原始权重向量解耦为两个量的乘积,如下所示。

w = g . v
Run Code Online (Sandbox Code Playgroud)

显然,要么使用 LHS 来计算输出,要么使用 RHS 来计算输出,这并不重要。然而,通过将其解耦为两个向量并将它们传递给优化器并删除w参数,可以实现更好的训练。有关原因,请参阅对事情进行了很好描述的论文。

因此,在测试过程中是否取消体重归一化并不重要。为了验证这一点,我尝试了以下小代码。

import torch
import torch.nn as nn
from torch.nn.utils import weight_norm as wn
from torch.nn.utils import remove_weight_norm as wnr

# define the model 'm'
m = wn(nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, padding=1, bias=True))

ip = torch.rand(1,1,5,5)
target = torch.rand(1,1,5,5)
l1 = torch.nn.L1Loss()
optimizer = torch.optim.Adam(m.parameters())



# begin training
for _ in range(5):
    out = m(ip)
    loss = l1(out,target)
    loss.backward()
    optimizer.step()

with torch.no_grad():
    m.eval()
    print('\no/p after training with wn: {}'.format(m(ip)))
    wnr(m)
    print('\no/p after training without wn: {}'.format(m(ip)))

# begin testing
m2 = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3,padding=1, bias=True)
m2.load_state_dict(m.state_dict())

with torch.no_grad():
    m2.eval()
    out = m2(ip)
    print('\nOutput during testing and without weight_norm: {}'.format(out))
Run Code Online (Sandbox Code Playgroud)

输出如下,

o/p after training with wn: 
tensor([[[[0.0509, 0.3286, 0.4612, 0.1795, 0.0307],
          [0.1846, 0.3931, 0.5713, 0.2909, 0.4026],
          [0.1716, 0.5971, 0.4297, 0.0845, 0.6172],
          [0.2938, 0.2389, 0.4478, 0.5828, 0.6276],
          [0.1423, 0.2065, 0.5024, 0.3979, 0.3127]]]])

o/p after training without wn: 
tensor([[[[0.0509, 0.3286, 0.4612, 0.1795, 0.0307],
          [0.1846, 0.3931, 0.5713, 0.2909, 0.4026],
          [0.1716, 0.5971, 0.4297, 0.0845, 0.6172],
          [0.2938, 0.2389, 0.4478, 0.5828, 0.6276],
          [0.1423, 0.2065, 0.5024, 0.3979, 0.3127]]]])

Output during testing and without weight_norm: 
tensor([[[[0.0509, 0.3286, 0.4612, 0.1795, 0.0307],
          [0.1846, 0.3931, 0.5713, 0.2909, 0.4026],
          [0.1716, 0.5971, 0.4297, 0.0845, 0.6172],
          [0.2938, 0.2389, 0.4478, 0.5828, 0.6276],
          [0.1423, 0.2065, 0.5024, 0.3979, 0.3127]]]])
Run Code Online (Sandbox Code Playgroud)

请注意,所有值都完全相同,因为仅发生了重新参数化。

关于,

然后我使用 C++ 代码和 libtorch 测试了两个模型。但结果并不相同。

请参阅https://github.com/pytorch/pytorch/issues/21275,其中报告了 TorchScript 的错误。

并关于,

我想知道weight_norm 在推理中起什么作用?有用吗?

答案是它什么也没做。你做x * 2x * (1+1)不重要。它没有什么用,但也没有坏处。所以最好把它去掉。