G-HL-PE.ELE32 Program-Engineering. Emerge-Logs Errors Python(3)-Torchs(2)
ss
sss
cpp_extension.py:383: UserWarning: Error checking compiler version for cl: [WinError 2] 系統(tǒng)找不到
指定的文件嘶炭。
HW-NIVIDA(cuda)
.cuda() 的因地制宜
cuda()能實現(xiàn)從 CPU 到 GPU 的內(nèi)存遷移, 但是對于模型nn.Module.cuda和張量Tensor.cuda的作用效果不同
對于 nn.Module 兩句效果一樣: 對model自身進行的內(nèi)存遷移
對于Tensor:
調(diào)用tensor.cuda只是返回這個tensor對象在GPU內(nèi)存上的拷貝齐遵,而不會對自身進行改變当辐。因此必須對tensor進行重新賦值发钝,即tensor=tensor.cuda.
.cuda() 的因地制宜
cuda()能實現(xiàn)從 CPU 到 GPU 的內(nèi)存遷移, 但是對于模型nn.Module.cuda和張量Tensor.cuda的作用效果不同
對于 nn.Module 兩句效果一樣: 對model自身進行的內(nèi)存遷移
對于Tensor:
調(diào)用tensor.cuda只是返回這個tensor對象在GPU內(nèi)存上的拷貝异希,而不會對自身進行改變袭景。因此必須對tensor進行重新賦值狠角,即tensor=tensor.cuda.
2. PyTorch 0.4 計算累積損失的不同
以廣泛使用的模式total_loss += loss.data[0]為例号杠。Python0.4.0之前,loss是一個封裝了(1,)張量的Variable丰歌,但Python0.4.0的loss現(xiàn)在是一個零維的標量姨蟋。對標量進行 索引是沒有意義的(似乎會報 invalid index to scalar variable 的錯誤)。使用loss.item可以從標量中獲取Python數(shù)字立帖。所以改為:
如果在累加損失時未將其轉(zhuǎn)換為Python數(shù)字芬探,則可能出現(xiàn)程序內(nèi)存使用量增加的情況。這是因為上面表達式的右側(cè)原本是一個Python浮點數(shù)厘惦,而它現(xiàn)在是一個零維張量偷仿。因此,總損失累加了張量和它們的梯度歷史宵蕉,這可能會產(chǎn)生很大的autograd 圖酝静,耗費內(nèi)存和計算資源。
3. PyTorch 0.4 編寫不限制設備的代碼
a3819b4f5ba651e9cf8905ff101491f3.png
4. torch. Tensor.detach的使用
detach的官方說明如下:
892cb0a026489de13ec914e11eaf8025.png
假設有模型A和模型B羡玛,我們需要將A的輸出作為B的輸入别智,但訓練時我們只訓練模型B. 那么可以這樣做:
input_B = output_A.detach
它可以使兩個計算圖的梯度傳遞斷開,從而實現(xiàn)我們所需的功能稼稿。
5. ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm)
出現(xiàn)這個錯誤的情況是薄榛,在服務器上的docker中運行訓練代碼時讳窟,batch size設置得過大,shared memory不夠(因為docker限制了shm).解決方法是敞恋,將Dataloader的num_workers設置為0.
6. pytorch中l(wèi)oss函數(shù)的參數(shù)設置
以CrossEntropyLoss為例:
57182ee1f352959aa889815798ff35a5.png
若 reduce = False丽啡,那么 size_average 參數(shù)失效,直接返回向量形式的 loss硬猫,即batch中每個元素對應的loss.
若 reduce = True补箍,那么 loss 返回的是標量:
如果 size_average = True,返回 loss.mean.
如果 size_average = False啸蜜,返回 loss.sum.
weight : 輸入一個1D的權值向量坑雅,為各個類別的loss加權,如下公式所示:
c4646e8b1163f6627d89b4605af1ddb9.png
ignore_index : 選擇要忽視的目標值衬横,使其對輸入梯度不作貢獻裹粤。如果 size_average = True,那么只計算不被忽視的目標的loss的均值蜂林。
reduction : 可選的參數(shù)有:‘none’ | ‘elementwise_mean’ | ‘sum’, 正如參數(shù)的字面意思遥诉,不解釋。7. pytorch的可重復性問題 8. 多GPU的處理機制
使用多GPU時悉尾,應該記住pytorch的處理邏輯是:
1.在各個GPU上初始化模型突那。
2.前向傳播時,把batch分配到各個GPU上進行計算构眯。
3.得到的輸出在主GPU上進行匯總愕难,計算loss并反向傳播,更新主GPU上的權值惫霸。
4.把主GPU上的模型復制到其它GPU上猫缭。
9. num_batches_tracked參數(shù)
今天讀取模型參數(shù)時出現(xiàn)了錯誤
114f54734c0b3f6310b1ff0d6403b394.png
大概可以看出,這個參數(shù)和訓練時的歸一化的計算方式有關壹店。
因此猜丹,我們可以知道該錯誤是由于訓練和測試所用的pytorch版本(0.4.1版本前后的差異)不一致引起的。具體的解決方案是:如果是模型參數(shù)(Orderdict格式硅卢,很容易修改)里少了num_batches_tracked變量射窒,就加上去,如果是多了就刪掉将塑。偷懶的做法是將load_state_dict的strict參數(shù)置為False脉顿,如下所示:
3265936229603edd60ffaba578b11049.png
還看到有人直接修改pytorch 0.4.1的源代碼把num_batches_tracked參數(shù)刪掉的,這就非常不建議了点寥。
10. 訓練時損失出現(xiàn)nan的問題
最近在訓練模型時出現(xiàn)了損失為nan的情況艾疟,發(fā)現(xiàn)是個大坑。暫時先記錄著。
可能導致梯度出現(xiàn)nan的三個原因:
1. 梯度爆炸蔽莱。也就是說梯度數(shù)值超出范圍變成nan. 通车芙可以調(diào)小學習率、加BN層或者做梯度裁剪來試試看有沒有解決盗冷。
2. 損失函數(shù)或者網(wǎng)絡設計怠苔。比方說,出現(xiàn)了除0正塌,或者出現(xiàn)一些邊界情況導致函數(shù)不可導嘀略,比方說log(0)恤溶、sqrt(0).
3. 臟數(shù)據(jù)乓诽。可以事先對輸入數(shù)據(jù)進行判斷看看是否存在nan.
補充一下nan數(shù)據(jù)的判斷方法:
注意咒程!像nan或者inf這樣的數(shù)值不能使用 == 或者 is 來判斷鸠天!為了安全起見統(tǒng)一使用 math.isnan 或者 numpy.isnan 吧。
例如:
45217bfdf5d576bd931a79fd4c373e3a.png
raiseValueError('Expected more than 1 value per channel when training, got input size {}'.format(size)
沒有什么特別好的解決辦法帐姻,在訓練前用 num_of_samples % batch_size 算一下會不會正好剩下一個樣本稠集。
可以考慮將DataLoader
的drop_last
選項設為True,這樣的話饥瓷,當最后一個batch湊不滿時剥纷,就會舍棄掉。
12. 優(yōu)化器的weight_decay項導致的隱蔽bug
我們都知道weight_decay指的是權值衰減呢铆,即在原損失的基礎上加上一個L2懲罰項晦鞋,使得模型趨向于選擇更小的權重參數(shù),起到正則化的效果棺克。但是我經(jīng)常會忽略掉這一項的存在悠垛,從而引發(fā)了意想不到的問題。
這次的坑是這樣的娜谊,在訓練一個ResNet50的時候确买,網(wǎng)絡的高層部分layer4暫時沒有用到,因此也并不會有梯度回傳纱皆,于是我就放心地將ResNet50的所有參數(shù)都傳遞給Optimizer進行更新了湾趾,想著layer4應該能保持原來的權重不變才對。 但是實際上派草,盡管layer4沒有梯度回傳搀缠,但是weight_decay的作用仍然存在,它使得layer4權值越來越小澳眷,趨向于0胡嘿。后面需要用到layer4的時候,發(fā)現(xiàn)輸出異常(接近于0)钳踊,才注意到這個問題的存在衷敌。
雖然這樣的情況可能不容易遇到勿侯,但是還是要謹慎:暫時不需要更新的權值,一定不要傳遞給Optimizer缴罗,避免不必要的麻煩助琐。
13. TensorDataset 數(shù)據(jù)加載速度
TensorDataset 提供了已經(jīng)完全加載到內(nèi)存中的矩陣的數(shù)據(jù)讀取接口。在使用 TensorDataset的時候面氓,如果直接用DataLoader
兵钮,會導致數(shù)據(jù)加載速度非常緩慢,嚴重拖慢訓練速度舌界,分析和解決方案詳見
https://huangbiubiu.github.io/2019/BEST-PRACTICE-PyTorch-TensorDataset
SW- jit\tensorboard..
AttributeError
module 'distutils' has no attribute 'version'
pytorch 的 tensorboard: torch.utils.tensorboard和 setuptools 版本不匹配
pip install tensorboardX
DT - type, feature, loss,
讀取模型參數(shù)錯誤
num_batches_tracked
參數(shù): 和訓練時的歸一化的計算方式有關掘譬。
因此,我們可以知道該錯誤是由于訓練和測試所用的pytorch版本(0.4.1版本前后的差異)不一致引起的呻拌。具體的解決方案是:如果是模型參數(shù)(Orderdict格式葱轩,很容易修改)里少了num_batches_tracked變量,就加上去藐握,如果是多了就刪掉靴拱。偷懶的做法是將load_state_dict的strict參數(shù)置為False,如下所示:
不建議直接修改源代碼 (把num_batches_tracked參數(shù)刪掉)
ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm) 出現(xiàn)這個錯誤的情況是猾普,在服務器上的docker中運行訓練代碼時袜炕,batch size設置得過大,shared memory不夠(因為docker限制了shm).
解決方法是初家,將Dataloader的num_workers設置為0.
隱層出現(xiàn) nan
RuntimeWarning
[nan] = self._nnLnrm(x)
RuntimeWarning: invalid value encountered in subtract
gae += vag - val # core[enbRppo.py:222]
RuntimeWarning: invalid value encountered in subtract
_np.subtract(arr, avg, out=arr, casting='unsafe', where=where) # numpy[nanfunctions.py:1740]
RuntimeWarning: invalid value encountered in subtract
return (valAqsa - valAmea) / (valAstd + 1e-5) # 3*2:1 core[ent_mpo.py:179]
[ENBrSPR] : getrDet
FutureWarning x2: Non-finite norm encountered in torch.nn.utils.clip_grad_norm_; continuing anyway.
Note that the default behavior will change in a future release to error out if a non-finite total norm is encountered. At that point, setting error_if_nonfinite=false will be required to retain the old behavior.
return _nn.utils.clip_grad_norm_(self._or_act.parameters(), nrmMgrd, error_if_nonfinite=False)
# core[enp_mpo.py:277][enp_mpo.py:279]
檢查用的什么層: _nn.LayerNorm
batch 部分輸入是全 0, 把這種 batch 提前屏蔽掉
FutureWarning:
Non-finite norm encountered in torch.nn.utils.clip_grad_norm_; continuing anyway.
Note that the default behavior will change in a future release to error out
if a non-finite total norm is encountered.
At that point, setting nn.utils.clip_grad_norm:
error_if_nonfinite = false
will be required to retain the old behavior.
Pytorch梯度截斷:torch.nn.utils.clip_grad_norm_
梯度裁剪:
既然在BP過程中會產(chǎn)生梯度消失(即偏導無限接近0偎窘,導致長時記憶無法更新),那么最簡單粗暴的方法笤成,設定閾值评架,當梯度小于閾值時,更新的梯度為閾值(梯度裁剪解決的是梯度消失或爆炸的問題炕泳,即設定閾值)
訓練時候的drop out的方法纵诞,用于解決神經(jīng)網(wǎng)絡訓練過擬合的方法
輸入是(NN參數(shù),最大梯度范數(shù)培遵,范數(shù)類型=2) 一般默認為L2 范數(shù)浙芙。
讓每一次訓練的結果都不過分的依賴某一部分神經(jīng)元,在訓練的時候隨機忽略一些神經(jīng)元和神經(jīng)的鏈接籽腕,使得神經(jīng)網(wǎng)絡變得不完整嗡呼, 是解決過擬合的一種方法。y =wx皇耗,W為所要學習的各種參數(shù)南窗,在過擬合中,W往往變化率比較大,這個時候 用clip_grad_norm 控制W 變化的不那么大万伤,把原來的cost =(Wx-realY)^2 -->cost=(Wx-realY)^2 +L2 正則
在訓練模型的過程中窒悔,我們有可能發(fā)生梯度爆炸的情況,這樣會導致我們模型訓練的失敗敌买。
我們可以采取一個簡單的策略來避免梯度的爆炸简珠,那就是梯度截斷Clip, 將梯度約束在某一個區(qū)間之內(nèi),在訓練的過程中虹钮,在優(yōu)化器更新之前進行梯度截斷操作聋庵。
損失出現(xiàn) nan
ddd
梯度出現(xiàn) nan
可能原因:
- 梯度爆炸。也就是說梯度數(shù)值超出范圍變成nan. 通耻搅唬可以調(diào)小學習率祭玉、加BN層或者做梯度裁剪來試試看有沒有解決。
- 損失函數(shù)或者網(wǎng)絡設計宅倒。比方說攘宙,出現(xiàn)了除0屯耸,或者出現(xiàn)一些邊界情況導致函數(shù)不可導拐迁,比方說log(0)、sqrt(0).
- 臟數(shù)據(jù)疗绣∠哒伲可以事先對輸入數(shù)據(jù)進行判斷看看是否存在nan.
raiseValueError
('Expected more than 1 value per channel when training, got input size {}'.format(size)
訓練前用 num_of_samples % batch_size 算一下會不會正好剩下一個樣本。
將DataLoader
的drop_last
選項設為True多矮,這樣的話缓淹,當最后一個batch湊不滿時,就會舍棄掉塔逃。
計算累積損失
栗子: total_loss += loss.data[0]
loss 是一個封裝了(1,)張量的 Variable
應使用loss.item可以從標量中獲取Python數(shù)字
如果在累加損失時未將其轉(zhuǎn)換為Python數(shù)字讯壶,則可能出現(xiàn)程序內(nèi)存使用量增加的情況。這是因為上面表達式的右側(cè)原本是一個Python浮點數(shù)湾盗,而它現(xiàn)在是一個零維張量伏蚊。因此,總損失累加了張量和它們的梯度歷史格粪,這可能會產(chǎn)生很大的autograd 圖躏吊,耗費內(nèi)存和計算資源。
權值衰減 weight_decay
原損失的基礎上加上一個L2懲罰項起到正則化的效果
訓練一個多層網(wǎng)絡, 直接將所有參數(shù)都 Optimize, 高層部分暫時沒用(沒有梯度回傳)但權重變小了?
盡管沒有梯度回傳帐萎,但是 weight_decay
依然起效使得不用層權值越來越小(趨于0)
不需更新的權值不要傳遞給 Optimizer
數(shù)據(jù)加載速度非常緩慢 TensorDataset
TensorDataset 提供了已經(jīng)完全加載到內(nèi)存中的矩陣的數(shù)據(jù)讀取接口
直接用 DataLoader
比伏,數(shù)據(jù)加載速度慢
Grad Norm
- Future Warning: Non-finite norm encountered in
torch.nn.utils.clip_grad_norm_
;
continuing anyway.
學習率過大: 考
使用了 ReLU 激活函數(shù) 以后, 某一步跨入了一個點, 出現(xiàn)了dead neuron 現(xiàn)象, 前面的參數(shù)全部不更新, 最后的結果變成了定值.base_lr,至少減小一個數(shù)量級疆导。如果有多個loss layer赁项,需要找出哪個損失層導致了梯度爆炸,并減小該層的loss_weight,而非是減小通用的base_lr悠菜。
設置clip gradient紫新,用于限制過大的diff。
壞樣本存在 參
樣本的全是0李剖,減去均值除以方差以后就變成了nan
并行mask設置失誤, 遺漏了一些導致padding傳入
希望模型輸出為0芒率,結果又用了log輸出來作為損失的方式。這就導致篙顺,在輸出可以做到為0的情況下偶芍,log之后就會nan
neg_outputs=model(x)
loss=torch.log(neg_outputs + 6e-7) # 6e-7 保證了最小值 損失就會飽和
自己定義的某個Tensor沒有初始化
比如代碼中實現(xiàn)一些簡單的weight matrix的時候,你直接使用 torch.FloatTensor 作為訓練參數(shù)德玫,但是FloatTensor 本身的初始化是不適用于深度神經(jīng)網(wǎng)絡的匪蟀,此時最好用 nn.init. 初始化損失函數(shù)的Bug
原因:有時候損失層中l(wèi)oss的計算可能導致NaN的出現(xiàn)。比如宰僧,給InfogainLoss層(信息熵損失)輸入沒有歸一化的值材彪,使用帶有bug的自定義損失層等等。
現(xiàn)象:觀測訓練產(chǎn)生的log時一開始并不能看到異常琴儿,loss也在逐步的降低段化,但突然之間NaN就出現(xiàn)了
檢查 loss 計算公式。一定要使用那種飽和類型的損失造成,例如你希望模型二分類显熏,loss不應該設置為,對于類別1晒屎,希望模型輸出為正無窮大喘蟆,對于類別0,希望模型輸出為負無窮大鼓鲁,這樣loss不會飽和蕴轨,模型會一直訓練下去,很容易nan骇吭。應該改為橙弱,對模型輸出的結果,加一層sigmoid绵跷,從而對于類別1膘螟,希望模型輸出為1,對于類別0碾局,模型輸出為0荆残。而對于sigmoid這種飽和函數(shù),輸出為1净当,輸入不需要是正無窮大内斯,6蕴潦,7,8這種數(shù)字就可以差不多輸出為1了俘闯。
注: the default behavior will change in a future release to error out if a non-finite total norm is encountered. At that point, setting error_if_nonfinite=false
will be required to retain the old behavior.
RuntimeError: [enforce fail at http://inline_container.cc:145