【全解】梯度下降+迴歸(一)

​ 首先要明白什麼是迴歸。迴歸的目的是通過幾個已知數據來預測另一個數值型數據的目標值。

假設特徵和結果滿足線性關係,即滿足一個計算公式h(x),這個公式的自變量就是已知的數據x,函數值h(x)就是要預測的目標值。這一計算公式稱爲迴歸方程,得到這個方程的過程就稱爲迴歸。

​ 假設房子的房屋面積和臥室數量爲自變量x,用x1表示房屋面積,x2表示臥室數量;房屋的交易價格爲因變量y,我們用h(x)來表示y。假設房屋面積、臥室數量與房屋的交易價格是線性關係。

image

他們滿足公式

image

上述公式中的θ爲參數,也稱爲權重,可以理解爲x1和x2對h(x)的影響度。對這個公式稍作變化就是

image

公式中θ和x都可以看成是向量,n是特徵數量。

假如我們依據這個公式來預測h(x),公式中的x是我們已知的(樣本中的特徵值),然而θ的取值卻不知道,只要我們把θ的取值求解出來,我們就可以依據這個公式來做預測了。

最小均方法(Least Mean squares)

​ 在介紹LMS之前先了解一下什麼損失函數的概念。

​ 我們要做的是依據我們的訓練集,選取最優的θ,在我們的訓練集中讓h(x)儘可能接近真實的值。h(x)和真實的值之間的差距,我們定義了一個函數來描述這個差距,這個函數稱爲損失函數,表達式如下:

image

​ 這裏的這個損失函數就是著名的最小二乘損失函數,這裏還涉及一個概念叫最小二乘法,這裏不再展開了。我們要選擇最優的θ,使得h(x)最近進真實值。這個問題就轉化爲求解最優的θ,使損失函數J(θ)取最小值。(損失函數還有其它很多種類型)

那麼如何解決這個轉化後的問題呢?這又牽扯到一個概念:LMS 和 梯度下降(Radient Descent)。

LMS是求取h(x)迴歸函數的理論依據,通過最小化均方誤差來求最佳參數的方法。

梯度下降

​ 我們要求解使得J(θ)最小的θ值,梯度下降算法大概的思路是:我們首先隨便給θ一個初始化的值,然後改變θ值讓J(θ)的取值變小,不斷重複改變θ使J(θ)變小的過程直至J(θ)約等於最小值。

首先我們給θ一個初始值,然後向着讓J(θ)變化最大的方向更新θ的取值,如此迭代。公式如下:

image

公式中α稱爲步長(learning rate),它控制θ每次向J(θ)變小的方向迭代時的變化幅度。J(θ)對θ的偏導表示J(θ)變化最大的方向。由於求的是極小值,因此梯度方向是偏導數的反方向。

  • α取值太小收斂速度太慢,太大則可能會Overshoot the minimum。
  • 越接近最小值時,下降速度越慢
  • 收斂: 當前後兩次迭代的差值小於某一值時,迭代結束

求解一下這個偏導,過程如下:

image

那麼θ的迭代公式就變爲:

image

上述表達式只針對樣本數量只有一個的時候適用,那麼當有m個樣本值時該如何計算預測函數?批梯度下降算法和隨機梯度下降算法

批梯度下降算法(BGD)

有上一節中單個樣本的參數計算公式轉化爲處理多個樣本就是如下表達:

image

這種新的表達式每一步計算都需要全部訓練集數據,所以稱之爲批梯度下降(batch gradient descent)。

注意,梯度下降可能得到局部最優,但在優化問題裏我們已經證明線性迴歸只有一個最優點,因爲損失函數J(θ)是一個二次的凸函數,不會產生局部最優的情況。(假設學習步長α不是特別大)

批梯度下降的算法執行過程如下圖:

image

大家仔細看批梯度下降的數學表達式,每次迭代的時候都要對所有數據集樣本計算求和,計算量就會很大,尤其是訓練數據集特別大的情況。那有沒有計算量較小,而且效果也不錯的方法呢?有!這就是:隨機梯度下降(Stochastic Gradient Descent, SGD)

隨機梯度下降算法(SGD)

隨機梯度下降在計算下降最快的方向時時隨機選一個數據進行計算,而不是掃描全部訓練數據集,這樣就加快了迭代速度。

隨機梯度下降並不是沿着J(θ)下降最快的方向收斂,而是震盪的方式趨向極小點。

隨機梯度下降表達式如下:

image

執行過程如下圖:

image

批梯度下降和隨機梯度下降在三維圖上對比如下:

微信圖片_20180220163831

基於梯度下降算法的python3實現如下:(註釋部分爲BGD的實現)

# -*- coding: cp936 -*-
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt


# 構造訓練數據
x = np.arange(0., 10., 0.2)
m = len(x)                                      # 訓練數據點數目
x0 = np.full(m, 1.0)
input_data = np.vstack([x0, x]).T               # 將偏置b作爲權向量的第一個分量
target_data = 2 * x + 5 + np.random.randn(m)


