PyTorch - normal() 初始化对梯度的影响
PyTorch - Effect of normal() initialization on gradients
假设我有一个神经网络,我在其中使用正态分布初始化,我想使用用于初始化的平均值作为网络参数。
我举个小例子:
import torch
parameter_vector = torch.tensor(range(10), dtype=torch.float, requires_grad=True)
sigma = torch.ones(parameter_vector.size(0), dtype=torch.float)*0.1
init_result = torch.normal(parameter_vector, sigma)
print('requires_grad:', init_result.requires_grad)
print('result: ', init_result)
这导致:
requires_grad: True
result: tensor([ 0.1026, 0.9183, 1.9586, 3.1778, 4.0538, 4.8056, 5.9561,
6.9501, 7.7653, 8.9583])
所以 requires_grad
标志显然是从平均值张量 resp 接管的。 parameter_vector
.
但这是否自动意味着 parameter_vector
将在 init_result
影响最终结果的较大网络中通过 backward()
更新?
特别是 normal()
看起来不像正常操作,因为它涉及随机性。
感谢@iacolippo(请参阅问题下方的评论)问题现在已解决。我只是想通过发布我现在正在使用的代码来补充这一点,所以这可能会对其他人有所帮助。
正如问题中所假设的那样,@iacolippo 也指出,问题中发布的代码不可反向传播:
import torch
parameter_vector = torch.tensor(range(5), dtype=torch.float, requires_grad=True)
print('- initial parameter weights:', parameter_vector)
sigma = torch.ones(parameter_vector.size(0), dtype=torch.float)*0.1
init_result = torch.normal(parameter_vector, sigma)
print('- normal init result requires_grad:', init_result.requires_grad)
print('- normal init vector', init_result)
#print('result: ', init_result)
sum_result = init_result.sum()
sum_result.backward()
print('- summed dummy-loss:', sum_result)
optimizer = torch.optim.SGD([parameter_vector], lr = 0.01, momentum=0.9)
optimizer.step()
print()
print('- parameter weights after update:', parameter_vector)
输出:
- initial parameter weights: tensor([0., 1., 2., 3., 4.], requires_grad=True)
- normal init result requires_grad: True
- normal init vector tensor([-0.0909, 1.1136, 2.1143, 2.8838, 3.9340], grad_fn=<NormalBackward3>)
- summed dummy-loss: tensor(9.9548, grad_fn=<SumBackward0>)
- parameter weights after update: tensor([0., 1., 2., 3., 4.], requires_grad=True)
如您所见,调用 backward()
不会引发错误(请参阅上面评论中的链接问题),但参数也不会通过 SGD-Step 更新。
工作示例 1
一种解决方案是使用此处给出的 formula/trick:https://stats.stackexchange.com/a/342815/133099
x=μ+σ sample(N(0,1))
要存档:
sigma = torch.ones(parameter_vector.size(0), dtype=torch.float)*0.1
init_result = torch.normal(parameter_vector, sigma)
更改为:
dim = parameter_vector.size(0)
sigma = 0.1
init_result = parameter_vector + sigma*torch.normal(torch.zeros(dim), torch.ones(dim))
更改这些行后,代码变得可逆,参数向量在调用 backward()
和 SGD-Step 后得到更新。
更改行的输出:
- initial parameter weights: tensor([0., 1., 2., 3., 4.], requires_grad=True)
- normal init result requires_grad: True
- normal init vector tensor([-0.1802, 0.9261, 1.9482, 3.0817, 3.9773], grad_fn=<ThAddBackward>)
- summed dummy-loss: tensor(9.7532, grad_fn=<SumBackward0>)
- parameter weights after update: tensor([-0.0100, 0.9900, 1.9900, 2.9900, 3.9900], requires_grad=True)
工作示例 2
另一种方法是使用 torch.distributions
(Documentation Link).
这样做上面代码中的相应行必须替换为:
i = torch.ones(parameter_vector.size(0))
sigma = 0.1
m = torch.distributions.Normal(parameter_vector, sigma*i)
init_result = m.rsample()
更改行的输出:
- initial parameter weights: tensor([0., 1., 2., 3., 4.], requires_grad=True)
- normal init result requires_grad: True
- normal init vector tensor([-0.0767, 0.9971, 2.0448, 2.9408, 4.1321], grad_fn=<ThAddBackward>)
- summed dummy-loss: tensor(10.0381, grad_fn=<SumBackward0>)
- parameter weights after update: tensor([-0.0100, 0.9900, 1.9900, 2.9900, 3.9900], requires_grad=True)
从上面的输出中可以看出——使用 torch.distributions
也会产生反向概率代码,其中参数向量在调用 backward()
和 SGD-Step 后得到更新。
我希望这对某人有帮助。
假设我有一个神经网络,我在其中使用正态分布初始化,我想使用用于初始化的平均值作为网络参数。
我举个小例子:
import torch
parameter_vector = torch.tensor(range(10), dtype=torch.float, requires_grad=True)
sigma = torch.ones(parameter_vector.size(0), dtype=torch.float)*0.1
init_result = torch.normal(parameter_vector, sigma)
print('requires_grad:', init_result.requires_grad)
print('result: ', init_result)
这导致:
requires_grad: True
result: tensor([ 0.1026, 0.9183, 1.9586, 3.1778, 4.0538, 4.8056, 5.9561,
6.9501, 7.7653, 8.9583])
所以 requires_grad
标志显然是从平均值张量 resp 接管的。 parameter_vector
.
但这是否自动意味着 parameter_vector
将在 init_result
影响最终结果的较大网络中通过 backward()
更新?
特别是 normal()
看起来不像正常操作,因为它涉及随机性。
感谢@iacolippo(请参阅问题下方的评论)问题现在已解决。我只是想通过发布我现在正在使用的代码来补充这一点,所以这可能会对其他人有所帮助。
正如问题中所假设的那样,@iacolippo 也指出,问题中发布的代码不可反向传播:
import torch
parameter_vector = torch.tensor(range(5), dtype=torch.float, requires_grad=True)
print('- initial parameter weights:', parameter_vector)
sigma = torch.ones(parameter_vector.size(0), dtype=torch.float)*0.1
init_result = torch.normal(parameter_vector, sigma)
print('- normal init result requires_grad:', init_result.requires_grad)
print('- normal init vector', init_result)
#print('result: ', init_result)
sum_result = init_result.sum()
sum_result.backward()
print('- summed dummy-loss:', sum_result)
optimizer = torch.optim.SGD([parameter_vector], lr = 0.01, momentum=0.9)
optimizer.step()
print()
print('- parameter weights after update:', parameter_vector)
输出:
- initial parameter weights: tensor([0., 1., 2., 3., 4.], requires_grad=True)
- normal init result requires_grad: True
- normal init vector tensor([-0.0909, 1.1136, 2.1143, 2.8838, 3.9340], grad_fn=<NormalBackward3>)
- summed dummy-loss: tensor(9.9548, grad_fn=<SumBackward0>)
- parameter weights after update: tensor([0., 1., 2., 3., 4.], requires_grad=True)
如您所见,调用 backward()
不会引发错误(请参阅上面评论中的链接问题),但参数也不会通过 SGD-Step 更新。
工作示例 1
一种解决方案是使用此处给出的 formula/trick:https://stats.stackexchange.com/a/342815/133099
x=μ+σ sample(N(0,1))
要存档:
sigma = torch.ones(parameter_vector.size(0), dtype=torch.float)*0.1
init_result = torch.normal(parameter_vector, sigma)
更改为:
dim = parameter_vector.size(0)
sigma = 0.1
init_result = parameter_vector + sigma*torch.normal(torch.zeros(dim), torch.ones(dim))
更改这些行后,代码变得可逆,参数向量在调用 backward()
和 SGD-Step 后得到更新。
更改行的输出:
- initial parameter weights: tensor([0., 1., 2., 3., 4.], requires_grad=True)
- normal init result requires_grad: True
- normal init vector tensor([-0.1802, 0.9261, 1.9482, 3.0817, 3.9773], grad_fn=<ThAddBackward>)
- summed dummy-loss: tensor(9.7532, grad_fn=<SumBackward0>)
- parameter weights after update: tensor([-0.0100, 0.9900, 1.9900, 2.9900, 3.9900], requires_grad=True)
工作示例 2
另一种方法是使用 torch.distributions
(Documentation Link).
这样做上面代码中的相应行必须替换为:
i = torch.ones(parameter_vector.size(0))
sigma = 0.1
m = torch.distributions.Normal(parameter_vector, sigma*i)
init_result = m.rsample()
更改行的输出:
- initial parameter weights: tensor([0., 1., 2., 3., 4.], requires_grad=True)
- normal init result requires_grad: True
- normal init vector tensor([-0.0767, 0.9971, 2.0448, 2.9408, 4.1321], grad_fn=<ThAddBackward>)
- summed dummy-loss: tensor(10.0381, grad_fn=<SumBackward0>)
- parameter weights after update: tensor([-0.0100, 0.9900, 1.9900, 2.9900, 3.9900], requires_grad=True)
从上面的输出中可以看出——使用 torch.distributions
也会产生反向概率代码,其中参数向量在调用 backward()
和 SGD-Step 后得到更新。
我希望这对某人有帮助。