13個算法工程師必須掌握的PyTorch Tricks

2020-12-14 酷扯兒

本文轉載自【微信公眾號:機器學習算法與Python精研 ,ID:AITop100】,經微信公眾號授權轉載,如需轉載原文作者聯繫

目錄

1、指定GPU編號

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

3、梯度裁剪

4、擴展單張圖片維度

5、one hot編碼

6、防止驗證模型時爆顯存

7、學習率衰減

8、凍結某些層的參數

9、對不同層使用不同學習率

10、模型相關操作

11、Pytorch內置one hot函數

12、網絡參數初始化

13、加載內置預訓練模型

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的命令需要放在和神經網絡相關的一系列操作的前面。

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

Keras有一個簡潔的API來查看模型的每一層輸出尺寸,這在調試網絡時非常有用。現在在PyTorch中也可以實現這個功能。

使用很簡單,如下用法:

from torchsummary import summary

summary(your_model, input_size=(channels, H, W))

input_size

是根據你自己的網絡模型的輸入尺寸進行設置。

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、擴展單張圖片維度

因為在訓練時的數據維度一般都是 (batch_size, c, h, w),而在測試時只輸入一張圖片,所以需要擴展維度,擴展維度有多個方法:

import cv2

import torch

image = cv2.imread(img_path)

image = torch.tensor(image)

print(image.size())

img = image.view(1, *image.size())

print(img.size())

# output:

# torch.Size([h, w, c])

# torch.Size([1, h, w, c])

import cv2

import numpy as np

image = cv2.imread(img_path)

print(image.shape)

img = image[np.newaxis, :, :, :]

print(img.shape)

# output:

# (h, w, c)

# (1, h, w, c)

或(感謝 @coldleaf 的補充)

import cv2

import torch

image = cv2.imread(img_path)

image = torch.tensor(image)

print(image.size())

img = image.unsqueeze(dim=0)

print(img.size())

img = img.squeeze(dim=0)

print(img.size())

# output:

# torch.Size([(h, w, c)])

# torch.Size([1, h, w, c])

# torch.Size([h, w, c])

tensor.unsqueeze(dim)

:擴展維度,dim指定擴展哪個維度。

tensor.squeeze(dim)

:去除dim指定的且size為1的維度,維度大於1時,squeeze()不起作用,不指定dim時,去除所有size為1的維度。

5、獨熱編碼

在PyTorch中使用交叉熵損失函數的時候會自動把label轉化成onehot,所以不用手動轉化,而使用MSE需要手動轉化成onehot編碼。

import torch

class_num = 8

batch_size = 4

def one_hot(label):

"""

將一維列錶轉換為獨熱編碼

"""

label = label.resize_(batch_size, 1)

m_zeros = torch.zeros(batch_size, class_num)

# 從 value 中取值,然後根據 dim 和 index 給相應位置賦值

onehot = m_zeros.scatter_(1, label, 1) # (dim,index,value)

return onehot.numpy() # Tensor -> Numpy

label = torch.LongTensor(batch_size).random_() % class_num # 對隨機數取餘

print(one_hot(label))

# output:

[[0. 0. 0. 1. 0. 0. 0. 0.]

[0. 0. 0. 0. 1. 0. 0. 0.]

[0. 0. 1. 0. 0. 0. 0. 0.]

[0. 1. 0. 0. 0. 0. 0. 0.]]

註:第11條有更簡單的方法。

6、防止驗證模型時爆顯存

驗證模型時不需要求導,即不需要梯度計算,關閉autograd,可以提高速度,節約內存。如果不關閉可能會爆顯存。

with torch.no_grad():

# 使用model進行預測的代碼

pass

感謝@zhaz 的提醒,我把 torch.cuda.empty_cache() 的使用原因更新一下。

這是原回答:

Pytorch 訓練時無用的臨時變量可能會越來越多,導致 out of memory,可以使用下面語句來清理這些不需要的變量。

官網 上的解釋為:

Releases all unoccupied cached memory currently held by the caching allocator so that those can be used in other GPU application and visible innvidia-smi. torch.cuda.empty_cache()

意思就是PyTorch的緩存分配器會事先分配一些固定的顯存,即使實際上tensors並沒有使用完這些顯存,這些顯存也不能被其他應用使用。這個分配過程由第一次CUDA內存訪問觸發的。

torch.cuda.empty_cache()

的作用就是釋放緩存分配器當前持有的且未佔用的緩存顯存,以便這些顯存可以被其他GPU應用程式中使用,並且通過

nvidia-smi

