Pytorch torch.optim 模块 优化器

Pytorch torch.optim 模块 优化器

1. 优化器: torch.optim 模块

PyTorch 中包含的优化器有:site

1.1 优化器 torch.optim.Optimizer

1.1.1 主要参数

  • params:需要通过优化器学习(即:优化,或训练)的参数,一般通过 model.parameters() 传入

    • 每一个模型的一组学习参数被称为一个 param_group
  • lr:学习速率,即每一 epoch 模型参数更新的程度

  • weight_decay:权重衰减 Weight Decay

  • 其他的参数,则根据具体的优化器而有所不同

参数组:优化器的传入参数也可以是一个 list,每个元素为 dict 类型,被称为参数组。每个 dict 用于设置优化参数,key 值为优化器的传入参数

  • 在 list 外的参数,被称为全局参数,用于设置未指定参数的参数组

  • 多用于模型参数微调(Fine-Tuning),只更新部分学习参数

实例:传入参数组

optimizer_1 = torch.optim.SGD(model.parameters(), lr=LEARNING_RATE)

optimizer_2 = torch.optim.SGD(
    # 参数组 1:模型的第1个线性层。特别设置参数 lr
    [{'params': model.layer1_linear.parameters(), 'lr': 0.5},  
    # 参数组 2:模型的的第2个线性层。未设置参数,由全局参数决定
     {'params': model.layer2_linear.parameters()}], 
    # 在 list 外的,为全局参数
    lr = LEARNING_RATE)

# 输出优化器的状态和传入参数
print(optimizer_2.state_dict())
# Output
# {'state': {}, 'param_groups': [{'lr': 0.5, ...}, 
#                                {'lr': 0.1, ...}]}

1.1.2 主要方法

.zero_grad(set_to_none=False):将优化器中所有待优化的 Tensor(传入优化器对象的 params)的梯度归零

.step(closure=None):执行一步优化(参数训练)过程

.add_param_group():添加参数组

.state_dict():返回一个 dict ,包含优化器状态,以及每个参数组的具体信息

  • 包含 2 个 key 值:'state''param_groups'

  • .state_dict()['param_groups']:返回 list 类型,每个元素为 dict 类型,表示一个参数组的具体信息

    • .state_dict()['param_groups'][0]['param']:返回参数组学习参数索引

.load_state_dict(state_dict):从指定的 dict 加载参数组的具体信息

实例:

# 输出 优化器的状态和 传入参数
print(optimizer_1.state_dict())
print(optimizer_2.state_dict())

1.1.3 主要属性

.defaults:返回 dict 类型,优化器的默认参数。默认参数不对优化器产生影响

.param_groups:返回 list 类型,每个元素为一个 dict,表示一个参数组的参数信息

  • .state_dict()['param_groups'] 类似,但是此方法能获取学习参数的具体数值,而不是索引

  • .param_groups[0]['params']:返回 list 类型,每个元素为 nn.Parameters 类,即学习参数

实例:

# 优化器 默认参数
print(optimizer_2.defaults)

# 优化器 参数组 具体信息
print(optimizer_2.param_groups)
print(optimizer_2.state_dict()['param_groups'])

# 获取 参数组1 的参数, 返回为 list 类型
param_group_1 = optimizer_2.param_groups[0]['params']
print(type(param_group_1), type(param_group_1[0]))
# 获取 参数组1 的 第1个参数
print(param_group_1[0].data)

1.1.4 权重衰减 Weight Decay

torch.optim.Optimizer 优化没有提供 L1 或 L2 正则化方法,但是提供了 Weight Decay 方法,可以实现 L2 正则化的效果。对于随机梯度下降法(SGD),Weight Decay 方法与 L2 正则化方法等价,但是,对于较为复杂的优化方法(比如 Adam)中,二者不完全等价(邱锡鹏,神经网络与深度学习)。

1.2 优化实例

1.2.1 优化器和模型的.zero_grad()方法使用区别

实例 1:网络模型训练实例,使用 optimizer.zero_grad() 方法

# Step 1: 定义优化器
optimizer = torch.optim.SGD(model.parameters(), lr=LEARNING_RATE)
for epoch in range(N_EPOCH):
    train_total_loss = 0.
    for i, (X_batch, Y_batch) in enumerate(dl_train): 
        optimizer.zero_grad()    # Step 2: 参数梯度归零
        out = model(X_batch)                           
        loss = loss_func(out, Y_batch.flatten())  
        loss.backward()          # Step 3: 反向传播,计算梯度
        optimizer.step()         # Step 4: 执行一步优化,更新参数
        train_total_loss += loss.item()

实例 2:使用梯度下降更新参数,使用 model.zero_grad() 方法

