使用pytorch時,訓練集數據太多達到上千萬張,Dataloader載入很慢怎麼辦?
訓練集全是16x16,32x32之類的小圖,達到上千萬張,訓練時發現數據載入很慢很慢很慢!!!看了下CPU 內存 GPU使用情況,發現CPU使用率都跑到90%去了,GPU使用率卻較低
PyTorch提速
原始文檔:https://www.yuque.com/lart/ugkv9f/ugysgn
聲明:大部分內容來自知乎和其他博客的分享,這裡只作為一個收集羅列。歡迎給出更多建議。 知乎回答(歡迎點贊哦):搬運到了github上:https://github.com/lartpang/PyTorchTricks有喜歡的可以三連下,或者繼續補充哦!
- pytorch dataloader數據載入佔用了大部分時間,各位大佬都是怎麼解決的? - 人民藝術家的回答 - 知乎 https://www.zhihu.com/question/307282137/answer/907835663
- 使用pytorch時,訓練集數據太多達到上千萬張,Dataloader載入很慢怎麼辦? - 人民藝術家的回答 - 知乎 https://www.zhihu.com/question/356829360/answer/907832358
changelog
- 2019年11月29日:更新一些模型設計技巧和推理加速的內容,補充了下apex的一個介紹鏈接, 另外刪了tfrecord,pytorch能用麼?這個我記得是不能,所以刪掉了(表示刪掉:&
- 2019年11月30日:補充MAC的含義,補充ShuffleNetV2的論文鏈接
- 2019年12月02日:之前說的pytorch不能用tfrecord,今天看到https://www.zhihu.com/question/358632497下的一個回答,漲姿勢了
- 2019年12月23日:補充幾篇關於模型壓縮量化的科普性文章
- 2020年2月7日: 從文章中摘錄了一點注意事項, 補充在了代碼層面小節
- 2020年4月30日:
- 添加了一個github的文檔備份
- 補充了卷積層和BN層融合的介紹的鏈接
- 另外這裡說明下,對於之前參考的很多朋友的文章和回答,沒有把鏈接和對應的內容提要關聯在一起,估計會導致一些朋友閱讀時相關的內容時的提問,無法問到原作者,這裡深感抱歉。
- 調整部分內容,將內容盡量與參考鏈接相對應
- 2020年5月18日:發現一個之前的錯誤:
non_blocking=False
的建議應該是non_blocking=True
.
預處理提速
- 盡量減少每次讀取數據時的預處理操作,可以考慮把一些固定的操作,例如 resize ,事先處理好保存下來,訓練的時候直接拿來用
- Linux上將預處理搬到GPU上加速:
- NVIDIA/DALI :https://github.com/NVIDIA/DALI
IO提速
使用更快的圖片處理
opencv
一般要比PIL
要快- 對於
jpeg
讀取,可以嘗試jpeg4py
- 存
bmp
圖(降低解碼時間)
小圖拼起來存放(降低讀取次數)
對於大規模的小文件讀取,建議轉成單獨的文件,可以選擇的格式可以考慮:TFRecord(Tensorflow)
、recordIO(recordIO)
、hdf5
、 pth
、n5
、lmdb
等等(https://github.com/Lyken17/Efficient-PyTorch#data-loader)
TFRecord
:https://github.com/vahidk/tfrecord- 藉助
lmdb
資料庫格式: - https://github.com/Fangyh09/Image2LMDB
- https://blog.csdn.net/P_LarT/article/details/103208405
- https://github.com/lartpang/PySODToolBox/blob/master/ForBigDataset/ImageFolder2LMDB.py
預讀取數據
- 預讀取下一次迭代需要的數據
【參考】
- 如何給你PyTorch裏的Dataloader打雞血 - MKFMIKU的文章 - 知乎 https://zhuanlan.zhihu.com/p/66145913
- 給pytorch 讀取數據加速 - 體hi的文章 - 知乎 https://zhuanlan.zhihu.com/p/72956595
藉助內存
- 直接載到內存裡面,或者把把內存映射成磁碟好了
【參考】
- 參見 https://zhuanlan.zhihu.com/p/66145913 的評論中 @雨宮夏一 的評論
藉助固態
- 把讀取速度慢的機械硬碟換成 NVME 固態吧~
【參考】
- 如何給你PyTorch裏的Dataloader打雞血 - MKFMIKU的文章 - 知乎 https://zhuanlan.zhihu.com/p/66145913
訓練策略
低精度訓練
- 在訓練中使用低精度(
FP16
甚至INT8
、二值網路、三值網路)表示取代原有精度(FP32
)表示 NVIDIA/Apex
:- https://blog.csdn.net/c9Yv2cf9I06K2A9E/article/details/100135729
- https://github.com/nvidia/apex
代碼層面
torch.backends.cudnn.benchmark = True
- Do numpy-like operations on the GPU wherever you can
- Free up memory using
del
- Avoid unnecessary transfer of data from the GPU
- Use pinned memory, and use
non_blocking=True
to parallelize data transfer and GPU number crunching - 文檔:https://pytorch.org/docs/stable/nn.html#torch.nn.Module.to
- 關於
non_blocking=True
的設定的一些介紹:Pytorch有什麼節省顯存的小技巧? - 陳瀚可的回答 - 知乎 https://www.zhihu.com/question/274635237/answer/756144739 - 網路設計很重要,外加不要初始化任何用不到的變數,因為 PyTorch 的初始化和
forward
是分開的,他不會因為你不去使用,而不去初始化 - 合適的
num_worker
: Pytorch 提速指南 - 雲夢的文章 - 知乎 https://zhuanlan.zhihu.com/p/39752167(這裡也包含了一些其他細節上的討論)
模型設計
來自 ShuffleNetV2 的結論:(內存訪問消耗時間,memory access cost
縮寫為 MAC
)
- 卷積層輸入輸出通道一致:卷積層的輸入和輸出特徵通道數相等時 MAC 最小,此時模型速度最快
- 減少卷積分組:過多的 group 操作會增大
MAC
,從而使模型速度變慢 - 減少模型分支:模型中的分支數量越少,模型速度越快
- 減少
element-wise
操作:element-wise
操作所帶來的時間消耗遠比在 FLOPs 上的體現的數值要多,因此要儘可能減少element-wise
操作(depthwise convolution
也具有低 FLOPs 、高 MAC 的特點)
其他:
- 降低複雜度:例如模型裁剪和剪枝,減少模型層數和參數規模
- 改模型結構:例如模型蒸餾,通過知識蒸餾方法來獲取小模型
推理加速
半精度與權重量化
在推理中使用低精度(FP16
甚至 INT8
、二值網路、三值網路)表示取代原有精度(FP32
)表示:
TensorRT
是 NVIDIA 提出的神經網路推理(Inference)引擎,支持訓練後 8BIT 量化,它使用基於交叉熵的模型量化演算法,通過最小化兩個分佈的差異程度來實現- Pytorch1.3 開始已經支持量化功能,基於 QNNPACK 實現,支持訓練後量化,動態量化和量化感知訓練等技術
- 另外
Distiller
是 Intel 基於 Pytorch 開源的模型優化工具,自然也支持 Pytorch 中的量化技術 - 微軟的
NNI
集成了多種量化感知的訓練演算法,並支持PyTorch/TensorFlow/MXNet/Caffe2
等多個開源框架
【參考】:
- 有三AI:【雜談】當前模型量化有哪些可用的開源工具?https://mp.weixin.qq.com/s?__biz=MzA3NDIyMjM1NA==mid=2649037243idx=1sn=db2dc420c4d086fc99c7d8aada767484chksm=8712a7c6b0652ed020872a97ea426aca1b06adf7571af3da6dac8ce991fd61001245e9bf6e9bmpshare=1scene=1srcid=sharer_sharetime=1576667804820sharer_shareid=1d0dbdb37c6b95413d1d4fe7d61ed8f1exportkey=A6g%2Fj50pMJYVXsedNyDVh9k%3Dpass_ticket=winxjBrzw0kHErbSri5yXS88yBx1a%2BAL9KKTG6Zt1MMS%2FeI2hpx%2BmeaLsrahnlOS#rd
網路 inference 階段 Conv 層和 BN 層融合
【參考】
- https://zhuanlan.zhihu.com/p/110552861
- PyTorch本身提供了類似的功能,但是我沒有使用過,希望有朋友可以提供一些使用體會:https://pytorch.org/docs/1.3.0/quantization.html#torch.quantization.fuse_modules
- 網路inference階段conv層和BN層的融合 - autocyz的文章 - 知乎 https://zhuanlan.zhihu.com/p/48005099
時間分析
- Python 的
cProfile
可以用來分析。(Python 自帶了幾個性能分析的模塊:profile
、cProfile
和hotshot
,使用方法基本都差不多,無非模塊是純 Python 還是用 C 寫的)
項目推薦
- 基於 Pytorch 實現模型壓縮(https://github.com/666DZY666/model-compression):
- 量化:8/4/2 bits(dorefa)、三值/二值(twn/bnn/xnor-net)
- 剪枝:正常、規整、針對分組卷積結構的通道剪枝
- 分組卷積結構
- 針對特徵二值量化的BN融合
擴展閱讀
- pytorch dataloader數據載入佔用了大部分時間,各位大佬都是怎麼解決的? - 知乎 https://www.zhihu.com/question/307282137
- 使用pytorch時,訓練集數據太多達到上千萬張,Dataloader載入很慢怎麼辦? - 知乎 https://www.zhihu.com/question/356829360
- PyTorch 有哪些坑/bug? - 知乎 https://www.zhihu.com/question/67209417
- https://sagivtech.com/2017/09/19/optimizing-pytorch-training-code/
- 26秒單GPU訓練CIFAR10,Jeff Dean也點贊的深度學習優化技巧 - 機器之心的文章 - 知乎 https://zhuanlan.zhihu.com/p/79020733
- 線上模型加入幾個新特徵訓練後上線,tensorflow serving預測時間為什麼比原來慢20多倍? - TzeSing的回答 - 知乎 https://www.zhihu.com/question/354086469/answer/894235805
- 相關資料 · 語雀 https://www.yuque.com/lart/gw5mta/bl3p3y
- ShuffleNetV2:https://arxiv.org/pdf/1807.11164.pdf
- 今天,你的模型加速了嗎?這裡有5個方法供你參考(附代碼解析): https://mp.weixin.qq.com/s?__biz=MzI0ODcxODk5OA==mid=2247511633idx=2sn=a5ab187c03dfeab4e64c85fc562d7c0dchksm=e99e9da8dee914be3d713c41d5dedb7fcdc9982c8b027b5e9b84e31789913c5b2dd880210eadmpshare=1scene=1srcid=sharer_sharetime=1576934236399sharer_shareid=1d0dbdb37c6b95413d1d4fe7d61ed8f1exportkey=A%2B3SqYGse83qyFva%2BYSy3Ng%3Dpass_ticket=winxjBrzw0kHErbSri5yXS88yBx1a%2BAL9KKTG6Zt1MMS%2FeI2hpx%2BmeaLsrahnlOS#rd
- pytorch常見的坑匯總 - 鬱振波的文章 - 知乎 https://zhuanlan.zhihu.com/p/77952356
- Pytorch 提速指南 - 雲夢的文章 - 知乎 https://zhuanlan.zhihu.com/p/39752167
1)小圖拼起來存放(降低讀取次數)
2)存bmp圖(降低解碼時間)
3)1張32*32的圖其實也就3K大,1000w也纔不到29G,現在訓練機器都是幾百G的內存,直接載到內存裡面,或者把把內存映射成磁碟好了。
io對cpu壓力不大的。90%的cpu肯定是在做計算。
讀寫的上限跟iops有關,iops又跟硬碟有關,拿阿里雲的普通ssd說的話,代碼寫的還行的話,一秒最多讀300-400m。載入慢可以先試試自己讀出來在做轉換。
訓練慢的話就上gpu吧。數據該壓縮的地方壓縮一下。
首先判斷是否是io瓶頸,數據數量多少和io速度沒關係,cpu很高的話說明問題在於cpu預處理而非磁碟io。
既然已經都幾千萬樣本了,個人認為就沒必要做實事的數據增強和預處理了。
離線數據增強好,load進去後直接餵給gpu就可以了。
1. DALI
2. 掛載內存檔tmpfs
推薦閱讀: