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])