Pytorch 0.3 調參指南&optimizer;learning rate;batch_size;Debug大法&數據集;網絡;結構;超參;訓練;迷人的坑(持續更新中)

 

1.調參指南:

通常我們需要調整的部分有:優化器optim、學習率、batch_sizes、

(1)optimizer:

通常我們使用的是:樸素的SGD、Adagrad、Adam,後兩者訓練速度很快相同學習率下收斂更快,但不適宜於精細調參,爲了迅速查看某方法是否work可以採用後兩者,對lr依賴較小,但不一定能夠找到最優點。

SGD:

optimizer_SGD = optim.SGD(model.parameters(), lr = 0.001, momentum = 0.9, weight_decay=5e-4)

Adagrad:

optimizer_Adag = optim.Adagrad(model.parameters(), lr = 0.001, lr_decay = 0, weight_decay=5e-4

weight_decay是Adagrad對於weight的一個L2懲罰項,一般默認爲0,如果發現權值變化過大,可以適當加一個值。

Adam:

class torch.optim.Adam(model.parameters(), lr=0.001, betas=(0.9, 0.999), eps=1e-08, weight_decay=0)

betas (Tuple[float, float], 可選) – 用於計算梯度以及梯度平方的運行平均值的係數(默認:0.9,0.999)

eps (float, 可選) – 爲了增加數值計算的穩定性而加到分母裏的項(默認:1e-8)

weight_decay:使用optimizer裏面的weight_decay相當於就是做的L2懲罰項,如下代表懲罰項係數:

此外也可以使用代碼完成L2懲罰項:

lambda = torch.tensor(1.)
l2_reg = torch.tensor(0.)
for param in model.parameters():
    l2_reg += torch.norm(param)
loss += lambda * l2_reg

但其中需要注意的是:

對於上述公式中的W,權值衰減只是希望對W(不包括偏置b進行L2正則化),很多時候如果對bias進行L2正則化將會導致嚴重的欠擬合,當然,你可以獲取模型中的所有權值,然後按照定義的方法顯式地進行處理,得到一個正則損失之後在交給優化器優化,這是一個通用的方法。不過最爲簡單的方法,還是在優化器中設置weight_decay,只會對W進行處理。

(2)learning rate:

對於一個learning from scratch的網絡,建議lr設置從0.01開始;如果fine-tuning則可以設置小一些從0.001開始。

具體來判斷學習率有一個很簡單但是方便的思路:

我們在網絡輸入訓練後,會得到一個loss,然後用於更新;完畢以後我們再講此輸入放入網絡中得到更新後的網絡對於同樣一個樣本的loss變化情況,如果基本呈下降趨勢則可以適當調大,直到loss變化開始發生明顯的振盪,表明到極限了,之前最大的能夠確保下降的學習率就是最合適的學習率:

optimizer.zero_grad()
output = net(input)
loss = criterion(output, target)
print('loss_before:', loss)
loss.backward()
optimizer.step
# test learning rate
output_new = net(input)
loss_new = criterion(output_new, target)
print('loss_after:', loss_new)

(3)Batch_size:

在顯存允許的條件下選擇合適的就好,太小了會容易過擬合。

 

2.Debug大法:

出現比如loss、acc之類的問題,有以下可以去檢查的地方:

(1)數據集部分:

是否有預處理?是否有歸一(均值方差)?是否有Shuffle?在打label的時候是否出錯?

dataloader有沒有問題?裏面的transform函數有沒有不妥的地方?傳進網絡的時候有沒有出錯?

(2)網絡部分:

網絡結構有沒有搭錯?初始化正確了嗎?參數賦值(pre-train)的時候有沒有對應賦正確?拿全0數據作爲輸入或者debug中間變量看是否有問題?

(3)訓練部分:

梯度正常回傳了嗎?參數正常更新了嗎?loss函數有沒有寫錯?Acc的測試寫對了嗎?打印一下中間變量來看看呢?訓練需要寫net.train(),測試需要寫net.eval()哦?

全局微調:最後一層隨機初始化,前面所有層爲最後一層學習率的1/10。

局部微調:最後一層隨機初始化,前面所有層參數鎖死。

————————————————————————————————————————————————————

一些可以再調整的地方:

(1)檢查權重初始化

如果不確定,請使用 Xavier 或 He 初始化。同樣,初始化也許會給你帶來壞的局部最小值,因此嘗試不同的初始化,看看是否有效。

(2)改變超參數

(3) 減少正則化

太多的正則化會導致網絡嚴重地欠擬合。減少正則化,比如 dropout、批歸一、權重/偏差 L2 正則化等。

(4) 從訓練模式轉換爲測試模式

一些框架有批歸一化層、Dropout層,而其他的層在訓練和測試時表現並不同。轉換到適當的模式有助於網絡更好地預測。

(4)可視化訓練

• 監督每層的激活值、權重和更新。確保它們的大小匹配。例如,參數更新的大小幅度(權重和偏差)應該是 1-e3。
• 考慮可視化庫,例如 Tensorboard 和 Crayon 。緊要時你也可以打印權重、偏差或激活值。
• 尋找平均值遠大於 0 的層激活。嘗試批歸一化層或者ELU單元。
• Deeplearning4j 指出了權重和偏差柱狀圖的期望值應該是什麼樣的:
對於權重,一段時間之後這些柱狀圖應該有一個近似高斯的(正態)分佈。對於偏差,這些柱狀圖通常會從 0 開始,並經常以近似高斯(LSTM是例外情況)結束。留意那些向正無窮或負無窮髮散的參數。留意那些變得很大的偏差。這有可能發生在分類網絡的輸出層,如果類別的分佈不均勻。
• 檢查層更新,它們應該呈高斯分佈。

(5)嘗試不同的優化器

優化器的選擇不應當妨礙網絡的訓練,除非你選擇了特別糟糕的超參數。但是,選擇一個合適的優化器非常有助於在最短的時間內獲得最多的訓練結果。描述算法的論文應該指定了優化器,如果沒有,我傾向於選擇Adam或者帶有動量的樸素SGD。

關於梯度下降的優化器可以參考Sebastian Ruder的 博文

(6)梯度爆炸、梯度消失

• 檢查隱藏層的更新情況,過大的值說明可能出現了梯度爆炸。這時,梯度截斷(Gradient clipping)可能會有所幫助。
• 檢查隱藏層的激活值。Deeplearning4j 中有一個很好的指導方針:“一個好的激活值標準差大約在 0.5 到 2.0 之間。明顯超過這一範圍可能就代表着激活值消失或爆炸。”

(7)增加、減少學習速率

低學習速率將會導致你的模型收斂很慢。高學習速率將會在開始階段減少你的損失,但是可能會導致你很難找到一個好的解決方案。試着把你當前的學習速率乘以 0.1 或 10然後進行循環。

(8) 克服NaN

在訓練 RNNs 時得到 NaN(Non-a-Number,非數)是一個很大的問題。一些解決它的方法:

• 減小學習速率,尤其是如果你在前 100 次迭代中就得到了NaN。
• NaNs 的出現可能是由於用零作了除數,或用零或負數作了自然對數。
• Russell Stewart 在《如何處理NaN》中分享了很多心得。
• 嘗試逐層評估你的網絡,這樣就會看見NaN到底出現在了哪裏。

附:完整可參考博文:http://imgtec.eetrend.com/blog/10381

 

3.迷人的坑:

在近日的學習中遇到了一些奇奇怪怪的關於pytorch的問題:

(1)對於一些中間變量我們在處理的時候最好不要自己單另一個temp,儘管初始temp爲Variable但是對於梯度部分很有可能傳導紊亂,最好是讓其用.**函數來直接對tensor進行操作穩妥第一。

(2)這個問題就很bug了,原本目的是要給兩個結構網路model1、model2賦值,如果是隻實例化了一次:

pre_vgg = torchvision.models.vgg16(pretrained=True)

發現在賦值的時候會讓其指向同一個內存空間,更保險的做法就是實例化的時候實例兩個:

pre_vgg1 = torchvision.models.vgg16(pretrained=True)
pre_vgg2 = torchvision.models.vgg16(pretrained=True)

在賦值的時候最好分開賦值,這樣能夠保證是在兩個不同的內存空間,使用.weight傳遞某層的參數:

model.features1 = pre_vgg1.features1
model.fc1[0].weight = pre_vgg1.classifier[0].weight 
model.fc1[0].bias = pre_vgg1.classifier[0].bias 

注意:在傳參數的時候可以print(net)看一下對應sequential裏面的層數的數值,賦weights或者bias是分開的,以列表形式存儲,不要賦錯了。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章