一、前言

前面学习 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 等实验时,才不会总被设备报错卡住。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