【问题标题】:Weights not updating on my neural net (Pytorch)我的神经网络上的权重没有更新(Pytorch)
【发布时间】:2020-07-23 19:48:33
【问题描述】:

我对神经网络完全陌生,所以我尝试大致遵循一些教程来创建一个神经网络,它可以区分给定的二进制图片是包含白色圆圈还是全黑。因此,我生成了 1000 个大小为 10000 的数组,代表一张 100x100 的图片,其中一半在某处包含一个白色圆圈。我的数据集的生成如下所示:

for i in range(1000):
   image = [0] * (IMAGE_SIZE * IMAGE_SIZE)

   if random() < 0.5:
      dataset.append([image, [[0]]])

   else:
      #inserts circle in image
      #...

      dataset.append([image, [[1]]])

np.random.shuffle(dataset)
np.save("testdataset.npy", dataset)

围绕分类的双重列表是因为网络似乎将该格式作为输出,所以我匹配了它。

现在,由于我对 pytorch 的工作原理并没有任何确切的了解,所以我现在真的不知道代码的哪些部分与解决我的问题相关,哪些不相关。因此,我在下面给出了网络和培训的代码,真的希望有人能向我解释我哪里出错了。如果代码太多,我很抱歉。代码运行没有错误,但如果我在训练前后打印参数,它们并没有以任何方式改变,并且网络总是为每个图像/数组返回一个 0。

IMAGE_SIZE = 100
EPOCHS = 3
BATCH_SIZE = 50
VAL_PCT = 0.1

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(IMAGE_SIZE * IMAGE_SIZE, 64)
        self.fc2 = nn.Linear(64, 64)
        self.fc3 = nn.Linear(64, 64)
        self.fc4 = nn.Linear(64, 1)
        
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = self.fc4(x)
        return F.log_softmax(x, dim = 1)
    
net = Net()
optimizer = optim.Adam(net.parameters(), lr = 0.01)
loss_function = nn.MSELoss()
dataset = np.load("testdataset.npy", allow_pickle = True)

X = torch.Tensor([i[0] for i in dataset]).view(-1, 10000)
y = torch.Tensor([i[1] for i in dataset])

val_size = int(len(X) * VAL_PCT)

train_X = X[:-val_size]
train_y = y[:-val_size]

test_X = X[-val_size:]
test_y = y[-val_size:]

for epoch in range(EPOCHS):
    for i in range(0, len(train_X), BATCH_SIZE):
        batch_X = train_X[i:i + BATCH_SIZE].view(-1, 1, 10000)
        batch_y = train_y[i:i + BATCH_SIZE]

        net.zero_grad()

        outputs = net(batch_X)
        loss = loss_function(outputs, batch_y)
        loss.backward()
        optimizer.step()

【问题讨论】:

  • 我在这个帖子中回答了一个与此类似的问题:stackoverflow.com/questions/62775976/… 如果这没有帮助,您能否提供代码来测试权重是否发生变化?
  • 如果我没看错,你的问题是你的网络只有一个输出权重,但是你应用了 softmax 函数。 softmax 函数将一组数字转换为类似于概率总和为 1 的东西。因此,您的输出将独立于您的输入。您可以在最后一层使用 2 个输出。我认为softmax中的dim必须是2,你编码的方式
  • @Youyoun 我现在读了你的另一个答案并改变了我的比较方式,所以权重确实发生了变化,我只是检查错了——尽管每个输入的网络仍然返回 0。
  • @McLawrence 我的最后一层现在返回 2 个输出,但是,当我尝试使用 output = net(test_X[0].view(-1, 1, 10000)) 测试网络时,结果总是否定的,例如 tensor([[[-0.9464, -0.4913]]]),而实际上它应该是 tensor([[0., 1.]]) .
  • 旁注,我建议你看看这些教程:pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html。他们很好地解释了 pytorch 的工作原理以及机器学习的一些基本概念。

标签: python machine-learning neural-network pytorch


【解决方案1】:

我会推荐使用optimizer.zero_grad() 而不是net.zero_grad(),因为它更常见且事实上的标准。你的训练循环应该是:

for epoch in range(EPOCHS):
    for i in range(0, len(train_X), BATCH_SIZE):
        batch_X = train_X[i:i + BATCH_SIZE].view(-1, 1, 10000)
        batch_y = train_y[i:i + BATCH_SIZE]

        optimizer.zero_grad()

        outputs = net(batch_X)
        loss = loss_function(outputs, batch_y)
        loss.backward()
        optimizer.step()

我建议您阅读一些有关不同损失函数的信息。看来您有分类问题,因为您应该使用 logits(二元分类)或交叉熵(多类)损失。我将对网络和损失函数进行以下更改:

class Net(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(IMAGE_SIZE * IMAGE_SIZE, 64)
        self.fc2 = nn.Linear(64, 64)
        self.fc3 = nn.Linear(64, 64)
        self.fc4 = nn.Linear(64, 1)
        
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.relu(self.fc3(x))
        x = self.fc4(x)
        return x
    
loss_function = nn.BCEWithLogitsLoss()

使用前查看文档:https://pytorch.org/docs/stable/nn.html#bcewithlogitsloss

祝你好运!

【讨论】:

  • If you do net.zero_grad() you do not update the hooks of the optimizer. It should fix your training. 你从哪里得到这些信息的?查看torch.nn.Module's zero_gradtorch.optim.Optimizer's zero_grad 源代码对于单个参数组都是等效的(就像这里的情况一样)。另见this answer
  • @SzymonMaszke,你是对的。我更改了答案以反映它。感谢您的关注。
【解决方案2】:
  1. 首先,使用神经网络来解决这类问题并不理想。神经网络训练高度非线性数据。对于此示例,您可以使用图像的平均强度来找出是否存在白色像素

  2. 然而,一个经典的逻辑回归问题会输出一个从 0 到 1 的值或概率

  3. 当您有多个类并将所有类的总和转换为等于 1 时使用 Softmax 函数

  4. log_softmax 实现:log( exp(x_i) / exp(x).sum() )。在这里,您的输出层仅包含 1 个神经元。 outputs = net(batch_X) 始终为 1。

【讨论】:

    猜你喜欢
    • 2015-05-03
    • 1970-01-01
    • 2020-03-28
    • 2021-08-06
    • 1970-01-01
    • 2018-12-16
    • 2021-06-25
    • 2018-05-11
    • 2020-01-16
    相关资源
    最近更新 更多