查看显卡信息

1
$ nvidia-smi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Tue Jun  1 15:40:45 2021
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 418.67 Driver Version: 418.67 CUDA Version: 10.1 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 Tesla V100-SXM2... Off | 00000000:00:1B.0 Off | 0 |
| N/A 56C P0 55W / 300W | 8124MiB / 16130MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 Tesla V100-SXM2... Off | 00000000:00:1C.0 Off | 0 |
| N/A 43C P0 51W / 300W | 4252MiB / 16130MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 2 Tesla V100-SXM2... Off | 00000000:00:1D.0 Off | 0 |
| N/A 41C P0 40W / 300W | 11MiB / 16130MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 3 Tesla V100-SXM2... Off | 00000000:00:1E.0 Off | 0 |
| N/A 62C P0 62W / 300W | 1582MiB / 16130MiB | 0% Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 2277 C ...buntu/miniconda3/envs/d2l-en/bin/python 3289MiB |
| 0 127232 C ...buntu/miniconda3/envs/d2l-en/bin/python 1389MiB |
+-----------------------------------------------------------------------------+

计算设备

在 PyTorch 中,CPU 和GPU 可以用torch.device('cpu')torch.device('cuda')表示。 应该注意的是,cpu设备意味着所有物理 CPU 和内存,这意味着 PyTorch 的计算将尝试使用所有 CPU 核心。然而,gpu设备只代表一个卡和相应的显存。如果有多个 GPU,使用torch.device(f'cuda:{i}')来表示第 i 块 GPU(i 从 0 开始)。另外,cuda:0cuda是等价的。

1
2
3
4
import torch
from torch import nn

torch.device('cpu'), torch.cuda.device('cuda'), torch.cuda.device('cuda:1')
1
2
3
(device(type='cpu'),
<torch.cuda.device at 0x7f723468cdc0>,
<torch.cuda.device at 0x7f7234655310>)

查询可用 GPU 的数量:

1
torch.cuda.device_count()
1
2

这两个函数允许在请求的 GPU 不存在的情况下运行代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
def try_gpu(i=0):
"""如果存在,则返回gpu(i),否则返回cpu()。"""
if torch.cuda.device_count() >= i + 1:
return torch.device(f'cuda:{i}')
return torch.device('cpu')

def try_all_gpus():
"""返回所有可用的GPU,如果没有GPU,则返回[cpu(),]。"""
devices = [
torch.device(f'cuda:{i}') for i in range(torch.cuda.device_count())]
return devices if devices else [torch.device('cpu')]

try_gpu(), try_gpu(10), try_all_gpus()
1
2
3
(device(type='cuda', index=0),
device(type='cpu'),
[device(type='cuda', index=0), device(type='cuda', index=1)])

张量与 GPU

查询张量所在的设备:

1
2
x = torch.tensor([1, 2, 3])
x.device
1
device(type='cpu')

无论何时我们要对多个项进行操作,它们都必须在同一个设备上。

存储在 GPU 上

1
2
X = torch.ones(2, 3, device=try_gpu())
X
1
2
tensor([[1., 1., 1.],
[1., 1., 1.]], device='cuda:0')

第二个 GPU 上创建一个随机张量:

1
2
Y = torch.rand(2, 3, device=try_gpu(1))
Y
1
2
tensor([[0.9333, 0.8735, 0.7784],
[0.3453, 0.5509, 0.3475]], device='cuda:1')

复制

要计算X + Y,需要决定在哪里执行这个操作。

1
2
3
Z = X.cuda(1)
print(X)
print(Z)
1
2
3
4
tensor([[1., 1., 1.],
[1., 1., 1.]], device='cuda:0')
tensor([[1., 1., 1.],
[1., 1., 1.]], device='cuda:1')
1
Y + Z
1
2
tensor([[1.9333, 1.8735, 1.7784],
[1.3453, 1.5509, 1.3475]], device='cuda:1')

假设变量Z已经存在于第二个 GPU 上,如果还是调用Z.cuda(1)将返回Z,而不会复制并分配新内存。

1
Z.cuda(1) is Z
1
True

神经网络与 GPU

神经网络模型可以指定设备,如下将模型参数放在 GPU 上:

1
2
3
4
net = nn.Sequential(nn.Linear(3, 1))
net = net.to(device=try_gpu())

net(X)
1
2
tensor([[-0.8412],
[-0.8412]], device='cuda:0', grad_fn=<AddmmBackward>)

确认模型参数存储在同一个 GPU 上:

1
net[0].weight.data.device
1
device(type='cuda', index=0)

总结

  • 我们可以指定用于存储和计算的设备,例如 CPU 或 GPU。默认情况下,数据在主内存中创建,然后使用 CPU 进行计算。
  • 深度学习框架要求计算的所有输入数据都在同一设备上,无论是 CPU 还是 GPU。
  • 不经意地移动数据可能会显著降低性能。一个典型的错误如下:计算 GPU 上每个小批量的损失,并在命令行中将其报告给用户(或将其记录在NumPy ndarray中)时,将触发全局解释器锁,从而使所有 GPU 阻塞。最好是为 GPU 内部的日志分配内存,并且只移动较大的日志。