PyTorch系列 | 如何加快你的模型訓練速度呢?

2021-03-02 人工智慧前沿講習
原題 | Speed Up your Algorithms Part 1 — PyTorch
譯者 | kbsc13("算法猿的成長"公眾號作者)原文 | https://towardsdatascience.com/speed-up-your-algorithms-part-1-pytorch-56d8a4ae7051聲明 | 翻譯是出於交流學習的目的,歡迎轉載,但請保留本文出於,請勿用作商業或者非法用途本文將主要介紹如何採用 cuda 和 pycuda 檢查、初始化 GPU 設備,並讓你的算法跑得更快。
PyTorch 是 torch 的 python 版本,它是 Facebook AI 研究組開發並開源的一個深度學習框架,也是目前非常流行的框架,特別是在研究人員中,短短幾年已經有追上 Tensorflow 的趨勢了。這主要是因為其簡單、動態計算圖的優點。pycuda 是一個 python 第三方庫,用於處理 Nvidia 的 CUDA 並行計算 API 。在 GPU 上存儲 Tensors 和運行模型的方法本文的代碼是用 Jupyter notebook,Github 地址為:https://nbviewer.jupyter.org/github/PuneetGrov3r/MediumPosts/blob/master/SpeedUpYourAlgorithms/1%29%20PyTorch.ipynb
檢查 cuda 是否可用的代碼非常簡單,如下所示:

import torchtorch.cuda.is_available()# True

獲取基本的設備信息,採用 torch.cuda 即可,但如果想得到更詳細的信息,需要採用 pycuda 。

import torchimport pycuda.driver as cudacuda.init()torch.cuda.current_device()cuda.Device(0).name() 

torch.cuda.get_device_name(0) # Get name device with ID '0'# 'Tesla K80'

import pycuda.driver as cudaimport pycuda.autoinit cuda.init() 
class aboutCudaDevices(): def __init__(self): pass
def num_devices(self): """返回 cuda 設備的數量""" return cuda.Device.count()
def devices(self): """獲取所有可用的設備的名稱""" num = cuda.Device.count() print("%d device(s) found:"%num) for i in range(num): print(cuda.Device(i).name(), "(Id: %d)"%i)
def mem_info(self): """獲取所有設備的總內存和可用內存""" available, total = cuda.mem_get_info() print("Available: %.2f GB\nTotal: %.2f GB"%(available/1e9, total/1e9))
def attributes(self, device_id=0): """返回指定 id 的設備的屬性信息""" return cuda.Device(device_id).get_attributes()
def __repr__(self): """輸出設備的數量和其id、內存信息""" num = cuda.Device.count() string = "" string += ("%d device(s) found:\n"%num) for i in range(num): string += ( " %d) %s (Id: %d)\n"%((i+1),cuda.Device(i).name(),i)) string += (" Memory: %.2f GB\n"%(cuda.Device(i).total_memory()/1e9)) return string
aboutCudaDevices()

import torchtorch.cuda.memory_allocated()torch.cuda.memory_cached()

但需要注意的是,上述函數並不會釋放被 tensors 佔用的 GPU 內存,因此並不能增加當前可用的 GPU 內存。

在 GPU 上存儲 Tensors 和運行模型的方法

如果是想存儲變量在 cpu 上,可以按下面代碼所示這麼寫:

a = torch.DoubleTensor([1., 2.])

變量 a 將保持在 cpu 上,並在 cpu 上進行各種運算,如果希望將它轉換到 gpu 上,需要採用 .cuda ,可以有以下兩種實現方法

a = torch.FloatTensor([1., 2.]).cuda()a = torch.cuda.FloatTensor([1., 2.])

這種做法會選擇默認的第一個 GPU,查看方式有下面兩種:

torch.cuda.current_device()
a.get_device()

另外,也可以在 GPU 上運行模型,例子如下所示,簡單使用 nn.Sequential 定義一個模型:

sq = nn.Sequential(         nn.Linear(20, 20),         nn.ReLU(),         nn.Linear(20, 4),         nn.Softmax())

怎麼判斷模型是否在 GPU 上運行呢,可以通過下述方法查看模型的參數是否在 GPU 上來判斷:

# From the discussions here: discuss.pytorch.org/t/how-to-check-if-model-is-on-cuda# 參考 https://discuss.pytorch.org/t/how-to-check-if-model-is-on-cuda/180
next(model.parameters()).is_cuda# True

