方向导数和梯度
为什么要了解方向导数和梯度?
学习神经网络的梯度下降时,我们经常会看到一句话:
沿着负梯度方向更新参数,损失函数下降得最快。
这句话很简单,理解起来还是需要有一些前置知识的:为什么梯度是一个向量?为什么它指向上升最快的方向?为什么前面还要学方向导数?
我会从这几个方面进行阐述:
导数 → 偏导数 → 方向导数 → 梯度 → 梯度下降
1. 从普通导数开始:站在曲线上看坡度
先看最熟悉的一元函数:
在某个位置 \(x_0\),导数 \(f'(x_0)\) 描述了函数在这里的瞬时变化率,也就是曲线在这一点的切线斜率:
可以把它理解成:我在 x 轴上向右走一点,函数值会变化多快?
- \(f'(x_0)>0\):向右走时函数值增大,也就是上坡。
- \(f'(x_0)<0\):向右走时函数值减小,也就是下坡。
- \(f'(x_0)=0\):当前位置暂时是平的,但不一定就是最低点。
例如:
在 x=2 这一刻,x 往前走一小步 Δx(很小很小),y 大约往前走 4 × Δx 这么多。
因为 \(x=2\) 时,导数是 4。用极限表示如下:
\(f'(2) = \lim_{\Delta x \to 0} \frac{f(2 + \Delta x) - f(2)}{\Delta x}\)
上边是 \(f(x)\) 在 x=2 这个时刻x增大 \(\Delta x\) 时 \(f(x)\) 增大多少,然后用这个增大值除以 \(\Delta x\) 就可以算出这个倍数,即为导数值。
在 2 附近,x 每增加一个很小的单位,函数值大约增加 4 倍的这个小量。
2. 到了多元函数,麻烦出现了:可以往很多方向走
现在看一个二元函数:
这时,x 和 y 一起决定函数值 z。图像不再是一条曲线,而更像是一张有高有低的地形图。
假设你站在曲面上的某一点,接下来可以:
- 沿 x 轴走;
- 沿 y 轴走;
- 往右上方斜着走;
- 往左下方走;
- 或者朝平面上的任意方向走。
问题来了:不同方向的坡度可能完全不同。
所以,多元函数不能再只用一个普通导数概括所有方向的变化情况。
3. 偏导数:先只看两个特殊方向
偏导数的做法很直接:一次只改变一个变量,其他变量暂时不动。
对 x 求偏导
保持 y 不变,只沿 x 轴方向走:
它表示函数沿 x 轴正方向的变化率。
对 y 求偏导
保持 x 不变,只沿 y 轴方向走:
它表示函数沿 y 轴正方向的变化率。
例如:
分别求偏导:
在点 \((1,1)\):
这表示:
- 沿 x 轴正方向走,函数值的变化率是 2;
- 沿 y 轴正方向走,函数值的变化率是 4。
从这里已经能看出,在这个点附近,函数对 y 的变化比对 x 的变化更加敏感。
但偏导数只检查了坐标轴方向。如果我想沿着右上方走呢?这就需要方向导数。
4. 方向导数:指定一个方向,再问这个方向有多陡
设我们准备沿向量 \(\mathbf v\) 的方向移动:
计算方向导数时,通常先把它变成单位向量:
然后,函数在点 \(\mathbf x\) 处沿单位方向 \(\mathbf u\) 的方向导数定义为:
这个极限可以这样理解:
- 从当前位置 \(\mathbf x\) 出发;
- 沿 \(\mathbf u\) 方向走一小步 \(t\);
- 用“函数值变化量 ÷ 实际移动距离”,得到这个方向的瞬时变化率。
因此,方向导数是一个数,不是一个方向。
- 方向导数大于 0:沿这个方向走会上坡;
- 方向导数小于 0:沿这个方向走会下坡;
- 方向导数等于 0:沿这个方向走,函数值在这一瞬间几乎不变;
- 绝对值越大:这个方向越陡。
5. 梯度:把各坐标方向的偏导数组装成一个向量
对于二元函数 \(f(x,y)\),梯度定义为:
对于 n 元函数:
注意:梯度不是一个导数值,而是一个向量。
它把函数在每个坐标轴方向上的变化情况收集到一起:
- 每个分量的正负,表示沿对应坐标轴往正方向移动时,函数是增大还是减小;
- 每个分量绝对值的大小,表示函数对这个变量有多敏感;
- 所有分量合在一起,形成函数在当前位置的整体变化信息。
还是刚才的函数:
它的梯度为:
在 \((1,1)\) 处:
导数描述函数在某个点附近的瞬时变化率。对于二元函数,梯度把函数沿 x 轴和 y 轴正方向的瞬时变化率组合成一个向量。
对于函数
\(f(x,y)=x^2+2y^2\)
它的梯度为:
\(∇f(x,y)=(2x,4y)\)
在 (1,1) 处:
\(∇f(1,1)=(2,4)\)
其中:
- 第一个分量 2 表示:在 (1,1) 附近,只沿 x 轴正方向移动一个很小的距离时,函数值大约按照变化率 2 增大;
- 第二个分量 4 表示:只沿 y 轴正方向移动一个很小的距离时,函数值大约按照变化率 4 增大;
- 两个分量都是正数,所以梯度箭头指向右上方;
- y 方向的分量 4 是 x 方向分量 2 的两倍,所以箭头向上延伸得更多,看起来更靠近 y 轴。
梯度箭头所指的方向,就是当前位置函数值增长最快的方向。
6. 方向导数和梯度到底是什么关系?
- 梯度:梯度是一个向量,其方向为变化最快的那个方向,其大小就是那个方向的变化率。 梯度方向是函数值上升最快的方向。
- 方向导数回答:“如果我指定往某个方向走,函数值变化得有多快?”
梯度提供当前位置的整体变化信息,方向导数则是从梯度中取出“某个指定方向上的变化率”。
当函数在该点可微时,方向导数可以直接写成:
也就是:方向导数 = 梯度与单位方向向量的点积。
根据点积公式:
因为 \(\mathbf u\) 是单位向量,所以 \(\lVert\mathbf u\rVert=1\):
这里的 \(\theta\) 是梯度与行走方向之间的夹角。
这条公式是理解梯度的关键。
| 夹角 | cos 值 | 方向导数 | 直观含义 |
|---|---|---|---|
| \(\theta=0^\circ\) | 1 | 最大 | 与梯度同向,上升最快 |
| \(\theta=90^\circ\) | 0 | 0 | 沿等高线走,高度暂时不变 |
| \(\theta=180^\circ\) | -1 | 最小 | 与梯度反向,下降最快 |
所以:
- 梯度方向,是函数值上升最快的方向;
- 负梯度方向,是函数值下降最快的方向;
- 梯度的模长,是最大的方向导数,也就是最陡上坡的坡度。
这不是一个需要死记的结论,而是由点积里的 \(\cos\theta\) 直接决定的:\(\cos\theta\) 最大只能是 1,此时两个方向完全相同。
7. 算一个完整例子
仍然使用:
在 \((1,1)\) 处,梯度为:
现在沿方向 \(\mathbf v=(3,4)\) 行走。它的长度是 5,所以单位方向为:
方向导数为:
也就是说,在 \((1,1)\) 附近沿这个方向每前进一个很小的单位,函数值大约增加 4.4 个单位。
那么上升最快的方向是什么?
就是梯度本身的方向。把梯度单位化:
沿这个方向的最大变化率为:
可以看到,4.472 的确比刚才方向上的 4.4 更大。沿负梯度方向时,方向导数则是 \(-\sqrt{20}\),函数下降最快。
8. 从等高线再看一次:为什么梯度垂直于等高线?
地图上的等高线表示“高度相同的点”。对于函数来说,等高线上的函数值保持不变。
如果沿等高线方向移动,瞬间的高度变化率为 0,因此:
两个向量点积为 0,说明它们互相垂直。
所以,梯度总是垂直于当前位置的等高线,并指向函数值增大的一侧。
直观地说:
- 沿等高线绕着山走,高度暂时不变;
- 垂直穿过等高线,才会最快改变高度;
- 梯度选择的是其中上坡的一边,负梯度选择的是下坡的一边。
9. 梯度下降:把“最快下坡”变成算法
假设函数 \(C(\boldsymbol\theta)\) 是我们想要减小的损失函数,其中 \(\boldsymbol\theta\) 表示全部参数。
梯度下降的更新公式是:
可以把它拆成三步:
- 计算当前参数位置的梯度;
- 取梯度的反方向;
- 沿这个方向走一小步,再重复。
其中 \(\eta\) 是学习率,它控制每一步走多远。
一个小例子
设损失函数为:
这个函数的最低点显然是 \((3,-1)\)。假设从 \((0,0)\) 出发:
所以:
若学习率 \(\eta=0.1\),更新一次:
更新前的损失:
更新后的损失:
损失确实降低了。不断重复,就会逐渐靠近最低点 \((3,-1)\)。
10. 为什么学习率不能太大,也不能太小?
负梯度只告诉我们“该往哪边走”,学习率决定“每步迈多大”。
- 学习率太小:方向可能没错,但走得非常慢;
- 学习率太大:可能一步跨过谷底,在两侧来回震荡,甚至越走越远;
- 学习率合适:前期快速下降,靠近低点后逐渐稳定。
需要特别注意:梯度下降通常只能保证不断寻找更低的位置,不能简单理解为“一定找到全局最低点”。初始位置、学习率、局部极小值、鞍点和平坦区域都会影响训练过程。
11. 回到神经网络:参数空间其实是一座高维大山
在我第一个章节提到的手写数字识别示例中,神经网络共有 13,002 个权重和偏置。我们可以把它们排成一个很长的参数向量:
损失函数接收这 13,002 个参数,最后只输出一个数:
损失越大,说明模型预测得越差;损失越小,说明预测结果越接近正确答案。
此时,梯度也有 13,002 个分量:
每个分量都在回答一个很具体的问题:
如果把对应的权重或偏置轻轻改变一点,损失会发生多大变化?
- 分量的正负告诉我们参数应该增大还是减小;
- 分量绝对值越大,说明损失对这个参数越敏感;
- 整个负梯度向量,则给出让所有参数共同配合、使损失下降最快的一组调整方向。
因此,所谓神经网络“学习”,从数学上看就是不断执行:
而反向传播解决的是另一个问题:怎样高效计算损失函数对所有权重和偏置的梯度。
12. 几个注意点
| 概念 | 结果是什么 | 它回答的问题 |
|---|---|---|
| 导数 | 一个数 | 一元函数在这里有多陡? |
| 偏导数 | 一个数 | 只改变某一个变量时,函数变化多快? |
| 方向导数 | 一个数 | 沿指定方向走时,函数变化多快? |
| 梯度 | 一个向量 | 哪个方向上升最快,各变量有多敏感? |
| 负梯度 | 一个向量 | 哪个方向下降最快? |
误区一:梯度就是斜率
不完全对。斜率通常是一个数,梯度是一个向量。梯度的方向表示最陡上坡方向,梯度的长度表示这个方向有多陡。
误区二:偏导数和方向导数互不相关
偏导数其实是方向导数的特殊情况:它只选择了坐标轴方向。
误区三:方向向量不需要单位化
如果只是代入点积计算,未单位化也能得到数值,但它混入了向量长度的影响。若要把结果解释为“每单位距离的变化率”,必须使用单位方向。
误区四:负梯度永远能一步到达最低点
负梯度只提供当前位置的局部最陡下降方向。函数弯曲后,下一步的方向也会变化,所以需要走一小步、重新计算,再继续走。
13. 总结
导数描述一条路上的坡度;偏导数描述坐标轴方向的坡度;方向导数描述任意指定方向的坡度;梯度把所有局部变化信息整理成一根“最陡上坡箭头”;沿着它的反方向走,就是梯度下降。
理解到这里,再看神经网络中的损失函数、梯度下降和反向传播,就不会只剩下一堆孤立公式了:模型训练,本质上是在一个我们无法画出来的高维地形中,一步一步寻找更低的位置。