PyTorch底层原理
动态计算图
Tape-based
Autograd的Tape-based机制。
PyTorch 的自动求导系统(Autograd)工作起来就像一个 磁带录音机:
- 过程: 当你执行前向传播(Forward)代码时,PyTorch 会在后台通过一个“磁带”按顺序记录下你做的每一个操作(加法、乘法、Reshape)。
- 反向: 当你调用
.backward()时,它就像按下“倒带播放”键,沿着这条记录反向回放,利用链式法则计算梯度。 - 特点: 录完一次,磁带就销毁了(释放内存)。下一次迭代(Next Epoch),你会拿出一盘新磁带重新录。这就是为什么它支持 Python 的
if/else循环——因为每次录的内容可以完全不同。
Storage/View分离
这是 PyTorch 高效处理数据的核心,也是初学者最容易踩坑的地方(比如修改了 View 导致原数据变了,或者报错 contiguous)。
- 原理: 一个
Tensor在内存里其实分成了两部分:- Storage (仓库): 一维的、连续的数字数组。这是真正存数据的地方。
- Metadata (元数据/视图): 记录形状(Size)、步长(Stride)、偏移量(Offset)。这决定了你“看起来”这个 Tensor 是什么样的。
- 举例:
当你调用
.view()或.reshape()改变形状时,PyTorch 并没有在内存中搬运数据! 它只是创建了一个新的“元数据头”,指向同一个 Storage,只是解读方式变了(比如把“2x3”解读为“3x2”)。 - 为什么重要:
- 极快: 改变形状几乎不消耗时间,因为不拷贝数据。
- 坑: 如果你修改了新 Tensor 的值, 旧 Tensor 的值也会变 (因为它们共用仓库)。这也解释了为什么有时候你需要调用
.contiguous()—— 也就是强迫 PyTorch 真的拷贝一份数据出来,不再共用老仓库。
Imperative Programming
PyTorch 并没有试图创造一种新的“图语言”,而是直接寄生在 Python 解释器之上:
- PyTorch 的对象就是 Python 的对象。
- PyTorch 的报错栈就是 Python 的报错栈。
- 它利用 Python 的引用计数机制来管理内存。
Explicit Device Management
这是 PyTorch 与其他框架(如 Keras)的一个显著区别原理。
- 原理: “你不动,我不动”。 PyTorch 默认数据都在 CPU 上,它绝不会自动帮你把数据移到 GPU,除非你显式地写代码要求它这么做。
- 代码体现:
.to('cuda')或.cuda()。 - 设计哲学: 这种设计虽然增加了代码量(你需要自己管理
device),但它给了开发者对硬件行为的 绝对控制权 。你知道每一块显存是什么时候被占用的,避免了“黑盒”带来的性能隐患。