动手学深度学习——PyTorch 基础:使用 GPU 详解
一、前言
前面学习 PyTorch 时,我们已经逐步接触了很多基础内容,比如:
-
模型构造
-
参数管理
-
自定义层
-
读写文件
-
前向传播和训练流程
但当模型开始稍微复杂一点、数据量稍微大一点之后,很快就会遇到一个现实问题:
为什么训练这么慢?
CPU 跑一轮都要很久,有没有办法加速?
这时候,GPU 就登场了。
在深度学习中,GPU 几乎是最重要的计算设备之一。
因为神经网络训练里有大量矩阵运算,而这正是 GPU 特别擅长的事情。
所以“使用 GPU”这一节,本质上要解决的就是:
如何让 PyTorch 中的张量和模型在 GPU 上运行,从而加快深度学习训练。
这一节非常重要,因为如果不会正确使用 GPU,后面很多稍大一点的实验都会非常痛苦。
二、为什么深度学习要用 GPU
1. 神经网络本质上包含大量矩阵计算
比如:
-
矩阵乘法
-
卷积计算
-
批量样本并行处理
这些运算量都很大。
2. CPU 更擅长通用逻辑控制
CPU 很适合:
-
分支判断
-
程序流程控制
-
各种通用任务
但面对超大规模并行数值运算时,效率通常不如 GPU。
3. GPU 更擅长并行计算
GPU 内部有大量计算核心,非常适合处理:
-
大规模矩阵乘法
-
张量计算
-
同类运算的批量并行
而神经网络训练恰好大量依赖这种计算。
所以可以简单理解为:
CPU 更像“全能型选手”,
GPU 更像“矩阵运算专家”。
三、GPU 在深度学习里到底加速了什么
很多人会觉得 GPU 好像是“让整个程序都快了”,其实不完全是。
GPU 主要加速的是:
-
张量运算
-
神经网络前向传播
-
反向传播中的梯度计算
-
参数更新涉及的大规模计算
也就是说:
GPU 加速的是数值密集型计算部分。
像:
-
文件读取
-
Python 控制逻辑
-
数据预处理中的部分操作
这些并不一定主要由 GPU 加速。
所以使用 GPU 的核心,不是“整个电脑都更快”,而是:
模型训练中最耗时的张量计算变快了。
四、PyTorch 中如何查看是否有 GPU
在 PyTorch 中,最常见的检查方法是:
import torch
print(torch.cuda.is_available())
如果输出是:
-
True:说明当前环境可以使用 CUDA GPU -
False:说明当前环境暂时不能使用 GPU
这通常是第一步先确认的内容。
五、什么是 CUDA
你在 PyTorch 里使用 GPU 时,经常会看到一个词:
cuda
这里的 CUDA 可以简单理解为:
NVIDIA 提供的 GPU 并行计算平台和接口体系。
在 PyTorch 语境下,大家常常把“使用 NVIDIA GPU”直接说成“用 CUDA”。
例如:
-
torch.device('cuda') -
x.cuda()
这些其实都在表示:
把数据或模型放到 NVIDIA GPU 上。
六、如何查看有几块 GPU
如果你的设备不止一张 GPU,可以这样查看:
import torch
print(torch.cuda.device_count())
它会返回当前可用 GPU 的数量。
例如:
-
返回
0:没有可用 GPU -
返回
1:有一块 GPU -
返回
2:有两块 GPU
七、如何查看某块 GPU 的名字
例如查看第 0 块 GPU:
import torch
print(torch.cuda.get_device_name(0))
如果你的电脑装有 NVIDIA 显卡,通常会看到类似:
-
NVIDIA GeForce RTX 4060 -
NVIDIA GeForce RTX 5060 Laptop GPU
这有助于确认当前到底用的是哪块显卡。
八、PyTorch 中设备 device 是什么
在 PyTorch 里,张量和模型并不只是“有数值”,它们还属于某个设备。
常见设备有两种:
-
cpu -
cuda
例如:
import torch
x = torch.tensor([1, 2, 3])
print(x.device)
默认通常会显示:
cpu
也就是说,这个张量默认是在 CPU 上。
所以:
PyTorch 中的张量和模型,都是有设备归属的。
这点特别重要,因为后面很多报错都和“设备不一致”有关。
九、如何创建一个 GPU 设备对象
在 PyTorch 中,通常这样写:
device = torch.device('cuda')
如果想明确指定第 0 块 GPU,可以写:
device = torch.device('cuda:0')
如果指定第 1 块 GPU:
device = torch.device('cuda:1')
当然,如果没有 GPU,也可以写:
device = torch.device('cpu')
所以 device 本质上就是在告诉 PyTorch:
后面的张量和模型应该放在哪个设备上。
十、如何把张量放到 GPU 上
最常见的方式是使用:
x = x.to(device)
例如:
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
x = torch.tensor([1.0, 2.0, 3.0])
x = x.to(device)
print(x)
print(x.device)
如果有 GPU,输出中会显示它在 cuda:0 上。
十一、除了 .to(device) 还有别的方式吗
有。
例如也可以直接用:
x = x.cuda()
这表示把张量移到默认 GPU 上。
不过更推荐的写法还是:
x = x.to(device)
因为这种写法更通用:
-
CPU 能用
-
GPU 能用
-
更方便切换设备
-
代码更统一
所以在实际项目里,.to(device) 是最常见的风格。
十二、如何直接在 GPU 上创建张量
除了先在 CPU 创建再搬过去,也可以直接指定设备创建:
import torch
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
x = torch.tensor([1.0, 2.0, 3.0], device=device)
print(x.device)
或者:
X = torch.rand(2, 3, device=device)
这表示新建张量时就直接放在目标设备上。
十三、如何把模型放到 GPU 上
这一步和张量完全类似:
net = net.to(device)
例如:
import torch
from torch import nn
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
net = nn.Sequential(
nn.Linear(10, 20),
nn.ReLU(),
nn.Linear(20, 1)
)
net = net.to(device)
这样模型内部参数就都会被移动到 GPU 上。
十四、为什么模型和数据必须在同一设备上
这是最关键的一个原则:
模型在哪个设备上,输入数据也必须在同一设备上。
例如:
-
模型在 GPU
-
输入张量在 CPU
这时做前向传播通常就会报错。
因为 PyTorch 不允许跨设备直接做运算。
例如下面这种写法就有问题:
net = net.to('cuda')
X = torch.rand(2, 10) # 默认在 CPU
Y = net(X) # 会报错
原因就是:
-
net在 GPU -
X在 CPU
设备不一致。
所以正确做法是:
X = X.to(device)
Y = net(X)
十五、训练时应该怎么使用 GPU
在训练循环中,通常至少要保证三样东西在同一设备上:
-
模型
-
输入数据
X -
标签
y
标准写法一般是:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
net = net.to(device)
for X, y in data_iter:
X = X.to(device)
y = y.to(device)
pred = net(X)
loss = loss_fn(pred, y)
这样设备才一致。
十六、一个常见训练模板
下面给你一个适合 CSDN 的基础训练模板:
import torch
from torch import nn
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
# 1. 定义模型
net = nn.Sequential(
nn.Linear(10, 32),
nn.ReLU(),
nn.Linear(32, 1)
).to(device)
# 2. 构造数据
X = torch.rand(16, 10).to(device)
y = torch.rand(16, 1).to(device)
# 3. 定义损失函数和优化器
loss_fn = nn.MSELoss()
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)
# 4. 前向传播
pred = net(X)
loss = loss_fn(pred, y)
# 5. 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
print("loss =", loss.item())
print("模型所在设备:", next(net.parameters()).device)
print("输入数据所在设备:", X.device)
这段代码已经把最核心的 GPU 使用流程串起来了。
十七、如何查看模型参数在哪个设备上
可以这样写:
print(next(net.parameters()).device)
这里的意思是:
-
取出模型中的第一个参数
-
查看它所在设备
如果输出是:
cuda:0
就说明模型参数已经在 GPU 上。
十八、如何把 GPU 上的张量拿回 CPU
这一步很常见,尤其是在:
-
打印结果
-
转成 NumPy
-
可视化
-
保存到某些不支持 GPU 张量的库
这时通常要先搬回 CPU:
x_cpu = x.cpu()
或者:
x_cpu = x.to('cpu')
例如:
x = torch.rand(3, device=device)
print(x.cpu())
十九、为什么 .numpy() 前常常要先 .cpu()
因为 NumPy 只能处理 CPU 内存中的数组,不能直接处理 GPU 张量。
所以如果一个张量在 GPU 上,通常需要这样写:
x_numpy = x.cpu().numpy()
如果还带梯度,有时会进一步写成:
x_numpy = x.detach().cpu().numpy()
这里:
-
detach():从计算图中分离 -
cpu():搬回 CPU -
numpy():转成 NumPy 数组
这是后面做可视化时特别常见的操作。
二十、多个 GPU 怎么办
如果只有一块 GPU,那么前面的内容已经够用了。
如果有多块 GPU,可以指定某一块:
device = torch.device('cuda:1')
这表示使用第 1 号 GPU。
在更复杂的多 GPU 并行训练里,还会涉及:
-
DataParallel -
DistributedDataParallel
但在基础阶段,先掌握单 GPU 的使用方式最重要。
二十一、为什么有时用了 GPU 还是不快
这是很多初学者容易困惑的问题。
即使把模型放到 GPU,上手后也会发现:
有时并没有想象中那么快。
常见原因包括:
1. 模型太小
如果模型很小,GPU 并行能力发挥不出来,反而数据搬运开销明显。
2. batch size 太小
每次送进去的数据太少,GPU 吃不饱。
3. 数据加载成为瓶颈
训练慢不一定卡在模型,有时卡在数据读取。
4. CPU 和 GPU 频繁搬运数据
设备切换太多也会拖慢速度。
5. 本身没有真正用到 GPU
比如模型在 GPU,但数据还在 CPU,或者根本没正确迁移。
所以“用了 GPU”不等于“一定特别快”,还要看:
-
模型规模
-
数据规模
-
batch size
-
数据加载效率
二十二、一个实用的设备选择写法
在很多项目里,你都会看到这种写法:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
它的好处是:
-
有 GPU 就自动用 GPU
-
没有 GPU 就退回 CPU
-
代码兼容性更好
后面把模型和数据都统一写成:
.to(device)
整个代码就会比较优雅。
二十三、封装一个选择 GPU 的函数
李沐《动手学深度学习》里也经常会写辅助函数,比如:
def try_gpu(i=0):
if torch.cuda.device_count() >= i + 1:
return torch.device(f'cuda:{i}')
return torch.device('cpu')
使用时:
device = try_gpu()
print(device)
如果有 GPU,就返回 cuda:0;
没有就返回 cpu。
如果还想取多个 GPU,也可以写:
def try_all_gpus():
devices = [torch.device(f'cuda:{i}')
for i in range(torch.cuda.device_count())]
return devices if devices else [torch.device('cpu')]
这在后面稍复杂的训练里也很方便。
二十四、一个适合 CSDN 的完整示例
下面给你一份适合直接放博客的完整演示代码:
import torch
from torch import nn
# 1. 选择设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print("当前设备:", device)
# 2. 创建张量并移动到设备上
X = torch.rand(2, 3).to(device)
print("X 所在设备:", X.device)
# 3. 定义模型并移动到设备上
net = nn.Sequential(
nn.Linear(3, 5),
nn.ReLU(),
nn.Linear(5, 1)
).to(device)
print("模型参数所在设备:", next(net.parameters()).device)
# 4. 前向传播
Y = net(X)
print("输出 Y 所在设备:", Y.device)
# 5. 把结果移回 CPU
Y_cpu = Y.cpu()
print("移回 CPU 后的设备:", Y_cpu.device)
这段代码已经完整展示了:
-
选择设备
-
张量放到 GPU
-
模型放到 GPU
-
前向传播
-
结果移回 CPU
二十五、这一节最容易犯的错误
1. 模型在 GPU,数据在 CPU
这是最常见报错来源。
2. 只把输入搬到 GPU,忘了标签也要搬
训练时 y 也必须和模型在同一设备。
3. 想直接对 GPU 张量调用 .numpy()
要先 .cpu(),必要时再 .detach()。
4. 没有 GPU 却硬写 cuda
这样在没有 CUDA 环境的机器上会直接报错。
5. 以为 GPU 会自动加速所有代码
实际上主要加速的是张量数值计算部分。
二十六、这一节的核心思想
如果把“使用 GPU”这一节压缩成一句话,我觉得最核心的是:
让模型参数和参与计算的张量处于同一 GPU 设备上,从而利用并行计算加速训练。
表面上看,这一节只是多了 .to(device) 这么一步;
但实际上,它让我们的模型训练从 CPU 时代进入了 GPU 加速时代。
这一步非常关键,因为后面无论是 CNN、RNN,还是更复杂的模型,如果不会正确使用 GPU,训练体验都会差很多。
二十七、我对这一节的理解
学这一节之前,我对 GPU 的理解更多还停留在“显卡很强、训练会更快”这种比较模糊的印象。
但真正写了 PyTorch 代码之后,我才发现:
GPU 不是自动帮你加速一切,而是要求你明确地把模型和张量放到同一个设备上。
这让我对 PyTorch 的运行机制理解更清楚了。
原来模型训练不仅有“数值和结构”,还有“设备归属”这个维度。
一旦设备不一致,模型就根本跑不起来;
而一旦管理好了设备,训练效率往往会明显提升。
二十八、结语
“使用 GPU”是 PyTorch 基础中非常重要的一节。
它不只是一个简单的 API 技巧,而是后面几乎所有深度学习实验都离不开的基础能力。
通过这一节,我们要真正掌握的是:
-
如何检查 GPU 是否可用
-
如何创建设备对象
-
如何把张量放到 GPU
-
如何把模型放到 GPU
-
为什么模型和数据必须在同一设备
-
如何把结果再搬回 CPU
这些内容一旦熟练掌握,后面写训练代码时就会顺手很多。
二十九、重点速记版
1. PyTorch 中检查 GPU 是否可用用什么
torch.cuda.is_available()
2. 如何创建设备对象
torch.device('cuda') 或 torch.device('cpu')
3. 如何把张量或模型搬到设备上
.to(device)
4. 为什么模型和输入必须在同一设备
因为 PyTorch 不允许跨设备直接计算。
5. 如何查看模型参数在哪个设备
next(net.parameters()).device
6. 为什么 GPU 张量不能直接 .numpy()
因为 NumPy 只能处理 CPU 数据,需先 .cpu()
7. 最常见的推荐写法是什么
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
以上就是我对《动手学深度学习》中 PyTorch 基础——使用 GPU 这一节的学习整理。
这一节让我真正从“会写模型”迈向了“会让模型高效运行”。虽然核心代码看起来只是 .to(device),但它背后对应的是 PyTorch 中非常重要的设备管理思想。
对于刚开始学深度学习的同学来说,这一节一定要亲手敲一遍,把“模型、输入、标签必须在同一设备上”这个原则彻底记住。这样后面做卷积神经网络、目标检测、Transformer 等实验时,才不会总被设备报错卡住。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)