未验证 提交 e4bd70f3 编写于 作者: 飞龙 提交者: GitHub

Merge pull request #81 from rickllyxu/dev

校对了Chapter16,翻译了附录CD
此差异已折叠。
# Appendix C. SVM 对偶问题
为了理解对偶性,你首先得理解拉格朗日乘子法。它基本思想是将一个有约束优化问题转化为一个无约束优化问题,其方法是将约束条件移动到目标函数中去。让我们看一个简单的例子,例如要找到合适的 $x$ 和 $y$ 使得函数 $f(x, y) = x^2 + 2y$ 最小化,且其约束条件是一个等式约束:$3x + 2y + 1 = 0$。 使用拉格朗日乘子法,我们首先定义一个函数,称为**拉格朗日函数**:$g(x, y, \alpha) = f(x, y) - \alpha(3x + 2y + 1)$. 每个约束条件(在这个例子中只有一个)与新的变量(称为拉格朗日乘数)相乘,作为原目标函数的减数。
Joseph-Louis Lagrange 大牛证明了如果 $(\bar{x}, \bar{y})$ 是原约束优化问题的解,那么一定存在一个 $\bar{\alpha}$ ,使得 $(\bar{x}, \bar{y}, \bar{\alpha})$ 是拉格朗日函数的不动点(不动点指的是,在该点处,该函数所有的偏导数均为0)。换句话说,我们可以计算拉格朗日函数 $g(x, y, \alpha) $ 关于 $x, y$ 以及 $\alpha$ 的偏导数;然后我们可以找到那些偏导数均为0的不动点;最后原约束优化问题的解(如果存在)一定在这些不动点里面。
在上述例子里,偏导数为
$\begin{align}\frac{\partial}{\partial x}g(x, y, \alpha) = 2x - 3\alpha \\ \frac{\partial}{\partial y}g(x, y, \alpha) = 2 - 2\alpha \\ \frac{\partial}{\partial \alpha}g(x, y, \alpha) = -3x - 2y - 1 \end{align}$
当这些偏导数均为0时,即 2x − 3α = 2 − 2α = − 3x − 2y − 1 = 0,即可得 $x = \frac{3}{2}, y=-\frac{11}{4}, \alpha=1$. 这是唯一一个不动点,那它一定是原约束优化问题的解。然而,上述方法仅应用于等式约束,幸运的是,在某些正则性条件下,这种方法也可被一般化应用于不等式约束条件(例如不等式约束,$3x + 2y + 1 \geq 0$)。如下公式 C-1 ,给了SVM硬间隔问题时的一般化拉格朗日函数。在该公式中,$\alpha^{(i)}$ 是 KKT 乘子,它必须大于或等于0. (译者注:$\alpha^{(i)}$ 是 $\geq0$ 抑或 $\leq0$ 取决于拉格朗日函数的写法,以及原目标函数函数最大化抑或最小化)
![公式C-1](../images/Appendix/E_C-1.png)
就像拉格朗日乘子法,我们可以计算上述式子的偏导数、定位不动点。如果该原问题存在一个解,那它一定在不动点$(\bar{w}, \bar{b}, \bar{\alpha})$之中,且遵循 KKT 条件:
- 遵循原问题的约束: $t^{(i)}((\bar{w})^T x^{(i)} +\bar{b}) \geq 1$, 对于 $i = 1, 2, ..., m$
- 遵循现问题里的约束,即 $\bar{\alpha}^{(i)} \geq 0$
- $\bar{\alpha}^{(i)} = 0$ 或者第`i`个约束条件是积极约束,意味着该等式成立:$t^{(i)}((\bar{w})^T x^{(i)} +\bar{b}) = 1$. 这个条件叫做 互补松弛 条件。它暗示了 $\bar{\alpha}^{(i)} = 0$ 和第`i`个样本位于SVM间隔的边界上(该样本是支撑向量)。
注意 KKT 条件是确定不动点是否为原问题解的必要条件。在某些条件下,KKT 条件也是充分条件。幸运的是,SVM 优化问题碰巧满足这些条件,所以任何满足 KKT 条件的不动点保证是原问题的解。
我们可以计算上述一般化拉格朗日函数关于`w``b`的偏导数,如 公式C-2.
![公式C-2](../images/Appendix/E_C-2.png)
令上述偏导数为0, 可得到公式C-3.
![公式C-3](../images/Appendix/E_C-3.png)
如果我们把上述式子代入到一般化拉格朗日函数(公式C-1)中,某些项会消失,从而得到公式C-4,并称之为原问题的对偶形式。
![公式C-4](../images/Appendix/E_C-4.png)
现在该对偶形式的目标是找到合适的向量 $\bar{\alpha}$ , 使得该函数 $L(w, b, \alpha)$ 最小化,且 $\bar{\alpha}^{(i)} \geq 0$. 现在这个有约束优化问题正是我们苦苦追寻的对偶问题。
一旦你找到了最优的 $\bar{\alpha}$, 你可以利用公式C-3第一行计算 $\bar{w}$。为了计算 $\bar{b}$, 你可以使用支撑向量的已知条件 $t^{(i)}((\bar{w})^T x^{(i)} +\bar{b}) = 1$, 当第 k 个样本是支撑向量时(即它对应的 $\alpha_k > 0$,此时使用它计算 $\bar{b} =1-t^{(k)}((\bar{w})^T . x^{(k)}) $. 对了,我们更喜欢利用所有支撑向量计算一个平均值,以获得更稳定和更准确的结果,如公式C-5.
![公式C-5](../images/Appendix/E_C-5.png)
# Appendix D 自动微分
这个附录解释了 TensorFlow 的自动微分功能是如何工作的,以及它与其他解决方案的对比。
假定你定义了函数 $f(x, y) = x^2y + y + 2$, 需要得到它的偏导数 $\frac{\partial f}{\partial x}$和 $\frac{\partial f}{\partial y}$,以用于梯度下降或者其他优化算法。你的可选方案有手动微分法,符号微分法,数值微分法,前向自动微分,和反向自动微分。TensorFlow实现的反向自动微分法。我们来看看每种方案。
## 手动微分法
第一个方法是拿起一直笔和一张纸,使用你的代数知识去手动的求偏导数。对于已定义的函数,求它的偏导并不太困难。你需要使用如下5条规则:
- 常数的导数为0.
- $\lambda x$ 的导数为 $\lambda$ , $\lambda$为常数。
- $x^{\lambda}$ 的导数是 $\lambda x^{\lambda - 1}$
- 函数的和的导数,等于函数的导数的和
- $\lambda$ 乘以函数,再求导,等于 $\lambda$ 乘以函数的导数
从上述这些规则,可得到公式D-1.
![公式D-1](../images/Appendix/E_D-1.png)
这个种方法应用于更复杂函数时将变得非常罗嗦,并且有可能出错。好消息是,像刚才我们做的求数学式子的偏导数可以被自动化,通过一个称为符号微分的过程。
## 符号微分
图D-1展示了符号微分是如何运行在相当简单的函数上的,$g(x,y) = 5 + xy$. 该函数的计算图如图的左边所示。通过符号微分,我们可得到图的右部分,它代表了 $\frac{\partial g}{\partial x} = 0 + (0 \times x + y \times 1) = y$, 相似地也可得到关于`y`的导数。
![D-1](../images/Appendix/D-1.png)
概算法先获得叶子结点的偏导数。常数5返回常数0, 因为常数的导数总是0。变量`x`返回常数1,变量`y`返回常数0因为 $\frac{\partial y}{\partial x} = 0$(如果我们找关于`y`的偏导数,那它将反过来)。
现在我们移动到计算图的相乘结点处,代数告诉我们,`u``v`相乘后的导数为 $\frac{\partial (u \times v)}{\partial x} = \frac{\partial v}{\partial x} \times u + \frac{\partial u}{\partial x} \times v $. 因此我们可以构造有图中大的部分,代表0 × x + y × 1.
最后我们往上走到计算图的相加结点处,正如5条规则里提到的,和的导数等于导数的和。所以我们只需要创建一个相加结点,连接我们已经计算出来的部分。我们可以得到正确的偏导数,即:$\frac{\partial g}{\partial x} = 0 + (0 \times x + y \times 1) $.
然而,这个过程可简化。对该图应用一些微不足道的剪枝步骤,可以去掉所有不必要的操作,然后我们可以得到一个小得多的只有一个结点的偏导计算图:$\frac{\partial g}{\partial x} = y$.
在这个例子里,简化操作是相当简单的,但对更复杂的函数来说,符号微分会产生一个巨大的计算图,该图可能很难去简化,以导致次优的性能。更重要的是,符号微分不能处理由任意代码定义的函数,例如,如下已在第9章讨论过的函数:
```python
def my_func(a, b):
z = 0
for i in range(100):
z = a * np.cos(z + i) + z * np.sin(b - i)
return z
```
## 数值微分
从数值上说,最简单的方案是去计算导数的近似值。回忆`h(x)`在 $x_0$ 的导数 $h^{'}(x_0)$,是该函数在该点处的斜率,或者更准确如公式D-2所示。
![E_D-2](../images/Appendix/E_D-2.png)
因此如果我们想要计算 $f(x,y)$ 关于`x`,在 $x=3, y=4$ 处的导数,我们可以简单计算 $f(3+\epsilon, 4) - f(3, 4)$ 的值,将这个结果除以 $\epsilon$, 且 $\epsilon$ 去很小的值。这个过程正是如下的代码所要干的。
```python
def f(x, y):
return x**2*y + y + 2
def derivative(f, x, y, x_eps, y_eps):
return (f(x + x_eps, y + y_eps) - f(x, y)) / (x_eps + y_eps)
df_dx = derivative(f, 3, 4, 0.00001, 0)
df_dy = derivative(f, 3, 4, 0, 0.00001)
```
不幸的是,偏导的结果并不准确(并且可能在求解复杂函数时更糟糕)。上述正确答案分别是 24 和 10 ,但我们得到的是:
```python
>>> print(df_dx)
24.000039999805264
>>> print(df_dy)
10.000000000331966
```
注意到为了计算两个偏导数, 我们不得不调用`f()`至少三次(在上述代码里我们调用了四次,但可以优化)。如果存在 1000 个参数,我们将会调用`f()`至少 1001 次。当处理大的神经网络时,这样的操作很没有效率。
然而,数值微分实现起来如此简单,以至于它是检查其他方法正确性的优秀工具。例如,如果它的结果与您手动计算的导数不同,那么你的导数可能包含错误。
## 前向自动微分
前向自动微分既不是数值微分,也不是符号微分,但在某些方面,它是他们爱的小孩儿。它依赖对偶数。对偶数是奇怪但迷人的,是 $a + b\epsilon$ 形式的数,这里 `a``b` 是实数,$\epsilon$ 是无穷小的数,满足 $\epsilon ^ 2 = 0$, 但 $\epsilon \ne 0$. 你可以认为对偶数 $42 + 24\epsilon$ 类似于有着无穷个0的42.0000⋯000024(但当然这是简化后的,仅仅给你对偶数什么的想法)。一个对偶数在内存中表示为一个浮点数对,例如,$42 + 24\epsilon$ 表示为 (42.0, 24.0)。
对偶数可相加、相乘、等等操作,正如公式D-3所示。
![E_D-3](../images/Appendix/E_D-3.png)
最重要的,可证明 h(a + bϵ) = h(a) + b × h′(a)ϵ,所以计算一次 h(a + ϵ) 就得到了两个值 h(a) 和 h′(a) 。图D-2展示了前向自动微分如何计算 $f(x,y)=x^2y + y + 2$ 关于`x`,在 $x=3, y=4$ 处的导数的。我们所要做的一切只是计算 $f(3+\epsilon, 4)$; 它将输出一个对偶数,其第一部分等于 $f(3, 4)$, 第二部分等于 $f^{'}(3, 4) = \frac{\partial f}{\partial x} (3,4)$.
![D-2](../images/Appendix/D-2.png)
为了计算 $\frac{\partial f}{\partial y} (3,4)$ 我们不得不再历经一遍计算图,但这次前馈的值为 $x=3, y = 4 + \epsilon$.
所以前向自动微分比数值微分准确得多,但它遭受同样的缺陷:如果有1000个参数,那为了计算所有的偏导数,得历经计算图 1000 次。这正是反向自动微分耀眼的地方:计算所有的偏导数,它只需要经历计算图2次。
## 反向自动微分
反向自动微分是 TensorFlow 采取的方案。它首先前馈经历计算图(即,从输入到输出),计算出每个结点的值。然后进行第二次经历,这次是反向经历(即,从输出到输入),计算出所有的偏导数。图D-3展示了第二次经历的过程。在第一次经历过程中,所有结点值已被计算,输入是 $x=3, y=4$。你可以在每个结点底部右方看到这些值(例如,$x \times x = 9$)。结点已被标号,从 $n_1$ 到 $n_7$。输出结点是 $n_7: f(3, 4) = n_7 = 42$.
![D-3](../images/Appendix/D-3.png)
这个计算关于每个连续结点的偏导数的思想逐渐地从上到下遍历图,直到到达变量结点。为实现这个,反向自动微分强烈依赖于链式法则,如公式D-4所示。
![E_D-4](../images/Appendix/E_D-4.png)
由于 $n_7$ 是输出结点,即 $f= n_7$, 所以 $\frac{\partial f}{\partial n_7} = 1$.
接着到了图的 $n_5$ 结点:当 $n_5$ 变化时,$f$ 会变化多少?答案是 $\frac{\partial f}{\partial n_5} = \frac{\partial f}{\partial n_7} \times \frac{\partial n_7}{\partial n_5}$. 我们已经知道 $\frac{\partial f}{\partial n_7} = 1$, 因此我们只需要知道 $\frac{\partial n_7}{\partial n_5}$ 就行。因为 $n_7$ 是 $n_5 + n_6$ 的和,因此可得到 $\frac{\partial n_7}{\partial n_5} = 1$, 因此 $\frac{\partial f}{\partial n_5}=1 \times 1 = 1$.
现在前进到 $n_4$: 当 $n_4$ 变化时,$f$ 会变化多少?答案是 $\frac{\partial f}{\partial n_4} = \frac{\partial f}{\partial n_5} \times \frac{\partial n_5}{\partial n_4}$. 由于 $n_5 = n_4 \times n_2$, 我们可得到 $\frac{\partial n_5}{\partial n_4} = n_2$, 所以 $\frac{\partial f}{\partial n_4}= 1 \times n_2 = 4$.
这个遍历过程一直持续,此时我们达到图的底部。这时我们已经得到了所有偏导数在点 $x=3, y=4$ 处的值。在这个例子里,我们得到 $\frac{\partial f}{\partial x} = 24, \frac{\partial f}{\partial y} = 10$. 听起来很美妙!
反向自动微分是非常强大且准确的技术,尤其是当有很多输入参数和极少输出时,因为它只要求一次前馈传递加上一次反向传递,就可计算所有输出关于所有输入的偏导数。最重要的是,它可以处理任意代码定义的函数。它也可以处理那些不完全可微的函数,只要 你要求他计算的偏导数在该点处是可微的。
如果你在 TensorFlow 中实现了新算子,你想使它与现有的自动微分相兼容,那你需要提供函数,该函数用于构建一个子图,来计算关于新算子输入的偏导数。例如,假设你实现了一个计算其输入的平方的函数,平方算子 $f(x)= x ^2$,在这个例子中你需要提供相应的导函数 $f^{'}(x)= 2x $. 注意这个导函数不计算一个数值结果,而是用于构建子图,该子图后续将计算偏导结果。这是非常有用的,因为这意味着你可以计算梯度的梯度(为了计算二阶导数,或者甚至更高维的导数)。
\ No newline at end of file
images/chapter_16/16-8.png

72.7 KB | W: | H:

images/chapter_16/16-8.png

162.9 KB | W: | H:

images/chapter_16/16-8.png
images/chapter_16/16-8.png
images/chapter_16/16-8.png
images/chapter_16/16-8.png
  • 2-up
  • Swipe
  • Onion skin
images/chapter_16/E16-1.png

8.0 KB | W: | H:

images/chapter_16/E16-1.png

56.5 KB | W: | H:

images/chapter_16/E16-1.png
images/chapter_16/E16-1.png
images/chapter_16/E16-1.png
images/chapter_16/E16-1.png
  • 2-up
  • Swipe
  • Onion skin
images/chapter_16/E16-2.png

7.5 KB | W: | H:

images/chapter_16/E16-2.png

52.2 KB | W: | H:

images/chapter_16/E16-2.png
images/chapter_16/E16-2.png
images/chapter_16/E16-2.png
images/chapter_16/E16-2.png
  • 2-up
  • Swipe
  • Onion skin
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册