【问题标题】:Multiple parameters recovery using Deep Learning使用深度学习恢复多参数
【发布时间】:2022-01-18 00:36:42
【问题描述】:

作为我实际研究问题的简化版本,假设我有一个二阶多项式函数 y = ax^2 + bx + c,我想使用深度神经网络给定变量 x 和函数 y 的值来预测参数 a、b 和 c。变量 x 和参数 a,b,c 是从 [0,1] 范围内的均匀分布中提取的。

当我尝试使用最常用的不同架构、成本函数和超参数组合来训练网络时,我总是遇到同样的问题:训练和测试损失迅速收敛到显着高于 0 的值,然后开始波动以一种奇怪的方式并且预测不准确(参见数字作为一般示例,b 的预测相似,c 略好但仍不令人满意)。即使我设置了更高的动量或更低的学习率,也会发生这种情况。此外,如果我尝试一次恢复一个参数,我也会遇到同样的问题。

例如,这是我在第一次测试中使用的 PyTorch 代码(4 层,前 3 层,然后是 ReLU、MSELoss、RMSprop 优化器,学习率 = 0.001,动量为 0.9)。

class PRNet(nn.Module):
    def __init__(self, input_size, output_size):
        super(PRNet, self).__init__()
        self.input_size = input_size
        self.fc1   = nn.Linear(self.input_size, 32)
        self.relu1 = nn.ReLU()
        self.fc2   = nn.Linear(32, 64)
        self.relu2 = nn.ReLU()
        self.fc3   = nn.Linear(64, 64)
        self.relu3 = nn.ReLU()
        self.fc4   = nn.Linear(64, output_size)

    def forward(self, x):
        output = self.fc1(x)
        output = self.relu1(output)
        output = self.fc2(output)
        output = self.relu2(output)
        output = self.fc3(output)
        output = self.relu3(output)
        output = self.fc4(output)
        return output

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

var_x    = np.random.rand(100000)
pars_abc = np.random.rand(3, 100000)
func_y   = pars[0]*var**2 + pars[1] * var + pars[2]

data = np.vstack((var_x, func_y)).T
parameters = pars_abc.T

X = torch.Tensor(data).to(device).float()
y = torch.Tensor(parameters).to(device).float()

train_size       = int(0.8 * len(data))
batch_size       = 100
train_dataset    = TensorDataset(X[:train_size], y[:train_size])
train_dataloader = DataLoader(train_dataset, batch_size=batch_size, shuffle=False)

prnet = PRNet(X.shape[1], 3).to(device)

loss_function = nn.MSELoss()
optimizer = torch.optim.RMSprop(prnet.parameters(), lr=1e-4, momentum=0.9)

num_epochs = 25

for epoch in range(0, num_epochs):
    print(f'Starting epoch {epoch+1}')
    current_loss = 0.0
    
    for i, batch in enumerate(train_dataloader, 0):
        inputs, targets = batch

        optimizer.zero_grad()

        outputs = prnet(inputs)
        test_outputs = prnet(X[train_size:].to(device))
       
        train_loss = loss_function(outputs, targets)
        test_loss  = loss_function(test_outputs, y[train_size:])

        train_loss_plot[epoch,i] = train_loss.item()
        test_loss_plot[epoch,i]  = test_loss.item()

        train_loss.backward()
        optimizer.step()

此问题的原因可能是什么?特征不够有代表性吗?我需要更适合这个问题的自定义损失吗?

【问题讨论】:

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


    【解决方案1】:

    在训练期间,当模型的损失开始波动时,出现这种模式的最可能原因是权重达到所需值的学习率很高。 p>

    考虑这个例子。假设在您的模型中,初始化为 0.1 的参数(权重)需要达到 0.00423 的值,并且学习率设置为 0.001。

    现在,让我们假设参数在经过几个 epoch 的训练后达到了 0.004 的值。梯度下降将尝试增加值以使其等于目标值,但由于学习率最多只有 3 位小数,参数值现在将变为 0.005。由于该值现在已增加,梯度下降将尝试减小该值,这会将参数值更改回 0.004,从而开始波动模式

    要解决这个问题,使用小的学习率将无济于事。因为如果您使用较小的学习率,那么模型将学习得太慢并且可能根本不会收敛。您可能正在寻找一种在训练中使用可变学习率策略的方法。使用这样的策略,您可以一开始就使用较大的学习率,以便模型学习得更快。之后,当模型参数接近目标值时,学习率应该自动降低,以使参数尽可能接近目标。这些策略称为学习率调度程序

    PyTorch 中有几个函数可让您使用您选择的学习率调度程序。您可以在他们的文档中查找它们。

    我建议你使用 Reduce LR on Plateau 调度程序。它会让你设置一个阈值和一个因素。每当您的模型损失没有改善超过指定的时期数阈值时,它就会降低学习率。

    https://pytorch.org/docs/stable/generated/torch.optim.lr_scheduler.ReduceLROnPlateau.html#torch.optim.lr_scheduler.ReduceLROnPlateau

    【讨论】:

    • 非常感谢!我不知道可变学习率政策,我学到了一些新东西。但是,不幸的是,这似乎并不能解决问题。我尝试将阈值设置为 0.1,缩放因子设置为 0.1,学习率下降到 1e-15,而没有任何损失减少。也许我在调度程序中设置了错误?
    • 是的,阈值决定了调度程序在降低学习率之前应该等待的 epoch 数,它应该是一个整数。您可以将其设置为 5 或 6。这将做的是,在训练期间,如果损失在 5 到 6 个 epoch 内没有减少,那么只有学习率会降低。您设置的比例因子值很好。您也可以设置一个最小 lr 值,这将确保学习率不会低于某个值,合理的值可以是 1e-5。
    • 据我了解,告诉调度器要等待多少个epoch的参数是耐心。我已将其设置为 1,因为在完成一个 epoch 之前优化器迭代了许多批次,然后调度程序可以运行。我认为阈值是考虑损失值相同并因此降低学习率的最小差异。我做了一个实验,将其设置为 1e-4,我看到了轻微的改进,但损失似乎仍然没有收敛。
    • 对不起,我的错。我把耐心误认为是门槛。如果您的损失仍然没有改善,那么我想您也尝试调整其他超参数。
    猜你喜欢
    • 2021-11-17
    • 1970-01-01
    • 1970-01-01
    • 2018-11-05
    • 1970-01-01
    • 1970-01-01
    • 2020-11-04
    • 2018-09-12
    • 2021-02-25
    相关资源
    最近更新 更多