momentum.md 8.2 KB
Newer Older
A
rename  
Aston Zhang 已提交
1
# 动量法
2

M
muli 已提交
3
(小批量)随机梯度修改了梯度下降中计算梯度的方式,它使用更少的样本来计算梯度。这一节我们将介绍动量法,它改变了如何使用梯度来更新自变量。在[“梯度下降和随机梯度下降”](./gd-sgd.md)一节中我们介绍了目标函数有关自变量的梯度代表了目标函数在当前点下降最快的方向。在每次迭代中,梯度下降算法根据自变量当前所在位置,沿着当前位置的梯度更新自变量。因此梯度下降也叫做最陡下降(steepest descent)。但自变量的迭代方向仅仅取决于自变量当前位置,这可能会带来一些问题。
4 5 6

## 梯度下降的问题

M
muli 已提交
7
让我们考虑一个输入和输出分别为二维向量$\boldsymbol{x} = [x_1, x_2]^\top$和标量的目标函数$f(\boldsymbol{x})=0.1x_1^2+2x_2$。跟[“梯度下降和随机梯度下降”](./gd-sgd.md)一节中不同的在于我们将$x_1^2$系数从$1$减小到了$0.1$。然后观察梯度下降优化该目标函数的迭代过程。先导入实验所需的包或模块。
A
Aston Zhang 已提交
8

M
muli 已提交
9
```{.python .input  n=2}
M
muli 已提交
10 11
import sys
sys.path.insert(0, '..')
12

M
muli 已提交
13 14
%matplotlib inline
import gluonbook as gb
M
muli 已提交
15
from mxnet import nd
M
muli 已提交
16 17
```

M
muli 已提交
18
下面实现基于这个目标函数的梯度下降,并演示使用学习率为$0.4$时自变量的迭代轨迹。
M
muli 已提交
19

M
muli 已提交
20
```{.python .input  n=3}
M
muli 已提交
21
eta = 0.4
A
Aston Zhang 已提交
22 23 24 25 26 27 28

def f_2d(x1, x2):
    return 0.1 * x1 ** 2 + 2 * x2 ** 2

def gd_2d(x1, x2, s1, s2):
    return (x1 - eta * 0.2 * x1, x2 - eta * 4 * x2, 0, 0)

M
muli 已提交
29
gb.show_trace_2d(f_2d, gb.train_2d(gd_2d))
A
Aston Zhang 已提交
30 31
```

M
muli 已提交
32
可以看到,同一位置上,目标函数在竖直方向($x_2$轴方向)比在水平方向($x_1$轴方向)的斜率的绝对值更大。因此,给定学习率,梯度下降迭代自变量时会使自变量在竖直方向比在水平方向移动幅度更大。因此,我们需要一个较小的学习率从而避免自变量在竖直方向上越过目标函数最优解。然而,这造成了图中自变量在水平方向上朝最优解移动较慢。
A
Aston Zhang 已提交
33

M
muli 已提交
34
下面我们试着将学习率调的稍大一点,此时自变量在竖直方向不断越过最优解并逐渐发散。
A
Aston Zhang 已提交
35 36

```{.python .input  n=4}
M
muli 已提交
37 38
eta = 0.6
gb.show_trace_2d(f_2d, gb.train_2d(gd_2d))
A
Aston Zhang 已提交
39 40
```

41 42
## 动量法

M
muli 已提交
43
动量法的提出是为了应对梯度下降的上述问题。在时间步$0$,动量法创建速度变量$\boldsymbol{v}_0\in\mathbb{R}^d$,并将其元素初始化成0。在时间步$t>0$,动量法对每次迭代的步骤做如下修改:
44

A
Aston Zhang 已提交
45
$$
A
aligned  
Aston Zhang 已提交
46
\begin{aligned}
M
muli 已提交
47 48
\boldsymbol{v}_t &\leftarrow \gamma \boldsymbol{v}_{t-1} + \eta_t \boldsymbol{g}_t \\
\boldsymbol{x}_t &\leftarrow \boldsymbol{x}_{t-1} - \boldsymbol{v}_t,
A
aligned  
Aston Zhang 已提交
49
\end{aligned}
A
Aston Zhang 已提交
50
$$
51

M
muli 已提交
52
其中,动量超参数$\gamma$满足$0 \leq \gamma < 1$。当$\gamma=0$时,动量法等价于小批量随机梯度下降。动量法中的学习率$\eta_t$和梯度$\boldsymbol{g_t}$已在[“小批量随机梯度下降”](minibatch-sgd.md)一节中描述。
M
muli 已提交
53

