Tensor → Module阶段一 · Python 与 PyTorch 基础
形状 · 设备 · 精度
已完成
阶段一 · Python 与 PyTorch 基础
形状 · 设备 · 精度
学习内容
掌握 Python 函数、类、文件与 JSON 读写、虚拟环境和依赖安装。学习 PyTorch Tensor 的形状、索引、广播、矩阵乘法、reshape、transpose,以及 nn.Module、forward()、device 和 dtype。
动手任务
在 Windows 的 VS Code 里写一个小型 PyTorch 模型,用 eval() 和 inference_mode() 完成前向推理。打印每一层的张量形状、数据类型和设备,再把模型与输入一起移到 GPU 上运行。
验收标准
能在运行前推导每层的输出形状。遇到矩阵维度或 CPU/GPU 设备不匹配时,能定位出错的张量并修正。
展开详细讲解与实验
机制怎么工作
张量的形状描述各轴长度,dtype 描述元素的表示方式,device 描述数据所在设备。对 [批大小, 序列长度, 特征数] 使用 Linear(4, 6) 时,每个位置独立做 4 → 6 的线性变换,前两轴保持不变。eval() 切换模块行为,inference_mode() 关闭这次推理所需之外的自动求导跟踪,实际推理通常需要两者。
一步一步理解
先把一层模型算出来
设输入向量 x=[1,2],权重矩阵的两行为 [3,4] 和 [5,6],偏置 b=[1,-1]。第一项输出为 1×3+2×4+1=12,第二项为 1×5+2×6−1=16。因此 Linear(2,2) 将这个位置变成 [12,16]。把多个位置放进同一张量时,每个位置都使用同一组权重分别计算。
为什么要保留批和序列两根轴
形状 [2,3,4] 中,第一根轴标记两条独立样本,第二根轴标记各自的三个位置,最后一根轴存四个特征。变成 [6,4] 虽然保留全部元素,却把样本边界藏起来了。逐位置线性层可以这样算,再还原形状;涉及位置间关系的注意力必须知道哪些位置属于同一条序列。
一次正确的计时
先运行若干次相同形状的前向,完成初始化与预热。GPU 测试在开始读时钟前同步,在前向结束后再次同步,再读结束时钟。重复多次,保留每次耗时。如果只研究模型前向,把输入搬移放在计时区间之外;如果研究完整请求,就把搬移计入并注明。
自测与答案
问题:输入 [8,16,32] 经过 Linear(32,64),输出是什么?答案是 [8,16,64],因为最后一轴从 32 变为 64。问题:eval() 后为什么还能产生梯度?因为它控制模块的评估行为;是否记录求导信息由求导模式另行控制。
动手步骤
- 新建 Python 虚拟环境,按 PyTorch 官方指引安装与你的设备匹配的版本。第一次可以直接在 CPU 上跑。
- 先在纸上写下输入、权重和输出的形状。运行代码并核对输出,再将输入最后一维改为 5,观察并解释报错。
- 有可用 GPU 时记录同一段代码的设备与精度。若要比较延迟,先预热,并在计时区间前后同步 GPU,区分前向计算和数据传输。
import torch
from torch import nn
torch.manual_seed(0)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = nn.Linear(4, 6).to(device).eval()
x = torch.randn(2, 3, 4, device=device)
with torch.inference_mode():
y = model(x)
for name, tensor in [("input", x), ("weight", model.weight), ("output", y)]:
print(name, tuple(tensor.shape), tensor.dtype, tensor.device)
assert y.shape == (2, 3, 6)
预期结果
输入是 (2, 3, 4),权重是 (6, 4),输出是 (2, 3, 6)。记录实际设备,并解释为什么权重的两个维度以 out_features、in_features 排列。
手算与排查
按维度复核
输入有 2 × 3 = 6 个位置,每个位置各做一次 4 → 6 的变换,输出共 36 个数。权重有 6 × 4 = 24 个数,另有 6 个偏置。若是 FP32,这个线性层的 30 个参数本身占 120 字节,未计张量元数据与中间结果。
从报错倒推
维度错误时先打印输入最后一维和权重第二维。设备错误时同时打印 model.weight.device 与 x.device。类型错误时查看 dtype。先修一项,再运行同一输入复核。
常见误区
只把模型移到 GPU 会造成设备不匹配。仅用主机时钟包住 CUDA 调用,还可能只测到提交工作所花的时间。