
CDA數據分析師 出品
相信大家在做一些算法經常會被龐大的數據量所造成的超多計算量需要的時間而折磨的痛苦不已,接下來我們圍繞四個方法來幫助大家加快一下Python的計算時間,減少大家在算法上的等待時間。下面為大家講述有關PyTorch的內容。
在PyTorch模塊中,我將展示如何使用torch和檢查、初始化GPU設備pycuda,以及如何使算法更快。
PyTorch是建立在torch的機器學習庫。它得到了Facebook AI研究小組的支持。在最近開發(fā)之后,由于它的簡單性,動態(tài)圖形以及它本質上是Python,它在被開發(fā)出來之后變得非常流行。它的速度仍然沒有落后,在很多情況下可以說是表現的非常好的。
pycuda允許你從python訪問Nvidia的CUDA并行計算API。
要檢查是否有cuda可用的設備Torch,可以簡單地運行一下下面的代碼:
import torch torch.cuda.is_available() # True
要獲取設備的基本信息,可以使用torch.cuda。但是,要獲取有關設備的更多信息,可以使用pycuda,這是一個圍繞CUDA庫開發(fā)的python包裝器。你可以使用:
import torch import pycuda.driver as cuda cuda.init() ##獲取默認設備的Id torch.cuda.current_device() # 0 cuda.Device(0).name() # '0'是你的GPU的id # Tesla K80
或者你可以這么用:
torch.cuda.get_device_name(0)#獲取ID為'0'的名稱設備 #'Tesla K80'
我編寫了一個簡單的類來獲取有關cuda兼容GPU的信息:
#一個簡單的類來了解你的cuda設備 import pycuda.driver as cuda import pycuda.autoinit #必須使用它的功能 cuda.init() # 需要使用它的功能 class aboutCudaDevices(): def __init__(self): pass def num_devices(self): """返回連接的設備數量.""" 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的屬性 = device_id""" return cuda.Device(device_id).get_attributes() def __repr__(self): """類表示為連接到它們的設備的數量.""" 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 # 你可以通過輸入它的名字來打印輸出(__repr__): aboutCudaDevices() # 1 設備(年代): # 1) Tesla K80 (Id: 0) # Memory: 12.00 GB
要獲取當前的內存使用情況,你可以使用pyTorch的函數:
import torch #返回當前的GPU內存使用 # 一個給定設備的容量(以字節(jié)為單位) torch.cuda.memory_allocated() #函數管理的當前的GPU內存 #以字節(jié)為給定設備緩存的分配器 torch.cuda.memory_cached()
在運行應用程序后,可以使用一個簡單的命令來清除緩存:
# 釋放緩存分配器當前持有的所有為占用的緩存內存 # 以便這些內存可以在其他GPU應用程序中可以使用 # 并且可以在NVIDIA-SMI中可以進行查看 torch.cuda.empty_cache()
但是,使用這個命令不會通過張量釋放占用的GPU內存,因此它無法增加可用于PyTorch的GPU內存量。
這些內存方法僅適用于GPU。所以這才是真正需要它的地方。
使用.cuda函數。
如果你想要在CPU上存儲一些內容,可以簡單地編寫代碼:
a = torch.DoubleTensor([1., 2.])
這個向量是存儲在CPU上的,你對它執(zhí)行的任何操作都是在CPU上執(zhí)行完成的。而要將其轉移到GPU上,你只需要執(zhí)行以下操作.cuda:
a = torch.FloatTensor([1., 2.]).cuda()
或者,
a = torch.cuda.FloatTensor([1., 2.])
這將為它選擇默認設備,該默認設備可通過以下命令查看:
torch.cuda.current_device() #0
或者,你也可以執(zhí)行以下操作:
a.get_device() #0
你也可以將一個模型發(fā)送到GPU設備。例如,考慮一個簡單的模塊nn.Sequential:
sq = nn.Sequential( nn.Linear(20,20), nn.ReLU(), nn.Linear( 20,4 ),nn.Softmax() )
要將其發(fā)送到GPU設備,只需執(zhí)行以下操作:
model = sq.cuda()
你可以檢查它是否在GPU設備上,為此,你必須檢查它的參數是否在GPU設備上,例如:
#可以在這里進行討論: discuss.pytorch.org/t/how-to-check-if-model-is-on-cuda next(model.parameters()).is_cuda # True
你可以為當前應用/存儲選擇一個GPU,該GPU可以與你上一個應用/存儲選擇的GPU不同。
正如在第(2)部分中已經看到的那樣,我們可以獲得所有與cuda兼容的設備及其Id使用pycuda的情況,在此我們就不再贅述了。
考慮到你有3個cuda兼容的設備,你可以初始化和分配tensors到一個特定的設備,就像這樣。
cuda0 = torch.device('cuda:0') cuda1 = torch.device('cuda:1') cuda2 = torch.device('cuda:2') # 如果你只使用 'cuda' , 張量/型號將會被發(fā)送到默認(當前)設備。(默認值= 0) 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) # 設備Id為'2'的地方 # 如果你只想使用3個GPU中的2個,那么你必須設置環(huán)境變量CUDA_VISIBLE_DEVICES 等于"0,2",如果你只想使用第一個和第三個GPU的話 #現在如果你想要檢查有多少個GPU時,它將顯示兩個(0,1) import os os.environ["CUDA_VISIBLE_DEVICES"] = "0,2"
當你對這些Tensors 進行任何操作時,無論選擇什么設備,都可以執(zhí)行該操作,結果會和Tensor保存在同一個設備上。
x = torch.Tensor([1., 2.]).to(cuda2) y = torch.Tensor([3., 4.]).to(cuda2) # 這個Tensor(張量)只會保存在'cuda2' 中 z = x + y
如果你有多個GPU,則可以在其中劃分應用程序的工作,但是他們之間的通信會帶來開銷。但是,如果你不需要過多的進行傳遞信息,那你可以嘗試一下。
實際上還有一個問題。在PyTorch中的所有GPU操作中,默認情況下都是異步的。盡管在CPU和GPU或兩個GPU之間復制數據時確實進行了必要的同步,但是,如果你在命令torch.cuda.Stream()的幫助下創(chuàng)建自己的數據流,那么你講不得不處理指令的同步
舉一個PyTorch文檔中的例子,這是不正確的:
cuda = torch.device('cuda') s = torch.cuda.Stream() # 創(chuàng)建一個新的數據流. A = torch.empty((100, 100), device=cuda).normal_(0.0, 1.0) with torch.cuda.stream(s): # 因為 sum() 可能會在normal_()結束之前開始執(zhí)行! B = torch.sum(A)
如果你想充分利用多個GPU,那么你可以:
在數據并行性中,我們將數據(從數據生成器中獲得的一個批次的數據)分割為較小的小型批次的數據,然后將其發(fā)送到多個GPU進行并行計算。
在PyTorch中,數據并行中是使用torch.nn.DataParallel實現的
我們將看到一個簡單的例子來了解實際情況。為此,我們將必須使用nn.parallel的某些功能:
#將模塊復制到設備id中的設備 replicas = nn.parallel.replicate(module, device_ids) #將輸入分配到設備id中的設備 inputs = nn.parallel.scatter(input, device_ids) #將模型應用于相應的輸入 outputs = nn.parallel.parallel_apply(replicas, inputs) #收集所有設備的結果到output_device result = nn.parallel.gather(outputs, output_device)
或者,只需要簡單地:
model = nn.DataParallel(model, device_ids=device_ids) result = model(input)
訓練集數據+Val w/數據加載器+SSD中對真實數據的數據擴充
方式1*V100/CUDA 9/CuDNN 74*V100/CUDA 9/CuDNN 7Pytorch27分鐘10分鐘Keras(TF)38分鐘18分鐘Tensorflow33分鐘22分鐘Chainer29分鐘8分鐘MXNet(Gluon)29分鐘10分鐘
訓練集W/在內存中的綜合數據
方式1*V100/CUDA 9/CuDnn 74*V100/CUDA 9 / CuDNN 7Pytorch25分鐘8分鐘Keras(TF)36分鐘15分鐘Tensorflow25分鐘14分鐘Chainer27分鐘7分鐘MxNet(Gluon)28分鐘8分鐘
現在,你可以清楚的看到,即使必須在開始和結束時與主設備進行通信,并行處理也絕對是有幫助的。并且僅在多GPU情況下,PyTorch比所有結果提供結果的時間更快僅僅略低于Chainer。Pytorch只需要通過對DataParallel的一次調用,就會使其變得簡單。
torch.multiprocessing是Python multiprocessing模塊的包裝,其API與原始模塊100%兼容。因此,你可以在此處使用Python的多處理模塊中的Queue',Pipe',Array'等。此外,為了使其更快,他們添加了一個方法,share_memory_()該方法允許數據進入一個狀態(tài),任何進程都可以直接使用它,因此將該數據作為參數傳遞給不同的進程將不會復制該數據。
你可以共享Tensors,模型的parameters,也可以根據需要在CPU或GPU上共享它們。
來自Pytorch的警告:(關于GPU上的共享) CUDA API要求導出到其他進程的分配只要在被其他進程使用時就保持有效。你應該小心并確保你共享的CUDA Tensors在必要時不會超出范圍。這對于共享模型參數應該不是問題,但是傳遞其他類型的數據時應格外小心。請注意,此限制不適用于共享CPU內存。
你可以在此處的“池和進程”部分中使用上面的方法,并且要獲得更快的速度,可以使用share_memory_()方法Tensor在所有進程之間共享(例如)而不被復制。
# import torch.multiprocessing as mp def 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() # 需要 'fork' 方法工作 processes = [] for i in range(4): # No. 的過程 p = mp.Process(target=train, args=(model,)) p.start() processes.append(p) for p in processes: p.join()
下一期我們繼續(xù)看加快Python計算的另一種方法——Numba~
數據分析咨詢請掃描二維碼
若不方便掃碼,搜微信號:CDAshujufenxi
SQL Server 中 CONVERT 函數的日期轉換:從基礎用法到實戰(zhàn)優(yōu)化 在 SQL Server 的數據處理中,日期格式轉換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關聯查詢效率:打破 “拆分必慢” 的認知誤區(qū) 在 MySQL 數據庫管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數據分析師:表結構數據 “獲取 - 加工 - 使用” 全流程的賦能者 表結構數據(如數據庫表、Excel 表、CSV 文件)是企業(yè)數字 ...
2025-09-18DSGE 模型中的 Et:理性預期算子的內涵、作用與應用解析 動態(tài)隨機一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數據分析師:解鎖表結構數據特征價值的專業(yè)核心 表結構數據(以 “行 - 列” 規(guī)范存儲的結構化數據,如數據庫表、Excel 表、 ...
2025-09-17Excel 導入數據含缺失值?詳解 dropna 函數的功能與實戰(zhàn)應用 在用 Python(如 pandas 庫)處理 Excel 數據時,“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗與 t 檢驗:差異、適用場景與實踐應用 在數據分析與統(tǒng)計學領域,假設檢驗是驗證研究假設、判斷數據差異是否 “ ...
2025-09-16CDA 數據分析師:掌控表格結構數據全功能周期的專業(yè)操盤手 表格結構數據(以 “行 - 列” 存儲的結構化數據,如 Excel 表、數據 ...
2025-09-16MySQL 執(zhí)行計劃中 rows 數量的準確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調優(yōu)中,EXPLAIN執(zhí)行計劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對象的 text 與 content:區(qū)別、場景與實踐指南 在 Python 進行 HTTP 網絡請求開發(fā)時(如使用requests ...
2025-09-15CDA 數據分析師:激活表格結構數據價值的核心操盤手 表格結構數據(如 Excel 表格、數據庫表)是企業(yè)最基礎、最核心的數據形態(tài) ...
2025-09-15Python HTTP 請求工具對比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請求(如接口調用、數據爬取 ...
2025-09-12解決 pd.read_csv 讀取長浮點數據的科學計數法問題 為幫助 Python 數據從業(yè)者解決pd.read_csv讀取長浮點數據時的科學計數法問題 ...
2025-09-12CDA 數據分析師:業(yè)務數據分析步驟的落地者與價值優(yōu)化者 業(yè)務數據分析是企業(yè)解決日常運營問題、提升執(zhí)行效率的核心手段,其價值 ...
2025-09-12用 SQL 驗證業(yè)務邏輯:從規(guī)則拆解到數據把關的實戰(zhàn)指南 在業(yè)務系統(tǒng)落地過程中,“業(yè)務邏輯” 是連接 “需求設計” 與 “用戶體驗 ...
2025-09-11塔吉特百貨孕婦營銷案例:數據驅動下的精準零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當下,精準營銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數據分析師與戰(zhàn)略 / 業(yè)務數據分析:概念辨析與協(xié)同價值 在數據驅動決策的體系中,“戰(zhàn)略數據分析”“業(yè)務數據分析” 是企業(yè) ...
2025-09-11Excel 數據聚類分析:從操作實踐到業(yè)務價值挖掘 在數據分析場景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數據中挖 ...
2025-09-10統(tǒng)計模型的核心目的:從數據解讀到決策支撐的價值導向 統(tǒng)計模型作為數據分析的核心工具,并非簡單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10