Adam优化算法理解与实现
Adam优化算法理解与实现
Adam优化算法是深度学习中常用的优化算法之一,它结合了动量梯度下降法和RMSprop的优点,能够自适应地调整每个参数的学习率。本文将从理论到实践,详细讲解Adam优化算法的原理和实现方法。
引入
在使用深度学习框架时,Adam优化器的出现频率非常高。那么,Adam优化算法究竟是什么?它为什么如此受欢迎?本文将为你解答这些问题。
1 Adam介绍
Adam优化算法是目前最流行的优化算法之一,它结合了动量梯度下降法(Momentum)和RMSprop的优点。Adam算法通过自适应地调整每个参数的学习率,使得优化过程更加高效。
Adam算法的更新过程如下:
$$
\begin{aligned}
v_t & = \beta_1 v_{t - 1} + (1 + \beta_1)grad_t\
s_t & = \beta_2 s_{t - 1} + (1 - \beta_2)grad_t^2
\end{aligned}
$$
这里$v$和$s$是不同的动量,前者用于记录上一次的梯度,后者则保留RMSprop的特长。
$v$和$s$的偏导计算如下:
$$
\begin{aligned}
v_t' & = \frac{v_t}{1 - \beta_1^t}\
s_t' & = \frac{s_t}{1-\beta_2^t}
\end{aligned}
$$
最终的更新如下:
$$
\begin{aligned}
grad_t' & = \frac{lr * v_t'}{\sqrt{s_t'} + \epsilon}\
\theta_t & = \theta_{t - 1} - grad_t'
\end{aligned}
$$
2 具体实现
为了更好地理解Adam优化算法,我们通过一个具体的线性回归例子来展示其实现过程。假设我们有一个线性函数$f(x) = ax + b$,我们的目标是通过最小化损失函数来找到最优的$a$和$b$。
损失函数定义为:
$$
\begin{aligned}
f(x) &= a x+b \
(y-f(x))^{2} & =(y-(a x+b))^{2} \
\frac{d y}{d a} &=-2 x(y-(a x+b)) \
\frac{d y}{d b} &=-2(y-(a x+b))
\end{aligned}
$$
下面是具体的Python实现代码:
import numpy as np
import matplotlib.pyplot as plt
from sympy import symbols, diff
def get_data():
ret_x = np.linspace(-1, 1, 100)
return ret_x, [(lambda x: 2 * x + 3)(x) for x in ret_x]
def grad():
x, y, a, b = symbols(["x", "y", "a", "b"])
loss = (y - (a * x + b))**2
return diff(loss, a), diff(loss, b)
def test2(n_iter=50, lr=0.1, batch_size=20, beta1=0.9, beta2=0.999, epsilon=1e-6, shuffle=True):
x, y = get_data()
ga, gb = grad()
n = len(x)
idx = np.random.permutation(n)
s, v = 0, 0
a, b = 0, 0
move_a, move_b = [a], [b]
move_lr_a, move_lr_b = [lr], [lr]
t = 1
for _ in range(n_iter):
if shuffle:
np.random.shuffle(idx)
batch_idxes = [idx[k: k + batch_size] for k in range(0, n, batch_size)]
for idxes in batch_idxes:
sum_ga, sum_gb = 0, 0
for j in idxes:
sum_ga += ga.subs({"x": x[j], "y": y[j], "a": a, "b": b})
sum_gb += gb.subs({"x": x[j], "y": y[j], "a": a, "b": b})
sum_ga /= batch_size
sum_gb /= batch_size
g = np.array([sum_ga, sum_gb])
v = beta1 * v + (1 - beta1) * g
s = beta2 * s + (1 - beta2) * g * g
v_norm = v / (1 - np.power(beta1, t))
s_norm = s / (1 - np.power(beta2, t))
t += 1
lr_a, lr_b = lr * v_norm[0], lr * v_norm[1]
move_lr_a.append(lr_a)
move_lr_b.append(lr_b)
g_a_norm = lr_a / (np.sqrt(float(s_norm[0])) + epsilon)
g_b_norm = lr_b / (np.sqrt(float(s_norm[1])) + epsilon)
a -= g_a_norm
b -= g_b_norm
move_a.append(a)
move_b.append(b)
plt.subplot(211)
plt.plot(move_a)
plt.plot(move_b)
plt.legend(["a", "b"])
plt.subplot(212)
plt.plot(move_lr_a)
plt.plot(move_lr_b)
plt.legend(["a", "b"])
plt.show()
if __name__ == '__main__':
test2()
运行上述代码,可以得到参数$a$和$b$的更新过程以及学习率的变化情况,如图所示:
从图中可以看出,Adam优化算法能够自适应地调整学习率,使得参数更新更加平稳和高效。