PyTorch中的CUDA的操作方法
前言
CUDA(Compute Unified Device Architecture)是NVIDIA推出的異構(gòu)計算平臺,PyTorch中有專門的模塊torch.cuda來設(shè)置和運行CUDA相關(guān)操作。本地安裝環(huán)境為Windows10,Python3.7.8和CUDA 11.6,安裝PyTorch最新穩(wěn)定版本1.12.1如下:
pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu116
一.常見CPU和GPU操作命令
1.查看PyTorch版本
print(torch.__version__) 1.12.1+cu116
2.查看GPU設(shè)備是否可用
print(torch.cuda.is_available()) True
3.PyTorch默認使用設(shè)備是CPU
print("default device: {}".format(torch.Tensor([4,5,6]).device)) default device: cpu
4.查看所有可用的cpu設(shè)備的數(shù)量
print("available cpu devices: {}".format(torch.cuda.os.cpu_count())) available cpu devices: 20
這里CPU設(shè)備數(shù)量指的是邏輯處理器的數(shù)量。
5.查看所有可用的gpu設(shè)備的數(shù)量
print("available gpu devices: {}".format(torch.cuda.device_count())) available gpu devices: 1
6.獲取gpu設(shè)備的名稱
print("gpu device name: {}".format(torch.cuda.get_device_name(torch.device("cuda:0")))) gpu device name: NVIDIA GeForce GTX 1080 Ti
7.通過device="cpu:0"指定cpu:0設(shè)備
device = torch.Tensor([1,2,3], device="cpu:0").device print("device type: {}".format(device)) device type: cpu
8.通過torch.device指定cpu:0設(shè)備
cpu1 = torch.device("cpu:0") print("cpu device: {}:{}".format(cpu1.type, cpu1.index)) cpu device: cpu:0
9.使用索引的方式,默認使用CUDA設(shè)備
gpu = torch.device(0) print("gpu device: {}:{}".format(gpu.type, gpu.index)) gpu device: cuda:0
10.通過torch.device("cuda:0)指定cuda:0設(shè)備
gpu = torch.device("cuda:0") print("gpu device: {}:{}".format(gpu.type, gpu.index)) gpu device: cuda:0
二.CPU和GPU設(shè)備上的Tensor
默認情況下創(chuàng)建Tensor是在CPU設(shè)備上的,但是可以通過copy_、to、cuda等方法將CPU設(shè)備中的Tensor轉(zhuǎn)移到GPU設(shè)備上。當(dāng)然也是可以直接在GPU設(shè)備上創(chuàng)建Tensor的。torch.tensor和torch.Tensor的區(qū)別是,torch.tensor可以通過device指定gpu設(shè)備,而torch.Tensor只能在cpu上創(chuàng)建,否則報錯。
1.Tensor從CPU拷貝到GPU上
# 默認創(chuàng)建的tensor是在cpu上創(chuàng)建的 cpu_tensor = torch.Tensor([[1,4,7],[3,6,9],[2,5,8]]) print(cpu_tensor.device) # 通過to方法將cpu_tensor拷貝到gpu上 gpu_tensor1 = cpu_tensor.to(torch.device("cuda:0")) print(gpu_tensor1.device) # 通過cuda方法將cpu_tensor拷貝到gpu上 gpu_tensor2 = cpu_tensor.cuda(torch.device("cuda:0")) print(gpu_tensor2.device) # 將gpu_tensor2拷貝到cpu上 gpu_tensor3 = cpu_tensor.copy_(gpu_tensor2) print(gpu_tensor3.device) print(gpu_tensor3)
輸出結(jié)果如下:
cpu
cuda:0
cuda:0
cpu
tensor([[1., 4., 7.],
[3., 6., 9.],
[2., 5., 8.]])
主要說明下這個copy_()方法,實現(xiàn)如下:
def copy_(self, src, non_blocking=False): ...... return _te.Tensor(*(), **{})
就是從src中拷貝元素到self的tensor中,然后返回self。以gpu_tensor3 = cpu_tensor.copy_(gpu_tensor2)
為例,就是把gpu中的gpu_tensor2拷貝到cpu中的cpu_tensor中。
2.直接在GPU上創(chuàng)建Tensor
gpu_tensor1 = torch.tensor([[2,5,8],[1,4,7],[3,6,9]], device=torch.device("cuda:0")) print(gpu_tensor1.device) # 在gpu設(shè)備上創(chuàng)建隨機數(shù)tensor print(torch.rand((3,4), device=torch.device("cuda:0"))) # 在gpu設(shè)備上創(chuàng)建0值tensor print(torch.zeros((2,5), device=torch.device("cuda:0")))
輸出結(jié)果,如下:
cuda:0
tensor([[0.7061, 0.2161, 0.8219, 0.3354],
[0.1697, 0.1730, 0.1400, 0.2825],
[0.1771, 0.0473, 0.8411, 0.2318]], device='cuda:0')
tensor([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]], device='cuda:0')
3.CUDA Streams
Steam是CUDA命令線性執(zhí)行的抽象形式,分配給設(shè)備的CUDA命令按照入隊序列的順序執(zhí)行。每個設(shè)備都有一個默認的Steam,也可以通過torch.cuda.Stream()創(chuàng)建新的Stream。如果不同Stream中的命令交互執(zhí)行,那么就不能保證命令絕對按順序執(zhí)行。下面的這個例子不同的Stream就可能會產(chǎn)生錯誤。
cuda = torch.device("cuda") # 創(chuàng)建默認的stream,A就是使用的默認stream s = torch.cuda.Stream() A = torch.randn((1,10), device=cuda) for i in range(100): # 在新的stream上對默認的stream上創(chuàng)建的tensor進行求和 with torch.cuda.stream(s): # 存在的問題是:torch.sum()可能會在torch.randn()之前執(zhí)行 B = torch.sum(A) print(B)
這個例子存在的問題是torch.sum()可能會在torch.randn()之前就執(zhí)行。為了保證Stream中的命令絕對按順序執(zhí)行,接下來使用Synchronize同步方法解決上面例子的問題:
cuda = torch.device("cuda") s = torch.cuda.Stream() A = torch.randn((1,10), device=cuda) default_stream = torch.cuda.current_stream() print("Default Stream: {}".format(default_stream)) # 等待創(chuàng)建A的stream執(zhí)行完畢 torch.cuda.Stream.synchronize(default_stream) for i in range(100): # 在新的stream上對默認的stream上創(chuàng)建的tensor進行求和 with torch.cuda.stream(s): print("current stream: {}".format(torch.cuda.current_stream())) B = torch.sum(A) print(B)
解決問題的思路就是通過torch.cuda.Stream.synchronize(default_stream)
等待創(chuàng)建A的stream執(zhí)行完畢,然后再執(zhí)行新的Stream中的指令。
除此之外,使用memory_cached方法獲取緩存內(nèi)存的大小,使用max_memory_cached方法獲取最大緩存內(nèi)存的大小,使用max_memory_allocated方法獲取最大分配內(nèi)存的大小??梢允褂胑mpty_cache方法釋放無用的緩存內(nèi)存。
三.固定緩沖區(qū)
緩存就是當(dāng)計算機內(nèi)存不足的時候,就會把內(nèi)存中的數(shù)據(jù)存儲到硬盤上。固定緩沖區(qū)就是說常駐內(nèi)存,不能把這部分?jǐn)?shù)據(jù)緩存到硬盤上??梢灾苯邮褂胮in_memory方法或在Tensor上直接調(diào)用pin_memory方法將Tensor復(fù)制到固定緩沖區(qū)。為什么要做固定緩沖區(qū)呢?目的只有一個,就是把CPU上的固定緩沖區(qū)拷貝到GPU上時速度快。Tensor上的is_pinned方法可以查看該Tensor是否加載到固定緩沖區(qū)中。
from torch.utils.data._utils.pin_memory import pin_memory x = torch.Tensor([[1,2,4], [5, 7, 9], [3, 7, 10]]) # 通過pin_memory()方法將x復(fù)制到固定緩沖區(qū) y = pin_memory(x) # 在tensor上直接調(diào)用pin_memory()方法將tensor復(fù)制到固定緩沖區(qū) z = x.pin_memory() # id()方法返回tensor的內(nèi)存地址,pin_memory()返回tensor對象的拷貝,因此內(nèi)存地址是不同的 print("id: {}".format(id(x))) print("id: {}".format(id(y))) print("id: {}".format(id(z))) # 當(dāng)tensor放入固定緩沖區(qū)后,就可以異步將數(shù)據(jù)復(fù)制到gpu設(shè)備上了 a = z.cuda(non_blocking=True) print(a) print("is_pinned: {}/{}".format(x.is_pinned(), z.is_pinned()))
輸出結(jié)果如下所示:
id: 1605289350472
id: 1605969660408
id: 1605969660248
tensor([[ 1., 2., 4.],
[ 5., 7., 9.],
[ 3., 7., 10.]], device='cuda:0')
is_pinned: False/True
說明:通過id()查看對象的內(nèi)存地址。
四.自動設(shè)備感知
1.適配CPU和GPU設(shè)備
自動設(shè)備感知本質(zhì)上就是有GPU時就使用GPU,沒有GPU時就使用CPU,即一套代碼適配CPU和GPU設(shè)備。GPU是否存在是通過torch.cuda.is_available()判斷的。
常見的寫法如下:
device = torch.device("cpu") if torch.cuda.is_available(): device = torch.device("cuda") a = torch.tensor([1,2,3], device=device) print(a)
輸出結(jié)果如下所示:
tensor([1, 2, 3], device='cuda:0')
2.模型遷移到GPU設(shè)備
在Module對象上調(diào)用to()方法可以把模型也遷移到GPU設(shè)備上,如下所示:
class LinearRegression(torch.nn.Module): def __init__(self): super(LinearRegression, self).__init__() self.linear = torch.nn.Linear(1, 1) def forward(self, x): return self.linear(x) regression = LinearRegression().to(device=device) for param in regression.parameters(): print(param)
從上述輸出參數(shù)中可以看到param都是device='cuda:0’上的tensor,所以可以說模型通過to()遷移到GPU設(shè)備上了。
到此這篇關(guān)于PyTorch中的CUDA的操作方法的文章就介紹到這了,更多相關(guān)PyTorch CUDA操作內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- python?windows安裝cuda+cudnn+pytorch教程
- 顯卡驅(qū)動CUDA?和?pytorch?CUDA?之間的區(qū)別
- pytorch?cuda安裝報錯的解決方法
- PyTorch?device與cuda.device用法介紹
- 將pytorch的網(wǎng)絡(luò)等轉(zhuǎn)移到cuda
- pytorch 如何用cuda處理數(shù)據(jù)
- pytorch中.to(device) 和.cuda()的區(qū)別說明
- PyTorch CUDA環(huán)境配置及安裝的步驟(圖文教程)
- Linux安裝Pytorch1.8GPU(CUDA11.1)的實現(xiàn)
- 詳解win10下pytorch-gpu安裝以及CUDA詳細安裝過程
- Pytorch使用CUDA流(CUDA?stream)的實現(xiàn)
相關(guān)文章
tkinter如何實現(xiàn)label超鏈接調(diào)用瀏覽器打開網(wǎng)址
這篇文章主要介紹了tkinter如何實現(xiàn)label超鏈接調(diào)用瀏覽器打開網(wǎng)址問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01Appium+Python自動化環(huán)境搭建實例教程
這篇文章主要介紹了Appium+Python自動化環(huán)境搭建實例教程,本文通過實例代碼圖文相結(jié)合給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-08-08Python Selenium 之?dāng)?shù)據(jù)驅(qū)動測試的實現(xiàn)
這篇文章主要介紹了Python Selenium 之?dāng)?shù)據(jù)驅(qū)動測試的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08python實現(xiàn)識別手寫數(shù)字 python圖像識別算法
這篇文章主要為大家詳細介紹了python實現(xiàn)識別手寫數(shù)字,python圖像識別算法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-01-01