Pytorch模型訓練(5) - Optimizer

《Optimizer》
  本文總結Pytorch中的Optimizer
  Optimizer是深度學習模型訓練中非常重要的一個模塊,它決定參數參數更新的方向,快慢和大小,好的Optimizer算法和合適的參數使得模型收斂又快又準
  但本文不會討論什麼任務用什麼Optimizer,及其參數設置,只是總結下Pytorch中的Optimizer

0 博客目錄

Pytorch模型訓練(0) - CPN源碼解析
Pytorch模型訓練(1) - 模型定義
Pytorch模型訓練(2) - 模型初始化
Pytorch模型訓練(3) - 模型保存與加載
Pytorch模型訓練(4) - Loss Function
Pytorch模型訓練(5) - Optimizer
Pytorch模型訓練(6) - 數據加載

1 torch.optim

  Pytorch的torch.optim是包含各種優化器算法的包,支持通用優化器方法,接口通用性好,也方便集成更加複雜的算法

  怎樣使用一個Optimizer ???
  要使用Optimizer,我們首先要創建一個Optimizer對象,該對象會保持當前狀態,並根據計算梯度來更新參數

1.1 創建Optimizer

  創建Optimizer時,需要爲其提供一些需要迭代的參數進行迭代,還可以指定一些可選的,特定的,用於優化的參數,如學習率,權重衰減等參數
  Example:

optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum=0.9)
optimizer = optim.Adam([var1, var2], lr = 0.0001)

  注意1:如果需要將模型移到GPU,可以通過".cuda"來實現

optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum=0.9).cuda()
optimizer = optim.Adam([var1, var2], lr = 0.0001).cuda()

  注意2:在訓練中,最好保持模型和優化在相同位置,即要在GPU,都在GPU

1.2 Optimizer參數

  Optimizer支持特殊參數指定選項,這樣需要用一個字典(dict)類型的可迭代參數代替變量(Variable)可迭代參數;它們有各自的參數組,用"params"關鍵字將他們獨立開(包含屬於它的參數列表)
  在需要不同層不同參數時,非常有用,如:

optim.SGD([
                {'params': model.base.parameters()},
                {'params': model.classifier.parameters(), 'lr': 1e-3}
            ], lr=1e-2, momentum=0.9)

  也就是,classifier.parameters的學習率爲1e-3,base.parameters的學習率爲le-2,動量0.9適用所有參數

1.3 Optimizer迭代

  迭代,更新參數,一般有下面2中方式:
  方式1:

optimizer.step()

  該方式能滿足大多需求,一般只要進行梯度需要,如backward(),這個step()函數就需要被召喚
  Example:

for input, target in dataset:
    optimizer.zero_grad()
    output = model(input)
    loss = loss_fn(output, target)
    loss.backward()
    optimizer.step()

  方式2:

optimizer.step(closure)

  一些特殊算法,如共軛梯度(Conjugate Gradient) 和 LBFGS 需要多次重新評估函數,所以需要傳入一個允許重新計算模型的閉包(closure),來清理梯度,計算loss並返回
  Example:

for input, target in dataset:
    def closure():
        optimizer.zero_grad()
        output = model(input)
        loss = loss_fn(output, target)
        loss.backward()
        return loss
    optimizer.step(closure)

2 Optimizer基類

torch.optim.Optimizer(params, defaults)

  所有Optimizer的基類

  參數:
  1)params:可迭代對象,需要被優化的參數對象,一般爲張量(torch.Tensor)或字典(dict)
  2)defaults:字典類型,一些優化選項,基本都有默認值

  方法:
  1)add_param_group(param_group)
    增加需要優化的參數到param_groups,如在使用預訓練模型進行微調時,很有用,可以將凍結層參數添加到訓練中
  2)load_state_dict(state_dict)
    加載優化器參數
  3)state_dict()
    返回優化器狀態,字典類型,包括優化器狀態和參數組
  4)step(closure)
    單步更新
  5)zero_grad()
    清空優化器參數的梯度

3 Optimizer

torch.optim.Adadelta(params, lr=1.0, rho=0.9, eps=1e-06, weight_decay=0)


