云镜收藏

稍后阅读

清单保存在当前浏览器,方便下次回来继续阅读。

清单还是空的

在笔记卡片或正文页点击“加入稍后阅读”即可收藏。

展开课程与本章目录
12 章学习路线01零基础准备:Python、NumPy 与正确安装02起步:环境、设备与第一枚 Tensor03张量基本功:索引、广播与线性代数04自动求导:从计算图到反向传播05神经网络工程:Module、损失与训练循环06数据管线:Dataset、DataLoader 与批处理07亲手搭 Transformer:从 Embedding 到注意力08稳定训练:初始化、AMP、裁剪与排错09性能与显存:Profiler、compile 与检查点10分布式训练:从 DDP 到 FSDP 与 TP11大模型生态:Transformers、PEFT、torchao 与 TorchTitan12方向实战:训练并优化一个迷你语言模型本章课程01先搭一个不容易坏的 PyTorch 环境02Tensor 到底是什么03创建、复制与共享内存04dtype 为什么会影响速度、显存和精度05CPU、CUDA 与设备无关代码06随机数、种子与可复现边界

第 02 章 · 入门

起步:环境、设备与第一枚 Tensor

从可复现的环境和第一枚张量开始,建立“形状、类型、设备”这三个贯穿 PyTorch 与大模型工程的基本坐标。

6 节课程校订于 2026年8月31日
环境配置Tensorshapedevice

预计用时90 分钟

前置知识Python 最小语法 · 已安装 PyTorch

完成标准解释 shape/dtype/device · 估算 Tensor 内存 · 写设备无关代码

本章进度0 / 6

先搭一个不容易坏的 PyTorch 环境

本节目标

本节围绕“先搭一个不容易坏的 PyTorch 环境”展开。运行示例后修改一项配置,记录 Tensor 的 shape、dtype、device、存储关系或随机状态。

清晰讲解

环境的关键不是“装上了”,而是 Python、PyTorch、CUDA 驱动和项目依赖能被复现。先用虚拟环境隔离项目,再用官方安装页按机器选择命令;不要凭博客复制带固定 CUDA 后缀的旧命令。

核对“先搭一个不容易坏的 PyTorch 环境”涉及的版本、设备、存储或随机状态,输出应能说明代码实际走过的路径。

代码示例

import torch
print(torch.__version__)
print('CUDA available:', torch.cuda.is_available())
print('CUDA runtime:', torch.version.cuda)
print('device count:', torch.cuda.device_count())

运行结果与观察

命令应打印 PyTorch 版本、cuda available 与设备名;CPU 机器显示 False / cpu 是正常结果,只有安装目标与硬件一致才算通过。

常见错误

  • 只看 nvidia-smi 就认定 PyTorch 可用;把系统 CUDA、驱动支持的 CUDA 和 PyTorch 自带运行时当成同一件事。
  • 排查“先搭一个不容易坏的 PyTorch 环境”时只看是否报错,没有核对版本、device、dtype、存储关系或随机状态。

与大模型方向的连接

先记录版本与设备能力,排错时就能区分“代码错误”和“运行环境不匹配”。

动手练习

把输出保存到项目 README,并解释每一行对复现实验有什么帮助。

查看参考答案与验收点

验收:示例可复现,关键 Tensor 属性与本节记录一致,并能说明“先搭一个不容易坏的 PyTorch 环境”涉及的设备、内存或随机状态。

官方资料


Tensor 到底是什么

本节目标

本节围绕“Tensor 到底是什么”展开。运行示例后修改一项配置,记录 Tensor 的 shape、dtype、device、存储关系或随机状态。

清晰讲解

Tensor 是带有形状、数据类型和设备信息的多维数组。标量是 0 维,向量是 1 维,矩阵是 2 维;语言模型常用 3 维激活 [batch, sequence, hidden],注意力内部还会拆成 4 维 [batch, heads, sequence, head_dim]

核对“Tensor 到底是什么”涉及的版本、设备、存储或随机状态,输出应能说明代码实际走过的路径。

代码示例

import torch
scalar = torch.tensor(3.0)
tokens = torch.tensor([[12, 8, 91], [4, 7, 0]])
hidden = torch.randn(2, 3, 16)
for x in (scalar, tokens, hidden):
    print(x.shape, x.ndim, x.dtype, x.device)

运行结果与观察

输出应明确显示每个 Tensor 的 shape、ndim、dtype 与 device;改变一个轴后,只允许与该轴相关的输出变化。若 shape 虽能广播但语义错误,本节仍判定未通过。

常见错误

  • 把“二维列表”机械等同于矩阵语义;忽略 token id 应是整数、模型激活通常是浮点数。
  • 排查“Tensor 到底是什么”时只看是否报错,没有核对版本、device、dtype、存储关系或随机状态。

与大模型方向的连接

不要只打印值。调试大模型时,先打印 shape / dtype / device 往往比阅读整段张量更有效。

动手练习

创建形状为 [2, 5, 32] 的随机隐藏状态,并用一句话解释三个轴。

查看参考答案与验收点

先把每个轴写成语义:例如 [B,T,C] 分别是批次、序列和隐藏维;再用 assert tensor.shape == (...) 固化预期。

官方资料


创建、复制与共享内存

本节目标

本节围绕“创建、复制与共享内存”展开。运行示例后修改一项配置,记录 Tensor 的 shape、dtype、device、存储关系或随机状态。

清晰讲解

torch.tensor 通常复制输入;torch.from_numpy 可与 NumPy 共享 CPU 内存;clone 复制数据但保留梯度关系,detach 切断自动求导历史。选择哪一个取决于你是否需要共享、复制或追踪梯度。

核对“创建、复制与共享内存”涉及的版本、设备、存储或随机状态,输出应能说明代码实际走过的路径。

代码示例

import numpy as np
import torch
a = np.array([1., 2., 3.], dtype=np.float32)
x = torch.from_numpy(a)
y = x.clone()
a[0] = 99
print(x)  # 与 NumPy 共享,首项变为 99
print(y)  # clone 后保持原值

运行结果与观察

修改 from_numpy 得到的 Tensor 时,原 NumPy 数组会同步变化;torch.tensor(array) 创建的副本不应变化。把两组输出并排比较即可判断是否共享内存。

常见错误

  • 以为所有转换都是零拷贝;对一个需要梯度的 Tensor 随意使用 .data 修改值。
  • 排查“创建、复制与共享内存”时只看是否报错,没有核对版本、device、dtype、存储关系或随机状态。

与大模型方向的连接

数据预处理常在 NumPy、Arrow 与 Tensor 之间转换;理解是否复制能避免隐蔽的数据污染和额外内存。

动手练习

分别验证 torch.tensor(a)torch.from_numpy(a) 在修改 NumPy 后的差异。

查看参考答案与验收点

验收:示例可复现,关键 Tensor 属性与本节记录一致,并能说明“创建、复制与共享内存”涉及的设备、内存或随机状态。

官方资料


dtype 为什么会影响速度、显存和精度

本节目标

本节围绕“dtype 为什么会影响速度、显存和精度”展开。运行示例后修改一项配置,记录 Tensor 的 shape、dtype、device、存储关系或随机状态。

清晰讲解

同样数量的元素,float32 每个占 4 字节,float16 与 bfloat16 通常占 2 字节。低精度能省显存并提高吞吐,但指数范围和有效精度不同;token id、类别标签等离散索引则通常使用 int64。

核对“dtype 为什么会影响速度、显存和精度”涉及的版本、设备、存储或随机状态,输出应能说明代码实际走过的路径。

代码示例

import torch
for dtype in (torch.float32, torch.float16, torch.bfloat16):
    x = torch.empty(1024, 1024, dtype=dtype)
    mib = x.numel() * x.element_size() / 1024**2
    print(dtype, f'{mib:.1f} MiB')
labels = torch.tensor([1, 0, 3], dtype=torch.long)

运行结果与观察

三种浮点类型的理论内存应依次约为 4、2、2 MiB;这验证 bfloat16 与 float16 同为 16 位,但数值范围不同。

常见错误

  • 为了省显存把所有东西都转成 float16,包括索引;误以为 bfloat16 比 float16 小。
  • 排查“dtype 为什么会影响速度、显存和精度”时只看是否报错,没有核对版本、device、dtype、存储关系或随机状态。

