更改 nn.Parameter 的某些元素时的副作用
Sideffects when changind some elements of nn.Parameter
我想要一些 nn.Parameter
依赖于数据,例如不同的人有不同的价值观。我意识到在训练一个人的同时,其他人的结果也会发生变化。我在下面创建了一个小演示。
我试图让一切都变得确定,正如预期的那样,改变 nn.Parameter
的大小不会改变结果。在训练了 100 个 epoch 之后,我总是得到 [1.0605, 1.0715, 1.0622, 0.9702]
for all_calibration_params[0]
。但是 all_calibration_params
的所有其他参数也会发生变化,并且它们都以相同的值变化,对于 all_calibration_params = nn.Parameter(torch.ones(10, 4))
我得到所有其他 9 个值的 [0.8455, 0.8455, 0.8455, 0.8455]
。我希望这些值保持 [1, 1, 1, 1]
。任何人都可以向我解释一下,为什么即使我在训练期间不使用它们,其他值也会改变?
谢谢。
import torch
from pytorch_lightning import LightningModule, Trainer, seed_everything
from torch import nn
from torch.utils.data import Dataset, DataLoader
import torch.nn.functional as F
class DemoDataset(Dataset):
"""
Generate random data, only for person 0.
Data is always random but output is always 1.
"""
def __init__(self):
pass
def __len__(self) -> int:
return 1_000
def __getitem__(self, idx):
return {
'person': torch.zeros(1),
'data': torch.rand(1),
'output': torch.ones(1),
}
class DemoModel(LightningModule):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.all_calibration_params = nn.Parameter(torch.ones(3, 4)) # all values are 1
self.fc_1 = nn.Linear(1, 4)
self.fc_2 = nn.Linear(4 + 4, 1)
def forward(self, person: torch.Tensor, data: torch.Tensor):
x = self.fc_1(data)
calibration_params = self.all_calibration_params[person].squeeze(1)
x = torch.cat((x, calibration_params), dim=1)
x = self.fc_2(x)
return x
class Model(DemoModel):
def __init__(self, learning_rate: float, weight_decay: float, *args, **kwargs):
super().__init__(*args, **kwargs)
self.learning_rate = learning_rate
self.weight_decay = weight_decay
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
def training_step(self, train_batch: dict, batch_idx: int):
data, person, output = train_batch['data'], train_batch['person'].long(), train_batch['output']
pred = self(person, data)
loss = F.mse_loss(pred, output)
return loss
if __name__ == '__main__':
seed_everything(42)
model = Model(learning_rate=1e-4, weight_decay=1e-5)
dataset = DemoDataset()
dataloader = DataLoader(dataset, batch_size=64)
print(model.all_calibration_params)
trainer = Trainer(
max_epochs=100,
deterministic=True
)
trainer.fit(model, dataloader)
print(model.all_calibration_params)
# model.all_calibration_params[1] should be [1, 1, 1, 1]
print(model.all_calibration_params[1], torch.ones(1, 4))
输出:
tensor([[1.0605, 1.0715, 1.0622, 0.9702],
[0.8455, 0.8455, 0.8455, 0.8455],
[0.8455, 0.8455, 0.8455, 0.8455]], requires_grad=True)
编辑:
如果 nn.Parameter
中的其他元素改变了输出,我添加了一个小测试,但没有,所以我不明白为什么它们在训练时会受到影响。
batch = next(iter(dataloader))
data, person = batch['data'], batch['person'].long()
output_org = model(person, data)
print(output_org[0])
model.freeze()
model.all_calibration_params[1:] = torch.ones(2, 4)
model.unfreeze()
output_mod = model(person, data)
print(output_mod[0])
print(torch.equal(output_org, output_mod))
输出:
tensor([0.6334], grad_fn=<SelectBackward>)
tensor([0.6334], grad_fn=<SelectBackward>)
True
您的数据集始终 returns 'person'
的 0
索引, 即 self.all_calibration_params[person]
将始终 select 第一行。
其他两行得到更新的原因是优化器上设置的权重衰减。这将更新所有参数,无论它们是否在模型推理期间被使用。
我想要一些 nn.Parameter
依赖于数据,例如不同的人有不同的价值观。我意识到在训练一个人的同时,其他人的结果也会发生变化。我在下面创建了一个小演示。
我试图让一切都变得确定,正如预期的那样,改变 nn.Parameter
的大小不会改变结果。在训练了 100 个 epoch 之后,我总是得到 [1.0605, 1.0715, 1.0622, 0.9702]
for all_calibration_params[0]
。但是 all_calibration_params
的所有其他参数也会发生变化,并且它们都以相同的值变化,对于 all_calibration_params = nn.Parameter(torch.ones(10, 4))
我得到所有其他 9 个值的 [0.8455, 0.8455, 0.8455, 0.8455]
。我希望这些值保持 [1, 1, 1, 1]
。任何人都可以向我解释一下,为什么即使我在训练期间不使用它们,其他值也会改变?
谢谢。
import torch
from pytorch_lightning import LightningModule, Trainer, seed_everything
from torch import nn
from torch.utils.data import Dataset, DataLoader
import torch.nn.functional as F
class DemoDataset(Dataset):
"""
Generate random data, only for person 0.
Data is always random but output is always 1.
"""
def __init__(self):
pass
def __len__(self) -> int:
return 1_000
def __getitem__(self, idx):
return {
'person': torch.zeros(1),
'data': torch.rand(1),
'output': torch.ones(1),
}
class DemoModel(LightningModule):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.all_calibration_params = nn.Parameter(torch.ones(3, 4)) # all values are 1
self.fc_1 = nn.Linear(1, 4)
self.fc_2 = nn.Linear(4 + 4, 1)
def forward(self, person: torch.Tensor, data: torch.Tensor):
x = self.fc_1(data)
calibration_params = self.all_calibration_params[person].squeeze(1)
x = torch.cat((x, calibration_params), dim=1)
x = self.fc_2(x)
return x
class Model(DemoModel):
def __init__(self, learning_rate: float, weight_decay: float, *args, **kwargs):
super().__init__(*args, **kwargs)
self.learning_rate = learning_rate
self.weight_decay = weight_decay
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=self.learning_rate, weight_decay=self.weight_decay)
def training_step(self, train_batch: dict, batch_idx: int):
data, person, output = train_batch['data'], train_batch['person'].long(), train_batch['output']
pred = self(person, data)
loss = F.mse_loss(pred, output)
return loss
if __name__ == '__main__':
seed_everything(42)
model = Model(learning_rate=1e-4, weight_decay=1e-5)
dataset = DemoDataset()
dataloader = DataLoader(dataset, batch_size=64)
print(model.all_calibration_params)
trainer = Trainer(
max_epochs=100,
deterministic=True
)
trainer.fit(model, dataloader)
print(model.all_calibration_params)
# model.all_calibration_params[1] should be [1, 1, 1, 1]
print(model.all_calibration_params[1], torch.ones(1, 4))
输出:
tensor([[1.0605, 1.0715, 1.0622, 0.9702],
[0.8455, 0.8455, 0.8455, 0.8455],
[0.8455, 0.8455, 0.8455, 0.8455]], requires_grad=True)
编辑:
如果 nn.Parameter
中的其他元素改变了输出,我添加了一个小测试,但没有,所以我不明白为什么它们在训练时会受到影响。
batch = next(iter(dataloader))
data, person = batch['data'], batch['person'].long()
output_org = model(person, data)
print(output_org[0])
model.freeze()
model.all_calibration_params[1:] = torch.ones(2, 4)
model.unfreeze()
output_mod = model(person, data)
print(output_mod[0])
print(torch.equal(output_org, output_mod))
输出:
tensor([0.6334], grad_fn=<SelectBackward>)
tensor([0.6334], grad_fn=<SelectBackward>)
True
您的数据集始终 returns 'person'
的 0
索引, 即 self.all_calibration_params[person]
将始终 select 第一行。
其他两行得到更新的原因是优化器上设置的权重衰减。这将更新所有参数,无论它们是否在模型推理期间被使用。