李沐矩阵公式推导
07节.自动求导
问题1:MulBackward0是指什么?
回答:MulBackward0
是 PyTorch 中自动微分引擎的一部分,它表示一个张量是通过乘法操作得到的,并且在反向传播时用于计算梯度。在 PyTorch 中,每个张量都有一个 grad_fn
属性,这个属性引用了一个创建了该张量的 Function
。对于通过乘法操作得到的张量,其 grad_fn
就是 MulBackward0
。
这里的“张量是通过乘法操作得到的”意味着:
-
有一个或多个原始张量(在这个例子中是a和b)。
-
这些原始张量经过乘法操作(*)。
-
乘法操作的结果是一个新张量(在这个例子中是c)。
-
这个新张量c的grad_fn属性被设置为MulBackward0,这是一个用于在反向传播中计算梯度的函数。
在更复杂的情况下,如果涉及多个变量和操作,PyTorch 的自动微分引擎会构建一个计算图,并使用这些
grad_fn
来逐步计算每个变量的梯度。
问题2:grad_fn有哪些取值
在PyTorch中,grad_fn
属性是用于自动微分的关键属性,它指向创建当前张量的函数。这个属性对于自动计算梯度至关重要,因为它记录了张量在计算图中的来源和创建方式。以下是一些常见的grad_fn
取值及其对应的操作:
AddBackward0
: 表示张量是通过加法操作创建的。MulBackward0
: 表示张量是通过乘法操作创建的。MatMulBackward
: 表示张量是通过矩阵乘法操作创建的。DivBackward0
: 表示张量是通过除法操作创建的。SumBackward0
: 表示张量是通过求和操作创建的。MeanBackward0
: 表示张量是通过求均值操作创建的。MaxBackward0
: 表示张量是通过取最大值操作创建的。MinBackward0
: 表示张量是通过取最小值操作创建的。SoftmaxBackward
: 表示张量是通过softmax操作创建的。LogSoftmaxBackward
: 表示张量是通过对数softmax操作创建的。Conv2dBackward
: 表示张量是通过二维卷积操作创建的。BatchNormBackward
: 表示张量是通过批量归一化操作创建的。
这些grad_fn
是反向传播过程中计算梯度的基本单元。当你调用.backward()
方法时,PyTorch会根据grad_fn
回溯计算图中的每个操作,从而计算出每个参数的梯度。
问题3:计算图的显示构造和隐式构造
在深度学习中,自动求导(Automatic Differentiation,AD)是一种用来计算导数的技术,它对于训练神经网络至关重要,因为它允许我们高效地计算损失函数相对于模型参数的梯度。自动求导可以通过两种方式实现:显示构造(Explicit Construction)和隐式构造(Implicit Construction)。
-
显示构造(Explicit Construction):
- 在显示构造中,计算图是显式地构建出来的。这意味着在程序运行时,会创建一个数据结构来表示计算图,其中包含了所有的操作和变量。
- 这种方法通常使用图数据结构来存储操作和变量之间的依赖关系。
- 优点是直观,易于理解和调试,因为整个计算过程是显式可见的。
- 缺点是可能会增加内存的使用,因为需要存储整个计算图。
-
隐式构造(Implicit Construction):
- 隐式构造不直接构建计算图,而是在运行时动态地计算梯度。
- 这种方法通常使用一种称为“反向传播”(Backpropagation)的技术,它通过链式法则递归地计算导数。
- 优点是内存使用效率更高,因为不需要存储整个计算图,只需要在需要计算梯度时进行计算。
- 缺点是可能不如显示构造直观,对于复杂的模型,调试和理解计算过程可能更加困难。
在实际应用中,如PyTorch和TensorFlow这样的深度学习框架,通常提供了自动求导的功能。PyTorch使用动态计算图(Dynamic Computational Graph),它在每次前向传播时构建计算图,并在反向传播时自动计算梯度,这是隐式构造的一种实现。而TensorFlow 1.x版本使用的是静态计算图(Static Computational Graph),它在定义模型时构建计算图,这是显示构造的一种实现。
在最新的TensorFlow 2.x版本中,也支持了动态计算图,使得用户体验更加接近于PyTorch。
这两种方法各有优势,选择哪一种取决于具体的应用场景和个人偏好。
问题4:正向传递和反向传递中,正向传递都保存了哪些变量
写在前面:反向传递的主要对象是loss(标量函数),自动微分的grad启动,需要先进行backward
在深度学习中,正向传递(forward pass)和反向传递(backward pass)是训练神经网络的两个关键步骤。在正向传递中,输入数据通过网络,每一层都会计算出相应的输出,直到最终产生预测结果。而在反向传递中,则是通过计算损失函数关于网络参数的梯度,来更新网络的权重。
在正向传递过程中,为了有效地进行反向传递,通常需要保存以下变量:
-
输入数据:网络的输入,用于在反向传递时计算梯度。
-
层的输出:每一层的输出值,这些值会作为下一层的输入,并且在计算梯度时需要用到。
-
层的参数:包括权重和偏置等,这些参数在反向传递中用于计算梯度。
-
中间变量:某些操作可能依赖于中间变量,比如在计算激活函数之前的数据,这些中间变量在反向传递中可能需要用到。
-
激活函数的输出:激活函数的输出不仅用于当前层的输出,还用于反向传递中计算梯度。
-
损失函数的值:在训练过程中,需要计算损失函数关于预测结果的梯度。
在某些深度学习框架中,如PyTorch,正向传递时会自动保存这些变量,以便在反向传递时使用。这种机制通常被称为自动微分(automatic differentiation)。
需要注意的是,不是所有的变量都需要保存。一些临时变量,比如中间的加法结果,通常不需要保存,因为它们可以通过原始变量重新计算得到。但是,如上所述的变量通常需要保存,以便在反向传递中有效地计算梯度。
问题5:zero_是什么写法
在PyTorch中,zero_()
是一个原地操作(in-place operation),它用于将一个张量(tensor)的所有元素设置为0。这个操作会直接修改原张量,而不是创建一个新的张量。
这里的下划线(_
)表示这是一个原地操作。PyTorch中的许多操作都有原地和非原地两种版本。原地操作会直接修改输入的数据,而非原地操作会返回一个新的数据副本。
例如,对于一个张量 x
,你可以使用 x.zero_()
来将所有元素设置为0,这会直接修改 x
。如果你想要保留原始的 x
并创建一个新的全0张量,你可以使用 x.new_zeros()
或者 torch.zeros_like(x)
。
在梯度计算的上下文中,x.grad.zero_()
用于清除之前计算的梯度,以确保在新的梯度计算中不会累积旧的梯度值。这是为了防止梯度累积,确保每次计算的梯度都是针对当前的参数状态。
所以每算一次新的梯度之前,都要做梯度的清零工作
问题6:反向求导的对象默认为标量函数,当出现向量函数时,有什么操作手段?
向量的反向计算:通常会计算一批(batch)训练样本中每个组成部分的损失函数的导数。
对此,我们的目的不是计算微分矩阵,而是单独计算批量中每个样本的偏导数之和。
x.grad.zero_()
y = x * x
u = y.detach()
z = u * x
z.sum().backward()#所以可以先求和,在反向传递,得到sum(grad)
x.grad == u
tensor([True, True, True, True])
问题7:线性回归方程解析解的计算过程
解析解 w ∗ = ( X ⊤ X ) − 1 X ⊤ y w^* = \left(X^{\top}X\right)^{-1}X^{\top}y w∗=(X⊤X)−1X⊤y的求导过程涉及对损失函数
∥ y − X w ∥ 2 \|y - Xw\|^2 ∥y−Xw∥2
(L(w) = \frac{1}{2}|y - Xw|^2) 的最小化。这里我们使用梯度下降法的思路,通过求损失函数对权重 (w) 的导数(梯度),并令其为零来找到最小值。
步骤 1: 定义损失函数
首先,定义损失函数 (L(w)):
KaTeX parse error: Undefined control sequence: \[ at position 1: \̲[̲ L(w) = \frac{1…
这里 (|y - Xw|^2) 表示预测值和实际值之间的误差平方和。
步骤 2: 展开损失函数
将损失函数展开:
[
L(w) = \frac{1}{2} (y - Xw)^{\top} (y - Xw)
]
这里使用了向量内积的性质。
步骤 3: 求导
为了找到最小化损失函数的 (w),我们需要对 (L(w)) 关于 (w) 求导,并令导数为0。首先计算 (L(w)) 的梯度:
[
\frac{\partial L(w)}{\partial w} = \frac{\partial}{\partial w} \left( \frac{1}{2} (y - Xw)^{\top} (y - Xw) \right)
]
使用链式法则,我们得到:
[
\frac{\partial L(w)}{\partial w} = \frac{1}{2} \left( -X^{\top} (y - Xw) + (y - Xw)^{\top} X \right)
]
由于 (X^{\top} (y - Xw)) 是一个向量,我们可以进一步简化为:
[
\frac{\partial L(w)}{\partial w} = -X^{\top} (y - Xw) + X^{\top} (y - Xw) = 0
]
这里 (-X^{\top} (y - Xw)) 和 (X^{\top} (y - Xw)) 相互抵消。
步骤 4: 解方程
将导数设为0,我们得到:
[
-X^{\top} (y - Xw) = 0
]
简化得到:
[
X^{\top} y - X^{\top} Xw = 0
]
进一步整理得到:
[
X^{\top} Xw = X^{\top} y
]
解这个方程,我们得到:
[
w = (X^{\top} X)^{-1} X^{\top} y
]
这就是线性回归的解析解。
总结
通过上述步骤,我们通过求导和解方程得到了线性回归模型的最优权重向量 (w)。这个过程展示了如何从损失函数的最小化问题中得到解析解。