# 兩種終止條件
loop_max = 10000   # 最大迭代次數(防止死循環)
epsilon = 1e-3

# 初始化權值
np.random.seed(0)
w = np.random.randn(2)
#w = np.zeros(2)

alpha = 0.001      # 步長(注意取值過大會導致振盪,過小收斂速度變慢)
diff = 0.
error = np.zeros(2)
count = 0          # 循環次數
finish = 0         # 終止標誌
# -------------------------------------------隨機梯度下降算法----------------------------------------------------------

while count < loop_max:
    count += 1

    # 遍歷訓練數據集,不斷更新權值
    for i in range(m):
        diff = np.dot(w, input_data[i]) - target_data[i]  # 訓練集代入,計算誤差值

        # 採用隨機梯度下降算法,更新一次權值只使用一組訓練數據
        w = w - alpha * diff * input_data[i]

        # ------------------------------終止條件判斷-----------------------------------------
        # 若沒終止,則繼續讀取樣本進行處理,如果所有樣本都讀取完畢了,則循環重新從頭開始讀取樣本進行處理。

    # ----------------------------------終止條件判斷-----------------------------------------
    # 注意:有多種迭代終止條件,和判斷語句的位置。終止判斷可以放在權值向量更新一次後,也可以放在更新m次後。
    if np.linalg.norm(w - error) < epsilon:     # 終止條件:前後兩次計算出的權向量的絕對誤差充分小
        finish = 1
        break
    else:
        error = w
print ('loop count = %d' % count,  '\tw:[%f, %f]' % (w[0], w[1]))


# -----------------------------------------------梯度下降法-----------------------------------------------------------


while count < loop_max:
    count += 1

    # 標準梯度下降是在權值更新前對所有樣例彙總誤差,而隨機梯度下降的權值是通過考查某個訓練樣例來更新的
    # 在標準梯度下降中,權值更新的每一步對多個樣例求和,需要更多的計算
    sum_m = np.zeros(2)
    for i in range(m):
        dif = (np.dot(w, input_data[i]) - target_data[i]) * input_data[i]
        sum_m = sum_m + dif     # 當alpha取值過大時,sum_m會在迭代過程中會溢出

    w = w - alpha * sum_m       # 注意步長alpha的取值,過大會導致振盪
    #w = w - 0.005 * sum_m      # alpha取0.005時產生振盪,需要將alpha調小

    # 判斷是否已收斂
    if np.linalg.norm(w - error) < epsilon:
        finish = 1
        break
    else:
        error = w
        
print ('loop count = %d' % count,  '\tw:[%f, %f]' % (w[0], w[1]))



# check with scipy linear regression
slope, intercept, r_value, p_value, slope_std_error = stats.linregress(x, target_data)
print ('intercept = %s slope = %s' %(intercept, slope))

plt.plot(x, target_data, 'k+')
plt.plot(x, w[1] * x + w[0], 'r')
plt.show()

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-s0biasjK-1592112372128)(D:\CSDN\Blog\1592103434656.png)]

隨機梯度下降可視化:

tensorflow 1.14實現:

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt


# 添加層
def add_layer(inputs, in_size, out_size, activation_function=None):
    W = tf.Variable(tf.random_normal([in_size, out_size]))
    b = tf.Variable(tf.zeros([1, out_size]) + 0.1)
    Wx_plus_b = tf.matmul(inputs, W) + b
    if activation_function is None:
        outputs = Wx_plus_b
    else:
        outputs = activation_function(Wx_plus_b)
    return outputs


# 生成輸入數據、噪點和輸出數據
x_data = np.linspace(-1, 1, 1000)[:, np.newaxis]
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise

xs = tf.placeholder(tf.float32, [None, 1])
ys = tf.placeholder(tf.float32, [None, 1])

# 隱藏層和輸出層
l1 = add_layer(xs, 1, 10, activation_function=tf.nn.relu)
prediction = add_layer(l1, 10, 1, activation_function=None)

# 損失值
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction),
                                    reduction_indices=[1]))

# 用梯度下降更新loss
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

# 初始化所有參數
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

figure = plt.figure()
ax = figure.add_subplot(1, 1, 1)
ax.scatter(x_data, y_data)
plt.ion()
plt.show()


# 訓練1000次
for i in range(1000):
    sess.run(train_step, feed_dict={xs: x_data, ys: y_data})
    if i % 50 == 0:
        # print(sess.run(loss, feed_dict={xs: x_data, ys: y_data}))
        try:
            ax.lines.remove(lines[0])
        except Exception:
            pass
        prediction_value = sess.run(prediction, feed_dict={xs: x_data, ys: y_data})
        lines = ax.plot(x_data, prediction_value, 'r-', lw=5)

        plt.pause(0.1)

結果展示:

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

reference;https://www.cnblogs.com/itmorn/p/11129806.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章