Deep Learning Software —— PyTorch¶
约 2588 个字 160 行代码 6 张图片 预计阅读时间 12 分钟

深度学习框架的核心在于
-
Allow rapid prototyping of new ideas
允许我们快速实现新的想法
-
Automatically compute gradients for you
能为我们自动计算梯度
-
Run it all efficiently on GPU (or TPU)
能在 GPU(或 TPU)上高效运行
Fundamental Concepts¶
- Tensor: Like a numpy array, but can run on GPU
- Autograd: Package for building computational graphs out of Tensors, and automatically computing gradients
- Module: A neural network layer; may store state or learnable weights
Autograd¶
Autograd 工作原理¶
在 PyTorch 中,我们可以借助 torch.autograd
来自动计算张量的梯度,这使得神经网络的反向传播变得非常简单,他也是 PyTorch 的核心特性之一
Autograd 的关键在于维护一个计算图,它会记录所有的计算操作,然后在反向传播时,根据这个计算图来计算梯度
- 前向传播:在前向传播过程中,PyTorch 会记录你对张量进行的每个操作(加法、乘法、矩阵乘法等)。这些操作会以计算图的形式被自动记录下来。
- 反向传播:一旦我们获得了损失值,我们可以通过调用 .backward() 方法来触发反向传播,计算所有相关张量的梯度。Autograd 会根据前向传播记录的操作顺序,从输出反向计算梯度,直到输入层。
具体来说,我们可以在创建张量时提供 requires_grad=True
参数来告诉 PyTorch 需要计算这个张量的梯度。当我们使用被设置为 requires_grad=True
的张量进行计算时,PyTorch 会自动记录这些计算操作,以构建计算图。
- 使用被设置为
requires_grad=True
的张量计算出的结果张量会被自动设置为requires_grad=True
。
当我们对最终的输出结果调用 .backward()
方法时,PyTorch 会自动计算所有相关张量的梯度,并且将这些梯度积累到对应张量的 .grad
属性中。
如何使用 Autograd¶
我们可以从下面这个简单的例子来看一下 Autograd 的使用方法
- 上述代码在每一次执行时,都会从无到有构建一个如右图所示的计算图,并在调用
loss.backward()
时,后从往前计算梯度。 - 当我们不希望某些操作被记录在计算图中时,我们可以使用
with torch.no_grad()
来包裹这些操作,以临时禁用 Autograd。 - 在每一次迭代结束后,我们需要调用
w1.grad.zero_()
和w2.grad.zero_()
来清空这两个张量的梯度,否则梯度就会在每一次迭代中不断积累,从而导致 bug。
Tip
-
如果我们不希望某些操作被记录在计算图中,可以使用 x.detach() 来创建一个新的张量,它与 x 拥有相同的数据,但不再记录操作。
例如
y = x.detach()
表示创建一个与 x 数据相同的张量,但对它的操作不会被记录到计算图中 -
有时需要在不影响主计算图的情况下对张量进行操作,requires_grad_() 方法允许我们直接改变张量的 requires_grad 属性:
例如
x.requires_grad_()
表示从现在开始记录 x 的梯度
自定义函数¶
当我们使用一个普通的 Python 函数来定义新的操作时,PyTorch 实际上会记录这个函数内部的每一个操作,从而构建相当复杂的计算图。
比如我们定义一个 sigmoid 函数,我们很容易知道它的导数是 sigmoid(x) * (1 - sigmoid(x))
,但是如果我们直接把它在 PyTorch 中使用,PyTorch Autograd 会把这个函数展开成非常复杂的计算图,这样会导致计算效率低下。

为了解决这个问题,我们可以使用 torch.autograd.Function
来自定义一个 Autograd 函数,这样我们就可以直接定义这个函数的前向传播和反向传播。
这样一来 PyTorch 就会直接使用把我们定义的函数视为一个整体,在计算图中只相当于一个节点,从而提高了计算效率。

