用PyTorch训练的神经网络输出每个输入的平均值

2024-09-30 10:36:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我使用PyTorch来让我的神经网络识别来自MNIST database的数字

import torch
import torchvision

我想实现一个非常简单的设计,类似于3Blue1Brown's video series about neural networks中所示的设计。以下设计特别实现了1.6%的错误率

class Net(torch.nn.Module):

    def __init__(self):
        super(Net, self).__init__()
        self.layer1 = torch.nn.Linear(784, 800)
        self.layer2 = torch.nn.Linear(800, 10)

    def forward(self, x):
        x = torch.sigmoid(self.layer1(x))
        x = torch.sigmoid(self.layer2(x))
        return x

这些数据是使用torchvision收集的,并以小批量组织,每个小批量包含32幅图像

batch_size = 32
training_set = torchvision.datasets.MNIST("./", download=True, transform=torchvision.transforms.ToTensor())
training_loader = torch.utils.data.DataLoader(training_set, batch_size=32)

我使用均方误差作为损失函数,使用学习率为0.001的随机梯度下降作为优化算法

net = Net()
loss_function = torch.nn.MSELoss()
optimizer = torch.optim.SGD(net.parameters(), lr=0.001)

最后,使用以下代码对网络进行培训和保存:

for images, labels in training_loader:
    optimizer.zero_grad()
    for i in range(batch_size):
        output = net(torch.flatten(images[i]))
        desired_output = torch.tensor([float(j == labels[i]) for j in range(10)])
        loss = loss_function(output, desired_output)
        loss.backward()
    optimizer.step()
torch.save(net.state_dict(), "./trained_net.pth")

但是,以下是一些测试图像的输出:

tensor([0.0978, 0.1225, 0.1018, 0.0961, 0.1022, 0.0885, 0.1007, 0.1077, 0.0994,
        0.1081], grad_fn=<SigmoidBackward>)
tensor([0.0978, 0.1180, 0.1001, 0.0929, 0.1006, 0.0893, 0.1010, 0.1051, 0.0978,
        0.1067], grad_fn=<SigmoidBackward>)
tensor([0.0981, 0.1227, 0.1018, 0.0970, 0.0979, 0.0908, 0.1001, 0.1092, 0.1011,
        0.1088], grad_fn=<SigmoidBackward>)
tensor([0.1061, 0.1149, 0.1037, 0.1001, 0.0957, 0.0919, 0.1044, 0.1022, 0.0997,
        0.1052], grad_fn=<SigmoidBackward>)
tensor([0.0996, 0.1137, 0.1005, 0.0947, 0.0977, 0.0916, 0.1048, 0.1109, 0.1013,
        0.1085], grad_fn=<SigmoidBackward>)
tensor([0.1008, 0.1154, 0.0986, 0.0996, 0.1031, 0.0952, 0.0995, 0.1063, 0.0982,
        0.1094], grad_fn=<SigmoidBackward>)
tensor([0.0972, 0.1235, 0.1013, 0.0984, 0.0974, 0.0907, 0.1032, 0.1075, 0.1001,
        0.1080], grad_fn=<SigmoidBackward>)
tensor([0.0929, 0.1258, 0.1016, 0.0978, 0.1006, 0.0889, 0.1001, 0.1068, 0.0986,
        0.1024], grad_fn=<SigmoidBackward>)
tensor([0.0982, 0.1207, 0.1040, 0.0990, 0.0999, 0.0910, 0.0980, 0.1051, 0.1039,
        0.1078], grad_fn=<SigmoidBackward>)

如您所见,网络似乎接近一种状态,每个输入的答案是:

[0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]

这种神经网络并不比猜测更好。我的设计或代码哪里出错了


Tags: selfoutputsizenetbatchtrainingnntorch
1条回答
网友
1楼 · 发布于 2024-09-30 10:36:27

以下几点对您很有用:

  • 乍一看,你的模型没有学习,因为你的预测和随机猜测一样好。第一步是监控你的损失,在这里你只有一个单一的纪元。至少您可以根据看不见的数据评估您的模型:

    validation_set = torchvision.datasets.MNIST('./', 
        download=True, train=False, transform=T.ToTensor())
    
    validation_loader = DataLoader(validation_set, batch_size=32)
    
  • 您正在使用MSE损失(L2范数)来训练分类任务,该任务是not the right tool for this kind of task。您可以使用负对数似然。PyTorch提供了^{},其中包括一个模块中的对数softmax和负对数似然损失。可以通过添加以下内容来实现此更改:

    loss_function = nn.CrossEntropyLoss()
    

    并在应用loss_function见下文)时使用正确的目标形状。由于损失函数将应用log softmax,因此您的模型输出上不应具有激活函数

  • 如果将sigmoid用作激活函数,则中间非线性将更好地用作ReLUsee related post)。乙状结肠更适合于二元分类任务。同样,由于我们使用的是nn.CrossEntropyLoss,我们必须删除layer2之后的激活

    class Net(torch.nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.flatten = nn.Flatten()
            self.layer1 = torch.nn.Linear(784, 800)
            self.layer2 = torch.nn.Linear(800, 10)
    
        def forward(self, x):
            x = self.flatten(x)
            x = torch.relu(self.layer1(x))
            x = self.layer2(x)
            return x
    
  • 不那么关键的一点是,您可以推断出整个批次的估计值,而不是一次一个元素地遍历每个批次。一个历元的典型训练循环如下所示:

    for images, labels in training_loader:
        optimizer.zero_grad()
        output = net(images)
        loss = loss_function(output, labels)
        loss.backward()
        optimizer.step()
    

通过这些类型的修改,您可以期望在单个历元后获得大约80%的验证

相关问题 更多 >

    热门问题