Pytorch 小操作

該文章部分轉載於 https://zhuanlan.zhihu.com/p/76459295

1.指定GPU編號

第一種方法

  • 設置當前使用的GPU設備僅爲0號設備,設備名稱爲 /gpu:0os.environ["CUDA_VISIBLE_DEVICES"] = "0"

  • 設置當前使用的GPU設備爲0,1號兩個設備,名稱依次爲 /gpu:0/gpu:1os.environ["CUDA_VISIBLE_DEVICES"] = "0,1" ,根據順序表示優先使用0號設備,然後使用1號設備。

    注:指定GPU的命令需要放在和神經網絡相關的一系列操作的前面。

第二種方法

device_ids = [0,1]
model = model.cuda(device_ids[0])  //將模型及參數主要放置在0號卡
if len(device_ids) > 1:
    self.model = nn.DataParallel(model, device_ids=device_ids) //使用多個GPU並行運算

2、查看模型每層輸出詳情

查看模型每層輸出詳情

from torchsummary import summary
summary(your_model, input_size=(channels, H, W))

3、梯度裁剪(Gradient Clipping)

import torch.nn as nn

outputs = model(data)
loss= loss_fn(outputs, target)
optimizer.zero_grad()
loss.backward()
nn.utils.clip_grad_norm_(model.parameters(), max_norm=20, norm_type=2)
optimizer.step()

nn.utils.clip_grad_norm_ 的參數:

  • parameters – 一個基於變量的迭代器,會進行梯度歸一化
  • max_norm – 梯度的最大範數
  • norm_type – 規定範數的類型,默認爲L2

不橢的橢圓 提出:梯度裁剪在某些任務上會額外消耗大量的計算時間,可移步評論區查看詳情

4、學習率衰減

import torch.optim as optim
from torch.optim import lr_scheduler

# 訓練前的初始化
optimizer = optim.Adam(net.parameters(), lr=0.001)
scheduler = lr_scheduler.StepLR(optimizer, 10, 0.1)  # # 每過10個epoch,學習率乘以0.1

# 訓練過程中
for n in n_epoch:
    scheduler.step()
    ...

可用的學習率衰減方法

  • 等間隔調整學習率 StepLR
torch.optim.lr_scheduler.StepLR(optimizer, step_size, gamma=0.1, last_epoch=-1)
 
'''
等間隔調整學習率,調整倍數爲 gamma 倍,調整間隔爲 step_size。間隔單位是step。需要注意的是, step 通常是指 epoch,不要弄成 iteration 了。
##########################################################
step_size(int)- 學習率下降間隔數,若爲 30,則會在 30、 60、 90…個 step 時,將學習率調整爲 lr*gamma。
gamma(float)- 學習率調整倍數,默認爲 0.1 倍,即下降 10 倍。
last_epoch(int)- 上一個 epoch 數,這個變量用來指示學習率是否需要調整。當last_epoch 符合設定的間隔時,就會對學習率進行調整。當爲-1 時,學習率設置爲初始值。
'''
  • 按需調整學習率 MultiStepLR
torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones, gamma=0.1, last_epoch=-1)
 
'''
按設定的間隔調整學習率。這個方法適合後期調試使用,觀察 loss 曲線,爲每個實驗定製學習率調整時機。
##########################################################
milestones(list)- 一個 list,每一個元素代表何時調整學習率, list 元素必須是遞增的。如 milestones=[30,80,120]
gamma(float)- 學習率調整倍數,默認爲 0.1 倍,即下降 10 倍。
'''
  • 指數衰減調整學習率 ExponentialLR
torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma, last_epoch=-1)
 
'''
按指數衰減調整學習率,調整公式: lr=lr∗gamma∗∗epoch lr = lr * gamma**epoch
gamma- 學習率調整倍數的底,指數爲 epoch,即 gamma**epoch
'''
  • 餘弦退火調整學習率 CosineAnnealingLR
torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max, eta_min=0, last_epoch=-1)
 
'''
以餘弦函數爲週期,並在每個週期最大值時重新設置學習率。以初始學習率爲最大學習率,以 2∗T_max 爲週期,在一個週期內先下降,後上升。
##########################################################
T_max(int)- 一次學習率週期的迭代次數,即 T_max 個 epoch 之後重新設置學習率。
eta_min(float)- 最小學習率,即在一個週期中,學習率最小會下降到 eta_min,默認值爲 0。
'''
  • 自適應調整學習率 ReduceLROnPlateau
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)
 
