【问题标题】:Neural network learning to sum two numbers神经网络学习对两个数字求和
【发布时间】:2021-04-26 00:32:57
【问题描述】:

我正在学习 Pytorch,我正在尝试实现一个非常简单的网络,该网络接受长度为 2 的输入,即平面中的一个点,旨在学习其组件的总和。

原则上,网络应该只学习一个权重矩阵 W = [1.,1.] 和零偏差的线性层,所以我希望训练误差非常低。但是,我不明白为什么我没有按预期得到这个。

我写的代码是这样的:

import torch
from torch import nn, optim
import numpy as np

device = torch.device("cuda:0" if      
torch.cuda.is_available() else "cpu")

N = 1000  # number of samples
D = 2  # input dimension
C = 1  # output dimension

def model(z):
  q = z[:,0]
  p = z[:,1]
  return q+p

X = torch.rand(N, D,requires_grad=True).to(device)
y = model(X)

lr = 1e-2 #Learning rate

Rete = nn.Sequential(nn.Linear(D, C))
Rete.to(device) #Convert to CUDA

criterion = torch.nn.MSELoss()
optimizer = torch.optim.Adam(Rete.parameters(), lr=lr)

for t in range(5000):

    y_pred = Rete(X)
    loss = criterion(y_pred, y)
    print("[EPOCH]: %i, [LOSS]: %.6f" % (t, loss.item()))    
    optimizer.zero_grad()
    optimizer.step()

【问题讨论】:

  • 你没有反向传播,即,做loss.backward()。另外,我相信optimizer.zero_grad() 应该在optimizer.step() 之后。

标签: deep-learning neural-network pytorch linear-regression


【解决方案1】:

有两个问题。

第一个问题是你忘了反向传播损失:

optimizer.zero_grad()
loss.backward() # you forgot this step
optimizer.step()

重要的是optimizer.zero_grad() 不能放在loss.backwards()optimizer.step() 之间,否则您将在执行梯度下降步骤之前重置梯度。一般而言,建议将optimizer.zero_grad() 放在循环的最开头,或者在您调用optimizer.step() 之后:

loss.backward()
optimizer.step()
optimizer.zero_grad() # this should go right after .step(), or at the very beginning of your training loop

即使在此更改之后,您仍会注意到您的模型仍未收敛:

[EPOCH]: 0, [LOSS]: 0.232405
[EPOCH]: 1, [LOSS]: 0.225010
[EPOCH]: 2, [LOSS]: 0.218473
...
[EPOCH]: 4997, [LOSS]: 0.178762
[EPOCH]: 4998, [LOSS]: 0.178762
[EPOCH]: 4999, [LOSS]: 0.178762

这导致我们遇到第二个问题,输出的形状 (y_pred) 和标签 (y) 的形状不匹配。 y_pred 的形状为 (N, C),但 y 的形状为 (N,)。要解决此问题,只需重塑 y 以匹配 y_pred

y = y.reshape(-1, C)

那么我们的模型就会收敛:

[EPOCH]: 0, [LOSS]: 1.732189
[EPOCH]: 1, [LOSS]: 1.680017
[EPOCH]: 2, [LOSS]: 1.628712
...
[EPOCH]: 4997, [LOSS]: 0.000000
[EPOCH]: 4998, [LOSS]: 0.000000
[EPOCH]: 4999, [LOSS]: 0.000000

这两个错误都会默默地失败,这使得调试它们变得困难。不幸的是,在进行机器学习时很容易遇到这类错误。我强烈建议您阅读此blog post,了解训练神经网络时的最佳实践,以最大程度地降低静默错误的风险。


完整代码:

import torch
import numpy as np

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

N = 1000  # number of samples
D = 2  # input dimension
C = 1  # output dimension

X = torch.rand(N, D).to(device)  # (N, D)
y = torch.sum(X, axis=-1).reshape(-1, C)  # (N, C)

lr = 1e-2  # Learning rate

model = torch.nn.Sequential(torch.nn.Linear(D, C))  # model
model.to(device)

criterion = torch.nn.MSELoss()  # loss function
optimizer = torch.optim.Adam(model.parameters(), lr=lr)  # optimizer

for epoch in range(1000):
    y_pred = model(X)  # forward step
    loss = criterion(y_pred, y)  # compute loss
    loss.backward()  # backprop (compute gradients)
    optimizer.step()  # update weights (gradient descent step)
    optimizer.zero_grad()  # reset gradients
    if epoch % 50 == 0:
        print(f"[EPOCH]: {epoch}, [LOSS]: {loss.item():.6f}")

【讨论】:

  • 非常感谢,正如您从我的错误中看到的那样,我对这个设置很陌生,但我正在努力学习理论和例子,我认为这是最好的方法。
  • @Dadeslam 完全同意,祝你好运!
猜你喜欢
  • 2016-07-11
  • 2020-05-15
  • 2016-05-01
  • 1970-01-01
  • 2016-05-25
  • 2019-03-15
  • 2011-08-17
  • 2020-10-29
  • 1970-01-01
相关资源
最近更新 更多