1. 程式人生 > >python3__機器學習__神經網路基礎演算法__梯度下降演算法

python3__機器學習__神經網路基礎演算法__梯度下降演算法

1.概述

【說明】

梯度下降演算法(Gradient Descent Optimization)是神經網路模型訓練最常用的優化演算法(n緯問題求最優解,梯度下降是最常用的方法);對於深度學習模型,基本都是採用梯度下降演算法來進行優化訓練。

【場景假設】

一人被困山上,需從山上下來(i.e. 找到山的最低點,也就是山谷)。但此時山上的濃霧很大,導致可視度很低。因此,下山的路徑就無法確定,他必須利用自己周圍的資訊去找到下山的路徑。這個時候,他就可以利用梯度下降演算法來幫助自己下山。具體來說就是,以他當前的所處的位置為基準,尋找這個位置最陡峭的地方,然後朝著山的高度下降的地方走

,同理,如果我們的目標是上山,也就是爬到山頂,那麼此時應該是朝著最陡峭的方向往上走。然後每走一段距離,都反覆採用同一個方法,最後就能成功的抵達山谷。

【梯度下降的基本過程】

首先,有一個可微分的函式(山),目標是找到函式的最小值(山底),依據之前的場景假設,最快的下山的方式是沿著當前位置最陡峭的方向,然後沿著此最陡峭的方向往下走,對應到可謂分的函式中,即找到給定點的梯度(是目標函式上升最快的方向),然後朝著梯度相反的方向,就能讓函式值下降的最快。

反覆使用該方法,反覆求取梯度,最後就能達到區域性的最小值。

2.梯度

(J(Θ) = 0.55-(5θ1+2θ2-12θ3))梯度是通過<>包裹起來的一組

偏導的向量。梯度(多元微分:偏導數)是微分中一個十分重要的概念,意義如下:

①在單變數函式中,梯度即函式的微分,代表著函式在某個給定點的切線的斜率

②在多變數函式中,梯度即向量,向量有方向,梯度的方向就是函式在給定點上升最快的方向

因此,若想找到函式的最小值,則需要千方百計的求取梯度,梯度的方向時函式上升最快的方向,梯度的反方向就是函式在給定點下降最快的方向。

 

3.梯度下降演算法的數學解釋

 J(Θ0):關於Θ0的函式,即目標函式

Θ0:current position當前所在位置

Θ1:next position 變換後的位置(下降一次)

α:學習率或者步長(太大太小均不好:太大,易錯過最低點;太小,效率太低)

▽J(Θ0):即引數Θ-的梯度

負號:朝梯度相反的方向前進

4.梯度下降演算法例項

4.1 單變數函式的梯度下降

目標函式:

Θ0: 1

α:0.4

import numpy as np
import matplotlib.pyplot as plt


def gradient_decent(x, a):
    return x-a*2*x


if "__main__" == __name__:
    lx = []
    x = 1.0
    for i in range(5):
        lx.append(x)
        y = gradient_decent(x, 0.4)
        x = y

    plt.figure(111, figsize=(9, 9))
    plt.title("one-dimension Gradient Decent", fontsize=15)

    # np.arange: 返回給定區間內的等間距值
    x1 = np.arange(-1.2, 1.2, step=0.001)
    y1 = np.power(x1, 2)
    x2 = np.sqrt(lx)
    plt.plot(x1, y1, label="target-func", color="black")
    plt.plot(x2, lx, label="gradient", color="red", marker="o")

    plt.xlabel("x", fontsize=15)
    plt.ylabel("y", fontsize=15)
    plt.legend()
    plt.show()

4.2 多變數函式的梯度下降

目標函式:

Θ0:(1, 3)

α:0.1

5.梯度下降演算法的實現

【場景】線性迴歸

【損失函式】

 

①m是資料集中點的個數

②½是一個常量,這樣是為了在求梯度的時候,二次方乘下來就和這裡的½抵消了,自然就沒有多餘的常數係數,方便後續的計算,同時對結果不會有影響

③y 是資料集中每個點的真實y座標的值

【原函式】

【梯度】 

5.1 梯度下降主體演算法

def gradient_descent(X, y, alpha):
    """
    梯度下降迭代計算
    :param X: 函式係數
    :param y: 真實的函式值
    :param alpha: 學習速率
    :return: 最低點座標
    """
    # 梯度下降 ==> 初始座標
    theta = np.array([1, 1]).reshape(2, 1)
    
    # 當前座標對應的 ==> 梯度
    gradient = gradient_function(theta, X, y)

    # np.absolute:逐個元素的計算絕對值
    # np.all:測試給定條件下是否全部元素為True
    while not np.all(np.absolute(gradient) <= 1e-5):

        # 計算下一個座標
        theta = theta - alpha*gradient
        gradient = gradient_function(theta, X, y)
    return theta

5.2 計算當前座標對應的梯度值

def gradient_function(theta, X, y):
    """
    計算當前座標theta對應的梯度
    :param theta: 當前位置              (2, 1)
    :param X: 輸入變數   [1, 變數值]     (m, 2)
    :param y: 真實值                    (m, 1)
    :return: 梯度值
    """
    # diff.shape: (m, 1)
    # 計算預測值與真實值之間的誤差
    # 為了對這個公式進行矩陣化,我們可以給每一個點x增加一維,這一維的值固定為1,這一維將會乘到Θ0上。這樣就方便我們統一矩陣化的計算
    diff = np.dot(X, theta) - y
    return (1./m)*np.dot(np.transpose(X), diff)

5.3 依據最低點座標反推出損失值

def error_function(min_gradient, X, y):
    """
    根據最小梯度反推出對應的 ”損失值“
    :param min_gradient: minimum gradient
    :param X: 輸入變數   [1, num]              (m, 2)
    :param y: 真實值                           (m, 1)
    :return: 最低點對應的損失值
    """

    # np.dot:計算兩個陣列的點積(矩陣乘法)
    # X: (m, 2)
    # min_gradient: (2, 1)
    # diff: (m, 1)
    diff = np.dot(X, min_gradient) - y

    # 計算最低點座標對應的誤差平方和
    # np.transpose: 將陣列的行列互換
    return (1./2*m)*np.dot(np.transpose(diff), diff)

5.4 程式呼叫入口

if "__main__" == __name__:
    # ====定義資料集
    # 資料量
    m = 20
    # inputX
    x0 = np.ones((m, 1))
    x1 = np.arange(1, m + 1).reshape(m, 1)

    # hp.hstack: 按順序堆疊陣列
    # fuction: 405.98496249324046
    X = np.hstack((x0, x1))

    y = np.array([3, 4, 5, 5, 2, 4, 7, 8, 11, 8, 12, 11, 13, 13, 16, 17, 18, 17, 19, 21]).reshape(m, 1)
    # 學習速率/步長
    alpha = 0.01

    # 獲得最低點
    optimal = gradient_descent(X, y, alpha)
    print("optimal:", optimal)
    # 根據最低點反推損失值
    print("error function:", error_function(optimal, X, y)[0, 0])