pytorch常見的坑匯總

2021-02-20 機器學習算法與自然語言處理

來自 | 知乎

地址 | https://zhuanlan.zhihu.com/p/77952356

作者 | 鬱振波

編輯 | 機器學習算法與自然語言處理公眾號

本文僅作學術分享,若侵權,請聯繫後臺刪文處理

最近剛開始用pytorch不久,陸陸續續踩了不少坑,記錄一下,個人感覺應該都是一些很容易遇到的一些坑,也在此比較感謝幫我排坑的小夥伴,持續更新,也祝願自己遇到的坑越來越少。

首先作為tensorflow的骨灰級玩家+輕微強迫症患者,一路打怪升級,從0.6版本用到1.2,再用到1.10,經歷了tensorfow數個版本更迭,這裡不得不說一下tf.data.dataset+tfrecord使用起來效率遠比dataloader高的多。

tensorflow有一個比較好用的隊列機制,tf.inputproducer + tfrecord, 但是inputproducer有一個bug,就是無法對每個epoch單獨shuffle,它只能整體shuffle,也就意味著我們無法進行正常的訓練流程(train幾個epoch,在validation上測一個epoch,最終選一個validation上的最好的結果,進行test)。後來我當時給官方提了一個issue,官方當時的回答是,這個bug目前無法解決,但是他們在即將到來的tf1.2版本中, 推出的新型數據處理API tf.contrib.data.dataset(tf1.3版本將其合併到了tf.data.dataset)可以完美解決這個bug,並且將於tf2.0摒棄tf.input_producer。然後tf1.2版本剛出來以後,我就立馬升級並且開始tf.data.dataset踩坑,踩了大概2周多的坑,(這個新版的API其實功能並不是非常強大,有不少局限性,在此就不展開)。

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

好像扯遠了,回歸pytorch,首先讓我比較尷尬的是pytorch並沒有一套屬於自己的數據結構以及數據讀取算法,dataloader個人感覺其實就是類似於tf中的feed,並沒有任何速度以及性能上的提升。

先總結一下遇到的坑:

1. 沒有比較高效的數據存儲,tensorflow有tfrecord, caffe有lmdb,cv.imread在網絡訓練過程中實屬浪費時間。這裡感謝一下小智大神 @智天成。

解決方案:

當時看到了一個還不錯的github連結,

Lyken17/Efficient-PyTorchgithub.com

主要是講如何使用lmdb,h5py,pth,lmdb,n5等數據存儲方式皆可以。

個人的感受是,h5在數據調用上比較快,但是如果要使用多線程讀寫,就儘量不要使用h5,因為h5的多線程讀寫好像比較麻煩。

Parallel HDF5 - h5py 2.9.0 documentationdocs.h5py.org

這裡貼一下h5數據的讀寫代碼(主要需要注意的是字符串的讀寫需要encode,decode,最好用create_dataset,直接寫的話讀的時候會報錯):

寫:
imagenametotal_.append(os.path.join('images', imagenametotal).encode())
with h5py.File(outfile) as f:
f.create_dataset('imagename', data=imagenametotal_)
f['part'] = parts_
f['S'] = Ss_
f['image'] = cvimgs
讀:
with h5py.File(outfile) as f:
imagename = [x.decode() for x in f['imagename']]
kp2ds = np.array(f['part'])
kp3ds = np.array(f['S'])
cvimgs = np.array(f['image'])

2. gpu imbalance,這裡感謝一下張航學長 @張航

老生常談的問題,第一個GPU顯存佔用多一點。

張航學長Hang Zhang (張航)提了一個開源的gpu balance的工具--PyTorch-Encoding。

使用方法還是比較便捷的,如下所示:

from balanced_parallel import DataParallelModel, DataParallelCriterion
model = DataParallelModel(model, device_ids=gpus).cuda()
criterion = loss_fn().cuda()

這裡其實有2個注意點,第一,測試的時候需要手動將gpu合併,代碼如下:

from torch.nn.parallel.scatter_gather import gather
preds = gather(preds, 0)

第二,當loss函數有多個組成的時候,比如 loss = loss1 + loss2 + loss3

那麼需要把這三個loss寫到一個class中,然後再forward裡面將其加起來。

其次,我們還可以用另外一個函數distributedDataParallel來解決gpu imbalance的問題.

使用方法如下:(註:此方法好像無法和h5數據同時使用)

from torch.utils.data.distributed import DistributedSampler
from torch.nn.parallel import DistributedDataParallel

torch.distributed.init_process_group(backend="nccl")
# 配置每個進程的gpu
local_rank = torch.distributed.get_rank()
torch.cuda.set_device(local_rank)
device = torch.device("cuda", local_rank)

#封裝之前要把模型移到對應的gpu
model.to(device)
model = torch.nn.parallel.DistributedDataParallel(model,device_ids=[local_rank],
output_device=local_rank)

#原有的dataloader上面加一個數據sample
train_loader = torch.utils.data.DataLoader(
train_dataset,
sampler=DistributedSampler(train_dataset)
)