torch.optim.Adagrad(params, lr=0.01, lr_decay=0, weight_decay=0, initial_accumulator_value=0)


torch.optim.Adam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0, amsgrad=False)


torch.optim.SparseAdam(params, lr=0.001, betas=(0.9, 0.999), eps=1e-08)

torch.optim.Adamax(params, lr=0.002, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)


torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)


torch.optim.ASGD(params, lr=0.01, lambd=0.0001, alpha=0.75, t0=1000000.0, weight_decay=0)


torch.optim.RMSprop(params, lr=0.01, alpha=0.99, eps=1e-08, weight_decay=0, momentum=0, centered=False)


torch.optim.Rprop(params, lr=0.01, etas=(0.5, 1.2), step_sizes=(1e-06, 50))


torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)

  這些Optimizer部分,我羅列的比較簡單,因爲在應用層,無非是他們的參數,而這些參數就關乎算法原理,不是本文重點,有興趣可以參見梯度下降算法原理的博客

4 學習率調節

  這些優化器中往往需要多個參數,共同控制才能達到優化目的,但大多數參數都有默認參考值,這些值都是大牛們經過多方驗證得出的,所以我們在訓練模型時,需要手動設置的參數並不多
  其中最需要我們手動調節的就是學習率,關於學習率衰減理論部分可參見個人博客;而Pytorch中怎麼調用呢?

torch.optim.lr_scheduler

  提供了基於epochs調節學習率的方法;主要有以下幾種:

torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1)

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

torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)

torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1)

torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1)

torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.1, patience=10, verbose=False, threshold=0.0001, threshold_mode='rel', cooldown=0, min_lr=0, eps=1e-08)

  Example:

optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
scheduler = ReduceLROnPlateau(optimizer, 'min')
for epoch in range(10):
train(...)
val_loss = validate(...)
# Note that step should be called after validate()
 scheduler.step(val_loss)

5 CPN Optimizer

  1)實例化Adam優化器

optimizer = torch.optim.Adam(model.parameters(),
                            lr = cfg.lr,
                            weight_decay=cfg.weight_decay)

  2)若resume,加載優化器狀態

if args.resume:
    if isfile(args.resume):
        print("=> loading checkpoint '{}'".format(args.resume))
        checkpoint = torch.load(args.resume)
        pretrained_dict = checkpoint['state_dict']
        model.load_state_dict(pretrained_dict)
        args.start_epoch = checkpoint['epoch']
        
        optimizer.load_state_dict(checkpoint['optimizer'])
        
        print("=> loaded checkpoint '{}' (epoch {})"
              .format(args.resume, checkpoint['epoch']))
        logger = Logger(join(args.checkpoint, 'log.txt'), resume=True)
    else:
        print("=> no checkpoint found at '{}'".format(args.resume))
else:        
    logger = Logger(join(args.checkpoint, 'log.txt'))
    logger.set_names(['Epoch', 'LR', 'Train Loss'])

  3)訓練時(學習率調節,train,優化器迭代,模型保存)

    for epoch in range(args.start_epoch, args.epochs):
    
    	#調節學習率
        lr = adjust_learning_rate(optimizer, epoch, cfg.lr_dec_epoch, cfg.lr_gamma)
        print('\nEpoch: %d | LR: %.8f' % (epoch + 1, lr)) 

        # train for one epoch
        #將優化器給train函數
        train_loss = train(train_loader, model, [criterion1, criterion2], optimizer)
        print('train_loss: ',train_loss)

        # append logger file
        logger.append([epoch + 1, lr, train_loss])

		#保存模型,也保存優化器狀態
        save_model({
            'epoch': epoch + 1,
            'state_dict': model.state_dict(),
            'optimizer' : optimizer.state_dict(),
        }, checkpoint=args.checkpoint)

  細節1:學習率調節函數adjust_learning_rate

def adjust_learning_rate(optimizer, epoch, schedule, gamma):
    """Sets the learning rate to the initial LR decayed by schedule"""
    if epoch in schedule:
        for param_group in optimizer.param_groups:
            param_group['lr'] *= gamma
    return optimizer.state_dict()['param_groups'][0]['lr']

  細節2:train函數,優化器迭代

    # compute gradient and do Optimization step
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章