【问题标题】:Two-Layer Neural Network in PyTorch does not ConvergePyTorch 中的两层神经网络不收敛
【发布时间】:2019-04-13 14:19:12
【问题描述】:

问题

我正在尝试使用不同的方法(TensorFlow、PyTorch 和从头开始)实现 2 层神经网络,然后根据 MNIST 数据集比较它们的性能。

我不确定自己犯了什么错误,但在 PyTorch 中准确率只有 10% 左右,这基本上是随机猜测。我认为权重可能根本没有更新。

请注意,我有意使用 TensorFlow 提供的数据集,以通过 3 种不同的方法使我使用的数据保持一致,以便进行准确的比较。

from tensorflow.examples.tutorials.mnist import input_data
import torch

class Net(torch.nn.Module):
    def __init__(self):
      super(Net, self).__init__()
      self.fc1 =  torch.nn.Linear(784, 100)
      self.fc2 =  torch.nn.Linear(100, 10)

    def forward(self, x):
      # x -> (batch_size, 784)
      x = torch.relu(x)
      # x -> (batch_size, 10)
      x = torch.softmax(x, dim=1)
      return x

net = Net()
net.zero_grad()
Loss = torch.nn.CrossEntropyLoss()
optimizer =  torch.optim.SGD(net.parameters(), lr=0.01)

for epoch in range(1000):  # loop over the dataset multiple times

    batch_xs, batch_ys = mnist_m.train.next_batch(100)
    # convert to appropriate settins
    # note the input to the linear layer should be (n_sample, n_features)
    batch_xs = torch.tensor(batch_xs, requires_grad=True)
    # batch_ys -> (batch_size,)
    batch_ys = torch.tensor(batch_ys, dtype=torch.int64)

    # forward
    # output -> (batch_size, 10)
    output = net(batch_xs)
    # result -> (batch_size,)
    result = torch.argmax(output, dim=1)
    loss = Loss(output, batch_ys)

    # backward
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

【问题讨论】:

    标签: deep-learning pytorch


    【解决方案1】:

    这里的问题是你没有应用你的全连接层fc1fc2

    您的forward() 目前看起来像:

    def forward(self, x):
        # x -> (batch_size, 784)
        x = torch.relu(x)
        # x -> (batch_size, 10)
        x = torch.softmax(x, dim=1)
        return x
    

    所以如果你把它改成:

    def forward(self, x):
        # x -> (batch_size, 784)
        x = self.fc1(x)             # added layer fc1
        x = torch.relu(x)  
    
        # x -> (batch_size, 10)
        x = self.fc2(x)             # added layer fc2
        x = torch.softmax(x, dim=1)
        return x
    

    它应该可以工作。

    关于 Umang Guptas 的回答:在我看来,在调用 backward() 之前调用 zero_grad(),就像 Mr.Robot 所做的那样,就可以了。这应该不是问题。


    编辑:

    所以我做了一个简短的测试 - 我将迭代设置为从 100010000 以查看更大的图景,如果它真的在减少。 (当然我也将数据加载到mnist_m,因为这不包含在您发布的代码中)

    我在代码中添加了打印条件:

    if epoch % 1000 == 0:
        print('Epoch', epoch, '- Loss:', round(loss.item(), 3))
    

    1000 迭代打印一次损失:

    Epoch 0 - Loss: 2.305
    Epoch 1000 - Loss: 2.263
    Epoch 2000 - Loss: 2.187
    Epoch 3000 - Loss: 2.024
    Epoch 4000 - Loss: 1.819
    Epoch 5000 - Loss: 1.699
    Epoch 6000 - Loss: 1.699
    Epoch 7000 - Loss: 1.656
    Epoch 8000 - Loss: 1.675
    Epoch 9000 - Loss: 1.659
    

    使用 PyTorch 0.4.1 版测试

    所以你可以看到随着 forward() 的改变,网络现在正在学习,其余的代码我保持不变。

    祝你好运!

    【讨论】:

    • 在步骤之前我不知道你可以zero_grad。谢谢!
    • @UmangGupta 没问题,因为在调用backward() 时会创建新的渐变。因此,您提出的两个版本实际上是等效的,因为循环 (after the loop is before the loop :-) 。这个顺序不起作用:backward-> zero_grad -> step,因为在执行 step 时梯度确实为零。希望这对你有意义! :)
    • 我认为 zero_grad 会清除计算图,因此后退将无效。我现在很困惑 zero_grad 实际上做了什么。
    • @UmangGupta 每次反向传播时都会累积梯度值,因此optimizer.zero_grad() 尝试将先前累积的梯度值归零,您可以获得实际梯度而不是历史总和。您可以查看autograd doc 了解更多信息。
    猜你喜欢
    • 1970-01-01
    • 2021-05-02
    • 2012-03-03
    • 2016-05-13
    • 2018-12-15
    • 2019-02-20
    • 2016-05-13
    • 1970-01-01
    • 2016-07-10
    相关资源
    最近更新 更多