【问题标题】:Training models interactively in Pytorch在 Pytorch 中交互式训练模型
【发布时间】:2020-05-19 10:23:45
【问题描述】:

我需要并行训练两个模型。每个模型都有不同的激活函数和可训练的参数。我想训练模型一和模型二,使模型一中的激活函数的参数(例如,alpha1)与模型二(例如,alpha2)中的参数分开 2;即 |alpha_1 - alpha_2| > 2. 我想知道如何将其包含在训练的损失函数中。

【问题讨论】:

    标签: parameters pytorch backpropagation custom-training


    【解决方案1】:

    示例模块定义

    我将使用torch.nn.PReLU 作为您所说的参数激活。 get_weight 为方便而创建。

    import torch
    
    
    class Module(torch.nn.Module):
        def __init__(self, in_features, out_features):
            super().__init__()
            self.input = torch.nn.Linear(in_features, 2 * in_features)
            self.activation = torch.nn.PReLU()
            self.output = torch.nn.Linear(2 * in_features, out_features)
    
        def get_weight(self):
            return self.activation.weight
    
        def forward(self, inputs):
            return self.output(self.activation(self.inputs(inputs)))
    

    模块和设置

    在这里,我使用一个优化器来优化您所说的两个模块的参数。 criterion 可以是 mean squared errorcross entropy 或您需要的任何其他内容。

    module1 = Module(20, 1)
    module2 = Module(20, 1)
    
    optimizer = torch.optim.Adam(
        itertools.chain(module1.parameters(), module2.parameters())
    )
    critertion = ...
    

    培训

    这是一个单一的步骤,您应该像往常一样将其打包在数据的 for 循环中,希望这足以让您明白这一点:

    inputs = ...
    targets = ...
    
    output1 = module1(inputs)
    output2 = module2(inputs)
    
    loss1 = criterion(output1, targets)
    loss2 = criterion(output2, targets)
    
    total_loss = loss1 + loss2
    total_loss += torch.nn.functional.relu(
        2 - torch.abs(module1.get_weight() - module2.get_weight()).sum()
    )
    total_loss.backward()
    
    optimizer.step()
    

    在这种情况下,这一行就是你所追求的:

    total_loss += torch.nn.functional.relu(
        2 - torch.abs(module1.get_weight() - module2.get_weight()).sum()
    )
    

    relu 被使用,因此网络不会仅仅从创建不同的权重中获得无限的好处。如果没有,损失将变为负值,权重之间的差异越大。这种情况下差异越大越好,但是gap大于等于2之后就没有区别了。

    如果您必须通过2 的阈值,您可能必须将2 增加到2.1 或其他值,因为当它接近2.0 时优化价值的动力很小。

    编辑

    如果没有明确给出阈值,这可能会很困难,但也许这样的事情会起作用:

    total_loss = (
        (torch.abs(module1) + torch.abs(module2)).sum()
        + (1 / torch.abs(module1) + 1 / torch.abs(module2)).sum()
        - torch.abs(module1 - module2).sum()
    )
    

    这对网络来说有点骇人听闻,但可能值得一试(如果您应用额外的 L2 正则化)。

    本质上,这种损失将在-inf, +inf 对应位置的权重对处具有最佳值,并且永远不会小于零。

    对于那些权重

    weights_a = torch.tensor([-1000.0, 1000, -1000, 1000, -1000])
    weights_b = torch.tensor([1000.0, -1000, 1000, -1000, 1000])
    

    每个部分的损失将是:

    (torch.abs(module1) + torch.abs(module2)).sum() # 10000
    (1 / torch.abs(module1) + 1 / torch.abs(module2)).sum() # 0.0100
    torch.abs(module1 - module2).sum() # 10000
    

    在这种情况下,网络可以通过在两个模块中使用相反的符号使权重更大并且忽略您想要优化的内容来获得简单的好处(两个模块的权重大 L2 可能会有所帮助,我认为最佳值将是 @ 987654342@/-1 如果L2alpha 等于1),我怀疑网络可能非常不稳定。

    使用这个损失函数,如果网络得到一个大权重错误的迹象,它将受到严重惩罚。

    在这种情况下,您将留下L2 alpha 参数来调整以使其工作,这不是那么严格,但仍然需要选择超参数。

    【讨论】:

    • 感谢您的回答。这就是我所追求的。我想知道是否可以设置边距,即 2 未知,以便网络训练尽可能多地增加权重的边距。
    • @Kevin 试图做一些你想做的事情(记住L2),但你仍然有超参数。保证金本身不是问题(如果没有L2,它将达到最大可能的保证金),但它可以创建一对+inf, -inf 权重并将整个损失推向零(但没有学到任何东西)。如果你想优化一些东西,你需要一个存在最小值的点,在这种情况下,由于 L2,它可能被认为是“更软”,但这并不是一个巨大的变化。在您的情况下,您既不想要0.0 权重也不想要+inf/-inf,所以总是需要权衡。
    • @Kevin 还注意到我已经添加了.sum(),因此在两种可能的解决方案中,损失都有一个单一的价值。
    • 感谢您的澄清。我想知道在您的训练循环中,我是否使用 for 循环每次更新一个模型,而不是一次更新两个模型,那么两种类型的训练将是等效的。
    • 这两种方法都可以,但并不等同,因为一次只能更新一组权重。
    猜你喜欢
    • 2019-09-11
    • 2018-01-03
    • 2020-02-07
    • 2021-09-11
    • 2019-07-17
    • 2018-02-20
    • 2019-12-08
    • 2019-12-20
    • 2021-10-29
    相关资源
    最近更新 更多