从最优化的角度来看,主要有一阶和二阶两类优化方案,那么从最简单的开始:
- Gradient Descent
while True:
weights_grad = evaluate_gradient(loss_fun, data, weights)
weights += - step_size*weightes_grad
缺点:
- 计算量过大
- 对于非凸函数不能保证全局最优
- SGD(Stochastic Gradient Descent)
while True:
data_batch = sample_training_data(data,256)
weights_grad = evaluate_gradient(loss_fun, data_batch, weights)
weights += - step_size * weighted_grad
注意此处代码给出的是mini-batch 的SGD,还有一种是针对每个输入数据的SGD(batch_size=1),该方法在优化过程中会有比较明显的震荡。
缺点:
- 可能出现的高方差使得收敛速度慢,稳定性差
- 需要选取合适的学习率
- 没有解决非凸函数问题
- SGD+Momentum
vx = 0
while True:
dx = compute_gradient(x)
### 通常rho取0.9或者0.99
vx = rho * vx +dx
x += - learning_rate * vx
优点:
- 能够遏制动荡
- 可以越过局部最小点和鞍点
缺点: - 可能因为高动量而越过最小值
- Nesterov
vx = 0
while True:
dx = compute_gradient(x)
old_v = v
v = rho * v - learning_rate * dx
x += - rho* old_v + (1+rho)* v
原本的数学公式应当写成:
不过括号中的导数不便于计算,因此经过化简得到上述结果。
其原理如下:为了改进动量方法的越过最小点问题,需要提前看一点。
- AdaGrad
grad_squared = 0
while True:
dx = compute_gradient(x)
grad_squared += dx * dx
x -= learning_rate * dx / (np.sqrt(grad_squared) + 1e-7)
- RMSprop
grad_squared = 0
while True:
dx = computer_gradient(x)
grad_squared = decay_rate * grad_squared + (1-decay_rate) * dx *dx
x -= learning_rate * dx / (np.sqrt(grad_squared) + 1e-7)
- Adam
first_moment = 0
second_moment = 0
for t in range(1, num_iterations):
dx = compute_gradient(x)
first_moment = beta1 * first_moment + (1-beta1) * dx
second_moment = beta2 * second_moment + (1-beta2)*dx*dx
# 为了修正一开始 first_mometn和 second_moment从0开始累积,有了以下两项
first_unbias = first_moment / (1 - beta1 ** t)
second_unbias = second_moment / (1 - beta2 **t)
x -= learning_rate * first_unbias / (np.sqrt(second_unbias) + 1e-7)