讓 PyTorch 訓練速度更快,你需要掌握這 17 種方法

2021-02-21 AI有道

選自 | efficientdl.com

作者 | LORENZ KUHN

轉自 | 機器之心

編輯 | 陳萍


掌握這 17 種方法,用最省力的方式,加速你的 Pytorch 深度學習訓練。

近日,Reddit 上一個帖子熱度爆表。主題內容是關於怎樣加速 PyTorch 訓練。原文作者是來自蘇黎世聯邦理工學院的計算機科學碩士生 LORENZ KUHN,文章向我們介紹了在使用 PyTorch 訓練深度模型時最省力、最有效的 17 種方法

該文所提方法,都是假設你在 GPU 環境下訓練模型。具體內容如下。學習率 schedule 的選擇對模型的收斂速度和泛化能力有很大的影響。Leslie N. Smith 等人在論文《Cyclical Learning Rates for Training Neural Networks》、《Super-Convergence: Very Fast Training of Neural Networks Using Large Learning Rates 》中提出了周期性(Cyclical)學習率以及 1Cycle 學習率 schedule。之後,fast.ai 的 Jeremy Howard 和 Sylvain Gugger 對其進行了推廣。下圖是 1Cycle 學習率 schedule 的圖示:

Sylvain 寫到:1Cycle 包括兩個等長的步幅,一個步幅是從較低的學習率到較高的學習率,另一個是回到最低水平。最大值來自學習率查找器選取的值,較小的值可以低十倍。然後,這個周期的長度應該略小於總的 epochs 數,並且,在訓練的最後階段,我們應該允許學習率比最小值小几個數量級。與傳統的學習率 schedule 相比,在最好的情況下,該 schedule 實現了巨大的加速(Smith 稱之為超級收斂)。例如,使用 1Cycle 策略在 ImageNet 數據集上訓練 ResNet-56,訓練迭代次數減少為原來的 1/10,但模型性能仍能比肩原論文中的水平。在常見的體系架構和優化器中,這種 schedule 似乎表現得很好。Pytorch 已經實現了這兩種方法:「torch.optim.lr_scheduler.CyclicLR」和「torch.optim.lr_scheduler.OneCycleLR」。參考文檔:https://pytorch.org/docs/stable/optim.html2. 在 DataLoader 中使用多個 worker 和頁鎖定內存當使用 torch.utils.data.DataLoader 時,設置 num_workers > 0,而不是默認值 0,同時設置 pin_memory=True,而不是默認值 False。參考文檔:https://pytorch.org/docs/stable/data.html來自 NVIDIA 的高級 CUDA 深度學習算法軟體工程師 Szymon Micacz 就曾使用四個 worker 和頁鎖定內存(pinned memory)在單個 epoch 中實現了 2 倍的加速。人們選擇 worker 數量的經驗法則是將其設置為可用 GPU 數量的四倍,大於或小於這個數都會降低訓練速度。請注意,增加 num_workers 將增加 CPU 內存消耗。把 batch 調到最大是一個頗有爭議的觀點。一般來說,如果在 GPU 內存允許的範圍內將 batch 調到最大,你的訓練速度會更快。但是,你也必須調整其他超參數,比如學習率。一個比較好用的經驗是,batch 大小加倍時,學習率也要加倍。OpenAI 的論文《An Empirical Model of Large-Batch Training》很好地論證了不同的 batch 大小需要多少步才能收斂。在《How to get 4x speedup and better generalization using the right batch size》一文中,作者 Daniel Huynh 使用不同的 batch 大小進行了一些實驗(也使用上面討論的 1Cycle 策略)。最終,他將 batch 大小由 64 增加到 512,實現了 4 倍的加速。然而,使用大 batch 的不足是,這可能導致解決方案的泛化能力比使用小 batch 的差。PyTorch 1.6 版本包括對 PyTorch 的自動混合精度訓練的本地實現。這裡想說的是,與單精度 (FP32) 相比,某些運算在半精度 (FP16) 下運行更快,而不會損失準確率。AMP 會自動決定應該以哪種精度執行哪種運算。這樣既可以加快訓練速度,又可以減少內存佔用。
import torchscaler = torch.cuda.amp.GradScaler()

for data, label in data_iter: optimizer.zero_grad() with torch.cuda.amp.autocast(): loss = model(data)
   scaler.scale(loss).backward()
   scaler.step(optimizer)
scaler.update()