'''
當某指標不再變化(下降或升高),調整學習率,這是非常實用的學習率調整策略。
##########################################################
mode(str)- 模式選擇,有 min 和 max 兩種模式, min 表示當指標不再降低(如監測loss), max 表示當指標不再升高(如監測 accuracy)。
factor(float)- 學習率調整倍數(等同於其它方法的 gamma),即學習率更新爲 lr = lr * factor
patience(int)- 忍受該指標多少個 step 不變化,當忍無可忍時,調整學習率。
verbose(bool)- 是否打印學習率信息, print(‘Epoch {:5d}: reducing learning rate of group {} to {:.4e}.’.format(epoch, i, new_lr))
threshold_mode(str)- 選擇判斷指標是否達最優的模式,有兩種模式, rel 和 abs。
當 threshold_mode == rel,並且 mode == max 時, dynamic_threshold = best * ( 1 +threshold );
當 threshold_mode == rel,並且 mode == min 時, dynamic_threshold = best * ( 1 -threshold );
當 threshold_mode == abs,並且 mode== max 時, dynamic_threshold = best + threshold ;
當 threshold_mode == rel,並且 mode == max 時, dynamic_threshold = best - threshold;
threshold(float)- 配合 threshold_mode 使用。
cooldown(int)- “冷卻時間“,當調整學習率之後,讓學習率調整策略冷靜一下,讓模型再訓練一段時間,再重啓監測模式。
min_lr(float or list)- 學習率下限,可爲 float,或者 list,當有多個參數組時,可用 list 進行設置。
eps(float)- 學習率衰減的最小值,當學習率變化小於 eps 時,則不調整學習率。
'''
  • 自定義調整學習率 LambdaLR
torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda, last_epoch=-1)
 
'''
爲不同參數組設定不同學習率調整策略。調整規則爲,
lr=base_lr∗lmbda(self.last_epoch)
fine-tune 中十分有用,我們不僅可爲不同的層設定不同的學習率,還可以爲其設定不同的學習率調整策略。
##########################################################
lr_lambda(function or list)- 一個計算學習率調整倍數的函數,輸入通常爲 step,當有多個參數組時,設爲 list。
'''

5、在不同的層使用不同的學習率

我們對模型的不同層使用不同的學習率。

還是使用這個模型作爲例子:

net = Network()  # 獲取自定義網絡結構
for name, value in net.named_parameters():
    print('name: {}'.format(name))

# 輸出:
# name: cnn.VGG_16.convolution1_1.weight
# name: cnn.VGG_16.convolution1_1.bias
# name: cnn.VGG_16.convolution1_2.weight
# name: cnn.VGG_16.convolution1_2.bias
# name: cnn.VGG_16.convolution2_1.weight
# name: cnn.VGG_16.convolution2_1.bias
# name: cnn.VGG_16.convolution2_2.weight
# name: cnn.VGG_16.convolution2_2.bias

對 convolution1 和 convolution2 設置不同的學習率,首先將它們分開,即放到不同的列表裏:

conv1_params = []
conv2_params = []

for name, parms in net.named_parameters():
    if "convolution1" in name:
        conv1_params += [parms]
    else:
        conv2_params += [parms]

# 然後在優化器中進行如下操作:
optimizer = optim.Adam(
    [
        {"params": conv1_params, 'lr': 0.01},
        {"params": conv2_params, 'lr': 0.001},
    ],
    weight_decay=1e-3,
)

我們將模型劃分爲兩部分,存放到一個列表裏,每部分就對應上面的一個字典,在字典裏設置不同的學習率。當這兩部分有相同的其他參數時,就將該參數放到列表外面作爲全局參數,如上面的weight_decay

也可以在列表外設置一個全局學習率,當各部分字典裏設置了局部學習率時,就使用該學習率,否則就使用列表外的全局學習率。

6、凍結某些層的參數

在加載預訓練模型的時候,我們有時想凍結前面幾層,使其參數在訓練過程中不發生變化。

我們需要先知道每一層的名字,通過如下代碼打印:

net = Network()  # 獲取自定義網絡結構
for name, value in net.named_parameters():
    print('name: {0},\t grad: {1}'.format(name, value.requires_grad))

假設前幾層信息如下:

name: cnn.VGG_16.convolution1_1.weight,	 grad: True
name: cnn.VGG_16.convolution1_1.bias,	 grad: True
name: cnn.VGG_16.convolution1_2.weight,	 grad: True
name: cnn.VGG_16.convolution1_2.bias,	 grad: True
name: cnn.VGG_16.convolution2_1.weight,	 grad: True
name: cnn.VGG_16.convolution2_1.bias,	 grad: True
name: cnn.VGG_16.convolution2_2.weight,	 grad: True
name: cnn.VGG_16.convolution2_2.bias,	 grad: True

後面的True表示該層的參數可訓練,然後我們定義一個要凍結的層的列表:

no_grad = [
    'cnn.VGG_16.convolution1_1.weight',
    'cnn.VGG_16.convolution1_1.bias',
    'cnn.VGG_16.convolution1_2.weight',
    'cnn.VGG_16.convolution1_2.bias'
]

凍結方法如下:

net = Net.CTPN()  # 獲取網絡結構
for name, value in net.named_parameters():
    if name in no_grad:
        value.requires_grad = False
    else:
        value.requires_grad = True

凍結後我們再打印每層的信息:

name: cnn.VGG_16.convolution1_1.weight,	 grad: False
name: cnn.VGG_16.convolution1_1.bias,	 grad: False
name: cnn.VGG_16.convolution1_2.weight,	 grad: False
name: cnn.VGG_16.convolution1_2.bias,	 grad: False
name: cnn.VGG_16.convolution2_1.weight,	 grad: True
name: cnn.VGG_16.convolution2_1.bias,	 grad: True
name: cnn.VGG_16.convolution2_2.weight,	 grad: True
name: cnn.VGG_16.convolution2_2.bias,	 grad: True

可以看到前兩層的weight和bias的requires_grad都爲False,表示它們不可訓練。

最後在定義優化器時,只對requires_grad爲True的層的參數進行更新。

optimizer = optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=0.01)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章