与大模型方向的连接

大模型显存估算从“元素数 × 每元素字节数”开始;后续还要加参数、梯度、优化器状态和激活。

动手练习

计算一个 [8, 2048, 4096] 激活分别使用三种浮点类型时的理论内存。

查看参考答案与验收点

验收:示例可复现,关键 Tensor 属性与本节记录一致,并能说明“dtype 为什么会影响速度、显存和精度”涉及的设备、内存或随机状态。

官方资料


CPU、CUDA 与设备无关代码

本节目标

本节围绕“CPU、CUDA 与设备无关代码”展开。运行示例后修改一项配置,记录 Tensor 的 shape、dtype、device、存储关系或随机状态。

清晰讲解

运算双方必须位于兼容设备上。可靠代码先决定 device,再把模型和批次移到同一设备;不要在模块内部到处写死 cuda:0。Apple 设备还可能使用 MPS,CPU 则始终是安全回退。

核对“CPU、CUDA 与设备无关代码”涉及的版本、设备、存储或随机状态,输出应能说明代码实际走过的路径。

代码示例

import torch
device = (
    torch.device('cuda') if torch.cuda.is_available()
    else torch.device('mps') if torch.backends.mps.is_available()
    else torch.device('cpu')
)
x = torch.randn(2, 3, device=device)
weight = torch.randn(3, 4, device=device)
print((x @ weight).device)

运行结果与观察

输出设备应与自动选择结果一致:无加速器时为 cpu,有 CUDA/MPS 时为对应设备;任何参与矩阵乘的 Tensor 都必须在同一设备。

常见错误

  • 模型在 CUDA、标签仍在 CPU;调用 .to(device) 却忘记接收返回值。
  • 排查“CPU、CUDA 与设备无关代码”时只看是否报错,没有核对版本、device、dtype、存储关系或随机状态。

与大模型方向的连接

训练脚本应该让设备成为配置,而不是散落在业务代码里的常量;分布式时每个进程还会绑定自己的本地 GPU。

动手练习

写一个 move_batch 函数,递归搬运字典中的 Tensor,同时保留字符串字段。

查看参考答案与验收点

验收:示例可复现,关键 Tensor 属性与本节记录一致,并能说明“CPU、CUDA 与设备无关代码”涉及的设备、内存或随机状态。

官方资料


随机数、种子与可复现边界

本节目标

本节围绕“随机数、种子与可复现边界”展开。运行示例后修改一项配置,记录 Tensor 的 shape、dtype、device、存储关系或随机状态。

清晰讲解

固定随机种子能控制参数初始化、采样等随机源,但不保证不同硬件、驱动或 PyTorch 版本得到逐位相同结果。复现应同时记录代码、数据版本、环境和关键配置。

核对“随机数、种子与可复现边界”涉及的版本、设备、存储或随机状态,输出应能说明代码实际走过的路径。

代码示例

import random
import numpy as np
import torch

seed = 42
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
if torch.cuda.is_available():
    torch.cuda.manual_seed_all(seed)
print(torch.rand(3))

运行结果与观察

相同环境与 seed 下,两次首次随机输出应一致;删除 torch 的 seed 后输出应变化。跨硬件或版本不要求逐位相同。

常见错误

  • 把“同一个 seed”理解成任何机器都完全一致;验证集仍开启随机增强。
  • 排查“随机数、种子与可复现边界”时只看是否报错,没有核对版本、device、dtype、存储关系或随机状态。

与大模型方向的连接

语言模型训练中的数据顺序、dropout 和采样都会消费随机状态;断点续训若不恢复 RNG 状态,轨迹就会分叉。

动手练习

连续运行两次脚本验证随机数一致,再去掉 torch.manual_seed 观察差异。

查看参考答案与验收点

验收:示例可复现,关键 Tensor 属性与本节记录一致,并能说明“随机数、种子与可复现边界”涉及的设备、内存或随机状态。

官方资料

章末资料

小测、项目与相关面试题

1. float16 与 bfloat16 的显存大小是否不同?

通常相同,都是每元素 2 字节;差别主要在指数范围和有效精度。

2. 调用 x.to(device) 会原地修改 x 吗?

通常不会,应接收返回值,例如 x = x.to(device)。