AdamW 是由 fast.ai 推廣的一種具有權重衰減(而不是 L2 正則化)的 Adam,在 PyTorch 中以 torch.optim.AdamW 實現。AdamW 似乎在誤差和訓練時間上都一直優於 Adam。Adam 和 AdamW 都能與上面提到的 1Cycle 策略很好地搭配。目前,還有一些非本地優化器也引起了很大的關注,最突出的是 LARS 和 LAMB。NVIDA 的 APEX 實現了一些常見優化器的融合版本,比如 Adam。與 PyTorch 中的 Adam 實現相比,這種實現避免了與 GPU 內存之間的多次傳遞,速度提高了 5%。如果你的模型架構保持不變、輸入大小保持不變,設置 torch.backends.cudnn.benchmark = True。7. 小心 CPU 和 GPU 之間頻繁的數據傳輸當頻繁地使用 tensor.cpu() 將張量從 GPU 轉到 CPU(或使用 tensor.cuda() 將張量從 CPU 轉到 GPU)時,代價是非常昂貴的。item() 和 .numpy() 也是一樣可以使用. detach() 代替。如果你創建了一個新的張量,可以使用關鍵字參數 device=torch.device('cuda:0') 將其分配給 GPU。如果你需要傳輸數據,可以使用. to(non_blocking=True),只要在傳輸之後沒有同步點。8. 使用梯度 / 激活 checkpointingCheckpointing 的工作原理是用計算換內存,並不存儲整個計算圖的所有中間激活用於 backward pass,而是重新計算這些激活。我們可以將其應用於模型的任何部分。具體來說,在 forward pass 中,function 會以 torch.no_grad() 方式運行,不存儲中間激活。相反的是, forward pass 中會保存輸入元組以及 function 參數。在 backward pass 中,輸入和 function 會被檢索,並再次在 function 上計算 forward pass。然後跟蹤中間激活,使用這些激活值計算梯度。因此,雖然這可能會略微增加給定 batch 大小的運行時間,但會顯著減少內存佔用。這反過來又將允許進一步增加所使用的 batch 大小,從而提高 GPU 的利用率。儘管 checkpointing 以 torch.utils.checkpoint 方式實現,但仍需要一些思考和努力來正確地實現。Priya Goyal 寫了一個很好的教程來介紹 checkpointing 關鍵方面。https://github.com/prigoyal/pytorch_memonger/blob/master/tutorial/Checkpointing_for_PyTorch_models.ipynb增加 batch 大小的另一種方法是在調用 optimizer.step() 之前在多個. backward() 傳遞中累積梯度。Hugging Face 的 Thomas Wolf 的文章《Training Neural Nets on Larger Batches: Practical Tips for 1-GPU, Multi-GPU & Distributed setups》介紹了如何使用梯度累積。梯度累積可以通過如下方式實現:
model.zero_grad()                                   for i, (inputs, labels) in enumerate(training_set):    predictions = model(inputs)                         loss = loss_function(predictions, labels)           loss = loss / accumulation_steps                    loss.backward()                                     if (i+1) % accumulation_steps == 0:                     optimizer.step()                                    model.zero_grad()                                   if (i+1) % evaluation_steps == 0:                       evaluate_model()                        

這個方法主要是為了規避 GPU 內存的限制而開發的。加速分布式訓練可能有很多方法,但是簡單的方法是使用 torch.nn.DistributedDataParallel 而不是 torch.nn.DataParallel。這樣一來,每個 GPU 將由一個專用的 CPU 核心驅動,避免了 DataParallel 的 GIL 問題。分布式訓練文檔地址:https://pytorch.org/tutorials/beginner/dist_overview.html梯度設置為. zero_grad(set_to_none=True) 而不是 .zero_grad()。這樣做可以讓內存分配器處理梯度,而不是將它們設置為 0。正如文檔中所說,將梯度設置為 None 會產生適度的加速,但不要期待奇蹟出現。注意,這樣做也有缺點,詳細信息請查看文檔。文檔地址:https://pytorch.org/docs/stable/optim.html12. 使用. as_tensor() 而不是. tensor()torch.tensor() 總是會複製數據。如果你要轉換一個 numpy 數組,使用 torch.as_tensor() 或 torch.from_numpy() 來避免複製數據。PyTorch 提供了很多調試工具,例如 autograd.profiler、autograd.grad_check、autograd.anomaly_detection。請確保當你需要調試時再打開調試器,不需要時要及時關掉,因為調試器會降低你的訓練速度。關於避免 RNN 中的梯度爆炸的問題,已經有一些實驗和理論證實,梯度裁剪(gradient = min(gradient, threshold))可以加速收斂。HuggingFace 的 Transformer 實現就是一個非常清晰的例子,說明了如何使用梯度裁剪。本文中提到的其他一些方法,如 AMP 也可以用。在 PyTorch 中可以使用 torch.nn.utils.clip_grad_norm_來實現。15. 在 BatchNorm 之前關閉 bias在開始 BatchNormalization 層之前關閉 bias 層。對於一個 2-D 卷積層,可以將 bias 關鍵字設置為 False:torch.nn.Conv2d(..., bias=False, ...)。在驗證期間關閉梯度計算,設置:torch.no_grad() 。要再三檢查一下輸入是否歸一化?是否使用了 batch 歸一化?原文連結:https://efficientdl.com/faster-deep-learning-in-pytorch-a-guide/

