Pytorch——momentum动量

一、Momentum:(动量,冲量):结合当前梯度与上一次更新信息,用于当前更新;

二、Momentum的作用?

主要是在训练网络时,最开始会对网络进行权值初始化,但是这个初始化不可能是最合适的;因此可能就会出现损失函数在训练的过程中出现局部最小值的情况,而没有达到全局最优的状态。

momentum的出现可以在一定程度上解决这个问题。动量来源于物理学,当momentum越大时,转换为势能的能量就越大,就越有可能摆脱局部凹区域,从而进入全局凹区域。momentum主要是用于权值优化。

没引入momentum之前的权重更新:

w = w - Lr * dw

上面的权重更新可以通过下图进行理解!

梯度下降法

 以单个参数w的损失函数L(w)为例,前提这个损失函数是可微的;

w^{*} = argmaxL(w) 

主要目的就是求解使得上述Loss的最小的w^{*},实际上就是寻找切线L斜率为0的全局最小值(这里可能会出现局部最小值,斜率也为0,也就引出了下面的momentum)

最简单的方法就是遍历所有的w的值,去找到使得loss最小的w^{*},但是这样做一点效率也没有;使用梯度下降法可以很好地解决这个问题;

  1. 首先随机选取一个初始的点w^{0} (当然也不一定要随机选取,如果有办法可以得到比较接近 的表
    现得比较好的w^{0}当初始点,可以有效地提高查找的w^{*}效率)
  2. 计算L在w = w^{0}的位置的微分,\frac{dL}{dw}|w = w^{0} ,几何角度就是切线的斜率;
  3. 如果切线斜率是negative负的,那么就应该使w变大,即往右踏一步;如果切线斜率是positive
    的,那么就应该使w变小,即往左踏一步,每一步的步长step_size就是w的改变量
    w的改变量step_size的大小取决于两件事 
  • 一是现在的微分值dL/dw有多大,微分值越大就表示所在位置比较陡峭,那么它将要移动的距离就越大,反之就越小;
  • 二是一个常数项 \eta ,其实就是学习率;它决定了每次踏出的step_size不仅取决于现在的斜率,还取决于提前设置好的学习率值,如果设置的学习率值比较大,那么每次踏出一步的时候,参数w更新的幅度就比较大,反之参数更新的幅度就比较小;学习也不能太大,太大可能会直接跳过全局最小值点;

     4.因此每次参数更新的大小是\eta* dL/dw ,为了满足斜率为负时w表大,斜率为正时w表小,应该使原来的w减去更新的数值,可以结合上图梯度下降法进行理解;即下式

 此时的w^{i}对应的斜率为0,我们找到了一个局部最小值,但是一旦出现微分为0的情况,参数就不会再继续更新了,但是这个没办法满足全局最小值;这个情况可以结合下图进行理解;于是引出了增加momentum的方法;下面继续看增加momentum的情况;

上面是针对单一参数而言的,针对多个参数的情况也是和处理单个参数的问题一样的,这里就不多赘述了。


引入momentum之后:

v= momentum*v - Lr*dw

w = w + v

其中w表示权重,Lr表示学习率,dw表示w的导数,v表示速度,一般初始化为0;momentum就是引入的动量,一般是设置为0.9。可以理解为,如果上一次的 momentum(v) 与当前的momentum负梯度方向是相同的,那这次下降的幅度就会加大,从而可以加快模型收敛。

指数加权平均:参考:通俗理解指数加权平均

ä¼åç®æ³ä¹ææ°ç§»å¨å æå¹³å

 

 通过代码进一步理解:

1、首先看一下指数加权平均

import torch
import numpy as np
import torch.optim as optim
import matplotlib.pyplot as plt
torch.manual_seed(1)

# 指数加权平均
def exp_w_func(beta,time_list):
    return [(1 - beta)*np.power(beta,exp) for exp in time_list]

beta = 0.9
num_point = 100
time_list = np.arange(num_point).tolist()

# 指数权重
weights = exp_w_func(beta,time_list)

plt.plot(time_list,weights,'-ro',label="Beta:{}\ny = B^t * (1-B)".format(beta))
plt.xlabel("time")
plt.ylabel("weight")
plt.legend()
plt.title("exponentially weighted average")
plt.show()
print(np.sum(weights))

0.9999734386011124

2、针对多个动量的情况

# multi weights
# 通常都是设置动量为0.9
beta_list = [0.98,0.95,0.9,0.8]
w_list = [exp_w_func(beta,time_list) for beta in beta_list]
for i,w in enumerate(w_list):
    plt.plot(time_list,w,label="Beta:{}".format(beta_list[i]))
    plt.xlabel("time")
    plt.ylabel("weight")
plt.legend()
plt.show()

3、optim.SGD中的momentum

# SGD中的momentum
def func(x):
    return torch.pow(2*x,2)  # y = (2x)^2 = 4*x^2   dy/dx = 8x

iteration = 100
m = 0.9
lr_list = [0.01,0.03]

momentum_list = list()
loss_rec = [[] for l in range(len(lr_list))]
iter_rec = list()

for i,lr in enumerate(lr_list):
    x = torch.tensor([2.],requires_grad=True)
    momentum = 0. if lr == 0.03 else m
    momentum_list.append(momentum)
    
    optimizer = optim.SGD([x],lr=lr,momentum=momentum)
    
    for iter in range(iteration):
        y = func(x)
        y.backward()
        optimizer.step()
        optimizer.zero_grad()
        loss_rec[i].append(y.item())
        
for i,loss_r in enumerate(loss_rec):
    plt.plot(range(len(loss_r)),loss_r,label="LR:{} M:{}".format(lr_list[i],momentum_list[i]))
plt.legend()
plt.xlabel("Iteration")
plt.ylabel('Loss value')
plt.show()

可以看出增加了动量的loss呈现波动,但是可以很快达到最小值,同样也会逐渐趋于平缓。

 

### 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`. 此外还包括了两个主要操作——初始化时复制查询编码器到密钥编码器;每次迭代结束之后执行一次动量更新.
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林语微光

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值