機器學習 -- 梯度下降法(Ⅷ 隨機梯度下降法)

之前這種梯度下降法又稱爲批量梯度下降法(Batch Gradient Descent)

        梯度下降法每次求梯度都需要將所有的樣本代入進行運算,當樣本的數量較大時,耗費的時間將會很多。爲了改進,提出了隨機梯度下降法。它採用的公式如下,即每次只取1個樣本進行運算。由於是隨機的,所以不能保證每次損失函數都能是下降的趨勢。

        由於我們使用的是隨機梯度下降法,所以導致我們的最終結果不會像批量梯度下降法一樣準確的朝着一個方向運算,而是曲線行下降。這時候我們就希望,越到下面,η值相應減小,事運算次數變多,從而精確計算結果。此時我們可以考慮η = 1 / 迭代次數。但是這種實現可能有時候有問題,比如當循環次數比較少的時候η值下降的太快,故可以在分母上加上一個常數b緩解情況,防止初始時η下降太快,讓分子也取常數a能使效果好點。(在此取經驗值a = 5,b = 50)

逐漸遞減的思想模擬的是搜索領域中模擬退火的思想。

\eta = \frac{t_0}{i\_iters + t_1}

 

一. 編程實現隨機梯度下降法

(1)導入數據集

import numpy as np
import matplotlib.pyplot as plt

m = 100000

x = np.random.random(size=m)
X = x.reshape(-1, 1)   # 整理成m * 1矩陣
y = x * 4. + 3. + np.random.normal(0, 3, size=m)

(2)首先嚐試使用批量梯度下降法進行擬合的過程

def J(theta, X_b, y):  
    try:  
        return np.sum((y - X_b.dot(theta)) ** 2) / len(y)  
    except:  
        return float('inf')  
      
def dJ(theta, X_b,y):  
    return X_b.T.dot(X_b.dot(theta) - y) * 2. / len(y)
  

def gradient_descent(X_b, y, initial_theta, eta, n_iters=1e4, epsilon=1e-8):
 
    theta = initial_theta
    cur_iter = 0

    while cur_iter < n_iters:
        gradient = dJ(theta, X_b, y)
        last_theta = theta
        theta = theta - eta * gradient
        # 損失函數減小的值已經不能小於我們要的精度了
        if (abs(J(theta, X_b, y) - J(last_theta, X_b, y)) < epsilon):
            break

        cur_iter += 1

    return theta


%%time
X_b = np.hstack([np.ones((len(X),1)),X])
init_theta = np.zeros(X_b.shape[1])
eta = 0.01
theta = gradient_descent(X_b, y, init_theta, eta)
# Wall time: 6.04 s

theta
# array([2.98044786, 4.01871093])

(3)使用隨機梯度下降法

# 只傳入一個樣本,故不需要除以m
def dJ_sgd(theta, X_b_i, y_i):  
    return X_b_i.T.dot(X_b_i.dot(theta) - y_i) * 2.
    
def sgd(X_b, y, initial_theta, n_iters=1e4):  
    
    t0 = 5
    t1 = 50
    
    # t爲當前迭代次數
    def learning_rate(t):
        return t0 / (t + t1)
    
    theta = initial_theta  
    i_iter = 0  
    
    # 由於梯度方向隨機,不能保證損失函數一直是減小的,很可能是跳躍的,故少一個判斷條件,只判斷當前循環次數
    for cur_iter in range(n_iters):
        # 隨機樣本索引
        rand_i = np.random.randint(len(X_b))
        gradient = dJ_sgd(theta, X_b[rand_i], y[rand_i])
        theta = theta - learning_rate(cur_iter) * gradient
        
    return theta


%%time
eta = 0.01
X_b = np.hstack([np.ones((len(X), 1)), X])
initial_theta = np.zeros(X_b.shape[1])
# 隨機的檢查了3分之一個樣本總量的樣本
theta = sgd(X_b, y, initial_theta, n_iters=len(X_b) // 3)
# Wall time: 172 ms

theta
# array([2.94416856, 3.97221276])

二. 使用sklearn的隨機梯度下降法

from sklearn.linear_model import SGDRegressor # sklearn中的隨機梯度下降只能運用在線性迴歸中
sgd_reg = SGDRegressor(n_iter=100) #可傳入參數,代表將全部樣本看100遍

%time 
sgd_reg.fit(X_train_standard, y_train)
sgd_reg.score(X_test_standard, y_test)

 

 

發佈了306 篇原創文章 · 獲贊 70 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章