重磅

AI有道年度技術文章電子版PDF來啦!

掃描下方二維碼,添加 AI有道小助手微信,可申請入群,並獲得2020完整技術文章合集PDF(一定要備註:入群 + 地點 + 學校/公司。例如:入群+上海+復旦。 

長按掃碼,申請入群

(添加人數較多,請耐心等待)

感謝你的分享,點讚,在看三  

相關焦點

  • 讓PyTorch訓練速度更快,你需要掌握這17種方法
    掌握這 17 種方法,用最省力的方式,加速你的 Pytorch 深度學習訓練。近日,Reddit 上一個帖子熱度爆表。主題內容是關於怎樣加速 PyTorch 訓練。原文作者是來自蘇黎世聯邦理工學院的計算機科學碩士生 LORENZ KUHN,文章向我們介紹了在使用 PyTorch 訓練深度模型時最省力、最有效的 17 種方法。
  • 提升PyTorch訓練速度,小哥哥總結了17種方法!
    掌握這 17 種方法,用最省力的方式,加速你的 Pytorch 深度學習訓練。該文所提方法,都是假設你在 GPU 環境下訓練模型。具體內容如下。學習率 schedule 的選擇對模型的收斂速度和泛化能力有很大的影響。Leslie N.
  • 如何提高PyTorch「煉丹」速度?這位小哥總結了17種方法,可直接上手更改的那種
    最近,有一位名叫Lorenz Kuhn的小哥,分享了他在煉丹過程中總結的17種投入最低、效果最好的提升訓練速度的方法,而且基本上都可以直接在PyTorch中進行更改,無需引入額外的庫。不過需要注意的是,這些方法都是假設是在GPU上訓練模型。這一分享在Reddit上得到了600的熱度。
  • PyTorch系列 | 如何加快你的模型訓練速度呢?
    -56d8a4ae7051聲明 | 翻譯是出於交流學習的目的,歡迎轉載,但請保留本文出於,請勿用作商業或者非法用途本文將主要介紹如何採用 cuda 和 pycuda 檢查、初始化 GPU 設備,並讓你的算法跑得更快。
  • 當代研究生應當掌握的5種Pytorch並行訓練方法(單機多卡)
    在打開 b 站 「學習」 之前看著那空著一半的顯卡決定寫點什麼餵飽它們~因此,從 V100-PICE/V100/K80 中各拿出 4 張卡,試驗一下哪種分布式學習庫速度最快!這下終於能把剩下的顯存吃完啦,又是老師的勤奮好學生啦(我真是個小機靈鬼)!
  • PyTorch深度學習模型訓練加速指南2021
    比如說,你正在PyTorch中訓練一個深度學習模型。你能做些什麼讓你的訓練更快結束?大多數情況下,我會專注於可以直接在PyTorch中進行的更改,而不需要引入額外的庫,並且我將假設你正在使用GPU訓練模型。1. 考慮使用另外一種學習率策略你選擇的學習率對收斂速度以及模型的泛化性能有很大的影響。
  • PyTorch多GPU並行訓練方法及問題整理
    , 直接在pycharm或者別的編輯器中,是沒法正常運行的, 因為這個需要在shell的命令行中運行, 如果想要正確執行這段代碼, 假設這段代碼的名字是main.py, 可以使用如下的方法進行(參考1 參考2):python -m torch.distributed.launch main.py注: 這裡如果使用了argparse, 一定要在參數裡面加上
  • 使用PyTorch Lightning自動訓練你的深度神經網絡
    如果你想知道我的原因,看看下面這篇文章:https://medium.com/swlh/why-i-switch-from-keras-to-pytorch-e48922f5846。由於我一直在使用PyTorch,所以我需要犧牲在Keras中只用幾行簡單的行代碼就可以進行訓練的樂趣,而編寫自己的訓練代碼。
  • 使用 PyTorch Lightning 將深度學習管道速度提高 10 倍
    今天,我們知道許多尚未開發的潛在訓練技術和深度學習模型架構都在我們的掌握之中!不幸的是,由於數據的規模和新的深度學習模型架構的規模,其中許多進步對於普通研究人員來說就像多汁蘋果對於沒有梯子的水果採摘者一樣難以獲得。有這麼多卓有成效的模型架構掛在深度學習潛力之樹上,我們應該問自己,「我們如何才能達到它們?」答案很簡單:要達到這些富有成效的架構,我們需要梯子!
  • 高效 PyTorch :如何消除訓練瓶頸
    從史丹福大學、 Udacity、 SalelsForce和Tesla等都採用這個深度學習框架清楚的表明了這一點。然而,每個工具都需要投入時間來最高效地使用和掌握它。在使用 PyTorch 兩年多之後,我決定總結一下我使用這個深度學習庫的經驗。高效 ——(系統或機器)達到最大生產力,而浪費的精力或費用卻最少。
  • 使用Pytorch訓練分類器詳解(附python演練)
    訓練網絡這裡事情開始變得有趣,我們只需要在數據迭代器上循環傳給網絡和優化器輸入就可以。接著這些方法會遞歸地遍歷所有模塊,並將它們的參數和緩衝器轉換為CUDA張量。 記住你也必須在每一個步驟向GPU發送輸入和目標:inputs, labels = inputs.to(device), labels.to(device)為什麼沒有注意到與CPU相比巨大的加速?因為你的網絡非常小。
  • PyTorch 多機多卡訓練:DDP 實戰與技巧
    概覽想要讓你的PyTorch神經網絡在多卡環境上跑得又快又好?那你definitely需要這一篇!No one knows DDP better than I do!– – magic_frog(手動狗頭)本文是DDP系列三篇中的第三篇。
  • 【Pytorch】Pytorch節省內存(顯存)的小技巧
    在用pytorch實現一個tensorflow project的時候遇到了GPU顯存超出 (out of memory) 的問題,不知道有什麼優化方法。訓練 CNN 時,Memory 主要的開銷來自於儲存用於計算 backward 的 activation,一般的 workflow 是這樣的 對於一個長度為 N 的 CNN,需要 O(N) 的內存。這篇論文給出了一個思路,每隔 sqrt(N) 個 node 存一個 activation,中需要的時候再算,這樣顯存就從 O(N) 降到了 O(sqrt(N))。
  • 【他山之石】pytorch常見的坑匯總
    在科研的道路上,更需藉助東風才能更快前行。為此,我們特別搜集整理了一些實用的代碼連結,數據集,軟體,編程技巧等,開闢「他山之石」專欄,助你乘風破浪,一路奮勇向前,敬請關注。好像扯遠了,回歸pytorch,首先讓我比較尷尬的是pytorch並沒有一套屬於自己的數據結構以及數據讀取算法,dataloader個人感覺其實就是類似於tf中的feed,並沒有任何速度以及性能上的提升。
  • 從數據到模型,你可能需要1篇詳實的pytorch踩坑指南
    由於這是一篇guide兼踩坑指南,本文主要針對自己碰到過的問題進行總結,歡迎讀者朋友們將自己遇到過的問題(附上解決方法就更好啦)留言,共同避坑。準備篇1.用好官方文檔對於pytorch還陌生的朋友,入門的好方法之一是直接看官方文檔。從類、函數到具體對象,都有詳盡清晰的介紹,同時提供了諸多示例。這一點個人認為比tf要略勝一籌。
  • PyTorch 1.7發布:支持CUDA 11、Windows分布式訓練
    木易 發自 凹非寺 量子位 報導 | 公眾號 QbitAI自從7月份CUDA 11發布以來,就陸陸續續聽到了網友類似的吐槽:這正說著
  • Pytorch中的分布式神經網絡訓練
    點擊上圖,查看教學大綱隨著深度學習的多項進步,複雜的網絡(例如大型transformer 網絡,更廣更深的Resnet等)已經發展起來,從而需要了更大的內存空間。經常,在訓練這些網絡時,深度學習從業人員需要使用多個GPU來有效地訓練它們。
  • 掌握這波調色訓練的正確方法,你離大師指日可待!
    不過小修認為,除了努力外,方式方法更重要。如果掌握不了正確的訓練方法,即便付出了一萬小時的努力,也可能無功而返。調色不是玄學,不像買雙色球一樣找不到規律,調色的能力是需要訓練的,所以,修圖系特邀知名修圖講師安澤,為大家定製了調色訓練方法課程,掌握調色訓練方法,自我訓練提升調色能力。
  • 聊聊Pytorch中的dataloader
    起初,我最開始單獨訓練一個網絡來完成landmark點回歸任務和分類任務,訓練的數據是txt格式,在訓練之前對數據進行分析,發現分類任務中存在嚴重的數據樣本不均衡的問題,那麼我事先針對性的進行數據採樣均衡操作,重新得到訓練和測試的txt數據和標籤,保證了整個訓練和測試數據的樣本均衡性。
  • 用Pytorch Lightning重構代碼速度更慢,修復後速度倍增
    用了 Lightning 訓練速度反而更慢,你遇到過這種情況嗎?PyTorch Lightning 是一種重構 PyTorch 代碼的工具,它可以抽出代碼中複雜重複的部分,使得 AI 研究可擴展並且可以快速迭代。然而近日一位名為 Florian Ernst 的博主卻發現 PyTorch Lightning 存在一個 bug——讓原本應該加速的訓練變得更慢了。