Parameters Pytorch中的交互训练模型

Parameters Pytorch中的交互训练模型,parameters,pytorch,backpropagation,custom-training,Parameters,Pytorch,Backpropagation,Custom Training,我需要同时训练两个模型。每个模型都有不同的激活函数和可训练参数。我想对模型一和模型二进行培训,使模型一(如alpha1)的激活功能参数与模型二(如alpha2)的参数之间的间隔为2;i、 e.,| alpha_1-alpha_2 |>2。我想知道如何将其包含在损失函数中进行培训。模块定义示例 我将使用torch.nn.PReLU作为您谈论的参数激活。 获取重量为方便而创建 import torch class Module(torch.nn.Module): def __init__

我需要同时训练两个模型。每个模型都有不同的激活函数和可训练参数。我想对模型一和模型二进行培训,使模型一(如alpha1)的激活功能参数与模型二(如alpha2)的参数之间的间隔为2;i、 e.,| alpha_1-alpha_2 |>2。我想知道如何将其包含在损失函数中进行培训。

模块定义示例 我将使用
torch.nn.PReLU
作为您谈论的参数激活。
获取重量
为方便而创建

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)))
模块和设置 在这里,我使用一个优化器来优化您提到的两个模块的参数<代码>标准可以是
均方误差
交叉熵
或您需要的任何其他东西

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
,因此网络不会仅从创建不同权重中获得无限收益。如果没有,重量差越大,损失就会变成负值。在这种情况下,差异越大越好,但当间隙大于或等于
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
可能会有所帮助,我认为如果
L2
alpha
等于
1
,最佳值应该是
1
-1),我怀疑网络可能非常不稳定

有了这个损失函数,如果网络得到一个大重量错误的信号,它将受到严重惩罚


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

谢谢您的回答。这就是我在中的目的。我想知道是否可以设置边距,即2未知,以便网络训练尽可能增加权重的边距尽可能多。@Kevin试图做一些你想做的事情(记住关于
L2
),但你仍然有超参数。边距本身并不是问题(没有
L2
,它将走向最大可能的边距),但它可以创建成对的
+inf,-inf
权重,并将整个损失推向零(但没有学到任何东西)。如果你想优化某个东西,你需要一个存在最小值的点,在这种情况下,由于L2,它可能被认为是“软”的,但这不是一个巨大的变化。在你的情况下,你既不想要
0.0
权重,也不想要
+inf/-inf
,所以总有一个折衷。@Kevin还注意到我添加了
.sum()
因此,在两种可能的解决方案中,损失都会增加一个值。感谢您的澄清。我想知道,在您的培训循环中,我是否使用for循环每次更新一个模型,而不是一次更新两个模型,那么这两种类型的培训都是等效的。您可以做任何一种,但它都不等效,因为只有一组模型权重将一次更新。