一直有一个疑问,我们生成一个模型,这个模型的参数传递给了优化器,优化器在优化的时候,模型的参数会有变化,这之间的关联到底是怎样的呢?如果想改变模型的参数,只能通过优化器更新吗?如果在优化器外面更新了,这个时候的参数会在模型中、优化器中同时起作用吗?答案是会的,因为我们传递给优化器的模型参数包括了模型参数的地址,我们在这个地址上进行更改,则全局都会同步产生变化。
其实我要解决的一个问题就是,我想在优化器对模型进行更新的情况下,我自己也对模型增加一个更新。下面是我的代码:
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.linear1 = nn.Linear(6,2)
self.conv1 = nn.Conv2d(2,2,3)
self.par = Parameter( torch.Tensor(4,2) )
def forward(self, input):
# prob = self.linear1(input)
# return prob
pass
net = Net()#生成模型,则参数也一同产生了
params = [{'params':value} for _, value in net.named_parameters() ] #将模型的可更新参数按照字典的形式存起来,一个模型参数对应一个字典,将字典放到列表中
optim = torch.optim.SGD( params, lr = 0.00035 )#将模型参数送给优化器
print('第一次遍历:')
for para in optim.param_groups:#看传递给优化器的模型参数的值和地址是不是内存共享的
if para['params'][0].size() == torch.Size([2, 6]):
print(id(para['params'][0]))
print(para['params'][0])
for key, value in net.named_parameters():#直接在模型中查看模型的参数的内存地址和值
if value.size() == torch.Size([2,6]):
print(id(value))
print(value)
print('weight',id(net.linear1.weight))#直接在模型中查看模型的参数的内存地址和值
print('data',id(net.linear1.weight.data))#直接在模型中查看模型的参数值
print(net.linear1.weight)
x = torch.randn(2,6)
net.linear1.weight.data.add(0.1) #这一步相当于在优化器以外对模型参数进行更改
print('第二次遍历:')
for para in optim.param_groups:#看看在优化器外改了模型参数,优化器中的模型参数值是否也会同步产生变化,答案是会产生变化
if para['params'][0].size() == torch.Size([2, 6]):
print(id(para['params'][0]))
print(para['params'][0])
for key, value in net.named_parameters():#看看在优化器外改了模型参数,是否起作用,结果是会起作用
if value.size() == torch.Size([2,6]):
print(id(value))
print(value)
print('weight',id(net.linear1.weight))#直接查看模型参数的地址
print('data',id(net.linear1.weight.data))#查看模型参数的值
print(net.linear1.weight)#看看模型参数变没变
程序运行结果为:
第一次遍历:
140487128355032
Parameter containing:
tensor([[ 0.2104, -0.1802, -0.0791, 0.1916, -0.3843, 0.2448],
[-0.0840, 0.2077, 0.0568, -0.0500, 0.1132, 0.0201]],
requires_grad=True)
140487128355032
Parameter containing:
tensor([[ 0.2104, -0.1802, -0.0791, 0.1916, -0.3843, 0.2448],
[-0.0840, 0.2077, 0.0568, -0.0500, 0.1132, 0.0201]],
requires_grad=True)
weight 140487128355032
data 140487128356904
Parameter containing:
tensor([[ 0.2104, -0.1802, -0.0791, 0.1916, -0.3843, 0.2448],
[-0.0840, 0.2077, 0.0568, -0.0500, 0.1132, 0.0201]],
requires_grad=True)
第二次遍历:
140487128355032
Parameter containing:
tensor([[ 0.2104, -0.1802, -0.0791, 0.1916, -0.3843, 0.2448],
[-0.0840, 0.2077, 0.0568, -0.0500, 0.1132, 0.0201]],
requires_grad=True)
140487128355032
Parameter containing:
tensor([[ 0.2104, -0.1802, -0.0791, 0.1916, -0.3843, 0.2448],
[-0.0840, 0.2077, 0.0568, -0.0500, 0.1132, 0.0201]],
requires_grad=True)
weight 140487128355032
data 140487128357048
Parameter containing:
tensor([[ 0.2104, -0.1802, -0.0791, 0.1916, -0.3843, 0.2448],
[-0.0840, 0.2077, 0.0568, -0.0500, 0.1132, 0.0201]],
requires_grad=True)
实验结果表明,往params这个字典中传递模型参数,以及将params传递给优化器的时候,传递的都是内存地址,因此只要在这个地址上进行数据更新,则全局都会进行更新,那么如何更新模型中的某个参数呢?如下所示,我要在每次进行forward()之前,将线性分类层的每个向量都进行标准化,则可以进行下面的操作:
self.encoder.module.classifier.weight.data.copy_(F.normalize( self.encoder.module.classifier.weight.data ,dim=1))
这里要注意一下,如果是将2048维的特征向量,分类乘1000份,则分类层的tensor的尺寸是[1000,2048],而不是[2048,1000],这块要注意一下。