【问题标题】:Weak optimizers in PytorchPytorch 中的弱优化器
【发布时间】:2020-08-31 04:57:24
【问题描述】:

考虑一个简单的线拟合a * x + b = x,其中ab 是优化后的参数,x 是由下式给出的观察向量

import torch
X = torch.randn(1000,1,1)

您可以立即看到确切的解决方案是a=1b=0 任何x,并且可以很容易地找到它:

import numpy as np
np.polyfit(X.numpy().flatten(), X.numpy().flatten(), 1)

我现在正在尝试通过 PyTorch 中的梯度下降来找到这个解决方案,其中均方误差用作优化标准。

import matplotlib.pyplot as plt
import numpy as np

import torch
import torch.nn as nn
from torch.optim import Adam, SGD, Adagrad, ASGD 

X = torch.randn(1000,1,1) # Sample data

class SimpleNet(nn.Module): # Trivial neural network containing two weights
    def __init__(self):
        super(SimpleNet, self).__init__()
        self.f1 = nn.Linear(1,1)

    def forward(self, x):
        x = self.f1(x)
        return x

# Testing default setting of 3 basic optimizers

K = 500
net = SimpleNet() 
optimizer = Adam(params=net.parameters())
Adam_losses = []
optimizer.zero_grad()   # zero the gradient buffers
for k in range(K):
    for b in range(1): # single batch
        loss = torch.mean((net.forward(X[b,:,:]) - X[b,:, :])**2)
        loss.backward()
        optimizer.step()
        Adam_losses.append(float(loss.detach()))

net = SimpleNet()
optimizer = SGD(params=net.parameters(), lr=0.0001)
SGD_losses = []
optimizer.zero_grad()   # zero the gradient buffers
for k in range(K):
    for b in range(1): # single batch
        loss = torch.mean((net.forward(X[b,:,:]) - X[b,:, :])**2)
        loss.backward()
        optimizer.step()
        SGD_losses.append(float(loss.detach()))

net = SimpleNet()     
optimizer = Adagrad(params=net.parameters())
Adagrad_losses = []
optimizer.zero_grad()   # zero the gradient buffers
for k in range(K):
    for b in range(1): # single batch
        loss = torch.mean((net.forward(X[b,:,:]) - X[b,:, :])**2)
        loss.backward()
        optimizer.step()
        Adagrad_losses.append(float(loss.detach()))

损失演化方面的训练进度可以表示为

令我惊讶的是,默认设置下算法的收敛速度非常慢。因此我有两个问题:

1) 是否有可能纯粹通过一些 Pytorch 优化器来实现任意小错误(损失)?由于损失函数是凸的,所以肯定是可能的,但是,我无法弄清楚如何使用 PyTorch 实现这一点。请注意,上述 3 个优化器无法做到这一点 - 查看 20000 次迭代的对数规模损失进度:

2) 我想知道优化器如何在复杂示例中正常工作,即使在这个极其简单的示例中也不能正常工作。或者(这是第二个问题)我错过了他们上面的应用程序有什么问题吗?

【问题讨论】:

    标签: optimization pytorch gradient-descent convergence


    【解决方案1】:

    你打电话给zero_grad的地方打错了。在每个时期,梯度被添加到前一个并反向传播。这使得损失在接近时发生振荡,但之前的梯度再次将其从解决方案中抛出。

    下面的代码可以轻松完成任务:

    import torch
    
    X = torch.randn(1000,1,1)
    
    net = SimpleNet()
    optimizer = Adam(params=net.parameters())
    for epoch in range(EPOCHS):
        optimizer.zero_grad()  # zero the gradient buffers
        loss = torch.mean((net.forward(X) - X) ** 2)
        if loss < 1e-8:
            print(epoch, loss)
            break
        loss.backward()
        optimizer.step()
    

    1) 是否有可能纯粹通过 一些 Pytorch 优化器的手段?

    是的,大约 1500 个 epoch 就可以达到上面的精度,你可以降低到机器的精度(在这种情况下是浮点数)

    2) 我想知道优化器如何在复杂的环境中正常工作 示例,即使在这个极其简单的情况下它们也不能很好地工作 例子。

    目前,在网络优化方面,我们没有比一阶方法更好的方法(至少广泛传播)。使用这些是因为对于高阶方法,计算梯度比 Hessians 快得多。复杂的非凸函数可能有很多最小值来完成我们交给它的任务,本身不需要全局最小值(尽管在某些情况下它们可能,请参阅this paper)。

    【讨论】:

    • 太好了,谢谢你的回答。用 zero_grad 的错误放置来解释我的错误完全回答了我的问题。
    • 将保留答案,也许它会对未来的读者有用。
    猜你喜欢
    • 2019-01-02
    • 1970-01-01
    • 2020-12-19
    • 1970-01-01
    • 2021-12-03
    • 1970-01-01
    • 2022-12-11
    • 2022-06-19
    • 2019-12-05
    相关资源
    最近更新 更多