最近重新开始学习《动手学深度学习》(D2L)。在“2.5 自动微分”这一节里,我看到了下面这段代码:
import torch
x = torch.arange(4.0)
x.requires_grad_(True)
y = 2 * torch.dot(x, x)
y.backward()
x.grad
最终得到:
tensor([0., 4., 8., 12.])
书中说,对于
$$
y=2x^\top x,
$$
它关于 (x) 的梯度是
$$
4x.
$$
计算本身并不难,但结果的形状让我产生了疑问。
如果把输入 (x) 看作一个 (n) 维列向量,那么输出 (y) 是标量,只有一个分量。按照我之前接触到的雅可比矩阵定义,导数的尺寸应该是
$$
\text{输出分量数}\times\text{输入分量数}
=1\times n.
$$
也就是说,结果似乎应该是一个行向量:
$$
4x^\top.
$$
为什么 D2L 写成了列向量 (4x)?
后来我才发现,同一组偏导数存在不同的排列约定:按照分子布局排列,结果是 (4x^\top);按照分母布局排列,结果是 (4x)。D2L 这里讨论的是梯度,因此写成了后一种分母布局的形式。下面我将从向量求导基础开始详细讲解。
向量求导基础
第一次看到“向量求导”这个词时,很容易觉得这是一套和普通微积分完全不同的东西。但至少对于本文讨论的“标量对向量求导”,最底层的计算方法并没有变化:只需要把向量拆成一个个分量,分别求偏导,再把得到的偏导数按照某种方式排列起来。
先看一个简单的例子。假设
$$
x=
\begin{bmatrix}
x_1\
x_2\
x_3
\end{bmatrix},
$$
定义标量函数
$$
y=x_1^2+2x_2^2+3x_3^2.
$$
所谓求 (y) 关于向量 (x) 的导数,可以先理解为:分别计算 (y) 对 (x) 中每个分量的偏导数。
对 (x_1) 求偏导:
$$
\frac{\partial y}{\partial x_1}=2x_1.
$$
对 (x_2) 求偏导:
$$
\frac{\partial y}{\partial x_2}=4x_2.
$$
对 (x_3) 求偏导:
$$
\frac{\partial y}{\partial x_3}=6x_3.
$$
于是我们得到三个偏导数:
$$
2x_1,\quad4x_2,\quad6x_3.
$$
到这里,真正的求导计算已经完成了。至于这些偏导数最后应该横着排成
$$
\begin{bmatrix}
2x_1&4x_2&6x_3
\end{bmatrix},
$$
还是竖着排成
$$
\begin{bmatrix}
2x_1\
4x_2\
6x_3
\end{bmatrix},
$$
是下一步才需要讨论的布局问题。无论采用哪一种布局,前面计算出来的偏导数都没有改变。
理解这个基本思路以后,再来看 D2L 中的四维向量。把 (x^\top x) 展开,可以得到:
$$
x^\top x=x_1^2+x_2^2+x_3^2+x_4^2.
$$
因此
$$
y
=2x^\top x
=2x_1^2+2x_2^2+2x_3^2+2x_4^2.
$$
分别计算 (y) 对四个输入分量的偏导:
$$
\frac{\partial y}{\partial x_1}=4x_1,
\qquad
\frac{\partial y}{\partial x_2}=4x_2,
$$
$$
\frac{\partial y}{\partial x_3}=4x_3,
\qquad
\frac{\partial y}{\partial x_4}=4x_4.
$$
于是,我们得到四个偏导数:
$$
4x_1,\quad4x_2,\quad4x_3,\quad4x_4.
$$
求导本身并没有争议。接下来的问题只是:这些偏导数应该横着排列,还是竖着排列?
同一组偏导数的两种布局
矩阵微积分中常见两种导数布局:
- 分子布局(numerator layout),有些资料也称为雅可比布局;
- 分母布局(denominator layout),有些资料也称为梯度布局。
“雅可比布局”和“梯度布局”并不是完全统一的名称,因此本文统一使用更中性的“分子布局”和“分母布局”。阅读其他资料时,也应该先确认作者怎样定义结果的形状。
为什么叫“分子布局”和“分母布局”
把向量 (y) 对向量 (x) 求导时,我们通常写成:
$$
\frac{\partial y}{\partial x}.
$$
这个式子看起来像一个分数:(y) 在上面,是“分子”;(x) 在下面,是“分母”。两种布局的名字,就来自结果的行数跟谁的分量数一致。
假设:
$$
y\in\mathbb R^m,
\qquad
x\in\mathbb R^n.
$$
也就是说,分子 (y) 有 (m) 个分量,分母 (x) 有 (n) 个分量。
- 分子布局的结果是 (m\times n):行数为 (m),与分子 (y) 的分量数相同;
- 分母布局的结果是 (n\times m):行数为 (n),与分母 (x) 的分量数相同。
可以简单记成:
$$
\begin{aligned}
\text{分子布局:}&\quad
\text{分子决定行,分母决定列},\
\text{分母布局:}&\quad
\text{分母决定行,分子决定列}.
\end{aligned}
$$
这里说的“分量数”有时也会被简称为向量的“维度”。例如 $x\in\mathbb R^4$ 有 4 个分量,可以称为 4 维向量。它和后面 PyTorch 中表示 Tensor 轴数的 ndim 不是同一个概念。
在本文的例子中,$y $是标量,可以看成只有 1 个分量;$x $有 4 个分量。因此:
$$
\begin{aligned}
\text{分子布局:}&\quad 1\times4,\
\text{分母布局:}&\quad 4\times1.
\end{aligned}
$$
分子布局:横着排列
分子布局按照
$$
\text{输出分量数}\times\text{输入分量数}
$$
组织偏导数。
这里 $y $只有一个分量,$x$有四个分量,所以结果是 $1\times4$ 的行向量:
$$
\left[
\frac{\partial y}{\partial x}
\right]_{\text{num}}
\begin{bmatrix}
\frac{\partial y}{\partial x_1}&
\frac{\partial y}{\partial x_2}&
\frac{\partial y}{\partial x_3}&
\frac{\partial y}{\partial x_4}
\end{bmatrix}.
$$
代入刚才算出的偏导数:
$$
\left[
\frac{\partial y}{\partial x}
\right]_{\text{num}}
\begin{bmatrix}
4x_1&4x_2&4x_3&4x_4
\end{bmatrix}.
$$
因为 (x) 是列向量,所以
$$
\boxed{
\left[
\frac{\partial y}{\partial x}
\right]_{\text{num}}
=4x^\top
}.
$$
所以,一开始认为答案应该是 $4x^\top$,在分子布局下并没有错。
分母布局:竖着排列
分母布局把同一组偏导数竖着排列:
$$
\left[
\frac{\partial y}{\partial x}
\right]_{\text{den}}
\begin{bmatrix}
\frac{\partial y}{\partial x_1}\
\frac{\partial y}{\partial x_2}\
\frac{\partial y}{\partial x_3}\
\frac{\partial y}{\partial x_4}
\end{bmatrix}.
$$
它也就是通常写成 (\nabla_x y) 的梯度:
$$
\nabla_x y
\begin{bmatrix}
4x_1\
4x_2\
4x_3\
4x_4
\end{bmatrix}.
$$
于是
$$
\boxed{\nabla_x y=4x}.
$$
两种布局可以直接对照:
| 表示方式 | 形状 | 结果 |
|---|---|---|
| 分子布局 | $1\times4$ | $4x^\top$ |
| 分母布局 | $4\times1$ | $4x$ |
它们包含完全相同的四个偏导数,只是排列方向不同。在这个例子中,可以写成:
$$
\nabla_x y
\left(
\left[
\frac{\partial y}{\partial x}
\right]_{\text{num}}
\right)^\top.
$$
这里用“横着排”和“竖着排”来建立直觉,已经足够解释 D2L 的例子。严格来说,雅可比和梯度并不只是同一个东西转置一下;但在本文这个例子中,它们包含同一组偏导数,并且正好互为转置。初学阶段先记住这层关系即可。
为什么 D2L 和 PyTorch 得到的是 $4x$
D2L 原文讨论的是“标量函数关于向量的梯度”,而不是要求以分子布局写出一个行向量。
因此,它把偏导数写成与 (x) 对应的梯度形式:
$$
\nabla_x y=4x.
$$
在代码中:
x = torch.arange(4.0)
所以 $x $的四个分量是:
$$
x_1=0,
\qquad
x_2=1,
\qquad
x_3=2,
\qquad
x_4=3.
$$
代入 $4x$:
$$
4x
\begin{bmatrix}
4\times0\
4\times1\
4\times2\
4\times3
\end{bmatrix}
\begin{bmatrix}
0\
4\
8\
12
\end{bmatrix}.
$$
因此 PyTorch 输出:
tensor([0., 4., 8., 12.])
还可以直接验证它确实等于 4 * x:
x.grad == 4 * x
得到:
tensor([True, True, True, True])
为什么框架把梯度保存成与参数相同的形状
神经网络训练通常会把模型预测和真实答案之间的差异汇总成一个标量损失:
$$
L(\theta)\in\mathbb R,
$$
其中 (\theta) 表示模型的所有参数。训练的目标,就是不断调整 (\theta),让损失 (L) 变小。
为了知道每个参数应该怎样调整,需要计算损失对参数的梯度:
$$
\nabla_\theta L.
$$
梯度中的每个分量,都对应损失对某一个参数的偏导数。它告诉我们:某个参数发生很小的变化时,损失会怎样变化。
最基本的梯度下降更新为:
$$
\theta
\leftarrow
\theta-\eta\nabla_\theta L,
$$
其中 $\eta $是学习率。
这里的$ \theta $和 $\nabla_\theta L $一一对应,所以可以直接进行逐元素更新。
实际模型的参数不一定是一维向量,也可能是权重矩阵或更高维 Tensor。PyTorch 会把每个参数的梯度保存在它的 .grad 属性中,并保持与参数相同的 shape,优化器随后使用这些梯度完成更新。
需要注意,这个顺序不能倒过来理解:不是为了方便更新,才把梯度“规定”成这种形状;而是梯度本来就与输入中的各个分量对应,框架将它保存成与参数相同的 shape,正好便于优化器使用。
一个容易忽略的 PyTorch 细节
数学公式通常把 (x) 写成列向量,但
x = torch.arange(4.0)
在 PyTorch 中的形状其实是:
torch.Size([4])
这里需要特别区分“4 维向量”和“一维 Tensor”中的两个“维”:
- 在数学中,$x\in\mathbb R^4 $表示 $x$有 4 个分量,因此常被称为一个 4 维向量(或 4 元向量);
- 在 PyTorch 中,
x.ndim == 1表示x只有一个轴,因此它是一个 一维 Tensor,这个轴的长度是 4。
可以用代码直接查看:
print(x.numel()) # 4,元素总数
print(x.ndim) # 1,轴的数量
print(x.shape) # torch.Size([4]),唯一一个轴的长度为 4
所以,“4 维向量”说的是向量包含多少个分量,“一维 Tensor”说的是张量有多少个轴。这两个“维”描述的不是同一件事。
这个一维 Tensor 既不是二维的 $1\times4 $行矩阵,也不是 $4\times1 $列矩阵。因此,从 tensor([0., 4., 8., 12.]) 这个显示结果本身,不能判断它是数学意义上的行向量还是列向量。
如果确实需要二维行、列结构,可以显式增加一个轴:
x_row = x.unsqueeze(0) # shape: [1, 4]
x_col = x.unsqueeze(1) # shape: [4, 1]
不过在 D2L 的这个例子里,我们不需要把 x 真的变成二维列矩阵。只需要知道:x.grad 保存的是标量 (y) 关于 x 的梯度,而且与 x 具有相同的 shape。
总结
对于
$$
y=2x^\top x,
$$
逐个分量求导后,我们得到:
$$
\frac{\partial y}{\partial x_i}=4x_i.
$$
这组偏导数可以按照两种形式排列:
$$
\begin{aligned}
\text{分子布局:}&\quad 4x^\top,\
\text{分母布局:}&\quad 4x.
\end{aligned}
$$
所以,$4x^\top$和 $4x$并不是谁对谁错。它们包含相同的偏导数,只是采用了不同的排列方式。D2L 讨论的是梯度,PyTorch 的 x.grad 保存的也是梯度,因此最终写成:
$$
\boxed{\nabla_x y=4x}.
$$
以后再遇到类似的形状问题,可以按三个步骤判断:
- 先把向量拆成分量,确认每个偏导数是多少;
- 再确认资料使用的是分子布局还是分母布局;
- 最后区分数学中的向量维度和程序中的 Tensor shape。
很多看起来互相矛盾的答案,其实并不是求导结果不同,而是数学计算、排列约定和程序表示被混在了一起。把这些层次分开,理解 D2L 中的 $4x$就不需要额外引入更复杂的矩阵微积分了。
参考资料
标题:向量求导为什么有时是行向量,有时是列向量?——分子布局与分母布局
作者:aopstudio
地址:https://neusoftware.top/articles/2026/09/08/1788858491797.html