一般来说这样的做法在实践中并不常见——大部分情况下直接使用 Python 函数就足够了。
Some Modules¶
nn¶
torch.nn
是 PyTorch 中的一个模块,它提供了很多有用的类和函数,用来帮助我们构建神经网络。
Example
- 所使用到的模块包括
nn.Linear
:全连接层nn.ReLU
:ReLU 激活函数nn.functional.mse_loss
:均方误差损失函数
- 这里我们使用
y_pred = model(x)
来向模型提供数据并让其前向传递,得到预测标签 - 在最后几行中我们更新模型中的所有参数,并且清空模型的梯度以避免梯度积累
optim¶
我们还可以使用 torch.optim
模块来对我们的模型进行优化,比如
这里我们首先指定了优化器的更新规则是 Adam,接着在每一次迭代中都通过 .step()
和 .zero_grad()
函数来进行优化并清空梯度积累。
自定义模块¶
- A PyTorch Module is a neural net layer; it inputs and outputs Tensors
- Modules can contain weights or other modules
我们可以使用 torch.nn
来定义自己的模块和神经网络层。
Computation Graphs¶
计算图是深度学习框架中至关重要的部分,用于表示计算的过程,以及计算过程中的依赖关系。
各个深度学习框架中的计算图可以分为动态计算图(Dynamic Computation Graphs)和静态计算图(Static Computation Graphs)两种。
DynamicComputation Graphs¶
在动态计算图中,图的构建是即时的,每次前向传播时都会重新构建计算图。
-
特点
- 即时构建:每次执行操作时都会立即创建计算图。也就是说,操作会在每次执行时动态地计算并记录计算过程。
-
灵活性强:用户可以在执行时修改网络结构,例如条件判断、循环等操作,可以根据输入数据的不同执行不同的路径。
我们甚至可以在每次迭代中改变网络结构,这样可以更灵活地构建网络,例如(一个仅供参考,实际中不建议这样做的例子
-
逐步执行:前向传播会根据当前输入逐步执行,每个操作都立即计算出结果并反馈给后续的计算。
- 优势
- 灵活性和易调试:允许在每次执行时改变网络结构,非常适合用于需要控制流的模型,如循环神经网络(RNN)或者带有条件判断和循环的复杂模型。允许我们随时修改网络结构,并且能够方便地进行调试。
- 简化代码:无需事先定义整个计算图,避免了构建复杂计算图时可能出现的静态错误。每次迭代时,计算图是“动态”地构建和执行的。
- 适应性强:动态计算图在处理变长序列、递归模型或需要自定义操作的任务时表现出极大的优势。PyTorch 和 TensorFlow 2.x 都使用动态计算图(Eager Execution)来提高代码的可读性和灵活性。
- 缺点
- 低效:由于每次迭代都会重新构建计算图,尤其是在批量处理和大规模训练时,可能无法充分利用硬件加速。
- 内存消耗较大:由于计算图是动态创建的,图的构建和维护过程可能需要更多的内存资源。
Static Computation Graphs¶
在静态计算图中,计算图在训练开始之前就已经构建好。网络的所有操作、参数、数据流等都事先确定,整个计算图在模型训练或推理过程中都保持不变。
- 特点
- 预先构建:计算图在训练开始之前就已经构建好,网络的所有操作、参数、数据流等都事先确定。
- 一次定义,多次使用:计算图只需要定义一次,之后可以重复使用,不需要每次迭代都重新构建。
- 优化空间:静态计算图可以进行图优化,框架可以根据已经建立好的计算图进行多种优化策略(例如:算子融合、内存共享等),提高计算效率。
- 优势
- 高效:计算图的优化能够让框架更好地利用硬件加速(如 GPU),并且减少冗余操作,提高训练效率。
- 内存使用优化:框架可以根据静态图进行内存布局优化,从而减少内存的消耗,特别是在复杂网络结构中。
- 并行性:由于计算图是静态的,框架可以预先分析图的结构并执行更加高效的并行计算,通常能在大规模训练中获得更高的性能。
- 缺点
- 灵活性差:静态计算图在训练开始之前就已经构建好,网络结构和数据流都是固定的,对于需要灵活性和动态调整的模型而言,静态计算图可能不太适用。
- 调试困难:静态计算图在构建过程中会进行优化,这导致实际执行的代码与我们书写的代码可能会有很大不同,这可能会大幅增加调试的难度。
Example
- 在上述代码中,我们首先定义了一个模型函数 model,然后使用
torch.jit.script
将这个函数转换为静态图。
又或者我们也可以在定义模型时使用 @torch.jit.script
装饰器来直接将模型转换为静态图
TensorFlow
TensorFlow 1.x 默认使用静态计算图,需要先定义计算图,然后在 Session 中执行计算图。(动态图是可选项,需要使用 tf.enable_eager_execution() 开启)
TensorFlow 2.x 引入了 Eager Execution,默认使用使用动态计算图,可以像 PyTorch 一样直接执行操作,不需要先定义计算图。(静态图是可选项,需要使用 tf.function 将函数转换为静态图)
TensorBoard
- PyTorch:使用
torch.utils.tensorboard
模块来记录训练过程,可以记录标量、图像、音频、文本等信息。 - TensorFlow:TensorBoard 是 TensorFlow 的可视化工具,可以用来展示计算图、损失曲线、参数分布等信息。
PyTorch vs TensorFlow