for epoch in range(N_EPOCH):
    train_total_loss = 0.
    for i, (X_batch, Y_batch) in enumerate(dl_train):
        model.zero_grad()       # Step 1: 参数梯度归零
        out = model(X_batch)                           
        loss = loss_func(out, Y_batch.flatten())  
        loss.backward()         # Step 2: 反向传播,计算梯度
        with torch.no_grad():   
            for param in model.parameters():    # 在更新参数时,取梯度追踪
                param -= LEARNING_RATE * param.grad     # Step 3: 更新参数
        train_total_loss += loss.item()

1.2.2 部分参数训练

训练部分学习参数,常用于模型微调(Fine-Tuning)

# 定义模型
model2 = BPNNModeler2(input_dim=INPUT_DIM, hidden_dim=HIDDEN_DIM, output_dim=OUTPUT_DIM)
# 模型初始参数
w1 = model2.layer1_linear.weight.data.clone()
b1 = model2.layer1_linear.bias.data.clone()
w2 = model2.layer2_linear.weight.data.clone()
b2 = model2.layer2_linear.bias.data.clone()

# 仅训练 model2 第2层的线性层,即 w2 和 b2
param = model2.layer2_linear.parameters()
# 定义优化器
optimizer = torch.optim.SGD(param, lr=LEANING_RATE)
for epoch in range(N_EPOCH):
    train_total_loss = 0.
    for i, (X_batch, Y_batch) in enumerate(dl_train): 
        optimizer.zero_grad()    # 参数梯度归零
        out = model2(X_batch)                           
        loss = loss_func(out, Y_batch.flatten())  
        loss.backward()          # 反向传播,计算梯度
        optimizer.step()         # 执行一步优化,更新参数
        train_total_loss += loss.item()
    # 检查 参数 是否改变
    w1_new = model2.layer1_linear.weight.data
    b1_new = model2.layer1_linear.bias.data
    w2_new = model2.layer2_linear.weight.data
    b2_new = model2.layer2_linear.bias.data
    print(epoch + 1, 
          'w1:', torch.sum(torch.abs(w1 - w1_new)).item(),    # 0
          'b1:', torch.sum(torch.abs(b1 - b1_new)).item(),    # 0
          'w2:', torch.sum(torch.abs(w2 - w2_new)).item(),    # 大于 0
          'b2:', torch.sum(torch.abs(b2 - b2_new)).item())    # 大于 0

另外一种微调方法,将不需要改变的学习参数(或类)自动梯度关闭,即

tensor.requires_grad_(False)
module.requires_grad_(False)

2. 学习速度策略:torch.optim.lr_scheduler 模块

PyTorch 中包含的学习速度策略有:site

通用参数

verbose: 默认为 False;是否在每个 Epoch print 学习速率

使用 lr_scheduler 模块调整优化器的学习速率时,在定义优化器时,需要设置参数 initial_lr,表示初始的学习速率,同时 lr 参数也不可忽略

optimizer = torch.optim.SGD(
    [{'params': model.parameters(), 'initial_lr': LEARNING_RATE}],  # 需要向 param group 传入 initial_lr 参数
    lr = LEARNING_RATE)  # lr 参数不可忽略

通过 optimizer.param_groups[0]['initial_lr'] 返回初始学习速率;通过 optimizer.param_groups[0]['lr'] 返回当前学习速率

2.1 StepLR()

torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1, verbose=False)

参数: 每隔 step_size epochs,lr 调整为 lr * gamma,如:

# 假设:lr = 1.0, gamma = 0.1, step_size = 10
# lr = 1.0     if  1 <= epoch < 10
# lr = 0.1     if 10 <= epoch < 20
# lr = 0.01    if 20 <= epoch < 30

实例: 设置 StepLR()

N_EPOCH = 50
LEARNING_RATE = 1.

# 定义 优化器
optimizer = torch.optim.SGD(
    [{'params': model.parameters(), 'initial_lr': LEARNING_RATE}],  # 需要向 param group 传入 initial_lr 参数
    lr = LEARNING_RATE)  # lr 参数不可忽略
# 定义 学习速率调整方式
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)

for epoch in range(N_EPOCH):
    train_total_loss = 0.
    # 训练
    for i, (X_batch, Y_batch) in enumerate(dl_train):  
        optimizer.zero_grad()
        out = model(X_batch)                        
        loss = loss_func(out, Y_batch.flatten())    
        loss.backward()
        optimizer.step()   
        train_total_loss += loss.item() 
    # 更新 学习速率
    scheduler.step() 

    # Print Traing information
    print('Epoch: {0:>4}, Train Loss: {1:>10.5f}, LR: {2:>10.8f}, Init LR: {3:>10.8f}'.format(
        epoch+1, 
        train_total_loss, 
        optimizer.param_groups[0]['lr'], 
        optimizer.param_groups[0]['initial_lr']))

参考资料

文中代码:Colab, GitHub

PyTorch 官方文档, torch.optim, site

邱锡鹏,第7.7节 网络正则化, 神经网络与深度学习,机械工业出版社, 2020, Github

posted @ 2022-05-24 12:36  veager  阅读(607)  评论(0编辑  收藏  举报