为什么在 Pytorch 中复制网络权重时它会在反向传播后自动更新?
Why is it in Pytorch when I make a COPY of a network's weight it would be automatically updated after back-propagation?
我编写了以下代码作为测试,因为在我的原始网络中我使用了 ModuleDict 并且取决于我提供的索引它会切片并仅训练该网络的一部分。
我想确保只有切片层会更新它们的权重,所以我写了一些测试代码来仔细检查。好吧,我得到了一些奇怪的结果。假设我的模型有 2 层,第 1 层是一个 FC,第 2 层是 Conv2d,如果我对网络进行切片并且只使用第 2 层,我希望第 1 层的权重保持不变,因为它们未被使用,第 2 层的权重将在 1 个纪元后更新。
所以我的计划是使用 for
循环从网络中获取所有权重 在训练之前,我会在 1 optimizer.step()
之后进行。两次我都会将这些权重完全分开存储在 2 Python 列表中,以便稍后比较它们的结果。好吧,出于某种原因,如果我将它们与 torch.equal()
进行比较,这两个列表是完全相同的,我认为这是因为内存中可能仍然存在某种隐藏的 link?因此,当我从循环中获取权重时,我尝试在权重上使用 .detach()
,结果仍然相同。 Layer2 的权重在这种情况下应该不同,因为它应该包含训练前网络的权重。
在下面的代码中注意到我实际上使用了 layer1 并忽略了 layer2。
完整代码:
class mymodel(nn.Module):
def __init__(self):
super().__init__()
self.layer1 = nn.Linear(10, 5)
self.layer2 = nn.Conv2d(1, 5, 4, 2, 1)
self.act = nn.Sigmoid()
def forward(self, x):
x = self.layer1(x) #only layer1 and act are used layer 2 is ignored so only layer1 and act's weight should be updated
x = self.act(x)
return x
model = mymodel()
weights = []
for param in model.parameters(): # loop the weights in the model before updating and store them
print(param.size())
weights.append(param)
critertion = nn.BCELoss() #criterion and optimizer setup
optimizer = optim.Adam(model.parameters(), lr = 0.001)
foo = torch.randn(3, 10) #fake input
target = torch.randn(3, 5) #fake target
result = model(foo) #predictions and comparison and backprop
loss = criterion(result, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
weights_after_backprop = [] # weights after backprop
for param in model.parameters():
weights_after_backprop.append(param) # only layer1's weight should update, layer2 is not used
for i in zip(weights, weights_after_backprop):
print(torch.equal(i[0], i[1]))
# **prints all Trues when "layer1" and "act" should be different, I have also tried to call param.detach in the loop but I got the same result.
你必须clone
参数,否则你只是复制参考。
weights = []
for param in model.parameters():
weights.append(param.clone())
criterion = nn.BCELoss() # criterion and optimizer setup
optimizer = optim.Adam(model.parameters(), lr=0.001)
foo = torch.randn(3, 10) # fake input
target = torch.randn(3, 5) # fake target
result = model(foo) # predictions and comparison and backprop
loss = criterion(result, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
weights_after_backprop = [] # weights after backprop
for param in model.parameters():
weights_after_backprop.append(param.clone()) # only layer1's weight should update, layer2 is not used
for i in zip(weights, weights_after_backprop):
print(torch.equal(i[0], i[1]))
这给出了
False
False
True
True
我编写了以下代码作为测试,因为在我的原始网络中我使用了 ModuleDict 并且取决于我提供的索引它会切片并仅训练该网络的一部分。
我想确保只有切片层会更新它们的权重,所以我写了一些测试代码来仔细检查。好吧,我得到了一些奇怪的结果。假设我的模型有 2 层,第 1 层是一个 FC,第 2 层是 Conv2d,如果我对网络进行切片并且只使用第 2 层,我希望第 1 层的权重保持不变,因为它们未被使用,第 2 层的权重将在 1 个纪元后更新。
所以我的计划是使用 for
循环从网络中获取所有权重 在训练之前,我会在 1 optimizer.step()
之后进行。两次我都会将这些权重完全分开存储在 2 Python 列表中,以便稍后比较它们的结果。好吧,出于某种原因,如果我将它们与 torch.equal()
进行比较,这两个列表是完全相同的,我认为这是因为内存中可能仍然存在某种隐藏的 link?因此,当我从循环中获取权重时,我尝试在权重上使用 .detach()
,结果仍然相同。 Layer2 的权重在这种情况下应该不同,因为它应该包含训练前网络的权重。
在下面的代码中注意到我实际上使用了 layer1 并忽略了 layer2。
完整代码:
class mymodel(nn.Module):
def __init__(self):
super().__init__()
self.layer1 = nn.Linear(10, 5)
self.layer2 = nn.Conv2d(1, 5, 4, 2, 1)
self.act = nn.Sigmoid()
def forward(self, x):
x = self.layer1(x) #only layer1 and act are used layer 2 is ignored so only layer1 and act's weight should be updated
x = self.act(x)
return x
model = mymodel()
weights = []
for param in model.parameters(): # loop the weights in the model before updating and store them
print(param.size())
weights.append(param)
critertion = nn.BCELoss() #criterion and optimizer setup
optimizer = optim.Adam(model.parameters(), lr = 0.001)
foo = torch.randn(3, 10) #fake input
target = torch.randn(3, 5) #fake target
result = model(foo) #predictions and comparison and backprop
loss = criterion(result, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
weights_after_backprop = [] # weights after backprop
for param in model.parameters():
weights_after_backprop.append(param) # only layer1's weight should update, layer2 is not used
for i in zip(weights, weights_after_backprop):
print(torch.equal(i[0], i[1]))
# **prints all Trues when "layer1" and "act" should be different, I have also tried to call param.detach in the loop but I got the same result.
你必须clone
参数,否则你只是复制参考。
weights = []
for param in model.parameters():
weights.append(param.clone())
criterion = nn.BCELoss() # criterion and optimizer setup
optimizer = optim.Adam(model.parameters(), lr=0.001)
foo = torch.randn(3, 10) # fake input
target = torch.randn(3, 5) # fake target
result = model(foo) # predictions and comparison and backprop
loss = criterion(result, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
weights_after_backprop = [] # weights after backprop
for param in model.parameters():
weights_after_backprop.append(param.clone()) # only layer1's weight should update, layer2 is not used
for i in zip(weights, weights_after_backprop):
print(torch.equal(i[0], i[1]))
这给出了
False
False
True
True