天天看點

Pytorch模型訓練(5) - Optimizer0 部落格目錄1 torch.optim2 Optimizer基類3 Optimizer4 學習率調節5 CPN Optimizer

《Optimizer》

  本文總結Pytorch中的Optimizer

  Optimizer是深度學習模型訓練中非常重要的一個子產品,它決定參數參數更新的方向,快慢和大小,好的Optimizer算法和合适的參數使得模型收斂又快又準

  但本文不會讨論什麼任務用什麼Optimizer,及其參數設定,隻是總結下Pytorch中的Optimizer

文章目錄

  • 0 部落格目錄
  • 1 torch.optim
    • 1.1 建立Optimizer
    • 1.2 Optimizer參數
    • 1.3 Optimizer疊代
  • 2 Optimizer基類
  • 3 Optimizer
  • 4 學習率調節
  • 5 CPN 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()