目錄
1 Adam及優(yōu)化器optimizer(Adam、SGD等)是如何選用的?
1)Momentum
2)RMSProp
3)Adam
2 Pytorch的使用以及Pytorch在以后學(xué)習(xí)工作中的應(yīng)用場(chǎng)景。
1)Pytorch的使用
2)應(yīng)用場(chǎng)景
3 不同的數(shù)據(jù)、數(shù)據(jù)集加載方式以及加載后各部分的調(diào)用處理方式。如DataLoder的使用、datasets內(nèi)置數(shù)據(jù)集的使用。
4 如何加快訓(xùn)練速度以及減少GPU顯存占用
技巧1:inplace=True
技巧2:with torch.no_grad():
技巧3:forward中的變量命名
技巧4:Dataloader數(shù)據(jù)讀取
技巧5:gradient accumulation
1 Adam及優(yōu)化器optimizer(Adam、SGD等)是如何選用的?
深度學(xué)習(xí)的優(yōu)化算法主要有GD,SGD,Momentum,RMSProp和Adam算法。Adam是一種計(jì)算每個(gè)參數(shù)的自適應(yīng)學(xué)習(xí)率的方法。相當(dāng)于 RMSprop + Momentum。
在講這個(gè)算法之前說一下移動(dòng)指數(shù)加權(quán)平均。移動(dòng)指數(shù)加權(quán)平均法加權(quán)就是根據(jù)同一個(gè)移動(dòng)段內(nèi)不同時(shí)間的數(shù)據(jù)對(duì)預(yù)測(cè)值的影響程度,分別給予不同的權(quán)數(shù),然后再進(jìn)行平均移動(dòng)以預(yù)測(cè)未來值。假定給定一系列數(shù)據(jù)值那么,我們根據(jù)這些數(shù)據(jù)來擬合一條曲線,所得的值
就是如下的公式:
其中,在上面的公式中,β等于歷史值的加權(quán)率。根據(jù)這個(gè)公式我們可以根據(jù)給定的數(shù)據(jù),擬合出下圖類似的一條比較平滑的曲線。
1)Momentum
通常情況我們?cè)谟?xùn)練深度神經(jīng)網(wǎng)絡(luò)的時(shí)候把數(shù)據(jù)拆解成一小批地進(jìn)行訓(xùn)練,這就是我們常用的mini-batch SGD訓(xùn)練算法,然而雖然這種算法能夠帶來很好的訓(xùn)練速度,但是在到達(dá)最優(yōu)點(diǎn)的時(shí)候并不能夠總是真正到達(dá)最優(yōu)點(diǎn),而是在最優(yōu)點(diǎn)附近徘徊。另一個(gè)缺點(diǎn)就是這種算法需要我們挑選一個(gè)合適的學(xué)習(xí)率,當(dāng)我們采用小的學(xué)習(xí)率的時(shí)候,會(huì)導(dǎo)致網(wǎng)絡(luò)在訓(xùn)練的時(shí)候收斂太慢;當(dāng)我們采用大的學(xué)習(xí)率的時(shí)候,會(huì)導(dǎo)致在訓(xùn)練過程中優(yōu)化的幅度跳過函數(shù)的范圍,也就是可能跳過最優(yōu)點(diǎn)。我們所希望的僅僅是網(wǎng)絡(luò)在優(yōu)化的時(shí)候網(wǎng)絡(luò)的損失函數(shù)有一個(gè)很好的收斂速度同時(shí)又不至于擺動(dòng)幅度太大。
所以 Momentum 優(yōu)化器剛好可以解決我們所面臨的問題,它主要是基于梯度的移動(dòng)指數(shù)加權(quán)平均。假設(shè)在當(dāng)前的迭代步驟第 t 步中,那么基于 Momentum 優(yōu)化算法可以寫成下面的公式:
其中,在上面的公式中vdw和vdb分別是損失函數(shù)在前 t-1 輪迭代過程中累積的梯度動(dòng)量,β是梯度累積的一個(gè)指數(shù),這里我們一般設(shè)置值為0.9。所以Momentum優(yōu)化器的主要思想就是利用了類似于移動(dòng)指數(shù)加權(quán)平均的方法來對(duì)網(wǎng)絡(luò)的參數(shù)進(jìn)行平滑處理的,讓梯度的擺動(dòng)幅度變得更小。
dW和db分別是損失函數(shù)反向傳播時(shí)候所求得的梯度,下面兩個(gè)公式是網(wǎng)絡(luò)權(quán)重向量和偏置向量的更新公式,α是網(wǎng)絡(luò)的學(xué)習(xí)率。當(dāng)我們使用Momentum優(yōu)化算法的時(shí)候,可以解決mini-batch SGD優(yōu)化算法更新幅度擺動(dòng)大的問題,同時(shí)可以使得網(wǎng)絡(luò)的收斂速度更快。
2)RMSProp
RMSProp算法的全稱叫 Root Mean Square Prop,是Geoffrey E. Hinton在Coursera課程中提出的一種優(yōu)化算法,在上面的Momentum優(yōu)化算法中,雖然初步解決了優(yōu)化中擺動(dòng)幅度大的問題。所謂的擺動(dòng)幅度就是在優(yōu)化中經(jīng)過更新之后參數(shù)的變化范圍,如下圖所示,藍(lán)色的為Momentum優(yōu)化算法所走的路線,綠色的為RMSProp優(yōu)化算法所走的路線。
為了進(jìn)一步優(yōu)化損失函數(shù)在更新中存在擺動(dòng)幅度過大的問題,并且進(jìn)一步加快函數(shù)的收斂速度,RMSProp算法對(duì)權(quán)重 W 和偏置 b 的梯度使用了微分平方加權(quán)平均數(shù)。 其中,假設(shè)在第 t 輪迭代過程中,各個(gè)公式如下所示:
算法的主要思想就用上面的公式表達(dá)完畢了。在上面的公式中sdw和sdb分別是損失函數(shù)在前 t?1 輪迭代過程中累積的梯度動(dòng)量,β是梯度累積的一個(gè)指數(shù)。所不同的是,RMSProp算法對(duì)梯度計(jì)算了微分平方加權(quán)平均數(shù)。這種做法有利于消除了擺動(dòng)幅度大的方向,用來修正擺動(dòng)幅度,使得各個(gè)維度的擺動(dòng)幅度都較小。另一方面也使得網(wǎng)絡(luò)函數(shù)收斂更快。(比如當(dāng) dW或者 db中有一個(gè)值比較大的時(shí)候,那么我們?cè)诟聶?quán)重或者偏置的時(shí)候除以它之前累積的梯度的平方根,這樣就可以使得更新幅度變?。榱朔乐狗帜笧榱?,使用了一個(gè)很小的數(shù)值?來進(jìn)行平滑,一般取值為10的負(fù)八次方。
3)Adam
有了上面兩種優(yōu)化算法,一種可以使用類似于物理中的動(dòng)量來累積梯度,另一種可以使得收斂速度更快同時(shí)使得波動(dòng)的幅度更小。那么將兩種算法結(jié)合起來所取得的表現(xiàn)一定會(huì)更好。Adam(Adaptive Moment Estimation)算法是將Momentum算法和RMSProp算法結(jié)合起來使用的一種算法。
很多論文里都會(huì)用 SGD,沒有 Momentum 等。SGD 雖然能達(dá)到極小值,但是比其他算法用的時(shí)間長(zhǎng),而且可能會(huì)被困在鞍點(diǎn)。
如果需要更快的收斂,或者是訓(xùn)練更深更復(fù)雜的神經(jīng)網(wǎng)絡(luò),需要用一種自適應(yīng)的算法。
整體來講,Adam 是最好的選擇。
2 Pytorch的使用以及Pytorch在以后學(xué)習(xí)工作中的應(yīng)用場(chǎng)景。
1)Pytorch的使用
①安裝pytorch
②使用Spyder創(chuàng)建一個(gè)project,點(diǎn)擊Projects--->New Project
③在其中輸入project名稱,選擇項(xiàng)目地址就ok了,比如我們創(chuàng)建Handwritten_numeral_recognition(手寫數(shù)字識(shí)別)
④創(chuàng)建一個(gè)module,創(chuàng)建一個(gè)test.py。
⑤輸入import torch,就可以開始pytorch的使用了。
2)應(yīng)用場(chǎng)景
①醫(yī)療

