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

2021-02-20 人工智慧前沿講習
原題 | 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 深度學習訓練。近日,Reddit 上一個帖子熱度爆表。主題內容是關於怎樣加速 PyTorch 訓練。原文作者是來自蘇黎世聯邦理工學院的計算機科學碩士生 LORENZ KUHN,文章向我們介紹了在使用 PyTorch 訓練深度模型時最省力、最有效的 17 種方法。
  • 讓 PyTorch 訓練速度更快,你需要掌握這 17 種方法
    主題內容是關於怎樣加速 PyTorch 訓練。原文作者是來自蘇黎世聯邦理工學院的計算機科學碩士生 LORENZ KUHN,文章向我們介紹了在使用 PyTorch 訓練深度模型時最省力、最有效的 17 種方法。
  • 提升PyTorch訓練速度,小哥哥總結了17種方法!
    掌握這 17 種方法,用最省力的方式,加速你的 Pytorch 深度學習訓練。該文所提方法,都是假設你在 GPU 環境下訓練模型。具體內容如下。學習率 schedule 的選擇對模型的收斂速度和泛化能力有很大的影響。Leslie N.
  • Pytorch 加載預訓練模型之ResNet系列
    Pytorch 加載預訓練模型之ResNet系列參考網址:https://github.com/Cadene/pretrained-models.pytorch
  • PyTorch深度學習模型訓練加速指南2021
    比如說,你正在PyTorch中訓練一個深度學習模型。你能做些什麼讓你的訓練更快結束?大多數情況下,我會專注於可以直接在PyTorch中進行的更改,而不需要引入額外的庫,並且我將假設你正在使用GPU訓練模型。1. 考慮使用另外一種學習率策略你選擇的學習率對收斂速度以及模型的泛化性能有很大的影響。
  • 高效 PyTorch :如何消除訓練瓶頸
    高效的 PyTorch 訓練pipeline是怎樣的呢?是產生準確率最高模型?還是跑得最快?或是容易理解和擴展?還是很容易並行計算?嗯,以上都是!在研究和生產領域, PyTorch都是一個很好用的工具。
  • 如何使用TensorRT對訓練好的PyTorch模型進行加速?
    ,其實就是讓你訓練的模型在測試階段的速度加快,比如你的模型測試一張圖片的速度是50ms,那麼用tensorRT加速的話,可能只需要10ms。當然具體能加速多少也不能保證,反正確實速度能提升不少。但是TensorRT坑爹的地方在於,有些模型操作是不支持的、又或者就算支持但是支持並不完善,對於這些難題,要麼自己寫插件,要麼就只能等待官方的更新了。現在我們訓練深度學習模型主流的框架有tensorflow,pytorch,mxnet,caffe等。
  • TensorRT加速PyTorch模型教程
    一.簡介TensorRT是Nvidia公司出的能加速模型推理的框架,其實就是讓你訓練的模型在測試階段的速度加快,比如你的模型測試一張圖片的速度是50ms,那麼用tensorRT加速的話,可能只需要10ms。當然具體能加速多少也不能保證,反正確實速度能提升不少。
  • TensorRT和PyTorch模型的故事
    一.簡介TensorRT是Nvidia公司出的能加速模型推理的框架,其實就是讓你訓練的模型在測試階段的速度加快,比如你的模型測試一張圖片的速度是50ms,那麼用tensorRT加速的話,可能只需要10ms。當然具體能加速多少也不能保證,反正確實速度能提升不少。
  • 用Pytorch Lightning重構代碼速度更慢,修復後速度倍增
    用了 Lightning 訓練速度反而更慢,你遇到過這種情況嗎?PyTorch Lightning 是一種重構 PyTorch 代碼的工具,它可以抽出代碼中複雜重複的部分,使得 AI 研究可擴展並且可以快速迭代。然而近日一位名為 Florian Ernst 的博主卻發現 PyTorch Lightning 存在一個 bug——讓原本應該加速的訓練變得更慢了。
  • PyTorch 多機多卡訓練:DDP 實戰與技巧
    概覽想要讓你的PyTorch神經網絡在多卡環境上跑得又快又好?那你definitely需要這一篇!No one knows DDP better than I do!– – magic_frog(手動狗頭)本文是DDP系列三篇中的第三篇。
  • 【他山之石】如何支撐上億類別的人臉訓練?顯存均衡的模型並行(PyTorch實現)
    Demo地址:https://github.com/bindog/pytorch-model-parallel地址:http://bindog.github.io/格靈深瞳首席科學家張徳兵:如何進行上億類的人臉識別?
  • 【NLP】Pytorch中文語言模型bert預訓練代碼
    這篇論文做了很多語言模型預訓練的實驗,系統的分析了語言模型預訓練對子任務的效果提升情況。有幾個主要結論:在目標領域的數據集上繼續預訓練(DAPT)可以提升效果;目標領域的語料與RoBERTa的原始預訓練語料越不相關,DAPT效果則提升更明顯。在具體任務的數據集上繼續預訓練(TAPT)可以十分「廉價」地提升效果。
  • TensorRT 加速 PyTorch 模型基本方法
    一.簡介TensorRT是Nvidia公司出的能加速模型推理的框架,其實就是讓你訓練的模型在測試階段的速度加快,比如你的模型測試一張圖片的速度是50ms,那麼用tensorRT加速的話,可能只需要10ms。當然具體能加速多少也不能保證,反正確實速度能提升不少。
  • 【昇騰社區】PyTorch網絡模型移植&訓練指南
    將原始模型及訓練腳本遷移到昇騰AI處理器上之前,可以將原始模型及訓練腳本在CPU上進行訓練,使用dump op方法獲取算子信息,與《PyTorch適配算子清單](#https://gitee.com/ascend/pytorch/blob/2.0.2.tr5/docs/zh/PyTorch%E9%80%82%E9%85%8D%E7%AE%97%E5%AD%90%E6%B8%85%E5%8D%95/PyTorch
  • 使用PyTorch Lightning自動訓練你的深度神經網絡
    基本代碼的比較在我們進入代碼之前,我想讓你看看下面的圖片。下面有2張圖片解釋了pytorch和pytorch lightning在編碼、建模和訓練上的區別。在左邊,你可以看到,pytorch需要更多的代碼行來創建模型和訓練。
  • 大規模圖訓練調優指南
    加快訓練速度對於大規模數據而言,訓練同樣要花很長時間。加快訓練速度也很關鍵。加快訓練速度方面主要在兩個方面:加快數據預處理和提高 GPU 利用率。解決方法也是兩個:增大batch_size,一般來說 GPU 利用率和batch_size成正比;加快數據加載:設置DataLoader的pin_memory=True, 適當增大num_workers(注意不要盲目增大,設置到使用的 CPU 利用率到 90% 左右就可以了,不然反而可能會因為開線程的消耗拖慢訓練速度)。
  • PyTorch多GPU並行訓練方法及問題整理
    os.environ['CUDA_VISIBLE_DEVICES'] = '0,3'但是要注意的是, 這個參數的設定要保證在模型加載到gpu上之前, 我一般都是在程序開始的時候就設定好這個參數, 之後如何將模型加載到多GPU上面呢?
  • 【Pytorch】新手如何入門pytorch?
    上面五步是我自己在學習pytorch的時候積累的經驗, 個人認為很適合入門,也足夠了.1. 關於如何照著example實現簡單的例子, 我的做法是認真看幾遍example的實現代碼.理解透,然後自己從頭寫, 實現相同的模型, 實在卡住了寫不下去可以看一下, 但是絕對不能copy and paste.
  • 【模型訓練】如何優雅地訓練大型模型?
    前陣子微軟開源了DeepSpeed訓練框架,從測試效果來看有10倍的速度提升,而且對內存進行了各種優化,最大可以訓練100B(illion)參數的模型。同時發布了這個框架訓練出的17B模型 Turing-NLG,處於目前壕賽事的頂端。