由于StackOverflow不支持LaTeX,因此我已在Data Science StackExchange网站上发布了此问题。在此处链接它是因为该站点可能更合适。
使用正确渲染的LaTeX的问题在这里:https://datascience.stackexchange.com/questions/48062/pytorch-does-not-seem-to-be-optimizing-correctly
我的想法是我正在考虑不同相位的正弦波之和。在间隔[0,2pi]中以一定的采样率s
对波进行采样。我需要以这样一种方式选择相位,使任何采样点处的波的总和最小化。
下面是Python代码。优化似乎没有正确计算。
import numpy as np
import torch
def phaseOptimize(n, s = 48000, nsteps = 1000):
learning_rate = 1e-3
theta = torch.zeros([n, 1], requires_grad=True)
l = torch.linspace(0, 2 * np.pi, s)
t = torch.stack([l] * n)
T = t + theta
for jj in range(nsteps):
loss = T.sin().sum(0).pow(2).sum() / s
loss.backward()
theta.data -= learning_rate * theta.grad.data
print('Optimal theta: \n\n', theta.data)
print('\n\nMaximum value:', T.sin().sum(0).abs().max().item())
下面是示例输出。
phaseOptimize(5, nsteps=100)
Optimal theta:
tensor([[1.2812e-07],
[1.2812e-07],
[1.2812e-07],
[1.2812e-07],
[1.2812e-07]], requires_grad=True)
Maximum value: 5.0
我认为这与广播有关
T = t + theta
和/或我计算损失函数的方式。
验证优化不正确的一种方法是简单地对数组$ \ theta_1,\ dots,\ theta_n $的随机值求损失函数,例如均匀分布在$ [0,2 \ pi] $中。在这种情况下,最大值几乎总是比phaseOptimize()
报告的最大值低得多。实际上,要简单得多是考虑$ n = 2 $的情况,并简单地将$ \ theta_1 = 0 $和$ \ theta_2 = \ pi $求值。在这种情况下,我们得到:
phaseOptimize(2, nsteps=100)
Optimal theta:
tensor([[2.8599e-08],
[2.8599e-08]])
Maximum value: 2.0
另一方面,
theta = torch.FloatTensor([[0], [np.pi]])
l = torch.linspace(0, 2 * np.pi, 48000)
t = torch.stack([l] * 2)
T = t + theta
T.sin().sum(0).abs().max().item()
产生
3.2782554626464844e-07
答案 0 :(得分:2)
您必须在循环内移动计算T
,否则它将始终具有相同的常数值,因此常数损失不变。
另一件事是将theta
初始化为索引处的不同值,否则由于问题的对称性,每个索引的梯度都相同。
另一件事是,您需要将梯度设为零,因为backward
只是对其进行累加。
这似乎可行:
def phaseOptimize(n, s = 48000, nsteps = 1000):
learning_rate = 1e-1
theta = torch.zeros([n, 1], requires_grad=True)
theta.data[0][0] = 1
l = torch.linspace(0, 2 * np.pi, s)
t = torch.stack([l] * n)
for jj in range(nsteps):
T = t + theta
loss = T.sin().sum(0).pow(2).sum() / s
loss.backward()
theta.data -= learning_rate * theta.grad.data
theta.grad.zero_()
答案 1 :(得分:1)
您被PyTorch和数学都咬了。首先,您需要
theta.grad = None
步骤之前设置backward
来缩小渐变。否则,梯度会累积,而不是覆盖以前的梯度T
。 PyTorch不是象征性的,与TensorFlow不同,T = t + theta
表示“ T等于当前t
和当前theta
的总和”,而不是“ T等于t
和{{ 1}},无论将来任何时候它们的价值如何。” 使用这些修复程序,您将获得以下代码:
theta
由于数学问题,它仍然无法按预期工作。
很容易看出损失函数的最小值是def phaseOptimize(n, s = 48000, nsteps = 1000):
learning_rate = 1e-3
theta = torch.zeros(n, 1, requires_grad=True)
l = torch.linspace(0, 2 * np.pi, s)
t = torch.stack([l] * n)
T = t + theta
for jj in range(nsteps):
T = t + theta
loss = T.sin().sum(0).pow(2).sum() / s
theta.grad = None
loss.backward()
theta.data -= learning_rate * theta.grad.data
T = t + theta
print('Optimal theta: \n\n', theta.data)
print('\n\nMaximum value:', T.sin().sum(0).abs().max().item())
也均匀地分布在theta
上。问题在于您正在将参数初始化为[0, 2pi)
,这将导致所有这些值相等(这是等距的两极!)。由于您的损失函数相对于torch.zeros
的排列是对称的,因此计算出的梯度是相等的,并且梯度下降算法永远无法“区分它们”。用更多的数学术语来说,您不够幸运地无法准确地在鞍点上初始化算法,因此它无法继续。如果添加任何噪音,它将收敛。例如,
theta