M
muli 已提交
54
在解释动量法的数学原理前,让我们先从实验中观察梯度下降在使用动量法后的迭代过程。
M
muli 已提交
55

M
muli 已提交
56 57 58 59 60
```{.python .input  n=5}
def momentum_2d(x1, x2, v1, v2):
    v1 = mom * v1 + eta * 0.2 * x1
    v2 = mom * v2 + eta * 4 * x2
    return x1 - v1, x2 - v2, v1, v2
M
muli 已提交
61 62 63 64 65 66 67

eta, mom = 0.4, 0.5
gb.show_trace_2d(f_2d, gb.train_2d(momentum_2d))
```

可以看到使用较小的学习率$\eta=0.4$和动量超参数$\gamma=0.5$时,动量法在竖直方向上的移动更加平滑,且在水平方向上更快逼近最优解。我们还发现,使用较大的学习率$\eta=0.6$时,自变量也不再发散。

M
muli 已提交
68 69
```{.python .input  n=11}
eta = 0.6
M
muli 已提交
70
gb.show_trace_2d(f_2d, gb.train_2d(momentum_2d))
A
Aston Zhang 已提交
71 72
```

A
Aston Zhang 已提交
73
### 指数加权移动平均
74

M
muli 已提交
75
为了从数学上理解动量法,让我们先解释指数加权移动平均(exponentially weighted moving average)。给定超参数$\gamma$且$0 \leq \gamma < 1$,当前时刻$t$的变量$y_t$是上一时刻$t-1$的变量$y_{t-1}$和当前时刻另一变量$x_t$的线性组合:
76

M
muli 已提交
77
$$y_t = \gamma y_{t-1} + (1-\gamma) x_t.$$
78

M
muli 已提交
79
我们可以对$y_t$展开:
80

A
Aston Zhang 已提交
81
$$
A
aligned  
Aston Zhang 已提交
82
\begin{aligned}
M
muli 已提交
83 84 85
y_t  &= (1-\gamma) x_t + \gamma y_{t-1}\\
         &= (1-\gamma)x_t + (1-\gamma) \cdot \gamma x_{t-1} + \gamma^2y_{t-2}\\
         &= (1-\gamma)x_t + (1-\gamma) \cdot \gamma x_{t-1} + (1-\gamma) \cdot \gamma^2x_{t-2} + \gamma^3y_{t-3}\\
A
Aston Zhang 已提交
86
         &\ldots
A
aligned  
Aston Zhang 已提交
87
\end{aligned}
A
Aston Zhang 已提交
88
$$
89

A
Aston Zhang 已提交
90 91
由于

M
muli 已提交
92
$$ \lim_{n \rightarrow \infty}  \left(1-\frac{1}{n}\right)^n = \exp(-1) \approx 0.3679,$$
A
Aston Zhang 已提交
93

M
muli 已提交
94
令$n = 1/(1-\gamma)$,那么有 $\left(1-1/n\right)^n = \gamma^{1/(1-\gamma)}$。所以当$\gamma \rightarrow 1$时,$\gamma^{1/(1-\gamma)}=\exp(-1)$。例如$0.95^{20} = 0.358 \approx \exp(-1)$。如果把$\exp(-1)$当做一个比较小的数,我们可以在近似中忽略所有含$\gamma^{1/(1-\gamma)}$和比$\gamma^{1/(1-\gamma)}$更高阶的系数的项。例如,当$\gamma=0.95$时,
A
Aston Zhang 已提交
95

M
muli 已提交
96
$$y_t \approx 0.05 \sum_{i=0}^{19} 0.95^i x_{t-i}.$$
A
Aston Zhang 已提交
97

M
muli 已提交
98
因此,在实际中,我们常常将$y$看作是对最近$1/(1-\gamma)$个时刻的$x$值的加权平均。例如,当$\gamma = 0.95$时,$y$可以被看作是对最近20个时刻的$x$值的加权平均;当$\gamma = 0.9$时,$y$可以看作是对最近10个时刻的$x$值的加权平均。且离当前时刻越近的$x$值获得的权重越大(越接近1)。
A
Aston Zhang 已提交
99 100 101 102 103 104


### 由指数加权移动平均理解动量法

现在,我们对动量法的速度变量做变形:

M
muli 已提交
105
$$\boldsymbol{v}_t \leftarrow \gamma \boldsymbol{v}_{t-1} + (1 - \gamma) \left(\frac{\eta_t}{1 - \gamma} \boldsymbol{g}_t\right). $$
A
Aston Zhang 已提交
106

M
muli 已提交
107
由指数加权移动平均的形式可得,速度变量$\boldsymbol{v}_t$实际上对序列$\{\eta_{t-i}\boldsymbol{g}_{t-i} /(1-\gamma):i=0,\ldots,1/(1-\gamma)-1\}$做了指数加权移动平均。换句话说,相比于小批量随机梯度下降,动量法在每个时间步的自变量更新量近似于将前者对应的最近$1/(1-\gamma)$个时间步的更新量做了指数加权移动平均后再除以$1-\gamma$。所以动量法中,自变量在各个方向上的移动幅度不仅取决当前梯度,还取决过去各个梯度在各个方向上是否一致。在本节之前示例的优化问题中,由于所有梯度在水平方向上为正(向右)、而在竖直方向上时正(向上)时负(向下),自变量在水平方向的移动幅度逐渐增大,而在竖直方向的移动幅度逐渐减小。这样,我们就可以使用较大的学习率,从而使自变量向最优解更快移动。
A
Aston Zhang 已提交
108

109

M
muli 已提交
110
## 从零开始实现
A
Aston Zhang 已提交
111

M
muli 已提交
112
相对于随机梯度下降,动量法需要对每个自变量维护同它一样形状的状态变量$\boldsymbol{v}$,且超参数里多了动量超参数。
113

M
muli 已提交
114
```{.python .input  n=13}
M
muli 已提交
115 116 117 118 119 120 121 122 123 124 125 126
features, labels = gb.get_data_ch7()

def init_momentum_states():
    v_w = nd.zeros((features.shape[1], 1))
    v_b = nd.zeros(1)
    return (v_w, v_b)

def sgd_momentum(params, states, hyperparams):
    hp = hyperparams 
    for p, v in zip(params, states):
        v[:] = hp['mom'] * v + hp['lr'] * p.grad
        p[:] -= v
A
Aston Zhang 已提交
127 128
```

M
muli 已提交
129
我们先将动量超参数`mom`设0.5,这时可以看成是使用最近2个时刻的$2\nabla f_\mathcal{B}(\boldsymbol{x})$的加权平均作为梯度的随机梯度下降,因此我们需要对应调下学习率(从上节的0.5减小到了0.02)。
A
Aston Zhang 已提交
130

M
muli 已提交
131
```{.python .input  n=15}
A
Aston Zhang 已提交
132 133
gb.train_ch7(sgd_momentum, init_momentum_states(),  {'lr': 0.02, 'mom': 0.5},
             features, labels)
134 135
```

M
muli 已提交
136
将动量超参数`mom`增大到了0.9时,这个特殊梯度是最近10个时刻的$10\nabla f_\mathcal{B}(\boldsymbol{x})$的加权平均。因此我们需要进一步调低学习率。
A
Aston Zhang 已提交
137

M
muli 已提交
138
```{.python .input  n=8}
A
Aston Zhang 已提交
139 140
gb.train_ch7(sgd_momentum, init_momentum_states(), {'lr': 0.004, 'mom': 0.9},
             features, labels)
A
Aston Zhang 已提交
141 142
```

A
Aston Zhang 已提交
143 144
## 使用Gluon的实现

M
muli 已提交
145
在Gluon中,只需要在随机梯度下降的训练器中通过`momentum`来指定动量超参数即可得到动量法。
A
Aston Zhang 已提交
146

M
muli 已提交
147
```{.python .input  n=9}
A
Aston Zhang 已提交
148 149
gb.train_gluon_ch7('sgd', {'learning_rate': 0.02, 'momentum': 0.5}, features,
                   labels)
A
Aston Zhang 已提交
150 151
```

A
Aston Zhang 已提交
152
## 小结
153

M
muli 已提交
154 155
* 动量法使用了指数加权移动平均的思想,其将过去时刻的梯度做了加权平均,且权重按时间指数衰减。
* 动量法使得相邻时间步之间的自变量更新在方向更加一致。
156 157 158

## 练习

A
Aston Zhang 已提交
159 160
* 使用其他动量超参数和学习率的组合,观察实验结果。

161

A
Aston Zhang 已提交
162
## 扫码直达[讨论区](https://discuss.gluon.ai/t/topic/1879)
A
Aston Zhang 已提交
163 164


A
Aston Zhang 已提交
165
![](../img/qr_momentum.svg)