Pytoch中用来优化模型权重的类是torch.optim.Optimizer, 其他各种我们所熟知的优化器都是Optimizer这个基类的子类, 我们今天就来谈谈如何构建一个模型的优化器对象实例.
先用一段代码来看看整体的步骤:
class trainer:
def __init__(self, args):
self.model = model #构建模型
if args.cuda:
self.model = self.model.cuda() #如果有可用的gpu,在构建模型的优化器之前要先把模型导入到gpu之中
self.optimizer = torch.optim.SGD(params=self.model.parameters(), lr=args.lr) #构建一个SDG类的实例
self.loss = torch.nn.nn.CrossEntropyLoss() #构建一个损失函数类实例
if args.cuda:
self.loss = self.loss.cuda() #同理导入近gpu
def traing(self):
#下面是一个训练过程,主要的步骤包括:
"""
1. 清空梯度
2. 动态调整学习率(非必须)
3. 前向传播
4. 计算loss
5. 反向传播
6. 更新参数
"""
self.optimizer.zero_grad()
output = self.model(input)
loss = sefl.loss(output, label)
loss.backward()
self.optimizer.step()
今天我们主要关注优化器optimizer这一块的内容.
所有的优化都继承torch.optim.Optimizer类
CLASS torch.optim.Optimizer(params, defaults)
我们重点关注params的传入, 其传入的数据类型有两种:
因此可以有两种传入参数的方式:
1.模型的权重共享同一个学习率, 直接将模型的参数全部传入进去:
self.optimizer = torch.optim.SGD(params=self.model.parameters(), lr=args.lr)
#这种方式下模型所有参数将用同一个学习率(learning_rate)来调整.
2.我们希望模型的权重不全都共享同一个学习率, 这个时候就需要用到第二种方式了:
1).首先将模型的参数分类,每一类都有不同的学习率!!!
def get_1x_lr_params(self):
modules = [self.backbone]
for i in range(len(modules)):
for m in modules[i].named_modules():
if isinstance(m[1], nn.Conv2d) or isinstance(m[1], SynchronizedBatchNorm2d) \
or isinstance(m[1], nn.BatchNorm2d):
for p in m[1].parameters():
if p.requires_grad:
yield p
def get_10x_lr_params(self):
modules = [self.aspp, self.decoder]
for i in range(len(modules)):
for m in modules[i].named_modules():
if isinstance(m[1], nn.Conv2d) or isinstance(m[1], SynchronizedBatchNorm2d) \
or isinstance(m[1], nn.BatchNorm2d):
for p in m[1].parameters():
if p.requires_grad:
yield p
2).构建一个优化参数列表
def optim_parameters(self, args):
return [{'params': self.get_1x_lr_params_NOscale(), 'lr': args.learning_rate},
{'params': self.get_10x_lr_params(), 'lr': 10 * args.learning_rate}]
3).传入模型的参数, 构建优化器
self.optimizer = torch.optim.SGD(params = self.model.optim_parameters(args))
大多数情况下, 我们还需要动态地调整优化器的学习率,那么该如何操作了:
每一个optimizer的实例都存在一个optimizer.param_groups的属性, 其是一个list类型, 列表中的每个元素都以dict的类型存放. 只需要调整dict中的’lr’项的值即可!!!
构建一个动态调整学习率的函数方法
#计算学习率
def lr_poly(base_lr, iter, max_iter, power):
return base_lr * ((1 - float(iter) / max_iter) ** (power))
#调整学习率, 将optimizer优化器实例传进来即可
def adjust_learning_rate(optimizer, i_iter):
lr = lr_poly(args.learning_rate, i_iter, args.num_steps, args.power)
# 修改优化器中的学习率超参数
optimizer.param_groups[0]['lr'] = lr
optimizer.param_groups[1]['lr'] = lr * 10