假設有 3 個 GPU ,我們可以初始化和分配 tensors 到任意一個指定的 GPU 上,代碼如下所示,這裡分配 tensors 到指定 GPU 上,有 3 種方法:

cuda0 = torch.device('cuda:0')cuda1 = torch.device('cuda:1')cuda2 = torch.device('cuda:2')
x = torch.Tensor([1., 2.], device=cuda1)x = torch.Tensor([1., 2.]).to(cuda1)x = torch.Tensor([1., 2.]).cuda(cuda1)
torch.cuda.set_device(2) import osos.environ["CUDA_VISIBLE_DEVICES"] = "0,2"

當你有多個 GPU 的時候,就可以將應用的工作劃分,但這裡存在相互之間交流的問題,不過如果不需要頻繁的交換信息,那麼這個問題就可以忽略。實際上,還有另一個問題,在 PyTorch 中所有 GPU 的運算默認都是異步操作。但在 CPU 和 GPU 或者兩個 GPU 之間的數據複製是需要同步的,當你通過函數 torch.cuda.Stream() 創建自己的流時,你必須注意這個同步問題。

cuda = torch.device('cuda')s = torch.cuda.Stream()  A = torch.empty((100, 100), device=cuda).normal_(0.0, 1.0)with torch.cuda.stream(s):            B = torch.sum(A)

在多模型中,每個 GPU 應用單獨一個模型,並且各自有預處理操作都完成好的一份數據拷貝;每個 GPU 採用切片輸入和模型的拷貝,每個 GPU 將單獨計算結果,並將結果都發送到同一個 GPU 上進行進一步的運算操作。
數據並行的操作要求我們將數據劃分成多份,然後發送給多個 GPU 進行並行的計算。
PyTorch 中實現數據並行的操作可以通過使用 torch.nn.DataParallel。下面是一個簡單的示例。要實現數據並行,第一個方法是採用 nn.parallel 中的幾個函數,分別實現的功能如下所示:複製(Replicate):將模型拷貝到多個 GPU 上;分發(Scatter):將輸入數據根據其第一個維度(通常就是 batch 大小)劃分多份,並傳送到多個 GPU 上;收集(Gather):從多個 GPU 上傳送回來的數據,再次連接回一起;並行的應用(parallel_apply):將第三步得到的分布式的輸入數據應用到第一步中拷貝的多個模型上。

replicas = nn.parallel.replicate(module, device_ids)inputs = nn.parallel.scatter(input, device_ids)outputs = nn.parallel.parallel_apply(replicas, inputs)result = nn.parallel.gather(outputs, output_device)

實際上,還有一個更簡單的也是常用的實現方法,如下所示,只需一行代碼即可:

model = nn.DataParallel(model, device_ids=device_ids)result = model(input)

根據文章 https://medium.com/@iliakarmanov/multi-gpu-rosetta-stone-d4fa96162986 以及 Github:https://github.com/ilkarman/DeepLearningFrameworks 得到的不同框架在採用單個 GPU 和 4 個 GPU 時運算速度的對比結果,如下所示:
從圖中可以看到數據並行操作儘管存在多 GPU 之間交流的問題,但是提升的速度還是很明顯的。而 PyTorch 的運算速度僅次於 Chainer ,但它的數據並行方式非常簡單,一行代碼即可實現。
torch.multiprocessing 是對 Python 的 multiprocessing 模塊的一個封裝,並且百分比兼容原始模塊,也就是可以採用原始模塊中的如 Queue 、Pipe、Array 等方法。並且為了加快速度,還添加了一個新的方法--share_memory_(),它允許數據處於一種特殊的狀態,可以在不需要拷貝的情況下,任何進程都可以直接使用該數據。
通過該方法,可以共享 Tensors 、模型的參數 parameters ,可以在 CPU 或者 GPU 之間共享它們。

import torch.multiprocessing as mpdef train(model):    for data, labels in data_loader:        optimizer.zero_grad()        loss_fn(model(data), labels).backward()        optimizer.step()  model = nn.Sequential(nn.Linear(n_in, n_h1),                      nn.ReLU(),                      nn.Linear(n_h1, n_out))model.share_memory() processes = []for i in range(4):     p = mp.Process(target=train, args=(model,))    p.start()    processes.append(p)for p in processes:     p.join()

https://pytorch.org/docs/stable/distributed.htmlhttps://documen.tician.de/pycuda/https://pytorch.org/docs/stable/notes/cuda.htmlhttps://discuss.pytorch.org/t/how-to-check-if-model-is-on-cudahttps://pytorch.org/tutorials/beginner/blitz/data_parallel_tutorial.htmlhttps://medium.com/@iliakarmanov/multi-gpu-rosetta-stone-d4fa96162986

