针对不同的输入版本独立训练神经网络模型

问题描述 投票:0回答:1

我正在使用 PyTorch 训练神经网络模型,称为“top_model”。下面,我概述了我的设置,然后详细描述了我面临的挑战。

class torch_top_model(nn.Module):
    def __init__(self):
        super(torch_top_model, self).__init__()
        self.input_layer = nn.Linear(25, 320)
        self.hidden_layer = nn.Linear(320, 64)
        self.output_layer = nn.Linear(64, 10)

    def forward(self, x):
        x = F.relu(self.input_layer(x))
        x = F.relu(self.hidden_layer(x))
        x = self.output_layer(x)
        return x

top_model = torch_top_model()
top_model.train()

我有一个大小为 (30, 25) 的输入张量。对于我的输入生成,我将 25 个特征分为 5 组,每组 5 个特征。

model_inputs = torch.rand(30, 25)
model_labels = torch.randint(0, 10, (30,))
top_model_inputs = {}

for i in range(5):  # 4 groups (5 columns each)
    top_model_inputs[i] = model_inputs[:, i*5:(i+1)*5]

在下一步中,我将生成输入数据的版本,其中一组特征(对应于每个键)被清零,而其他特征保持不变。

for key in range(1, len(top_model_inputs.keys())):
    temp = []
    for k in top_model_inputs:
      if k == key:
        temp.append(torch.zeros_like(top_model_inputs[k]))
      else:
        temp.append(top_model_inputs[k])
    temp_tensor = torch.cat(temp, dim=1)
    inputs[key] = temp_tensor

接下来我开始模型训练:

weights_and_biases = {i:top_model.state_dict() for i in range(1,5)}
optimizer = {i:torch.optim.Adam(top_model.parameters(), lr=0.01) for i in range(1,5)}
criterion = nn.CrossEntropyLoss()
top_models = {i:copy.deepcopy(top_model) for i in range(1,5)}
epochs = 3

for i in range(epochs):
  for key in range(1, len(top_model_inputs.keys())):
    top_models[key].load_state_dict(weights_and_biases[key])
    outputs = top_models[key](inputs[key])
    loss = criterion(outputs, model_labels)
    optimizer[key].zero_grad()
    loss.backward()
    if i == 2:
      w2 = weights_and_biases[2]['input_layer.weight'].clone().detach()
    optimizer[key].step()
    weights_and_biases[key] = top_models[key].state_dict()
    if i == 1:
      w1 = weights_and_biases[1]['input_layer.weight'].clone().detach()

      print("w1-w2: ", torch.norm(w1-w2))

我的问题:对于输入的每个版本,当我在历元中运行算法时,我只希望更新相应输入的权重和偏差。例如,在 epoch1 中,我希望模型仅更新输入[1]的weights_and_biases[1],输入[2]的weights_and_biases[2]等。本质上,我希望在每个时期内针对每个输入版本单独更新 top_model 的参数(权重和偏差),然后在下一个时期使用这些更新的参数。

我面临的问题:权重被其他输入版本的weight_and_biases 重用。例如,输入[2]正在使用weight_and_biases[1]。因此,我在不同输入版本的更新前后得到零范数差异。

如何跨epoch独立更新不同输入版本的模型参数?如果无需多次深度复制模型即可实现这一点,这将是一个更有效的解决方案。

optimization deep-learning pytorch neural-network
1个回答
0
投票

我认为您对这里的一些非常基本的编程方面感到困惑。让我们逐步完成一些事情。

您创建模型:

top_model = torch_top_model()

此时您只有一个模型。现在你创建这个字典:

weights_and_biases = {i:top_model.state_dict() for i in range(1,5)}

此时您仍然有一个模型。

weights_and_biases
中的条目都引用相同的模型状态字典。字典值都是指向完全相同对象的指针。

您创建优化器字典

optimizer = {i:torch.optim.Adam(top_model.parameters(), lr=0.01) for i in range(1,5)}

此时您仍然有一个模型。每个字典值都是不同的优化器对象,但它们都引用相同的权重对象。

您创建模型副本字典

top_models = {i:copy.deepcopy(top_model) for i in range(1,5)}

现在您已经创建了四个新模型。您总共有五个模型 -

top_models
中的四个加上您克隆的原始模型。

现在你的火车环路了

top_models[key].load_state_dict(weights_and_biases[key])
outputs = top_models[key](inputs[key])
loss = criterion(outputs, model_labels)
optimizer[key].zero_grad()
loss.backward()

如果您理解所编写的代码,您就可以清楚地看到为什么这不起作用。您可以将

top_models[key]
中的模型与优化器
optimizer[key]
一起使用。
top_models[key]
指向您创建的模型副本之一。
optimizer[key]
指向原始模型的权重。他们引用不同的对象。通过
top_models[key].load_state_dict(weights_and_biases[key])
加载状态字典不会改变这一点,因为它将数据值从
weights_and_biases[key]
复制到
top_models[key].load_state_dict
中的张量对象中。

您看到权重没有变化的原因是您没有更新它们。您使用

top_models[key]
中的权重计算损失,但优化器引用原始
top_model
中的权重。两者之间没有任何联系。如果您实际检查优化器中参数的梯度值 (
optimizer[key].param_groups[0]['params'][0].grad
),您会发现它是
None
,因为没有计算梯度。优化器中的参数与您用于计算损失的参数无关。

我认为您也对自己想要实现的目标感到困惑。当您说

I would like the model to update only weights_and_biases[1] for inputs[1], weights_and_biases[2] for inputs[2]
时,这意味着您想要在不同的输入上训练单独的模型。当您说
If this can be achieved without deep copying the model
时,这意味着您想要一个模型。

您可以在所有版本的输入上训练单个模型,也可以在单独的输入上训练模型的单独实例。

© www.soinside.com 2019 - 2024. All rights reserved.