pytorch中的parameter与buffer

先上结论:

  1. parameter在反向传播会被optimizer.step更新,buffer在反向传播不会被更新
  2. parameter和buffer都被保存在model.state_dict()返回的OrderedDict中(这也是模型保存的对象)
  3. 模型进行设备移动时,模型中注册的参数(parameter和buffer),即model.state_dict()中的内容会同时进行移动

咱来解释一下!

先创建这两种参数吧!

1.创建parameter

  • 直接将模型的成员变量self.xxx 通过nn.Parameter()创建,这样会自动注册到parameters中
  • 通过nn.Parameter()创建普通parameter对象,而不作为模型的成员变量,然后将parameter对象通过register_parameter()进行注册

这两种方式创建的parameter都可以通model.parameters()返回,注册后的参数也会自动保存到model.state_dict()中去。

# 方式一
self.param = nn.Parameter(torch.randn(3, 3))
# 方式二
param = nn.Parameter(torch.randn(3, 3))  # 普通 Parameter 对象
self.register_parameter("param", param)

2.创建buffer

通过register_buffer()进行注册,buffer可以通model.buffers()返回,注册完后参数会自动保存到model.state_dict()中去。

self.register_buffer('my_buffer', torch.randn(2, 3))

parameter在反向传播会被optimizer.step更新,buffer在反向传播不会被更新

import torch
import torch.nn as nn

class Net(torch.nn.Module):
    def __init__(self, n_feature, n_output):
        super(Net, self).__init__()
        self.register_buffer('my_buffer', torch.randn(2, 3))
        self.linear = torch.nn.Linear(n_feature, n_output)
        
    def forward(self, x):
        x = self.linear(x)  # 输出值
        return x


model = Net(3, 1)
print('更新前:')
#  parameter和buffer都被保存在`model.state_dict() `返回的`OrderedDict`中
print(model.state_dict())