3.gpu利用率不高+gpu現存佔用浪費

常用配置:

1主函數前面加:(這個會犧牲一點點現存提高模型精度)

cudnn.benchmark = True
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.enabled = True

2訓練時,epoch前面加:(定期清空模型,效果感覺不明顯)

torch.cuda.empty_cache()

3無用變量前面加:(同上,效果某些操作上還挺明顯的)

del xxx(變量名)

4dataloader的長度_len_設置:(dataloader會間歇式出現卡頓,設置成這樣會避免不少)

def __len__(self):
return self.images.shape[0]

5dataloader的預加載設置:(會在模型訓練的時候加載數據,提高一點點gpu利用率)

train_loader = torch.utils.data.DataLoader(
train_dataset,
pin_memory=True,
)

6網絡設計很重要,外加不要初始化任何用不到的變量,因為pyroch的初始化和forward是分開的,他不會因為你不去使用,而不去初始化。

7最後放一張目前依舊困擾我的圖片:

可以看到,每個epoch剛開始訓練數據的時候,第一個iteration時間會佔用的非常多,pytorch這裡就做的很糟糕,並不是一個動態分配的過程,我也看到了一個看上去比較靠譜的解決方案,解決方案如下 @風車車:

風車車:在深度學習中餵飽gpuzhuanlan.zhihu.com

但是我看了下代碼,可能需要重構dataloader,看了評論好像還有問題,有點懶,目前還沒有踩坑,準備後面有時間踩一下。

暫且更新到這裡,後續遇到什麼坑陸續補充,也歡迎大家給我補充,pytorch初學者小白一枚。

更個新;順便吐槽一下上面的dali,局限性很大,比較trick的數據預處理很難搞定。

8 apex混合單精度模型

事實證明,apex並沒有官網說的那麼玄乎,只能減低顯存,並不能提速(12G顯存大概可以降低到8G左右,效果還挺明顯的,但是,速度降低了大概1/3,好像有點得不償失)。

編譯之後提速也很有限,再此留個坑,有小夥伴能解決的可以私信我哈,如果可以解決我會仔細羅列一遍。。

最近分享了一些奇技淫巧的深度環境工具:

鬱振波:打造舒適的深度學習環境(工具篇)zhuanlan.zhihu.com

重磅!憶臻自然語言處理-學術微信交流群已成立

可以掃描下方二維碼,小助手將會邀請您入群交流,

注意:請大家添加時修改備註為 [學校/公司 + 姓名 + 方向]

例如 —— 哈工大+張三+對話系統。

號主,微商請自覺繞道。謝謝!

推薦閱讀:

【長文詳解】從Transformer到BERT模型

賽爾譯文 | 從頭開始了解Transformer

百聞不如一碼!手把手教你用Python搭一個Transformer

