pytorch入坑指南

1. 內存爆炸問題

1.1 loss.item或 float(loss)

首先附上主要代碼
在這裏插入圖片描述
下圖接上圖
在這裏插入圖片描述
上面爲定義的TextCNN模型,下圖爲主要的訓練及預測測試集的過程
在這裏插入圖片描述
下圖接上圖
在這裏插入圖片描述
可以從第三張圖片看到綠框部分有一個tr_loss = float(tr_loss)。在pytorch中涉及需要求導/梯度變量的計算將保存在內存中,如果不釋放指向計算圖形的指針,這些變量在循環訓練中就會超出你內存。因此千萬不要在循環中累積歷史記錄。
如果不加tr_loss = float(tr_loss),tr_loss(可求導變量,一直會保留副本在內存中)就會一直有副本,並保留在內存中,經過多個epoch後,就會撐爆內存。一般釋放副本的方式爲tr_loss.item()上面提到的tr_loss = float(tr_loss)也可以,但更推薦使用tr_loss.item()。如果沒有釋放副本(內存),就會出現以下錯誤:
在這裏插入圖片描述
看似是內存問題,其實使我們代碼寫的有問題。
有時我們需要算累積的loss,也是一樣的方式,如下所示:

total_loss = 0
for i in range(10000):
    optimizer.zero_grad()
    output = model(input)
    loss = criterion(output)
    loss.backward()
    optimizer.step()
    total_loss += loss.item()

仔細想一想,pytorch訓練的時候有一個optimizer.zero_grad()似乎也是釋放計算圖,因此不會撐爆內存

1.2 with torch.no_grad()

第三張圖片還有一個綠框部分即with torch.no_grad()這個作用也是防止內存爆炸。
模型訓練階段,會存儲一些用於反向傳播的內部信息。當需要由訓練階段(反向傳播)轉至預測階段時,需要使用model.eval()with torch.no_grad()model.eval()是告訴計算機,我現在不需要訓練了(反向傳播),我要開始測試了,這時,計算機就會固定住dropout和batch normalization(不會取平均,而是用訓練好的值),簡單理解就是不需要更新參數了,而是用訓練好的參數進行預測。由於不需要更新參數,故不會產生用於反向傳播的內部信息,更不會存儲到內存了。with torch.no_grad()是爲了釋放訓練過程中產生的用於反向傳播的內部信息,從而釋放內存。不管是對訓練集進行預測,還是對測試集進行預測,都需要使用with torch.no_grad()

2. 如何觀察內存變化

第一章提到內存爆炸,那麼如何觀察內存的變化呢

2.1 cpu

當使用cpu訓練模型時,可在命令行輸入top然後按大寫的M即可看到佔用內存最大的程序。
在這裏插入圖片描述
圖片中紅框部分就是cpu佔用率,說明我們現在使用了7.5%的內存

2.2 GPU

當我們使用cuda時,使用命令watch -n 0.1 nvidia-smi觀察內存變化
在這裏插入圖片描述
上圖顯示我們共有4塊GPU,一塊大約16G(圖中綠框),目前,我們僅使用了其中一塊GPU,利用率爲96%(紅框部分,該數表示程序96%的部分都在GPU上跑,剩餘4%在cpu跑),目前共佔用GPU的顯存爲4G左右(藍框部分)

3. 多塊GPU(數據並行),lstm參數展平

當我們有多塊GPU,並且全部使用時,訓練lstm,需要進行參數展平的操作,否則會有一堆提示信息(這不算報錯吧,warning)
在這裏插入圖片描述
由於多次循環,滿屏基本都是上圖中的warning了。
那麼怎樣進行參數展平,只需要在lstm cell前加lstm.flatten_parameters(),如下圖所示
在這裏插入圖片描述
這個問題好像有時候出現,有時候不出現。。。且僅使用多塊GPU時出現(如果只使用一塊GPU,還沒有出現過)

4. 多塊GPU與DataLoder

pytroch中有DataLoader,可以將數據劃分成多個batch,DataLodaer有一個參數num_workers,這是pytroch加快速度的一種方法,其允許批量並行加載。所以,你可以一次加載許多批量,而不是一次加載一個。但是當既使用DataLoder又使用多塊GPU時,就可能出現segmentation faultmentation fault的問題,看了很多博客,大概是DataLoder是多線程,與多塊GPU發生了衝突,故有人建議將num_worker設成1,然而我不管設成1還是0還是會出現segmentation fault的問題。有一篇大神的博客https://meteorix.github.io/2019/04/30/pytorch-coredump/從c++的角度去debug問題,其最終使用了線程加鎖,解決了問題,不過,我嘗試在DataLoder加鎖,還是沒有解決問題(可能是加鎖位置不對)。最終採用了最極端的方式,放棄DataLoder,換用其他方式,最終不再報錯。
由於上述問題是多線程與多GPU衝突的問題,故僅僅使用一塊GPU應該不會報錯,即使使用多塊GPU,上述問題也不一定出現,因爲這個問題是隨機性的。。。我在測試中,有一次程序的確跑通了。
在這裏插入圖片描述
棄用了紅框的DataLoder,換用綠框的方式

5. pytroch訓練及預測部分怎麼寫

回顧第一章的TextCNN,我的代碼是在一個epoch訓練結束後,再對整個訓練集和測試集進行預測,獲得loss和acc並存儲在列表中。此外,還有另外一種寫法。訓練集和測試集都分成很多batch,一個epoch中的每個batch都記錄下loss和acc,當一個epoch結束後,求一個epoch下n個batch的平均值(loss和acc)作爲一個epoch的loss和acc。
在這裏插入圖片描述
參考鏈接:https://blog.csdn.net/weixin_40446557/article/details/103387629

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