基于U-net的醫(yī)學(xué)影像分割
通過Pytorch深度學(xué)習(xí)框架,編寫分割腦部解剖結(jié)構(gòu)程序。
②工業(yè)
比如通過Pytorch深度學(xué)習(xí)框架,編寫設(shè)備的剩余壽命預(yù)測(cè)、故障診斷程序。
3 不同的數(shù)據(jù)、數(shù)據(jù)集加載方式以及加載后各部分的調(diào)用處理方式。如DataLoder的使用、datasets內(nèi)置數(shù)據(jù)集的使用。
- dataloader本質(zhì)是一個(gè)可迭代對(duì)象,使用iter()訪問,不能使用next()訪問;
- 使用iter(dataloader)返回的是一個(gè)迭代器,然后可以使用next訪問;
- 也可以使用`for inputs, labels in dataloaders`進(jìn)行可迭代對(duì)象的訪問;
- 一般我們實(shí)現(xiàn)一個(gè)datasets對(duì)象,傳入到dataloader中;然后內(nèi)部使用yeild返回每一次batch的數(shù)據(jù);
pytorch 的數(shù)據(jù)加載到模型的操作順序是這樣的:
① 創(chuàng)建一個(gè) Dataset 對(duì)象
② 創(chuàng)建一個(gè) DataLoader 對(duì)象
③ 循環(huán)這個(gè) DataLoader 對(duì)象,將img, label加載到模型中進(jìn)行訓(xùn)練
dataset = MyDataset()
dataloader = DataLoader(dataset)
num_epoches = 100
for epoch in range(num_epoches):
????for img, label in dataloader:
????????....
所以,作為直接對(duì)數(shù)據(jù)進(jìn)入模型中的關(guān)鍵一步, DataLoader非常重要。
4 如何加快訓(xùn)練速度以及減少GPU顯存占用
到底什么在占用顯存?
輸入的數(shù)據(jù)占用空間其實(shí)并不大,比如一個(gè)(256, 3, 100, 100)的Tensor(相當(dāng)于batchsize=256的100*100的三通道圖片。)只占用31M顯存。
實(shí)際上,占用顯存的大頭在于:1. 動(dòng)輒上千萬的模型參數(shù);2. 模型中間變量;3. 優(yōu)化器中間參數(shù)。
第一點(diǎn)模型參數(shù)不必介紹;第二點(diǎn),中間變量指每個(gè)語(yǔ)句的輸出。而在backward時(shí),這部分中間變量會(huì)翻倍(因?yàn)樾枰A粼虚g值)。第三點(diǎn),優(yōu)化器在梯度下降時(shí),模型參數(shù)在更新時(shí)會(huì)產(chǎn)生保存中間變量,也就是模型的params在這時(shí)翻倍。
技巧1:inplace=True
一些激活函數(shù)與Dropout有一個(gè)參數(shù)"inplace",默認(rèn)設(shè)置為False,當(dāng)設(shè)置為True時(shí),我們?cè)谕ㄟ^ReLU()計(jì)算時(shí)得到的新值不會(huì)占用新的空間而是直接覆蓋原來的值,這也就是為什么當(dāng)inplace參數(shù)設(shè)置為True時(shí)可以節(jié)省一部分內(nèi)存的緣故。但在某些需要原先的值的情況下,就不可設(shè)置inplace。
此操作相當(dāng)于針對(duì)顯存占用第二點(diǎn)(模型中間變量)的優(yōu)化。
技巧2:with torch.no_grad():
對(duì)于只需要forward而不需要backward的過程(validation和test),使用torch.no_grad做上下文管理器(注意要在model.eval()之后),可以讓測(cè)試時(shí)batchsize擴(kuò)大近十倍,而且也可以加速測(cè)試過程。此操作相當(dāng)于針對(duì)顯存占用第二點(diǎn)(因?yàn)橹苯記]有backward了)和第三點(diǎn)進(jìn)行優(yōu)化。
model.eval()
with torch.no_grad():
pass
技巧3:forward中的變量命名
在研究pytorch官方架構(gòu)和大神的代碼后可發(fā)現(xiàn)大部分的forward都是以x=self.conv(x)的形式,很少引入新的變量,所以啟發(fā)兩點(diǎn)以減少顯存占用(1)把不需要的變量都用x代替,(2)變量用完之后馬上用del刪除(此操作慎用,清除顯存的同時(shí)使得backProp速度變慢)。此操作相當(dāng)于針對(duì)第二點(diǎn)(模型中間變量)進(jìn)行優(yōu)化。
技巧4:Dataloader數(shù)據(jù)讀取
一定要使用pytorch的Dataloader來讀取數(shù)據(jù)。按照以下方式來設(shè)置:
loader = data.Dataloader(PYTORCH_DATASET, num_works=CPU_COUNT,
?????????????????????????pin_memory=True, drop_last=True)
第一個(gè)參數(shù)是用pytorch制作的TensorDataset,第二個(gè)參數(shù)是CPU的數(shù)量(默認(rèn)為0,在真正訓(xùn)練時(shí)建議調(diào)整),第三個(gè)參數(shù)默認(rèn)為False,用來控制是否把數(shù)據(jù)先加載到緩存再加載到GPU,建議設(shè)置為True,第四個(gè)參數(shù)用于扔掉最后一個(gè)batch,使得訓(xùn)練更為穩(wěn)定。
將pin_memory開啟后,在通過dataloader讀取數(shù)據(jù)后將數(shù)據(jù)to進(jìn)GPU時(shí)把non_blocking設(shè)置為True,可以大幅度加快數(shù)據(jù)計(jì)算的速度。
for input_tensor in loader:
????input_tensor.to(gpu, non_blocking=True)
????model.forward(input_tensor)
技巧5:gradient accumulation
梯度積累通過累計(jì)梯度來解決本地顯存不足的問題,即不在每個(gè)batch都更新模型參數(shù),而是每經(jīng)過accumulation steps步后,更新一次模型參數(shù)。相當(dāng)于針對(duì)第三點(diǎn)(n步才更新一次參數(shù))來進(jìn)行優(yōu)化。且由于參數(shù)更新的梯度計(jì)算是算力消耗的一部分,故梯度累計(jì)還可以一定程度上加快訓(xùn)練速度。文章來源:http://www.zghlxwxcb.cn/news/detail-466173.html
loss = model(input_tensor)
loss.backward()
if batch_idx % accumulate_steps == 0:
????optim.step()
????optim.zero_grad()
相當(dāng)于一個(gè)epoch的步數(shù)(step)變少了(一個(gè)step相當(dāng)于參數(shù)更新一次),但單個(gè)step的計(jì)算時(shí)間變長(zhǎng)了(略小于n倍的原來時(shí)間)。文章來源地址http://www.zghlxwxcb.cn/news/detail-466173.html
到了這里,關(guān)于Pytorch基本概念和使用方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!