相關焦點

  • PyTorch常見的12坑
    6. pytorch中loss函數的參數設置以CrossEntropyLoss為例:7. pytorch的可重複性問題參考這篇博文:https://blog.csdn.net/hyk_1996/article/details/84307108 8. 多GPU的處理機制使用多GPU時,應該記住pytorch的處理邏輯是:1.在各個GPU上初始化模型。2.前向傳播時,把batch分配到各個GPU上進行計算。
  • 【Pytorch】pytorch權重初始化方式與原理
    來自 | 知乎地址 | https://zhuanlan.zhihu.com/p/100937718作者 | 機器學習入坑者
  • 新手必備 | 史上最全的PyTorch學習資源匯總
    【磐創AI導讀】之前的文章中,我們總結了適合新手快速入門的Tensorflow學習資源匯總,今天我們將為大家介紹另一個深度學習框架
  • 【乾貨】史上最全的PyTorch學習資源匯總
    該文檔的官網:http://pytorchchina.com 。    · Pytorch-Seq2seq(https://github.com/IBM/pytorch-seq2seq):Seq2seq是一個快速發展的領域,新技術和新框架經常在此發布。
  • Pytorch深度學習從入門到成仙系列二
    安裝 Anaconda 完畢後,我們在安裝 PyTorch 之前最好先創建一個 pytorch 的虛擬環境。之所以創建虛擬環境是因為 Python 為不同的項目需求創建不同的虛擬環境非常常見。
  • GitHub趨勢榜第一:TensorFlow+PyTorch深度學習資源大匯總
    /cnn/cnn-basic.ipynb具有He初始化的CNNPyTorch:https://github.com/rasbt/deeplearning-models/blob/master/pytorch_ipynb/cnn/cnn-he-init.ipynb概念
  • 經驗 | PyTorch 開發部署時 5 個常見錯誤
    在這裡,我想分享在生產中使用PyTorch最常見的5個錯誤。考慮過使用CPU嗎?使用多線程?使用更多的GPU內存?這些坑我們都踩過。錯誤 #1 — 在推理模式下保存動態圖如果你以前使用過TensorFlow,那麼你可能知道TensorFlow和PyTorch之間的關鍵區別 —— 靜態圖和動態圖。
  • pytorch專題前言 | 為什麼要學習pytorch?
    2.為什麼要學習pytorch呢?3.學習了pytorch我怎麼應用呢?4.按照什麼順序去學習pytorch呢?5.網上那麼多資料如何選擇呢?現在開始逐一的對以上問題提出自己的看法,可能想的不夠周全,歡迎討論區一起探討!1.生物學科的朋友需要學編程麼?需要!
  • 資料|【乾貨】PyTorch學習資源匯總
    該文檔的官網:http://pytorchchina.com知乎專欄PyTorch學習筆記,搜索名字:餘霆嵩,地址為https://zhuanlan.zhihu.com/c_1056853059086430208PyTorch視頻教程B站PyTorch視頻教程:首推的是B站中近期點擊率非常高的一個PyTorch視頻教程,雖然視頻內容只有八集,但講的深入淺出,
  • 在Linux系統中安裝深度學習框架Pytorch
    為pytorch創建一個虛擬環境,這是推薦的做法,這樣在創建其他環境如tensorflow時,就不會互相衝突。在終端輸入:conda create -n pytorch python=3.7 再輸入 conda activate pytorch進入該環境,此外conda deactivate退出該環境。進入該環境後,命令行前面有(pytorch)。
  • 初學AI神經網絡應該選擇Keras或是Pytorch框架?
    與Keras一樣,它也抽象出了深層網絡編程的許多混亂部分(大神踩過的坑,我們就沒有必要踩了)。就學習難易和語言高級程度而言,Pytorch介於Keras和TensorFlow之間。但比起Keras具有更大的靈活性和控制能力,但又不必進行任何複雜的聲明式編程,如果想深入了解機器學習pytorch庫就是不錯的選擇。
  • 【小白學PyTorch】18.TF2構建自定義模型
    pytorch常見運算詳解小白學PyTorch | 9 tensor數據結構與存儲結構小白學PyTorch | 8 實戰之MNIST小試牛刀小白學PyTorch | 7 最新版本torchvision.transforms常用API翻譯與講解
  • 小白學PyTorch | 10 pytorch常見運算詳解
    5 對數運算 在上學的時候,我們知道ln是以e為底的,但是在pytorch中,並不是這樣。pytorch中log是以e自然數為底數的,然後log2和log10才是以2和10為底數的運算。
  • 專欄 | pytorch入門總結指南(1)
    https://github.com/bharathgs/Awesome-pytorch-list總結內容包括了,github上的各類高星tutorial(其實內容上基本差不多大同小異的),pytorch中文手冊,《deep learning with pytorch》《深度學習框架pytorch快速開發與實戰》,《深度學習入門之torch》以及官方文檔,說老實話
  • PyTorch 學習筆記(七):PyTorch的十個優化器
    同時提供每月大咖直播分享、真實項目需求對接、乾貨資訊匯總,行業技術交流。pytorch中是這樣的:v=ρ∗v+gp=p−lr∗v = p - lr∗ρ∗v - lr∗g其他框架:v=ρ∗v+lr∗gp=p−v = p - ρ∗v - lr∗gρ是動量,v是速率,g是梯度,p是參數,其實差別就是在ρ∗v這一項,pytorch中將此項也乘了一個學習率。
  • 用 PyTorch 實現一個簡單的分類器
    所以我總結了一下自己當初學習的路線,準備繼續深入鞏固自己的 pytorch 基礎;另一方面,也想從頭整理一個教程,從沒有接觸過 pytorch 開始,到完成一些最新論文裡面的工作。以自己的學習筆記整理為主線,大家可以針對參考。第一篇筆記,我們先完成一個簡單的分類器。
  • 一個Seq2seq模型的Pytorch實現庫
    註:文末附【深度學習與自然語言處理】交流群介紹一個Seq2seq模型的實現tutorial,使用pytorch和torchtext實現。目前已經有2400個start,質量應該不錯。深度學習與神經網絡,pytorch官方中文教程,利用Python進行數據分析,機器學習學習筆記,pandas官方文檔中文版,effective java(中文版)等20項福利資源
  • 深度學習框架搭建之PyTorch
    如果學習過 NumPy 以及常見的深度學習概念(如卷積層,循環層等),非常容易上手PyTorch。目前主流的深度學習框架主要有 TensorFlow,PyTorch,mxnet,caffe和Keras 等。
  • Pytorch 中文文檔和中文教程
    簡單介紹GitHub項目管理:https://github.com/apachecn/pytorch-doc-zhPytorch 版本地址:https://pytorch.apachecn.org項目所翻譯的Pytorch版本包括以下幾個版本:(中文文檔 + 中文教程)1.4中文版本(https://github.com/apachecn/pytorch-doc-zh
  • PyTorch 0.2發布:更多NumPy特性,高階梯度、分布式訓練等
    PyTorch還提供了一個ImageNet訓練案例來進行說明:https://github.com/pytorch/examples/tree/master/imagenet新的nn層0.2版本有一些新特性:引入forward_pre_hook,在調用forward函數之前執行用戶指定的閉包。