首页 > 解决方案 > 为什么这个模型在没有手动权重初始化步骤的情况下无法收敛(pytorch 线性回归)

问题描述

我正在尝试创建一个最简单的 1 线性层网络来拟合线性回归。只是为了帮助自己更好地理解 Pytorch 的工作原理。但是,我在模型训练中遇到了一个奇怪的问题。

在我的模型的 init() 方法中,我必须添加一个手动初始化步骤(如下所示),以使模型快速收敛到我的回归函数。(权重值 2、3 是随机数,我可以在这里放任何值,模型仍然会收敛)

self.layer1.weight = torch.nn.Parameter(torch.Tensor([2, 3]))

没有这条线,模型永远不会收敛,训练损失只是在几十万范围内随机波动。有了这条线,它迅速下降到接近 1。

我假设这是因为默认初始权重参数太小,如果我不将它们初始化为远离零。然后我改变了初始值,发现只要我有这条线,收敛总是有效的,我设置的确切值无关紧要。我尝试使用调试器单步执行这一行并使用vars()方法检查self.layer1的属性,唯一改变的是权重,其他一切都保持不变。有人可以解释这里的幕后情况吗?谢谢。

我的整个脚本:

import torch
import numpy as np

class Net(torch.nn.Module):

    def __init__(self, input_dim, output_dim):
        super(Net, self).__init__()
        self.layer1 = torch.nn.Linear(input_dim, output_dim, bias=False)

        # the line below is the strange initialization required to 
        # have the model converge. 
        self.layer1.weight = torch.nn.Parameter(torch.Tensor([2, 3]))

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

# generate data using the linear regression setup y = 5 * x1 + 3 * x2

sample_size = 10000
input_dim = 2
output_dim = 1
epoch = 30
bs = 100

data = np.random.randn(sample_size, 3)
data[:, :2] = data[:, :2] * 100
# add a normal noise term
data[:, 2] = 5 * data[:, 0] + 3 * data[:, 1] + np.random.randn(sample_size)
data = torch.Tensor(data)
train_x = data[:, :input_dim]
train_y = data[:, input_dim]

net = Net(input_dim, output_dim)
criterion = torch.nn.MSELoss()
optimizer = torch.optim.RMSprop(net.parameters(), lr=.01)

for i in range(epoch):

    batch = 0
    while batch * bs < train_x.shape[0]:

        batch_x = train_x[batch * bs : (batch + 1) * bs, :]
        batch_y = train_y[batch * bs : (batch + 1) * bs]

        pred_y = net.forward(batch_x)
        loss = criterion(pred_y, batch_y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        if batch % 100 == 0:
            #print(f"{i} {batch} {loss}")
            print(net.layer1.weight)
        batch += 1

标签: initializationpytorchlinear-regressiongradient

解决方案


快速说明:您的代码无法编译,请修改此行,如下所示:

self.layer1.weight = torch.nn.Parameter(torch.Tensor([[2, 3]]))

无论权重初始化如何,我都无法让您的模型收敛。经过一些实验,我发现将批量大小降低到一个就可以了:

$ python main.py
Parameter containing:
tensor([[0.7388, 0.3678]], requires_grad=True)
Parameter containing:
tensor([[1.7438, 1.0657]], requires_grad=True)
Parameter containing:
tensor([[2.3338, 1.5431]], requires_grad=True)
Parameter containing:
tensor([[2.9008, 1.9784]], requires_grad=True)
Parameter containing:
tensor([[3.2375, 2.1437]], requires_grad=True)
Parameter containing:
tensor([[3.6419, 2.4014]], requires_grad=True)
Parameter containing:
tensor([[4.0652, 2.6458]], requires_grad=True)
Parameter containing:
tensor([[4.5095, 2.7628]], requires_grad=True)
Parameter containing:
tensor([[4.7711, 2.8982]], requires_grad=True)
Parameter containing:
tensor([[4.9131, 2.9768]], requires_grad=True)
Parameter containing:
tensor([[4.9887, 2.9979]], requires_grad=True)

...

推荐阅读