机器学习常用优化算法【一】—— Gradient Descent 系列

    技术2024-07-02  77

    一、Gradient Descent(梯度下降算法)

    (1)、Batch Gradient descent(BGD, 指计算梯度时用的是全部样本的梯度的均值)

    Batch Gradient descent 是一种求最小局部变量的一阶迭代优化算法。利用gradient descent来求一个函数的最小值,我们每一步都在当前点加上一个负梯度的倍数。如果我们采用的是正梯度,则计算的是函数的局部最大值。这就像我们要从山上的某个点下山,如何最快的到达山底,我们的方法就是在当前点选择下山的最陡的方向走,这就是梯度下降。

    给定一个多变量函数 F ( x ) F(x) F(x),同时在点 a a a处可微,则从点 a a a处下降最快的方向就是 − ∇ F ( a ) -\nabla F(a) F(a),表示为如下形式:

    a n + 1 = a n − γ ∇ F ( a n ) a_{n + 1} = a_{n} - \gamma \nabla F(a_n) an+1=anγF(an)

    γ ∈ R + \gamma \in R_+ γR+,且足够下,有 F ( a n ) ≥ F ( a n + 1 ) F(a_n) \geq F(a_{n + 1}) F(an)F(an+1).

    python_code.py x = 6 step_size = 0.01 # 每次移动的步长 step_tolerance = 0.00001 # 停止条件 max_iterations = 10000 # 运行最大进行的迭代次数 # Derivate function f'(x) df = lambda x: 4 * x ** 3 - 9 * x ** 2 for j in range(max_iterations): step = step_size * df(x) x -= step if abs(step) < step_tolerance: break print('Minimum:', x) # 2.2499646074278457 print('Exact:', 9/4) # 2.25 print('Iterations:',j) # 69

    不管是这里的BGD还是后面的SGD、MBGD,只要确定了损失函数,则其梯度公式也就确定了,所不同的是这个梯度的值,这是什么意思呢?

    给个例子:

    假设有三个数据[3, 5, 9, 2], 确定的loss function为 J ( x ) = 10 ∗ x 5 + 8 ∗ x 2 J(x) = 10 *x^5 + 8 * x^2 J(x)=10x5+8x2,其确定的梯度公式为 ∇ J ( x ) = 50 ∗ x 4 + 16 ∗ x \nabla J(x) = 50 * x^4 + 16* x J(x)=50x4+16x,我们将 ∇ J ( x ) \nabla J(x) J(x)的带入数据后算出来的值记为params_grad。

    对于BGD,其算的是所有样本的均值,即 p a r a m s _ g r a d = ∇ J ( 3 ) + ∇ J ( 5 ) + ∇ J ( 9 ) + ∇ J ( 2 ) 4 = 91113.5 params\_grad = \frac{\nabla J(3) + \nabla J(5) +\nabla J(9) +\nabla J(2)}{4} = 91113.5 params_grad=4J(3)+J(5)+J(9)+J(2)=91113.5;

    对于SGD,其算的某个样本的值(例如取x = 3),即

    p a r a m s _ g r a d = ∇ J ( 3 ) = 4098 params\_grad = \nabla J(3) = 4098 params_grad=J(3)=4098

    而对MBGD,其算的某些样本的的均值(例如取x = 3, 5),即

    p a r a m s _ g r a d = ∇ J ( 3 ) + ∇ J ( 5 ) 2 = 17714.0 params\_grad = \frac{\nabla J(3) + \nabla J(5)}{2} = 17714.0 params_grad=2J(3)+J(5)=17714.0

    所以这给出多个训练样本的时候的部分代码:

    for i in range(nb_epochs): params_grad = evaluate_gradient(loss_function, data, params) params = params - learning_rate * params_grad

    BGD对于凸函数能够收敛到全局最优,但对于非凸函数,能收敛到局部最优。

    (2)、Stochastic Gradient Descent(SGD,随机梯度下降)

    SGD使用一个训练样本 ( x ( i ) , y ( i ) (x^{(i)}, y^{(i)} (x(i),y(i)来更新参数的。 a n + 1 = a n − γ ∇ F ( a n , x ( i ) , y ( i ) ) a_{n + 1} = a_{n} - \gamma \nabla F(a_n, x^{(i)}, y^{(i)}) an+1=anγF(an,x(i),y(i))

    相比于BGD,SGD有可能能够跳出当前的局部最优点,然后去获得一个很好的局部最优点;但是SGD也容易困于局部最优,并且在某些情况下可能被困于鞍点。

    for i in range(nb_epochs): np.random.shuffle(data) for example in data: params_grad = evaluate_gradient(loss_function, example, params) params = params - learning_rate * params_grad

    (3)、Mini-Batch Gradient Descent

    MBGD使用一部分训练样本 ( x ( i : i + n ) , y ( i : i + n ) (x^{(i: i + n)}, y^{(i: i + n)} (x(i:i+n),y(i:i+n)来更新参数的。 a n + 1 = a n − γ ∇ F ( a n , x ( i + n ) , y ( i + n ) ) a_{n + 1} = a_{n} - \gamma \nabla F(a_n, x^{(i + n)}, y^{(i + n)}) an+1=anγF(an,x(i+n),y(i+n))

    有如下优点:

    1)减少了参数更新的方差,使得更加稳定收敛;

    2)通常的mini-batch 的大小为50~256;

    for i in range(nb_epochs): np.random.shuffle(data) for batch in get_batches(data, batch_size = 50): params_grad = evaluate_gradient(loss_function, batch, params) params = params - learning_rate * params_grad
    Processed: 0.013, SQL: 9