網(wǎng)站建設(shè)可行分析性報(bào)告真正永久免費(fèi)的建站系統(tǒng)有哪些
優(yōu)化器Optimizer
什么是優(yōu)化器
pytorch
的優(yōu)化器:管理并更新模型中可學(xué)習(xí)參數(shù)的值,使得模型輸出更接近真實(shí)標(biāo)簽
導(dǎo)數(shù):函數(shù)在指定坐標(biāo)軸上的變化率
方向?qū)?shù):指定方向上的變化率(二元及以上函數(shù),偏導(dǎo)數(shù))
梯度:一個(gè)向量,方向是使得方向?qū)?shù)取得最大值的方向
Pytorch
的Optimizer
參數(shù)
- defaults:優(yōu)化器超參數(shù)
- state:參數(shù)的緩存,如momentum的緩存
param_groups
:管理的參數(shù)組- _step_count:記錄更新次數(shù),學(xué)習(xí)率調(diào)整中使用
基本方法:
- zero_grad():清空所管理參數(shù)的梯度
pytorch
特性:張量梯度不會自動清零
-
step():執(zhí)行一步更新
-
add_param_group()
:添加參數(shù)組
-
state_dict()
:獲取優(yōu)化器當(dāng)前狀態(tài)信息字典
-
load_state_dict()
:加載狀態(tài)信息字典
使用代碼幫助理解和學(xué)習(xí)
import os
import torch
import torch.optim as optimBASE_DIR = os.path.dirname(os.path.abspath(__file__))weight = torch.randn((2, 2), requires_grad=True)
weight.grad = torch.ones((2, 2))# 需要傳入一個(gè)可迭代對象
optimizer = optim.SGD([weight], lr=1)print("weight before step:{}".format(weight.data))
optimizer.step()
print("weight after step:{}".format(weight.data))weight before step:tensor([[-0.0606, -0.3197],[ 1.4949, -0.8007]])
weight after step:tensor([[-1.0606, -1.3197],[ 0.4949, -1.8007]])
weight = weight - lr * weight.grad
上面學(xué)習(xí)率是1,把學(xué)習(xí)率改為0.1試一下
optimizer = optim.SGD([weight], lr=0.1)weight before step:tensor([[ 0.3901, 0.2167],[-0.3428, -0.7151]])
weight after step:tensor([[ 0.2901, 0.1167],[-0.4428, -0.8151]])
接著上面的代碼,我們再看一下add_param_group
方法
# add_param_group方法
print("optimizer.param_groups is \n{}".format(optimizer.param_groups))w2 = torch.randn((3, 3), requires_grad=True)
optimizer.add_param_group({"params": w2, "lr": 0.0001})
print("optimizer.param_groups is\n{}".format(optimizer.param_groups))optimizer.param_groups is
[{'params': [tensor([[ 0.1749, -0.2018],[ 0.0080, 0.3517]], requires_grad=True)], 'lr': 0.1, 'momentum': 0, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}]optimizer.param_groups is
[{'params': [tensor([[ 0.1749, -0.2018],[ 0.0080, 0.3517]], requires_grad=True)], 'lr': 0.1, 'momentum': 0, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}, {'params': [tensor([[ 0.4538, -0.8521, -1.3081],[-0.0158, -0.2708, 0.0302],[-0.3751, -0.1052, -0.3030]], requires_grad=True)], 'lr': 0.0001, 'momentum': 0, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}]
關(guān)于zero_grad()
、step()
、state_dict()
、load_state_dict()
這幾個(gè)方法比較簡單就不再贅述。
SGD
隨機(jī)梯度下降
learning_rate學(xué)習(xí)率
這里學(xué)習(xí)率為1,可以看到并沒有達(dá)到梯度下降的效果,反而y值越來越大,這是因?yàn)楦碌牟椒ヌ蟆?/p>
我們以y = 4*x^2
這個(gè)函數(shù)舉例,將y值作為要優(yōu)化的損失值,那么梯度下降的過程就是為了找到y(tǒng)的最小值(即此函數(shù)曲線的最小值);如果我們把學(xué)習(xí)率設(shè)置為0.2,就可以得到這樣一個(gè)梯度下降的圖
def func(x):return torch.pow(2*x, 2)x = torch.tensor([2.], requires_grad=True)
iter_rec, loss_rec, x_rec = list(), list(), list()
lr = 0.2
max_iteration = 20for i in range(max_iteration):y = func(x)y.backward()print("iter:{}, x:{:8}, x.grad:{:8}, loss:{:10}".format(i, x.detach().numpy()[0], x.grad.detach().numpy()[0], y.item()))x_rec.append(x.item())x.data.sub_(lr * x.grad)x.grad.zero_()iter_rec.append(i)loss_rec.append(y.item())plt.subplot(121).plot(iter_rec, loss_rec, '-ro')
plt.xlabel("Iteration")
plt.ylabel("Loss value")x_t = torch.linspace(-3, 3, 100)
y = func(x_t)
plt.subplot(122).plot(x_t.numpy(), y.numpy(), label="y = 4*x^2")
plt.grid()y_rec = [func(torch.tensor(i)).item() for i in x_rec]
plt.subplot(122).plot(x_rec, y_rec, '-ro')
plt.legend()
plt.show()
這里其實(shí)存在一個(gè)下降速度更快的學(xué)習(xí)率,那就是0.125,一步就可以將loss更新為0,這是因?yàn)槲覀円呀?jīng)了這個(gè)函數(shù)表達(dá)式,而在實(shí)際神經(jīng)網(wǎng)絡(luò)模型訓(xùn)練的過程中,是不知道所謂的函數(shù)表達(dá)式的,所以只能選取一個(gè)相對較小的學(xué)習(xí)率,然后以訓(xùn)練更多的迭代次數(shù)來達(dá)到最優(yōu)的loss。
動量(Momentum,又叫沖量)
結(jié)合當(dāng)前梯度與上一次更新信息,用于當(dāng)前更新
為什么會出現(xiàn)動量這個(gè)概念?
當(dāng)學(xué)習(xí)率比較小時(shí),往往更新比較慢,通過引入動量,使得后續(xù)的更新受到前面更新的影響,可以更快的進(jìn)行梯度下降。
指數(shù)加權(quán)平均:當(dāng)前時(shí)刻的平均值(Vt)與當(dāng)前參數(shù)值(θ)和前一時(shí)刻的平均值(Vt-1)的關(guān)系。
根據(jù)上述公式進(jìn)行迭代展開,因?yàn)?<β<1,當(dāng)前時(shí)刻的平均值受越近時(shí)刻的影響越大(更近的時(shí)刻其所占的權(quán)重更高),越遠(yuǎn)時(shí)刻的影響越小,我們可以通過下面作圖來看到這一變化。
import numpy as np
import matplotlib.pyplot as pltdef exp_w_func(beta, time_list):return [(1-beta) * np.power(beta, exp) for exp in time_list]beta = 0.9
num_point = 100
time_list = np.arange(num_point).tolist()weights = exp_w_func(beta, time_list)plt.plot(time_list, weights, '-ro', label="Beta: {}\n = B * (1-B)^t".format(beta))
plt.xlabel("time")
plt.ylabel("weight")
plt.legend()
plt.title("exponentially weighted average")
plt.show()
這里β是一個(gè)超參數(shù),設(shè)置不同的值,其對于過去時(shí)刻的權(quán)重計(jì)算如下圖
beta_list = [0.98, 0.95, 0.9, 0.8]
w_list = [exp_w_func(beta, time_list) for beta in beta_list]
for i, w in enumerate(w_list):plt.plot(time_list, w, label="Beta: {}".format(beta_list[i]))plt.xlabel("time")plt.ylabel("weight")
plt.legend()
plt.show()
從圖中可以得到這一結(jié)論:β值越小,記憶周期越短,β值越大,記憶周期越長。
pytorch
中帶有momentum參數(shù)的更新公式
對于y=4*x^2
這個(gè)例子,在沒有momentum時(shí),我們對比學(xué)習(xí)率分別為0.01和0.03會發(fā)現(xiàn),0.03收斂的更快。
如果我們給learning_rate=0.01增加momentum參數(shù),會發(fā)現(xiàn)其可以先一步0.03的學(xué)習(xí)率到達(dá)loss的較小值,但是因?yàn)閯恿枯^大的因素,在達(dá)到了最小值后還會反彈到一個(gè)大的值。
Pytorch
中的優(yōu)化器
optim.SGD
主要參數(shù):
params
:管理的參數(shù)組lr
:學(xué)習(xí)率- momentum:動量系數(shù),貝塔
weight_decay
:L2
正則化系數(shù)nesterov
:是否采用NAG,默認(rèn)False
optim.Adagrad
:自適應(yīng)學(xué)習(xí)率梯度下降法
optim.RMSprop
:Adagrad的改進(jìn)
optim.Adadelta
:Adagrad的改進(jìn)
optim.Adam
:RMSprop結(jié)合Momentum
optim.Adamax
:Adam增加學(xué)習(xí)率上限
optim.SparseAdam
:稀疏版的Adam
optim.ASGD
:隨機(jī)平均梯度下降
optim.Rprop
:彈性反向傳播
optim.LBFGS
:BFGS的改進(jìn)
學(xué)習(xí)率調(diào)整
前期學(xué)習(xí)率大,后期學(xué)習(xí)率小
pytorch
中調(diào)整學(xué)習(xí)率的基類
class _LRScheduler
主要屬性:
- optimizer:關(guān)聯(lián)的優(yōu)化器
- last_epoch:記錄epoch數(shù)
base_lrs
:記錄初始學(xué)習(xí)率
主要方法:
- step():更新下一個(gè)epoch的學(xué)習(xí)率
get_lr()
:虛函數(shù),計(jì)算下一個(gè)epoch的學(xué)習(xí)率
StepLR
等間隔調(diào)整學(xué)習(xí)率
主要參數(shù):
- step_size:調(diào)整間隔數(shù)
- gamma:調(diào)整系數(shù)
調(diào)整方式:lr = lr * gamma
import torch
import torch.optim as optim
import matplotlib.pyplot as pltLR = 0.1
iteration = 10
max_epoch = 200weights = torch.randn((1,), requires_grad=True)
target = torch.zeros((1, ))optimizer = optim.SGD([weights], lr=LR, momentum=0.9)scheduler_lr = optim.lr_scheduler.StepLR(optimizer, step_size=50, gamma=0.1) # 設(shè)置學(xué)習(xí)率下降策略lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):lr_list.append(scheduler_lr.get_lr())epoch_list.append(epoch)for i in range(iteration):loss = torch.pow((weights-target), 2)loss.backward()optimizer.step()optimizer.zero_grad()scheduler_lr.step()plt.plot(epoch_list, lr_list, label='Step LR Scheduler')
plt.xlabel('Epoch')
plt.ylabel('Learning Rate')
plt.legend()
plt.show()
MultiStepLR
功能:按給定間隔調(diào)整學(xué)習(xí)率
主要參數(shù):
- milestones:設(shè)定調(diào)整時(shí)刻數(shù)
- gamma:調(diào)整系數(shù)
調(diào)整方式:lr = lr * gamma
# MultiStepLR
milestones = [50, 125, 160]
scheduler_lr = optim.lr_scheduler.MultiStepLR(optimizer, milestones=milestones, gamma=0.1)
只需要改變這里代碼,其他部分與StepLR
中基本一致
ExponentialLR
功能:按指數(shù)衰減調(diào)整學(xué)習(xí)率
主要參數(shù):
- gamma:指數(shù)的底
調(diào)整方式:lr = lr * gamma ** epoch
# Exponential LR
gamma = 0.95
scheduler_lr = optim.lr_scheduler.ExponentialLR(optimizer, gamma=gamma)
CosineAnnealingLR
功能:余弦周期調(diào)整學(xué)習(xí)率
主要參數(shù):
- T_max:下降周期
- eta_min:學(xué)習(xí)率下限
調(diào)整方式:
# CosineAnnealingLR
t_max = 50
scheduler_lr = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=t_max, eta_min=0)
ReduceLRonPlateau
功能:監(jiān)控指標(biāo),當(dāng)指標(biāo)不再變化則調(diào)整學(xué)習(xí)率
主要參數(shù):
mode
:min/max,兩種模式,min觀察下降,max觀察上升- factor:調(diào)整系數(shù)
- patience:“耐心”,接受幾次不變化
cooldown
:“冷卻時(shí)間”,停止監(jiān)控一段時(shí)間- verbose:是否打印日志
min_lr
:學(xué)習(xí)率下限eps
:學(xué)習(xí)率衰減最小值
# Reduce LR on Plateau
loss_value = 0.5
accuray = 0.9factor = 0.1
mode = 'min'
patience = 10
cooldown = 10
min_lr = 1e-4
verbose = Truescheduler_lr = optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=factor, mode=mode, patience=patience,cooldown=cooldown, min_lr=min_lr, verbose=verbose)
for epoch in range(max_epoch):for i in range(iteration):optimizer.step()optimizer.zero_grad()# if epoch == 5:# loss_value = 0.4# 把要監(jiān)控的指標(biāo)傳進(jìn)去scheduler_lr.step(loss_value)Epoch 12: reducing learning rate of group 0 to 1.0000e-02.
Epoch 33: reducing learning rate of group 0 to 1.0000e-03.
Epoch 54: reducing learning rate of group 0 to 1.0000e-04.
LambdaLR
功能:自定義調(diào)整策略
主要參數(shù):
lr_lambda
:function or list
# lambda LRlr_init = 0.1
weights_1 = torch.randn((6, 3, 5, 5))
weights_2 = torch.ones((5, 5))optimizer = optim.SGD([{'params': [weights_1]},{'params': [weights_2]}
], lr=lr_init)lambda1 = lambda epoch: 0.1 ** (epoch // 20)
lambda2 = lambda epoch: 0.95 ** epochscheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=[lambda1, lambda2])lr_list, epoch_list = list(), list()
for epoch in range(max_epoch):for i in range(iteration):optimizer.step()optimizer.zero_grad()scheduler.step()lr_list.append(scheduler.get_lr())epoch_list.append(epoch)print('epoch: {:5d}, lr:{}'.format(epoch, scheduler.get_lr()))