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']))
参考资料
PyTorch 官方文档, torch.optim, site
邱锡鹏,第7.7节 网络正则化, 神经网络与深度学习,机械工业出版社, 2020, Github