相關焦點

  • 提升PyTorch訓練速度,小哥哥總結了17種方法!
    掌握這 17 種方法,用最省力的方式,加速你的 Pytorch 深度學習訓練。該文所提方法,都是假設你在 GPU 環境下訓練模型。具體內容如下。學習率 schedule 的選擇對模型的收斂速度和泛化能力有很大的影響。Leslie N.
  • 9個讓PyTorch模型訓練提速的技巧
    不要讓你的神經網絡變成這樣讓我們面對現實吧,你的模型可能還停留在石器時代。我敢打賭你仍然使用32位精度或GASP甚至只在一個GPU上訓練。Lightning是在Pytorch之上的一個封裝,它可以自動訓練,同時讓研究人員完全控制關鍵的模型組件。Lightning 使用最新的最佳實踐,並將你可能出錯的地方最小化。我們為MNIST定義LightningModel並使用Trainer來訓練模型。
  • PyTorch中使用DistributedDataParallel進行多GPU分布式模型訓練
    先進的深度學習模型參數正以指數級速度增長:去年的GPT-2有大約7.5億個參數,今年的GPT-3有1750億個參數。雖然GPT是一個比較極端的例子但是各種SOTA模型正在推動越來越大的模型進入生產應用程式,這裡的最大挑戰是使用GPU卡在合理的時間內完成模型訓練工作的能力。
  • PyTorch 1.4 發布:支持 Java 和分布式模型並行訓練
    1.4 還增加了新的實驗性功能,其中包括基於 RPC 的分布式模型並行訓練以及對 Java 的語言綁定。此外,PyTorch 1.4 是支持 Python 2 的最後一個版本,同時也是支持 C++11 的最後一個版本。因此官方建議從 1.4 開始遷移到 Python 3,並使用 C++14 進行構建,以方便將來從 1.4 過渡到 1.5。
  • 一大波PyTorch圖像分割模型來襲,俄羅斯程式設計師出品新model zoo
    一大波基於PyTorch的圖像分割模型整理好了就等你來用~這個新集合由俄羅斯的程式設計師小哥Pavel Yakubovskiy一手打造,包含四種模型架構和30種預訓練骨幹模型(backbone),官方文檔列舉了四條主要特點:高級API(兩行代碼構建神經網絡)4種模型架構:Unet,Linknet,FPN,PSPNet每個架構有30種可用的編碼器所有編碼器都具有預先訓練的權重
  • onnx實現對pytorch模型推理加速
    3.torch.nn.Module.load_state_dict:使用反序列化狀態字典加載model's參數字典保存加載模型2種方式,在保存模型進行推理時,只需要保存訓練過的模型的學習參數即可,一個常見的PyTorch約定是使用.pt或.pth文件擴展名保存模型。
  • 保護隱私快速訓練,Facebook開源Opacus,用差分隱私訓練PyTorch
    那麼,如何方便地使用差分隱私來訓練機器學習模型呢?近日,Facebook 開源了 Opacus 庫,支持以這種方式訓練 PyTorch 模型。近日,Facebook 開源了一個新型庫 Opacus,它支持使用差分隱私來訓練 PyTorch 模型,擴展性優於目前的 SOTA 方法。
  • 獨家 :教你用Pytorch建立你的第一個文本分類模型!
    Out of Vocabulary words,如何解決變長序列的訓練問題,舉出了具體實例。學習如何使用PyTorch實現文本分類理解文本分類中的關鍵點學習使用壓縮填充方法在我的編程歷程中,我總是求助於最先進的架構。現在得益於深度學習框架,比如說PyTorch,Keras和 TensorFlow,實現先進的架構已經變得更簡單了。這些深度學習框架提供了一種實現複雜模型架構和算法的簡單方式,不需要你掌握大量的專業知識和編程技能。
  • 【Pytorch】Pytorch多機多卡分布式訓練
    官方pytorch(v1.0.10)在分布式上給出的api有這麼幾個比較重要的:1. torch.nn.parallel.DistributedDataParallel :這個從名字上就能看出來與DataParallel相類似,也是一個模型wrapper。這個包是實現多機多卡分布訓練最核心東西,它可以幫助我們在不同機器的多個模型拷貝之間平均梯度。
  • 獨家 | 教你用Pytorch建立你的第一個文本分類模型!
    Out of Vocabulary words,如何解決變長序列的訓練問題,舉出了具體實例。學習如何使用PyTorch實現文本分類理解文本分類中的關鍵點學習使用壓縮填充方法在我的編程歷程中,我總是求助於最先進的架構。現在得益於深度學習框架,比如說PyTorch,Keras和 TensorFlow,實現先進的架構已經變得更簡單了。這些深度學習框架提供了一種實現複雜模型架構和算法的簡單方式,不需要你掌握大量的專業知識和編程技能。
  • PyTorch上也有Keras了,訓練模型告別Debug,只需專注數據和邏輯
    魚羊 發自 凹非寺量子位 報導 | 公眾號 QbitAI在開始一個新的機器學習項目時,難免要重新編寫訓練循環,加載模型,分布式訓練……然後在Debug的深淵裡看著時間譁譁流逝,而自己離項目核心還有十萬八千裡。
  • 一個簡單的更改讓PyTorch讀取表格數據的速度提高20倍
    深度學習:需要速度在訓練深度學習模型時,性能至關重要。 數據集可能非常龐大,而低效的訓練方法意味著迭代速度變慢,超參數優化的時間更少,部署周期更長以及計算成本更高。由於有許多潛在的問題要探索,很難證明花太多時間來進行加速工作是合理的。 但是幸運的是,有一些簡單的加速方法!
  • 【小白學PyTorch】18.TF2構建自定義模型
    模型的構建訪問遍歷存儲(附代碼)小白學PyTorch | 5 torchvision預訓練模型與數據集全覽小白學PyTorch | 4 構建模型三要素與權重初始化小白學PyTorch | 3 淺談Dataset和Dataloader
  • 一行代碼即可調用18款主流模型!PyTorch Hub輕鬆解決論文可復現性
    PyTorch Hub包含了一系列與圖像分類、圖像分割、生成以及轉換相關的預訓練模型庫,例如ResNet、BERT、GPT、VGG、PGAN、MobileNet等經典模型,PyTorch Hub試圖以最傻瓜的方式,提高研究工作的復現性。有多簡單呢?
  • PyTorch常見的12坑
    假設有模型A和模型B,我們需要將A的輸出作為B的輸入,但訓練時我們只訓練模型B.大概可以看出,這個參數和訓練時的歸一化的計算方式有關。因此,我們可以知道該錯誤是由於訓練和測試所用的pytorch版本(0.4.1版本前後的差異)不一致引起的。
  • Facebook發布PyTorch 1.1,開源AI模型優化簡化工具BoTorch & Ax
    項目地址:https://github.com/pytorch/pytorch/releases/tag/v1.1.0官方博客:https://pytorch.org/blog/optimizing-cuda-rnn-with-torchscript/與之前的版本相比,PyTorch 1.1 具備以下特性:提供 TensorBoard 的官方支持
  • 【乾貨】基於pytorch的CNN、LSTM神經網絡模型調參小結
    ,另一個方式是隨機初始化詞向量,兩種方式相互比較的話當時是使用預訓練好的詞向量效果會好很多,但是自己訓練的詞向量並不見得會有很好的效果,因為語料數據可能不足,像已經訓練好的詞向量,像Google News那個詞向量,是業界公認的詞向量,但是由於數量巨大,如果硬體設施(GPU)不行的話,還是不要去嘗試這個了。
  • 9個技巧讓你的PyTorch模型訓練變得飛快!
    **任何使用Pytorch進行深度學習模型研究的人,如研究人員、博士生、學者等,我們在這裡談論的模型可能需要你花費幾天的訓練,甚至是幾周或幾個月。Lightning 使用最新的最佳實踐,並將你可能出錯的地方最小化。我們為MNIST定義LightningModel並使用Trainer來訓練模型。
  • 32分鐘訓練神經機器翻譯,速度提升45倍
    然而如果我們從一開始就考慮降低模型訓練時間,那麼很多概念都能迅速驗證。在 Facebook 開發者的試驗中,他們採用了低精度和大批量等一系列加速訓練方法,並成功地將需要 24 小時訓練的 NMT 降低到 32 分鐘。該項目相關的分布式訓練代碼已開源。
  • Transformers2.0讓你三行代碼調用語言模型,兼容TF2.0和PyTorch
    藉助於更新後的 Transformers 庫,科學家和實踐者可以更方便地在開發同一語言模型的訓練、評估和製作階段選擇不同的框架。那麼更新後的 Transformers 2.0 具有哪些顯著的特徵呢?對 NLP 研究者和實踐者又會帶來哪些方面的改善呢?機器之心進行了整理。