# 一次更新
loss_fn = nn.L1Loss()
optimizer = torch.optim.SGD(model.parameters(), lr=1e-2)
input = torch.ones(3, requires_grad=True)
output = model(input)
target = torch.ones([1])
loss = loss_fn(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()

print('更新后:')
print(model.state_dict())

其中, parameter的创建在torch.nn.Linear中的__init__中完成,其成员变量weights和bias是parameter对象,并进行了初始化:

self.weight = Parameter(torch.Tensor(out_features, in_features))
if bias:
      self.bias = Parameter(torch.Tensor(out_features))
  else:
      self.register_parameter('bias', None)

Out:

更新前:
OrderedDict([('my_buffer', tensor([[-0.6783, -0.1426, -0.5545],
        [-0.0529, -1.6932,  0.3820]])), ('linear.weight', tensor([[-0.5150, -0.1703,  0.2062]])), ('linear.bias', tensor([0.1766]))])
更新后:
OrderedDict([('my_buffer', tensor([[-0.6783, -0.1426, -0.5545],
        [-0.0529, -1.6932,  0.3820]])), ('linear.weight', tensor([[-0.5050, -0.1603,  0.2162]])), ('linear.bias', tensor([0.1866]))])

可以看出my_buffer未更新,linear.weightlinear.bias更新了。

torch.nn.Parameter是继承自torch.Tensor的子类,其主要作用就是作为nn.Module中的可训练参数使用。parameter在反向传播会被optimizer.step更新,但是buffer在反向传播不会被更新。

为什么不直接将不需要进行参数更新的变量作为模型类的成员变量就,还要进行注册?

  1. 不进行注册,参数不能保存到model.state_dict(),也就无法进行模型的保存
  2. 模型进行参数在CPU和GPU移动时, 执行 model.to(device) ,注册后的参数也会自动进行设备移动
class Net(torch.nn.Module):
    def __init__(self, n_feature, n_output):
        super(Net, self).__init__()

        self.register_buffer('my_buffer', torch.randn(2, 3))
        # 普通的成员变量
        self.my_tensor = torch.randn(1)

        self.linear = torch.nn.Linear(n_feature, n_output)

    def forward(self, x):
        x = self.linear(x)  # 输出值
        return x


model = Net(3, 1)
model.cuda()
print(model.state_dict())
print(model.my_tensor)

Out:

OrderedDict([('my_buffer', tensor([[-0.3508, -1.4253,  0.7532],
        [-2.0955,  1.6653, -0.7471]], device='cuda:0')), ('linear.weight', tensor([[-0.0708, -0.0424,  0.5221]], device='cuda:0')), ('linear.bias', tensor([0.5139], device='cuda:0'))])
tensor([-0.9557])

可以看到普通的成员变量self.my_tensor不在model.state_dict()中,模型移动到GPU上后,普通的成员变量也不会跟着移动,但是buffer对象my_buffer、parameter对象linear.weightlinear.bias都移动到GPU了。

参考博客:

https://blog.youkuaiyun.com/weixin_38145317/article/details/104917218
https://zhuanlan.zhihu.com/p/89442276

### MOCO模型在PyTorch中的实现 MOCO ( Momentum Contrast ) 是一种用于自监督学习的方法,在图像表示学习方面表现出色。为了实现在PyTorch环境下的MOCO模型,可以遵循官方提供的指南以及社区贡献者的实践案例。 #### 官方资源教程 PyTorch官方网站提供了详细的自监督学习教程,其中涵盖了多种方法和技术细节[^1]。对于希望深入了解并应用MOCO算法的研究者来说,这些材料是非常宝贵的起点。 #### 社区项目实例 GitHub上存在多个开源项目实现了基于PyTorch框架的MOCO版本。例如,有开发者分享了一个完整的MOCO v2实现方案,该方案不仅包含了训练过程所需的全部组件,还附带了预处理脚本和评估工具。 以下是简化版的MOCO V2架构图解: ```mermaid graph LR; A(Image) --> B(Encoder_q); C(Negative Keys Queue) -.-> D(Momentum Encoder_k); E(Augmentation) --> F(Random Crop & Color Jitter); G(Cross-GPU Shuffle/Unshuffle) --> H(Loss Computation); I(Query Key Update with Momentum) --> J(Parameter Updates via SGD or AdamW); ``` 此图表展示了数据流经编码器、增强模块、损失计算直至参数更新的过程。 #### 实现要点 - **队列机制**:维护一个负样本键(negative keys)队列来存储先前批次的数据特征向量。 - **动量更新策略**:通过引入第二个网络作为目标网络,并采用缓慢变化的方式同步权重给查询网络。 - **对比损失函数**:定义正对之间的相似度得分高于所有可能形成的错误配对。 下面是一段简单的Python代码片段展示如何初始化MOCO模型结构: ```python import torch.nn as nn from torchvision import models class MoCo(nn.Module): """ Build a MoCo model with: a query encoder, a key encoder, and a queue. """ def __init__(self, base_encoder, dim=128, K=65536, m=0.999, T=0.07): super(MoCo, self).__init__() self.K = K self.m = m self.T = T # create the encoders self.encoder_q = base_encoder(num_classes=dim) self.encoder_k = base_encoder(num_classes=dim) for param_q, param_k in zip(self.encoder_q.parameters(), self.encoder_k.parameters()): param_k.data.copy_(param_q.data) # initialize param_k.requires_grad = False # not update by gradient # create the queue self.register_buffer("queue", torch.randn(dim, K)) self.queue = nn.functional.normalize(self.queue, dim=0) self.register_buffer("queue_ptr", torch.zeros(1, dtype=torch.long)) @torch.no_grad() def _momentum_update_key_encoder(self): """Momentum update of the key encoder""" for param_q, param_k in zip(self.encoder_q.parameters(), self.encoder_k.parameters()): param_k.data = param_k.data * self.m + param_q.data * (1. - self.m) def main(): resnet = models.resnet50 moco = MoCo(resnet).cuda() if __name__ == '__main__': main() ``` 这段代码创建了一个基本形式的MoCo类,它接收基础编码器作为输入,并设置了必要的超参数如维度大小`dim`, 队列长度`K`, 动量系数`m` 和 温度参数 `T`. 此外还包括了两个主要操作——初始化时复制查询编码器到密钥编码器;每次迭代结束之后执行一次动量更新.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值