命令可見。注意使用此命令不會釋放tensors佔用的顯存。

對於不用的數據變量,Pytorch 可以自動進行回收從而釋放相應的顯存。

更詳細的優化可以查看 優化顯存使用 和 顯存利用問題。

7、學習率衰減

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()

...

可以隨時查看學習率的值:

optimizer.param_groups[0]['lr']

還有其他學習率更新的方式:

1、自定義更新公式:

scheduler = lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda epoch:1/(epoch+1))

2、不依賴epoch更新學習率:

lr_scheduler.ReduceLROnPlateau()

提供了基於訓練中某些測量值使學習率動態下降的方法,它的參數說明到處都可以查到。

提醒一點就是參數 mode='min' 還是'max',取決於優化的的損失還是準確率,即使用

scheduler.step(loss)

還是

scheduler.step(acc)

8、凍結某些層的參數

參考:https://www.zhihu.com/question/311095447/answer/589307812

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

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

net = Network() # 獲取自定義網絡結構

for name, value in net.named_parameters():

print('name: {0}, 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)

9、對不同層使用不同學習率

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

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

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`。

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

10、模型相關操作

這個內容比較多,我寫成了一篇文章:https://zhuanlan.zhihu.com/p/73893187

11、Pytorch內置one_hot函數

感謝@yangyangyang 補充:Pytorch 1.1後,one_hot可以直接用

torch.nn.functional.one_hot

然後我將Pytorch升級到1.2版本,試用了下 one_hot 函數,確實很方便。

具體用法如下:

import torch.nn.functional as F

import torch

tensor = torch.arange(0, 5) % 3 # tensor([0, 1, 2, 0, 1])

one_hot = F.one_hot(tensor)

# 輸出:

# tensor([[1, 0, 0],

# [0, 1, 0],

# [0, 0, 1],

# [1, 0, 0],

# [0, 1, 0]])

F.one_hot

會自己檢測不同類別個數,生成對應獨熱編碼。我們也可以自己指定類別數:

tensor = torch.arange(0, 5) % 3 # tensor([0, 1, 2, 0, 1])

one_hot = F.one_hot(tensor, num_classes=5)

# 輸出:

# tensor([[1, 0, 0, 0, 0],

# [0, 1, 0, 0, 0],

# [0, 0, 1, 0, 0],

# [1, 0, 0, 0, 0],

# [0, 1, 0, 0, 0]])

升級 Pytorch (cpu版本)的命令:

conda install pytorch torchvision -c pytorch

(希望Pytorch升級不會影響項目代碼)

12、網絡參數初始化

神經網絡的初始化是訓練流程的重要基礎環節,會對模型的性能、收斂性、收斂速度等產生重要的影響。

以下介紹兩種常用的初始化操作。

(1) 使用pytorch內置的torch.nn.init方法。

常用的初始化操作,例如正態分布、均勻分布、xavier初始化、kaiming初始化等都已經實現,可以直接使用。具體詳見PyTorch 中 torch.nn.init 中文文檔。

init.xavier_uniform(net1[0].weight)

(2) 對於一些更加靈活的初始化方法,可以藉助numpy。

對於自定義的初始化方法,有時tensor的功能不如numpy強大靈活,故可以藉助numpy實現初始化方法,再轉換到tensor上使用。

for layer in net1.modules():

if isinstance(layer, nn.Linear): # 判斷是否是線性層

param_shape = layer.weight.shape

layer.weight.data = torch.from_numpy(np.random.normal(0, 0.5, size=param_shape))

# 定義為均值為 0,方差為 0.5 的正態分布

13、加載內置預訓練模型

torchvision.models

模塊的子模塊中包含以下模型:

AlexNetVGGResNetSqueezeNetDenseNet導入這些模型的方法為:

import torchvision.models as models

resnet18 = models.resnet18()

alexnet = models.alexnet()

vgg16 = models.vgg16()

有一個很重要的參數為

pretrained

,默認為

False

,表示只導入模型的結構,其中的權重是隨機初始化的。

如果

pretrained

True

,表示導入的是在

ImageNet

數據集上預訓練的模型。

import torchvision.models as models

resnet18 = models.resnet18(pretrained=True)

alexnet = models.alexnet(pretrained=True)

vgg16 = models.vgg16(pretrained=True)

相關焦點

  • 3個Tricks幫你提升你Debug Pytorch的效率
    對於你自己的數據集,你必須自己計算。經過歸一化處理後,像素點的均值為0,標準差為1,就像分類器的權重一樣。我們可以通過看TensorBoard的直方圖來確認這一點。想法很簡單:如果我們改變第n個輸入樣本,它應該只對第n個輸出有影響。
  • 算法工程師路線圖(經驗濃縮,純乾貨!)
    今天我就來分享下算法工程師的學習路徑,並推薦一些我認為特別有價值的學習資料和學習方法。因為我自己是從數學轉到算法的,走過不少彎路的,希望這份路線圖能幫助各位想成為算法工程師的朋友少走點彎路,快速進步。基礎篇1.
  • pytorch必須掌握的4種邊界Padding方法
    卷積操作作為卷積神經網絡的核心模塊,在其計算過程中必須考慮圖像「邊緣像素
  • 讓PyTorch訓練速度更快,你需要掌握這17種方法
    然後,這個周期的長度應該略小於總的 epochs 數,並且,在訓練的最後階段,我們應該允許學習率比最小值小几個數量級。與傳統的學習率 schedule 相比,在最好的情況下,該 schedule 實現了巨大的加速(Smith 稱之為超級收斂)。
  • 小白如何成為合格的算法工程師?
    想要從事算法工程師,需要具備什麼樣的能力?又要從哪裡入手呢?下面趣找課將仔細為你闡述:一、熟知算法和數據結構這是基礎必學的,作為算法工程師,需要掌握最基礎的排序、遞歸、動態規劃、樹、堆棧、隊列等算法和數據結構。如果想要去大公司,那麼必須要熟知這兩塊技能點,掌握基本功。
  • 國外大神的機器學習算法大匯總;如何用 50 行 PyTorch 代碼實現...
    近日有國外大神祭出了一張神圖,圖中針對機器學習領域幾乎所有的常見算法進行了分類大匯總。大會的主題包括:深度學習算法、計算機視覺、自然語言理解、自動駕駛和強化學習等。雷鋒網(公眾號:雷鋒網)按:RE·WORK 是一家專門從事前沿科學和突破性技術相關活動的組織公司,其常規合作夥伴包括蘋果、IBM、微軟和谷歌等。
  • 書單|算法工程師的修煉與成長
    從2015年以一個產品經理的視角加入網際網路行業,到2016年毅然選擇跨專業考研至計算機專業,到2019年加入BAT成為一名算法工程師,我的個人命運隨著時代的步伐不斷的波動。一年,可以平靜如水,波瀾不驚。一年,也可以發生很多改變。在體驗生活的新鮮感和刺激時,也經歷了許多波折。
  • 國外大神的機器學習算法大匯總如何用50行PyTorch代碼實現GANs|AI...
    近日有國外大神祭出了一張神圖,圖中針對機器學習領域幾乎所有的常見算法進行了分類大匯總。不但簡單介紹了每一種算法的大概含義,還整理了它們的常見應用和優缺點,各位開發者絕對不可錯過。詳情:https://static.coggle.it/diagram/WHeBqDIrJRk-kDDY微軟創新杯報名截止日期延長至2月28日
  • 程式設計師必須掌握的核心算法有哪些?
    一、算法最最基礎1、時間複雜度2、空間複雜度一般最先接觸的就是時間複雜度和空間複雜度的學習了,這兩個概念以及如何計算,是必須學的,也是必須最先學的,主要有最大複雜度、平均複雜度等,直接通過博客搜索學習即可。
  • Linux運維工程師入門必須掌握的7個關鍵知識及必讀書目
    隨著網際網路技術的發展,Linux運維工程師的需求量也在大增。Linux作為一個全能的作業系統,想徹底搞明白作業系統的方方面面是不太可能的事情,短時間內更是不太現實的。本文針對Linux運維工程師總結了前期必須掌握的內容,大家可以有針對性的學習和練習,爭取早日稱為一名優秀的運維工程師。
  • linux運維工程師必須掌握的幾種工具
    linux系統基礎,這個不用說了,是基礎中的基礎,連這個都不會就別幹了,參考書籍,可以看鳥哥linux基礎篇,至少要掌握這書60%內容,沒必須全部掌握,但基本命令總得會吧.   網絡服務,服務有很多種,每間公司都會用到不同的,但基礎的服務肯定要掌握,如FTP, DNS,SAMBA, 郵件, 這幾個大概學一下就行,LAMP和LNMP是必須要熟練,我所指的不是光光會搭建,而是要很熟悉裡面的相當配置才行,因為公司最關鍵的絕對是WEB伺服器,所以nginx和apache要熟悉,特別是nginx一定要很熟悉才行,至少有些公司還會用tomcat,這個也最好學一下。
  • 月薪30k的Linux運維工程師必須要掌握的10個技術點
    對於剛入門或準備入門Linux運維的來說,今天千鋒廣州小編整理總結了以下10個必須掌握的技術點和相關工具:3、shell腳本和另一個腳本語言shell是運維人員必須具備的,不懂這個連入職都不行,至少也要寫出一些系統管理腳本,最簡單也得寫個監控CPU,內存比率的腳本。
  • 淺談算法工程師的職業定位與發展
    算法理論這裡提到的算法理論實際上是指算法相關的基礎知識,主要分為兩塊:1. 數據結構;2. 算法設計與分析。數據結構是算法的基石,掌握必要的數據結構才有可能去實現一個算法。前文提到算法工程師還關心解的質量和效率,而算法設計與分析的理論可以有效地指導我們如何做這件事。
  • JAVA必須掌握的數據結構和算法
    貝爾曼-福特算法(略)貝爾曼-福特(Bellman-Ford)算法是一種在圖中求解最短路徑問題的算法狄克斯特拉算法(略)A*算法(略)安全算法:深度搜索和廣度搜索(必學)最短路徑算法:Floyd,Dijkstra(必學)最小生成樹算法:Prim,Kruskal(必學)實際常用算法:關鍵路徑、拓撲排序(原理與應用)二分圖匹配:配對、匈牙利算法(原理與應用)拓展:中心性算法、社區發現算法(原理與應用)
  • PyTorch 1.7發布,支持CUDA 11、Windows分布式訓練
    PyTorch 1.7 部分新特性,詳情參見 https://github.com/pytorch/pytorch/releases/tag/v1.7.0。參考連結:https://pytorch.org/blog/pytorch-1.7-released/https://github.com/pytorch/pytorch/releases/tag/v1.7.0https://www.reddit.com/r/MachineLearning
  • pytorch主要模塊及函數使用方法
    pytorch接口文檔:官方文檔:https://pytorch.org/docs/stable/index.html中文文檔:https://pytorch-cn.readthedocs.io/zh/latest/package_references/torch-optim/1:datasets.ImageFolder 圖片數據集加載器from torchvision import datasets
  • 如何學好數據結構與算法,前Facebook 工程師這麼說
    語言只是工具,算法才是代碼的靈魂,是一切編程活動的核心。想寫出性能良好的代碼,提高編程效率,從普通程式設計師成長為優秀的工程師,必須掌握算法。想寫出被廣泛使用的開源框架,提升自己的技術影響力,就要有紮實的算法功底。  尤其重要的是,算法是國內外一線網際網路公司在面試中的必考知識點。
  • 寫給純小白的深度學習環境搭建寶典:pytorch+tensorflow
    如果你對循環神經網絡的基本原理還不了解,可以通過小編的精講深度學習RNN三大核心點,三分鐘掌握循環神經網絡進行簡單了解。下面進入實戰環節。Anaconda+pytorch環境準備如果你的電腦帶有GPU,可以先安裝Nvidia驅動 + cuda + cudnn,然後再搭建環境,這樣可以達到更高的運行速度。
  • 程序猿離大廠百萬年薪AI算法工程師有多遠?
    如果你想成為大廠算法工程師,今天就是改變命運時候。大廠紛紛押寶AI「新基建」的到來也讓很多企業看到了轉型升級刻不容緩,BAT作為最早一批向AI轉型的企業,起到了很好的示範作用。3月10日,阿里巴巴達摩院宣布成立達摩院第15個實驗室——XG實驗室,專門研究下一代網絡通信技術,也就是5G技術。阿里達摩院披露的6個5G業務率先進軍的領域,分別是超高清視頻、在線辦公、AR/VR、工業網際網路、智能物流、自動駕駛。截至19年底,中國已經建成13萬個5G基站,而這些基站配套的通信技術、應用軟體及其他一些前瞻性研究,將共同完善5G領域的新基建生態。
  • 如何準備算法工程師面試,斬獲一線網際網路公司機器學習崗offe
    本文將分三個部分:1.機器學習算法工程師的能力結構;2.算法工程師面試中的一些不確定性因素和解決辦法;3.準備算法工程師面試的十條建議。雖然每個崗位都有JD,但拋開具體的崗位需求,從稍高的角度看待這個問題,一名算法工程師的技術能力基本可以拆解成下面四個方面:知識、工具、邏輯、業務。如果用技能雷達圖的形式來展現機器學習崗相關的幾個職位所需的能力,大致應如下圖所示,大家可以初步體會一下。