日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Lesson 4.5 梯度下降优化基础:数据归一化与学习率调度

發(fā)布時間:2025/4/5 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Lesson 4.5 梯度下降优化基础:数据归一化与学习率调度 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Lesson 4.5 梯度下降優(yōu)化基礎(chǔ):數(shù)據(jù)歸一化與學(xué)習(xí)率調(diào)度

在上一小節(jié)中,我們討論了關(guān)于隨機(jī)梯度下降和小批量梯度下降的基本算法性質(zhì)與使用流程。我們知道,在引入了一定的樣本隨機(jī)性之后,能夠幫助參數(shù)點(diǎn)跨越局部最小值點(diǎn),但對于機(jī)器學(xué)習(xí)的任何算法,在引入隨機(jī)性提升算法性能的時候也將面臨隨機(jī)性本身所造成的麻煩。在上一小節(jié)中我們看到,隨機(jī)梯度下降會伴隨著收斂過程不穩(wěn)定、收斂結(jié)果持續(xù)震蕩等問題,當(dāng)然面對更加復(fù)雜的數(shù)據(jù)集,隨機(jī)梯度下降還會面臨收斂所需迭代次數(shù)過多等問題。當(dāng)然,相比隨機(jī)梯度下降,上述問題有所緩解,但很明顯通過增加每次迭代的樣本數(shù)量來減少隨機(jī)性進(jìn)而緩解上述問題并不是長久之計。要真正幫助隨機(jī)梯度下降和小批量梯度下降解決隨機(jī)性所造成的“麻煩”,就必須采用一些圍繞迭代過程的優(yōu)化方法,而所有的圍繞迭代過程的優(yōu)化方法中,最基礎(chǔ)也是最通用的兩種方法,分別是數(shù)據(jù)歸一化方法和學(xué)習(xí)率調(diào)度。

# 科學(xué)計算模塊 import numpy as np import pandas as pd# 繪圖模塊 import matplotlib as mpl import matplotlib.pyplot as plt# 自定義模塊 from ML_basic_function import *

機(jī)器學(xué)習(xí)領(lǐng)域的優(yōu)化方法分類很多類,包括模型結(jié)果優(yōu)化、評估指標(biāo)優(yōu)化、收斂過程優(yōu)化等等,此處介紹的優(yōu)化方法是圍繞梯度下降過程的收斂過程優(yōu)化方法。

一、數(shù)據(jù)歸一化方法

數(shù)據(jù)歸一化方法的本質(zhì)是一種對數(shù)據(jù)進(jìn)行線性轉(zhuǎn)換的方法,通過構(gòu)建一種樣本空間之間的線性映射關(guān)系來進(jìn)行數(shù)據(jù)數(shù)值的轉(zhuǎn)化,這種轉(zhuǎn)化并不會影響數(shù)據(jù)分布,即不會影響數(shù)據(jù)的內(nèi)在規(guī)律,只是對數(shù)據(jù)的數(shù)值進(jìn)行調(diào)整。數(shù)據(jù)歸一化有很多方法,并且在機(jī)器學(xué)習(xí)領(lǐng)域有諸多用途,不僅是能夠作為梯度下降的優(yōu)化算法,同時還能幫助一些數(shù)據(jù)集避免量綱不一致等問題。

經(jīng)典機(jī)器學(xué)習(xí)領(lǐng)域的數(shù)據(jù)歸一化算法主要有兩種,分別是0-1標(biāo)準(zhǔn)化(Max-Min Normalization)和Z-Score標(biāo)準(zhǔn)化。我們先討論歸一化基本流程,再探討歸一化對機(jī)器學(xué)習(xí)算法在各方面的影響。

關(guān)于歸一化和標(biāo)準(zhǔn)化的概念辨析
??一般來說,歸一化和標(biāo)準(zhǔn)化都是指對數(shù)據(jù)進(jìn)行數(shù)值轉(zhuǎn)化,根據(jù)維基百科的解釋,都是Feature scaling(特征縮放)的方法,并且都可以稱為normalization。但某些場景下也會有不同的稱呼,例如將0-1標(biāo)準(zhǔn)化稱為normalization,也就是歸一化,而把Z-Score標(biāo)準(zhǔn)化稱為Standardization,即標(biāo)準(zhǔn)化。課上對二者概念不做具體區(qū)分。

1.數(shù)據(jù)歸一化計算公式

1.1 0-1標(biāo)準(zhǔn)化

0-1標(biāo)準(zhǔn)化是最簡單同時也是最常用的標(biāo)準(zhǔn)化方法。該方法通過在輸入特征中逐列遍歷其中里的每一個數(shù)據(jù),將Max和Min的記錄下來,并通過Max-Min作為基數(shù)(即Min=0,Max=1)進(jìn)行數(shù)據(jù)的歸一化處理,基本公式為:xnormalization=x?MinMax?Min{x}_{normalization}=\frac{x-Min}{Max-Min}xnormalization?=Max?Minx?Min?
實(shí)際計算過程中需要逐列進(jìn)行處理,即用每一列中的元素減去當(dāng)前列的最小值,再除以該列的極差。例如:

a = np.arange(12).reshape(6, 2) a #array([[ 0, 1], # [ 2, 3], # [ 4, 5], # [ 6, 7], # [ 8, 9], # [10, 11]]) # 計算每列最大值 a.max(axis = 0) #array([10, 11]) np.max(a, 0) #array([10, 11]) # 計算每列最小值 a.min(axis = 0) #array([0, 1]) # 計算每列極差 a.max(axis = 0) - a.min(axis = 0) #array([10, 10]) (a - a.min(axis = 0)) #array([[ 0, 0], # [ 2, 2], # [ 4, 4], # [ 6, 6], # [ 8, 8], # [10, 10]]) # 對數(shù)據(jù)集a進(jìn)行歸一化計算 (a - a.min(axis = 0)) / (a.max(axis = 0) - a.min(axis = 0)) #array([[0. , 0. ], # [0.2, 0.2], # [0.4, 0.4], # [0.6, 0.6], # [0.8, 0.8], # [1. , 1. ]])

至此,我們將a的兩列都放縮到了0-1區(qū)間內(nèi),這也是0-1標(biāo)準(zhǔn)化名稱的由來。當(dāng)然,我們可以定義一個函數(shù)完成上述過程:

def maxmin_norm(X):"""max—min normalization標(biāo)準(zhǔn)化函數(shù)"""maxmin_range = X.max(axis=0) - X.min(axis=0)return (X - X.min(axis=0)) / maxmin_range maxmin_norm(a) #array([[0. , 0. ], # [0.2, 0.2], # [0.4, 0.4], # [0.6, 0.6], # [0.8, 0.8], # [1. , 1. ]])

0-1標(biāo)準(zhǔn)化也被稱為離差標(biāo)準(zhǔn)化

1.2 Z-Score標(biāo)準(zhǔn)化

和0-1標(biāo)準(zhǔn)化不同,Z-score標(biāo)準(zhǔn)化利用原始數(shù)據(jù)的均值(mean)和標(biāo)準(zhǔn)差(standard deviation)進(jìn)行數(shù)據(jù)的標(biāo)準(zhǔn)化。同樣是逐列進(jìn)行操作,每一條數(shù)據(jù)都減去當(dāng)前列的均值再除以當(dāng)前列的標(biāo)準(zhǔn)差,在這種標(biāo)準(zhǔn)化操作下,如果原數(shù)據(jù)服從正態(tài)分布,處理之后的數(shù)據(jù)服從標(biāo)準(zhǔn)正態(tài)分布。Z-Score標(biāo)準(zhǔn)化計算公式如下:xnormalization=x?μσ{x}_{normalization}=\frac{x-\mu }{\sigma }xnormalization?=σx?μ?
其中μ\muμ代表均值,σ\sigmaσ代表標(biāo)準(zhǔn)差。當(dāng)然,我們也可通過如下方式對張量進(jìn)行Z-Score標(biāo)準(zhǔn)化處理。

a #array([[ 0, 1], # [ 2, 3], # [ 4, 5], # [ 6, 7], # [ 8, 9], # [10, 11]]) # 每列均值 a.mean(0) #array([5., 6.]) # 每列標(biāo)準(zhǔn)差 a.std(0) #array([3.41565026, 3.41565026]) (a - a.mean(0)) #array([[-5., -5.], # [-3., -3.], # [-1., -1.], # [ 1., 1.], # [ 3., 3.], # [ 5., 5.]]) # Z-Score標(biāo)準(zhǔn)化 (a - a.mean(0)) / a.std(0) #array([[-1.46385011, -1.46385011], # [-0.87831007, -0.87831007], # [-0.29277002, -0.29277002], # [ 0.29277002, 0.29277002], # [ 0.87831007, 0.87831007], # [ 1.46385011, 1.46385011]])

和0-1標(biāo)準(zhǔn)化不同,Z-Score標(biāo)準(zhǔn)化并不會將數(shù)據(jù)放縮在0-1之間,而是均勻地分布在0的兩側(cè)。類似這種數(shù)據(jù)也被稱為Zero-Centered Data,在深度學(xué)習(xí)領(lǐng)域有重要應(yīng)用。當(dāng)然我們可以將上述過程封裝為一個函數(shù):

def z_score(X):"""Z-Score標(biāo)準(zhǔn)化函數(shù)"""return (X - X.mean(axis=0)) / X.std(axis=0)

一種更加嚴(yán)謹(jǐn)?shù)淖龇?#xff0c;是在分母項、也就是標(biāo)準(zhǔn)差上加上一個非常小的常數(shù)μ\muμ,從而使得分母恒大于0。

z_score(a) #array([[-1.46385011, -1.46385011], # [-0.87831007, -0.87831007], # [-0.29277002, -0.29277002], # [ 0.29277002, 0.29277002], # [ 0.87831007, 0.87831007], # [ 1.46385011, 1.46385011]])

Z-Score標(biāo)準(zhǔn)化也被稱為0均值標(biāo)準(zhǔn)化

1.3 非線性標(biāo)準(zhǔn)化

除了0-1標(biāo)準(zhǔn)化和Z-Score標(biāo)準(zhǔn)化外,還有一類使用非線性函數(shù)進(jìn)行歸一化操作的方法。其中最具代表性的是Sigmoid標(biāo)準(zhǔn)化。

Sigmoid標(biāo)準(zhǔn)化其實(shí)非常好理解,就是利用Sigmoid函數(shù)對數(shù)據(jù)集的每一列進(jìn)行處理,由于Sigmoid函數(shù)特性,處理之后的數(shù)據(jù)也將被壓縮到0-1之間。

a #array([[ 0, 1], # [ 2, 3], # [ 4, 5], # [ 6, 7], # [ 8, 9], # [10, 11]])# 借助此前定義的Sigmoid函數(shù) sigmoid(a) #array([[0.5 , 0.73105858], # [0.88079708, 0.95257413], # [0.98201379, 0.99330715], # [0.99752738, 0.99908895], # [0.99966465, 0.99987661], # [0.9999546 , 0.9999833 ]])

當(dāng)然,相比Sigmoid標(biāo)準(zhǔn)化,Z-Score標(biāo)準(zhǔn)化實(shí)際用途更廣。

2.數(shù)據(jù)歸一化算法執(zhí)行過程

我們以0-1標(biāo)準(zhǔn)化為例,來探討數(shù)據(jù)歸一化處理對量綱的影響以及在實(shí)際建模過程中的計算流程。當(dāng)然其他標(biāo)準(zhǔn)化也類似。

對于0-1標(biāo)準(zhǔn)化來說,表面上看起來只是將每一列數(shù)據(jù)都放縮至0-1區(qū)間內(nèi),但實(shí)際上卻有著非常多的用途。一個最簡單的使用場景是,當(dāng)數(shù)據(jù)集中不同列的量綱不一致時,通過對每一列的0-1標(biāo)準(zhǔn)化處理,能夠消除因?yàn)檫@種不一致而引發(fā)的算法學(xué)習(xí)偏差。例如,在鳶尾花數(shù)據(jù)中,每一列都是以厘米作為單位,整體數(shù)據(jù)分布相對統(tǒng)一,但如果把其中某一列改為毫米、而其他幾列改為米作為單位,則以毫米為單位的列數(shù)值將特別大,而其他幾列數(shù)值將特別小,如此一來就會對包括線性方程在內(nèi)的一系列模型建模造成重大影響,模型將無法“均勻的”從各列中提取信息。

iris_df = pd.read_csv("iris.csv") iris_df


以線性回歸為例進(jìn)行說明,假設(shè)現(xiàn)在有數(shù)據(jù)集滿足y=200x1?x2+1y=200x_1-x_2+1y=200x1??x2?+1關(guān)系,數(shù)據(jù)基本情況如下:

# 設(shè)置隨機(jī)數(shù)種子 np.random.seed(24) # 擾動項取值為0.01 features, labels = arrayGenReg(w = [200, -1, 1], delta=0.01)features #array([[ 1.32921217, -0.77003345, 1. ], # [-0.31628036, -0.99081039, 1. ], # [-1.07081626, -1.43871328, 1. ], # ..., # [ 1.5507578 , -0.35986144, 1. ], # [-1.36267161, -0.61353562, 1. ], # [-1.44029131, 0.50439425, 1. ]]) labels #array([[ 2.67622128e+02], # [-6.12475992e+01], # [-2.11718753e+02], # ... # [ 3.11506066e+02], # [-2.70918237e+02], # [-2.87561020e+02]])

數(shù)據(jù)的真實(shí)規(guī)律是第一個特征其實(shí)對標(biāo)簽的取值起到非常重大的作用,但在實(shí)際數(shù)據(jù)獲取記錄過程中,如果量綱錯配,即給了第一個特征一個非常大的量綱、第二個特征一個非常小的量綱,那么數(shù)據(jù)情況和實(shí)際建模情況就將如下所示:

features[:,:1] = features[:,:1] * 0.1 #取出來是一個二維數(shù)組,features[:,0]取出來是一維數(shù)組 features[:,1:2] = features[:,1:2] * 10 features #array([[ 0.13292122, -7.70033452, 1. ], # [ -0.03162804, -9.90810387, 1. ], # [ -0.10708163, -14.3871328 , 1. ], # ..., # [ 0.15507578, -3.5986144 , 1. ], # [ -0.13626716, -6.13535618, 1. ], # [ -0.14402913, 5.04394254, 1. ]])

則在進(jìn)行線性回歸建模時,算得各列線性關(guān)系如下:

np.linalg.lstsq(features, labels, rcond=-1)[0] #array([[ 1.99999619e+03], # [-9.99852807e-02], # [ 9.99705410e-01]]) np.linalg.lstsq(features, labels, rcond=-1)[0][0] #array([1999.99618924]) np.linalg.lstsq(features, labels, rcond=-1)[0][1] #array([-0.09998528]) 1999.99618924 / -0.09998528 #-20002.906320210335

此時模型為了捕捉第一列相對更加重要的特性,計算所得的第一列特征取值非常大,甚至是第二列特征系數(shù)的10的5次方倍左右。盡管上述模型結(jié)果仍然是可以使用的結(jié)果,但特征系數(shù)差異性的增加(由200倍變成20000倍差異)會導(dǎo)致兩個問題,其一是部分系數(shù)太小而導(dǎo)致計算精度問題,其二則是在特征重要性判別上會忽視系數(shù)較小的特征。而為了能夠消除這種量綱差異所帶來的規(guī)律挖掘方面的影響,我們就需要采用歸一化方法。例如對上述數(shù)據(jù)集進(jìn)行歸一化處理之后再進(jìn)行建模過程如下:

features_max = features[:, :2].max(0) features_min = features[:, :2].min(0) features_range = features[:, :2].max(0) - features[:, :2].min(0)(features[:, :2] - features_min) / features_range #array([[0.72219451, 0.35489507], # [0.44561184, 0.32515777], # [0.31878564, 0.26482801], # ..., # [0.75943302, 0.41014271], # [0.26972912, 0.37597436], # [0.25668241, 0.52655264]]) maxmin_norm(features[:, :2]) #array([[0.72219451, 0.35489507], # [0.44561184, 0.32515777], # [0.31878564, 0.26482801], # ..., # [0.75943302, 0.41014271], # [0.26972912, 0.37597436], # [0.25668241, 0.52655264]]) features[:, :2] = maxmin_norm(features[:, :2]) features #array([[0.72219451, 0.35489507, 1. ], # [0.44561184, 0.32515777, 1. ], # [0.31878564, 0.26482801, 1. ], # ..., # [0.75943302, 0.41014271, 1. ], # [0.26972912, 0.37597436, 1. ], # [0.25668241, 0.52655264, 1. ]]) #標(biāo)簽歸一化(1)回歸問題(2)0——1標(biāo)準(zhǔn)化 # (1)轉(zhuǎn)化為正值

注意,關(guān)于標(biāo)簽是否需要?dú)w一化的問題,一般來說這并不是一個典型的操作,在絕大多數(shù)情況下我們也并不會對標(biāo)簽進(jìn)行歸一化操作。但此處,由于需要在歸一化后全都為正數(shù)的特征上進(jìn)行回歸類問題預(yù)測,且標(biāo)簽取值有正有負(fù),因此可以考慮對標(biāo)簽進(jìn)行歸一化處理,以方便觀測后續(xù)模型參數(shù)。不過盡管如此,此處的標(biāo)簽歸一化也并不是必須的。

w = np.linalg.lstsq(features, maxmin_norm(labels), rcond=-1)[0] w #array([[ 0.99847747], # [-0.00622912], # [ 0.00410845]])

此時我們能發(fā)現(xiàn),盡管參數(shù)取值和背后真實(shí)規(guī)律有差異,但基本能夠體現(xiàn)第一個特征重要性遠(yuǎn)高于第二個特征的一般規(guī)律,并且二者基本相差200倍的關(guān)系。

-0.00622912 * 200 #-1.2458240.00410845 * 200 #0.8216899999999999

很明顯,該結(jié)果是一個相對更加準(zhǔn)確的結(jié)果。而如果我們現(xiàn)在假設(shè)數(shù)據(jù)集滿足上述關(guān)系,那么對于新進(jìn)來的數(shù)據(jù),應(yīng)該如何預(yù)測呢?其實(shí)非常簡單,只需要借助訓(xùn)練數(shù)據(jù)中計算出的極值對新數(shù)據(jù)進(jìn)行處理即可,例如我們又獲得數(shù)據(jù)如下:

features1, labels1 = arrayGenReg(num_examples = 100, w = [200, -1, 1], delta=0.01) features1[:,:1] = features1[:,:1] * 0.1 features1[:,1:2] = features1[:,1:2] * 10

相同總體中獲取的滿足相同規(guī)律的數(shù)據(jù),當(dāng)然新數(shù)據(jù)理論上應(yīng)該是“不帶”標(biāo)簽的。

features1[:, :2] = (features1[:, :2] - features_min) / features_range features1[:5] #array([[0.90106853, 0.51624561, 1. ], # [0.73491277, 0.6617905 , 1. ], # [0.25451935, 0.53039679, 1. ], # [0.47933854, 0.43441831, 1. ], # [0.24460548, 0.63027853, 1. ]])

此時模型預(yù)測輸出結(jié)果為:

yhat = features1.dot(w) yhat[:5] #array([[0.90058932], # [0.73377993], # [0.25493639], # [0.48001114], # [0.24441544]])

此時需要知道的是,由于在訓(xùn)練參數(shù)w的時候是對標(biāo)簽也進(jìn)行了歸一化處理的,所以當(dāng)前預(yù)測結(jié)果和真實(shí)標(biāo)簽還差了一個歸一化過程,此時如果是面對完全未知情況進(jìn)行預(yù)測,我們需要講yhat逆向歸一化處理,即

labels_min = labels.min(0) labels_max = labels.max(0) labels_range = labels.max(0) - labels.min(0) yhat = yhat * labels_range + labels_min yhat[:5] #array([[ 479.25093691], # [ 280.4665185 ], # [-290.1646276 ], # [ -21.94619293], # [-302.70229372]])

比較真實(shí)標(biāo)簽:

labels1[:5] #array([[ 479.25042102], # [ 280.45978588], # [-290.16538845], # [ -21.94008706], # [-302.70455066]])

能夠看出,在經(jīng)過歸一化處理之后模型能夠排除量綱差異所導(dǎo)致的學(xué)習(xí)偏倚問題,最終得到一個準(zhǔn)確率較高的結(jié)果。

當(dāng)然,如果是劃分訓(xùn)練集和測試集進(jìn)行建模并且進(jìn)行歸一化操作,那么在遵循“在訓(xùn)練集上訓(xùn)練,在測試集上進(jìn)行測試”的基本原則下,我們首先在訓(xùn)練集上進(jìn)行數(shù)據(jù)歸一化處理并記錄各列的極值,然后當(dāng)模型訓(xùn)練完成之后,再借助訓(xùn)練集各列的極值來對測試集數(shù)據(jù)進(jìn)行歸一化,再帶入模型進(jìn)行測試。當(dāng)然,如果這個過程對標(biāo)簽也進(jìn)行了歸一化處理,則標(biāo)簽的歸一化過程和特征歸一化過程無異,唯一需要注意的是如果是對未知數(shù)據(jù)進(jìn)行預(yù)測,即需要模型輸出和真實(shí)采集到數(shù)據(jù)類似的結(jié)果,則需要在模型輸出的歸一化的標(biāo)簽基礎(chǔ)上進(jìn)行逆向歸一化處理。

此外,一般來說如果是Z-Score標(biāo)準(zhǔn)化,則無需對標(biāo)簽進(jìn)行標(biāo)準(zhǔn)化處理。

3.數(shù)據(jù)歸一化算法評價

此處我們通過量綱不一致問題引出歸一化方法,但歸一化方法卻并不一定、且不僅僅應(yīng)用于處理量綱不一致問題中。

首先,并非所有模型都受到數(shù)據(jù)各列的絕對數(shù)值大小影響,在通用的模型中,線性模型和距離類模型是兩類典型的會受到各列絕對數(shù)值大小影響的模型,例如線性回歸、KNN、K-Means(一種無監(jiān)督的聚類模型)等,并且邏輯回歸在使用ECOC編碼進(jìn)行類別判別時也是利用距離來判別樣本最終歸屬,此時,由于各列的絕對數(shù)值會影響模型學(xué)習(xí)的偏重,模型會更加側(cè)重于學(xué)習(xí)那些數(shù)值比較大的列,而無法“均勻”的從各列中提取有效信息,因此有時會出現(xiàn)較差的模型結(jié)果。但有些模型卻不受此影響,典型的如樹模型。

辯證的看,“均勻”的從各列提取有效信息其實(shí)也并不一定是最好的做法,本身對于有監(jiān)督學(xué)習(xí)算法來說,大多數(shù)數(shù)據(jù)集各列的重要性就不是等價的。但是,比起無法“均勻”的從各列提取有效信息,更可怕的是我們會不受控制的“不均勻”的去提取有效信息,這也是歸一化要解決的核心問題。

其次,我們需要知道,一旦對數(shù)據(jù)進(jìn)行歸一化處理,數(shù)據(jù)就將失去可解釋性,也就是失去了量綱。例如對于鳶尾花數(shù)據(jù)來說,原始數(shù)據(jù)代表花瓣花萼的長寬測量結(jié)果,而如果我們對其進(jìn)行歸一化處理,則每條數(shù)據(jù)就無法再給予明確的現(xiàn)實(shí)意義,這也是在很多要求可解釋性的情況下我們應(yīng)該避免使用歸一化方法的原因。

不僅是歸一化方法,其實(shí)所有的樣本空間的映射都會改變數(shù)據(jù)集的可解釋性。

其三,歸一化方法屬于仿射變換的一種特殊形式,而所有的仿射變換其實(shí)都不會影響數(shù)據(jù)集原始分布,也就是并不影響數(shù)據(jù)集真實(shí)規(guī)律,只會影響某些算法挖掘規(guī)律的難度(也就是受到特征絕對數(shù)值影響的算法)。例如對如下數(shù)據(jù),我們可以觀察其歸一化前后的數(shù)據(jù)分布變化情況:

# 設(shè)置隨機(jī)數(shù)種子 np.random.seed(24) # 擾動項取值為0.01 features, labels = arrayGenReg(delta=0.01)# 繪制圖像進(jìn)行觀察 plt.subplot(121) plt.plot(features[:, 0], labels, 'o') plt.subplot(122) plt.plot(maxmin_norm(features[:, 0]), maxmin_norm(labels), 'o')

仿射變換指的是樣本空間平移(加減某個數(shù))和放縮(乘除某個數(shù))的變換。0-1標(biāo)準(zhǔn)化過程中,平移就是減去每一列最小值,放縮就是除以某一列的極差。

最后,也是最重要的一點(diǎn),那就是對于梯度下降算法來說,歸一化能夠提高收斂速度,例如下圖所示,經(jīng)過歸一化處理之后的數(shù)據(jù),在進(jìn)行損失函數(shù)構(gòu)造時損失函數(shù)的等高線圖將更加均勻,此時梯度下降的收斂速度也將更快,具體理論理解詳見下文論述,而在實(shí)際使用過程中,經(jīng)過歸一化的數(shù)據(jù)在梯度下降過程中往往收斂更快,這其實(shí)是相比消除量綱影響,歸一化方法更加重要應(yīng)用場景。

在提高收斂速度方面,Z-Score效果要好于0-1標(biāo)準(zhǔn)化。

此處可以舉例說明。還是以前兩節(jié)的等高線圖案例進(jìn)行說明,嘗試對比在進(jìn)行數(shù)據(jù)歸一化前后兩組數(shù)據(jù)損失函數(shù)的等高線圖及收斂軌跡圖。

# 創(chuàng)建數(shù)據(jù)及進(jìn)行深拷貝 x = np.array([[1, 1], [3, 1]]) x_norm = np.copy(x) x_norm[:, :1] = z_score(x_norm[:, :1]) x_norm #array([[-1, 1], # [ 1, 1]]) y = np.array([[2], [4]]) y #array([[2], # [4]])

則歸一化前的SSE損失函數(shù)為:SSE=(2?w?b)2+(4?3w?b)SSE = (2-w-b)^2+(4-3w-b)SSE=(2?w?b)2+(4?3w?b)
而歸一化之后的損失函數(shù)為:SSE=(2+w?b)2+(4?w?b)2SSE = (2+w-b)^2 + (4-w-b)^2SSE=(2+w?b)2+(4?w?b)2
對比兩個損失函數(shù)的等高線圖及梯度下降軌跡圖:

np.random.seed(24) w = np.random.randn(2, 1) w_norm = np.copy(w)w, w_res = w_cal_rec(x, w, y, gd_cal = lr_gd, lr = 0.1, itera_times = 100) w_norm, w_res_norm = w_cal_rec(x_norm, w_norm, y, gd_cal = lr_gd, lr = 0.1, itera_times = 100)plt.subplot(121) # 網(wǎng)格點(diǎn)坐標(biāo) x1, x2 = np.meshgrid(np.arange(1, 2, 0.001), np.arange(-1, 1, 0.001)) # 繪制等高線圖 plt.contour(x1, x2, (2-x1-x2)**2+(4-3*x1-x2)**2) # 參數(shù)點(diǎn)移動軌跡圖 plt.plot(np.array(w_res)[:, 0], np.array(w_res)[:, 1], '-o', color='#ff7f0e') plt.subplot(122) # 網(wǎng)格點(diǎn)坐標(biāo) x1, x2 = np.meshgrid(np.arange(0, 4, 0.01), np.arange(-1, 3, 0.01)) # 繪制等高線圖 plt.contour(x1, x2, (2+x1-x2)**2+(4-x1-x2)**2) # 繪制參數(shù)點(diǎn)移動軌跡圖 plt.plot(np.array(w_res_norm)[:, 0], np.array(w_res_norm)[:, 1], '-o', color='#ff7f0e')


能夠看出經(jīng)過歸一化處理的之后的數(shù)據(jù)損失函數(shù)等高線更加均勻,收斂效率更高。

關(guān)于歸一化能夠讓等高線更加均勻從而加快迭代收斂過程的理解:
??從理論角度出發(fā),其實(shí)梯度下降過程每一步參數(shù)點(diǎn)移動的方向是能夠讓梯度最快速下降的方向,也就是圖片上垂直于等高線的方向。但這種所謂的最快速的方向只在開始移動的一瞬間滿足,由于梯度是連續(xù)變化的函數(shù),因此當(dāng)移動了一小步之后“最優(yōu)方向”其實(shí)就可能發(fā)生了變化,但參數(shù)只能在下次移動時再改變方向,因此中間其實(shí)很長一段距離參數(shù)并不不一定是沿著最優(yōu)方向在進(jìn)行移動。這里需要注意,如果下一次移動的方向和上一次移動方向一致或者類似,那就說明這次移動過程中參數(shù)并沒有偏離方向太多,反之則這次移動走了很多彎路。而當(dāng)損失函數(shù)的等高線是均勻分布時,外圈的垂直線也就是內(nèi)圈的垂直線,此時參數(shù)兩次移動過程大概率最優(yōu)方向一致,也就是說相同的移動能夠更大程度降低損失函數(shù)值,而如果類似圖1中的情況,內(nèi)外圈分布不均勻,則參數(shù)兩次迭代過程最優(yōu)方向?qū)l(fā)生偏移,也就是說明上一次迭代過程有很長一段距離沒有沿著最優(yōu)方向迭代,該次迭代只降低了有限的損失函數(shù)計算值。經(jīng)次過程不斷迭代,由于經(jīng)過歸一化的損失函數(shù)每次迭代效率都更高,因此相比其他損失函數(shù),經(jīng)過歸一化的數(shù)據(jù)只需要更少次的迭代就能抵達(dá)最小值點(diǎn),這也就是加快收斂速度的根本原因。

另外需要注意的是,收斂更快往往也意味著能夠收斂至更靠近全局最小值的點(diǎn)。

4.Z-Score標(biāo)準(zhǔn)化算法評價及橫向?qū)Ρ?/h3>

從大類上來分,Z-Score的使用場景要遠(yuǎn)高于0-1標(biāo)準(zhǔn)化使用場景。當(dāng)然這也并不是絕對的,要區(qū)分二者使用情景,我們首先需要進(jìn)一步了解二者算法性能。

  • 生成Zero-Centered Data

一般來說,由于Z-Score標(biāo)準(zhǔn)化生成數(shù)據(jù)的Zero-Centered特性,使得其在深度學(xué)習(xí)領(lǐng)域備受歡迎(是Batch Normalization的一種特殊情況)。而在機(jī)器學(xué)習(xí)領(lǐng)域?qū)τ跇?biāo)簽同時存在正負(fù)值的回歸類問題,使用Z-Score能夠避免對標(biāo)簽進(jìn)行歸一化。

  • 標(biāo)準(zhǔn)正態(tài)分布

由于該方法同時也是正態(tài)分布轉(zhuǎn)換為標(biāo)準(zhǔn)正態(tài)分布的計算公式,因此如果原始數(shù)據(jù)滿足正態(tài)分布,則經(jīng)過Z-Score轉(zhuǎn)化之后就能轉(zhuǎn)化為標(biāo)準(zhǔn)正態(tài)分布,進(jìn)而可以利用標(biāo)準(zhǔn)正態(tài)分布諸多統(tǒng)計性質(zhì)。

  • 保留極端值分布

還有一點(diǎn)非常實(shí)用的功能,就是相比0-1標(biāo)準(zhǔn)化,Z-Score標(biāo)準(zhǔn)化能夠保留極端值的分布。例如有數(shù)據(jù)如下:

a = np.arange(8).reshape(4, 2) a[1, 1] = 100 a #array([[ 0, 1], # [ 2, 100], # [ 4, 5], # [ 6, 7]])

其中第二列的第二個值就是極端值,如果對a進(jìn)行0-1標(biāo)準(zhǔn)化處理,則計算結(jié)果如下:

maxmin_norm(a) #array([[0. , 0. ], # [0.33333333, 1. ], # [0.66666667, 0.04040404], # [1. , 0.06060606]])

我們會發(fā)現(xiàn),由于極端值的存在,會將其他數(shù)值壓縮在一個非常小的范圍內(nèi)。而如果此時我們采用Z-Score進(jìn)行標(biāo)準(zhǔn)化,則計算結(jié)果如下:

z_score(a) #array([[-1.34164079, -0.65692457], # [-0.4472136 , 1.72970047], # [ 0.4472136 , -0.56049527], # [ 1.34164079, -0.51228063]])

我們發(fā)現(xiàn),極端值仍然還是極端值(相對該列其他數(shù)值而言),此時我們即可采用極端值處理方法對其進(jìn)行處理(刪除或者蓋帽)。

不過相比0-1標(biāo)準(zhǔn)化,Z-Score標(biāo)準(zhǔn)化問題也比較明顯,那就是需要進(jìn)行均值和方差的計算,而該過程將耗費(fèi)更大的計算量。

二、梯度下降算法優(yōu)化初階

歸一化和學(xué)習(xí)率調(diào)度,是梯度下降算法優(yōu)化的基本方法。

1.數(shù)據(jù)歸一化與梯度下降算法優(yōu)化

接下來,我們討論歸一化與梯度下降之間的關(guān)系。此前我們通過簡單例子觀察了數(shù)據(jù)歸一化對梯度下降的影響——即歸一化能夠改變損失函數(shù)形態(tài),而這種改變將顯著加快梯度下降的迭代收斂過程,直觀判斷是歸一化之后的損失函數(shù)等高線圖更加均勻。本小節(jié)我們將從梯度下降算法優(yōu)化角度出發(fā),討論數(shù)據(jù)歸一化和梯度下降之間的關(guān)系。

在機(jī)器學(xué)習(xí)模型優(yōu)化體系中,構(gòu)建損失函數(shù)和損失函數(shù)求解是模型優(yōu)化的兩大核心命題,通過損失函數(shù)的構(gòu)建和求解,就能夠找到模型最優(yōu)參數(shù)。但對于很多復(fù)雜模型來說,損失函數(shù)構(gòu)建和求解并非易事,而梯度下降作為損失函數(shù)求解的重要方法,如何優(yōu)化梯度下降求解過程,使其能夠“又快又好”的找到最小值點(diǎn),就成了決定建模成敗的核心因素。當(dāng)然,從梯度下降到隨機(jī)梯度下降再到小批量梯度下降,我們可以理解其為算法層面上的優(yōu)化,但除此以外還有許多圍繞優(yōu)化梯度下降求解過程的算法和方法,例如本節(jié)介紹的歸一化和學(xué)習(xí)率調(diào)度方法。

當(dāng)然,優(yōu)化方法的學(xué)習(xí)也需要遵循循序漸進(jìn)的過程,本節(jié)我們?nèi)匀贿€是在線性回歸損失函數(shù)、也就是凸函數(shù)上進(jìn)行基本優(yōu)化思路的介紹和基本優(yōu)化方法的學(xué)習(xí),圍繞現(xiàn)線性回歸的凸函數(shù)損失函數(shù)求解,其實(shí)是可以使用最小二乘法一步到位求出數(shù)值解的,但也正是因?yàn)槠渥顑?yōu)解明確存在,也就給了我們進(jìn)行對照實(shí)驗(yàn)的基礎(chǔ)。我們將利用梯度下降算法,在更加復(fù)雜的數(shù)據(jù)集上,探索如何使用優(yōu)化方法,來逼近明確存在的全域最小值點(diǎn),并在這個過程中深化對優(yōu)化方法的理解,進(jìn)而能夠在后續(xù)更加復(fù)雜的損失函數(shù)上、甚至是非凸的損失函數(shù)上,憑借我們的理解和所掌握的工具,用好最小二乘法這把利器進(jìn)行更快更好的最優(yōu)參數(shù)的求解。

  • 數(shù)據(jù)準(zhǔn)備

此處我們選取Lesson 1中的鮑魚數(shù)據(jù)集,并且采用其中相關(guān)性比較強(qiáng)的幾列進(jìn)行建模分析。數(shù)據(jù)集讀取過程如下:

aba_data = pd.read_csv("abalone.csv") aba_data


其中,我們選取鮑魚數(shù)據(jù)集中的Length(身體長度)和Diameter(身體寬度/直徑)作為特征,Whole weight(體重)作為標(biāo)簽進(jìn)行線性回歸建模分析。

aba_value = aba_data.values aba_value #array([[ 1. , 0.455 , 0.365 , ..., 0.101 , 0.15 , 15. ], # [ 1. , 0.35 , 0.265 , ..., 0.0485, 0.07 , 7. ], # [-1. , 0.53 , 0.42 , ..., 0.1415, 0.21 , 9. ], # ..., # [ 1. , 0.6 , 0.475 , ..., 0.2875, 0.308 , 9. ], # [-1. , 0.625 , 0.485 , ..., 0.261 , 0.296 , 10. ], # [ 1. , 0.71 , 0.555 , ..., 0.3765, 0.495 , 12. ]]) features = aba_value[:, 1: 3] features #array([[0.455, 0.365], # [0.35 , 0.265], # [0.53 , 0.42 ], # ..., # [0.6 , 0.475], # [0.625, 0.485], # [0.71 , 0.555]]) labels = aba_value[:, 4:5] labels #array([[0.514 ], # [0.2255], # [0.677 ], # ..., # [1.176 ], # [1.0945], # [1.9485]])

然后分別準(zhǔn)備一份原始數(shù)據(jù)與歸一化后的數(shù)據(jù)。

features = np.concatenate((features, np.ones_like(labels)), axis=1)# 深拷貝features用于歸一化 features_norm = np.copy(features)# 歸一化處理 features_norm[:, :-1] = z_score(features_norm[:, :-1]) features #array([[0.455, 0.365, 1. ], # [0.35 , 0.265, 1. ], # [0.53 , 0.42 , 1. ], # ..., # [0.6 , 0.475, 1. ], # [0.625, 0.485, 1. ], # [0.71 , 0.555, 1. ]]) features_norm #array([[-0.57455813, -0.43214879, 1. ], # [-1.44898585, -1.439929 , 1. ], # [ 0.05003309, 0.12213032, 1. ], # ..., # [ 0.6329849 , 0.67640943, 1. ], # [ 0.84118198, 0.77718745, 1. ], # [ 1.54905203, 1.48263359, 1. ]]) features.shape #(4177, 3)
  • 建模過程

首先是參數(shù)初始化與定義核心參數(shù)

# 設(shè)置初始參數(shù) np.random.seed(24) n = features.shape[1] w = np.random.randn(n, 1) w_norm = np.copy(w)# 記錄迭代過程損失函數(shù)取值變化 Loss_l = [] Loss_norm_l = []# 迭代次數(shù)/遍歷數(shù)據(jù)集次數(shù) epoch = 100w #array([[ 1.32921217], # [-0.77003345], # [-0.31628036]])

接下來,首先進(jìn)行梯度下降算法嘗試。

for i in range(epoch):w = w_cal(features, w, labels, lr_gd, lr = 0.02, itera_times = 1)Loss_l.append(MSELoss(features, w, labels))w_norm = w_cal(features_norm, w_norm, labels, lr_gd, lr = 0.02, itera_times = 1)Loss_norm_l.append(MSELoss(features_norm, w_norm, labels))
  • 觀察結(jié)果

和上一小節(jié)介紹的一樣,我們可以通過損失函數(shù)變化曲線來觀察梯度下降執(zhí)行情況

plt.plot(list(range(epoch)), np.array(Loss_l).flatten(), label='Loss_l') plt.plot(list(range(epoch)), np.array(Loss_norm_l).flatten(), label='Loss_norm_l') plt.xlabel('epochs') plt.ylabel('MSE') plt.legend(loc = 1)


我們發(fā)現(xiàn),經(jīng)過歸一化后的數(shù)據(jù)集,從損失函數(shù)變化圖像上來看,收斂速度更快(損失函數(shù)下降速度更快),且最終收斂到一個更優(yōu)的結(jié)果。

Loss_l[-1] #array([[0.12121076]]) Loss_norm_l[-1] #array([[0.05988496]]) w #array([[ 1.71641833], # [-0.46009876], # [ 0.13633803]]) w_norm #array([[ 1.22387436], # [-0.76710614], # [ 0.80942526]])

這里需要注意,由于我們沒有對標(biāo)簽進(jìn)行歸優(yōu)化,因此兩個迭代過程可以直接進(jìn)行絕對數(shù)值的大小關(guān)系比較。

  • 對比全域最小值點(diǎn)

當(dāng)然,由于上述損失函數(shù)是凸函數(shù),因此我們可以用最小二乘法直接求解全域最優(yōu)解。這里需要注意,由于歸一化只對數(shù)據(jù)進(jìn)行平移和放縮而不改變數(shù)據(jù)分布規(guī)律,因此即使最小值點(diǎn)位置不同,但最終對應(yīng)的對標(biāo)簽的預(yù)測結(jié)果應(yīng)該保持一致,并且全域最小值點(diǎn)對應(yīng)MSE數(shù)值也應(yīng)該一致。

w1 = np.linalg.lstsq(features, labels, rcond=-1)[0] w1 #array([[ 1.87229017], # [ 2.33724788], # [-1.1056427 ]]) w2 = np.linalg.lstsq(features_norm, labels, rcond=-1)[0] w2 #array([[0.22482186], # [0.2319204 ], # [0.82874216]]) features.dot(w1) #array([[0.59934481], # [0.16902955], # [0.8683152 ], # ..., # [1.12792415], # [1.19810388], # [1.5208559 ]]) features_norm.dot(w2) #array([[0.59934481], # [0.16902955], # [0.8683152 ], # ..., # [1.12792415], # [1.19810388], # [1.5208559 ]]) MSELoss(features_norm, w2, labels) #array([[0.03318563]]) MSELoss(features, w1, labels) #array([[0.03318563]])
  • 結(jié)論分析

通過上述計算結(jié)果,我們不難分析,其實(shí)在進(jìn)行梯度下降計算過程中,在以0.02作為學(xué)習(xí)率進(jìn)行迭代的過程中,兩組模型都沒有收斂到全域最小值點(diǎn),也就是出現(xiàn)了類似如下情況:

plt.title('lr=0.001') show_trace(gd(lr=0.001))


但有趣的是,為何在相同學(xué)習(xí)率下,在歸一化之后的數(shù)據(jù)集上進(jìn)行梯度下降,卻更加接近全域最小值點(diǎn),這又是什么原因呢?回顧此前我們所討論的歸一化對損失函數(shù)的影響,從等高線圖上來看是等高線變得更加均勻,但實(shí)際上是整個損失函數(shù)在不同區(qū)域?qū)?yīng)梯度都更加均勻,從而在靠近最小值點(diǎn)附近的梯度也比歸一化之前的損失函數(shù)梯度要大,也就是說,雖然學(xué)習(xí)率相同,但由于歸一化之后最小值點(diǎn)附近梯度要更大,因此同樣的迭代次,在歸一化之后的損失函數(shù)上參數(shù)點(diǎn)將移動至更加靠近最小值地附近的點(diǎn)。也就類似如下情況:

def gd1(lr = 0.02, itera_times = 20, w = 10):"""梯度下降計算函數(shù):param lr: 學(xué)習(xí)率:param itera_times:迭代次數(shù):param w:參數(shù)初始取值:return results:每一輪迭代的參數(shù)計算結(jié)果列表""" results = [w]for i in range(itera_times):w -= lr * 28 * 2 * (w - 2) # gd函數(shù)系數(shù)是28results.append(w)return resultsdef show_trace1(res):"""梯度下降軌跡繪制函數(shù)"""f_line = np.arange(-6, 10, 0.1)plt.plot(f_line, [28 * np.power(x-2, 2) for x in f_line])plt.plot(res, [28 * np.power(x-2, 2) for x in res], '-o')plt.xlabel('x')plt.ylabel('Loss(x)')plt.subplot(121) plt.title('28(x-2)**2') show_trace(gd(lr=0.001)) plt.subplot(122) plt.title('56(x-2)**2') show_trace1(gd1(lr=0.001))


學(xué)習(xí)率相同,迭代次數(shù)相同,但經(jīng)過歸一化的損失函數(shù)更加陡峭,靠近最小值點(diǎn)附近梯度更大,因此最終收斂到一個更加靠近最小值點(diǎn)附近的點(diǎn)。而這個問題要如何解決,我們首先想到的是增加學(xué)習(xí)率,但問題是學(xué)習(xí)率增加多少才合適呢?試著增加10倍看下結(jié)果:

# 設(shè)置初始參數(shù) np.random.seed(24) n = features.shape[1] w = np.random.randn(n, 1) w_norm = np.copy(w)# 記錄迭代過程損失函數(shù)取值變化 Loss_l = [] Loss_norm_l = []# 迭代次數(shù)/遍歷數(shù)據(jù)集次數(shù) epoch = 100for i in range(epoch):w = w_cal(features, w, labels, lr_gd, lr = 0.2, itera_times = 1)Loss_l.append(MSELoss(features, w, labels))w_norm = w_cal(features_norm, w_norm, labels, lr_gd, lr = 0.2, itera_times = 1)Loss_norm_l.append(MSELoss(features_norm, w_norm, labels))plt.plot(list(range(epoch)), np.array(Loss_l).flatten(), label='Loss_l') plt.plot(list(range(epoch)), np.array(Loss_norm_l).flatten(), label='Loss_norm_l') plt.xlabel('epochs') plt.ylabel('MSE') plt.legend(loc = 1)

Loss_l[-1] #array([[0.06004797]]) Loss_norm_l[-1] #array([[0.04334334]])

我們發(fā)現(xiàn),在提高學(xué)習(xí)率之后,梯度下降效果略有提升,能夠收斂到一個更加趨近于全域最小值的點(diǎn),并且歸一化之后的損失函數(shù)收斂速度明顯更快。但以當(dāng)前學(xué)習(xí)率,還是無法收斂止最小值點(diǎn),此時我們可以不斷嘗試,直到“測出”最佳學(xué)習(xí)率為止。當(dāng)然,在Scikit-Learn中其實(shí)也提供了這種類似枚舉去找出最佳超參數(shù)取值的方法,但如果是面對超大規(guī)模數(shù)據(jù)集的建模,受到計算資源的限制,我們其實(shí)是無法反復(fù)建模來找到最優(yōu)學(xué)習(xí)率的,此時就需要采用一種更加先進(jìn)的計算流程來解決這個問題。

伴隨數(shù)據(jù)集復(fù)雜程度提升,尋找最小值點(diǎn)過程將越來越復(fù)雜。并且哪怕是凸函數(shù),很多情況也無法用最小二乘法一步到位求出最優(yōu)解,仍然需要依靠梯度下降來求解,此時能夠使用梯度下降的優(yōu)化算法來幫助進(jìn)行順利求解,就變得至關(guān)重要。

2.學(xué)習(xí)率調(diào)度

  • 基本概念

其實(shí)梯度下降優(yōu)化的核心目標(biāo)就是希望“更快更好”的找到最小值點(diǎn),歸一化是通過修改損失函數(shù)來達(dá)成這個目標(biāo),而所謂學(xué)習(xí)率調(diào)度,則是通過調(diào)整學(xué)習(xí)率來達(dá)到這個目標(biāo)。值得注意的是,此時找到一個確定的最優(yōu)學(xué)習(xí)率并不是目標(biāo),“更快更好”找到最小值點(diǎn)才是目標(biāo),因此我們完全可以考慮在迭代過程動態(tài)調(diào)整學(xué)習(xí)率。而所謂學(xué)習(xí)率調(diào)度,也并不是一個尋找最佳學(xué)習(xí)率的方法,而是一種伴隨迭代進(jìn)行、不斷調(diào)整學(xué)習(xí)率的策略。

學(xué)習(xí)率調(diào)度方法有很多種,目前流行的也達(dá)數(shù)十種之多,而其中一種最為通用的學(xué)習(xí)率調(diào)度方法是學(xué)習(xí)率衰減法,指的是在迭代開始時設(shè)置較大學(xué)習(xí)率,而伴隨著迭代進(jìn)行不斷減小學(xué)習(xí)率。通過這樣的學(xué)習(xí)率設(shè)置,能夠讓梯度下降收斂速度更快、效果更好。

  • 實(shí)踐過程

例如在上述例子中,我們不妨設(shè)置這樣的減速衰減的一個學(xué)習(xí)調(diào)度策略,衰減過程比例由如下函數(shù)計算得出:

lr_lambda = lambda epoch: 0.95 ** epoch lr_lambda(0) #1.0 lr_lambda(2) #0.9025 lr_l = [] for i in range(10):lr_l.append(lr_lambda(i)) lr_l #[1.0, # 0.95, # 0.9025, # 0.8573749999999999, # 0.8145062499999999, # 0.7737809374999998, # 0.7350918906249998, # 0.6983372960937497, # 0.6634204312890623, # 0.6302494097246091]

即假設(shè)初始學(xué)習(xí)率為0.5,則第一次迭代時實(shí)際學(xué)習(xí)率為0.5*1,第二輪迭代時學(xué)習(xí)率為0.5*0.95,以此類推。

據(jù)此,我們可以優(yōu)化梯度下降迭代過程,此時我們對比恒定學(xué)習(xí)率和學(xué)習(xí)率衰減的兩個梯度下降過程,并且都采用歸一化后的數(shù)據(jù)集進(jìn)行計算:

# 設(shè)置初始參數(shù) np.random.seed(24) n = features.shape[1] w = np.random.randn(n, 1) w_lr = np.copy(w)# 記錄迭代過程損失函數(shù)取值變化 Loss_l = [] Loss_lr_l = []# 迭代次數(shù)/遍歷數(shù)據(jù)集次數(shù) epoch = 20for i in range(epoch):w = w_cal(features_norm, w, labels, lr_gd, lr = 0.2, itera_times = 10) #迭代十次更新wLoss_l.append(MSELoss(features_norm, w, labels))w_lr = w_cal(features_norm, w_lr, labels, lr_gd, lr = 0.5*lr_lambda(i), itera_times = 10)Loss_lr_l.append(MSELoss(features_norm, w_lr, labels))plt.plot(list(range(epoch)), np.array(Loss_l).flatten(), label='Loss_l') plt.plot(list(range(epoch)), np.array(Loss_lr_l).flatten(), label='Loss_lr_l') plt.xlabel('epochs') plt.ylabel('MSE') plt.legend(loc = 1)

Loss_lr_l[-1] #array([[0.03416214]]) Loss_l[-1] #array([[0.03671235]])

這里有一點(diǎn)進(jìn)行了微調(diào),那就是我們實(shí)際上是令梯度下降計算過程中每迭代10次更新一次學(xué)習(xí)率,總共更新了20次學(xué)習(xí)率,即總共迭代了200次,最后10次更新時學(xué)習(xí)率為0.5*lr_lambda(20),即

0.5*lr_lambda(20) #0.17924296120427094

整體來看學(xué)習(xí)率變化區(qū)間橫跨0.18-0.5之間,而最終上述學(xué)習(xí)率調(diào)度也確實(shí)起到了更好的效果。

  • 算法評價

接下來,簡單總結(jié)學(xué)習(xí)率調(diào)度的使用場景和注意事項。

首先,在很多海量數(shù)據(jù)處理場景下,學(xué)習(xí)率調(diào)度的重大價值在于能夠提供對學(xué)習(xí)率超參數(shù)設(shè)置更大的容錯空間。在很多情況下,搜索出一個最佳學(xué)習(xí)率取值進(jìn)而設(shè)置恒定學(xué)習(xí)率進(jìn)行梯度下降,難度會遠(yuǎn)高于設(shè)置一組學(xué)習(xí)率衰減的參數(shù)。并且有的時候,剛開始學(xué)習(xí)率設(shè)置過大其實(shí)也可以通過多輪迭代進(jìn)行調(diào)整,其所消耗的算力也遠(yuǎn)低于反復(fù)訓(xùn)練模型尋找最佳恒定學(xué)習(xí)率。

其次,盡管上述例子我們是在梯度下降中使用學(xué)習(xí)率衰減這一調(diào)度策略,但實(shí)際上更為一般的情況是學(xué)習(xí)率調(diào)度和小批量梯度下降或者隨機(jī)梯度下降來配合使用。一般來說梯度下降的使用場景在于小規(guī)模數(shù)據(jù)集且損失函數(shù)較為簡單的情況,此時可利用梯度下降+枚舉找到最佳學(xué)習(xí)率的策略進(jìn)行模型訓(xùn)練,其相關(guān)操作的技術(shù)門檻相對較低(枚舉法可借助Scikit-Learn的網(wǎng)格搜索);而對于更大規(guī)模的數(shù)據(jù)集且損失函數(shù)情況更加復(fù)雜時,則需要考慮小批量梯度下降+學(xué)習(xí)率調(diào)度方法來進(jìn)行梯度下降求解損失函數(shù)。

當(dāng)然,除了學(xué)習(xí)率衰減外還有很多學(xué)習(xí)率調(diào)度策略,甚至有些學(xué)習(xí)率調(diào)度策略會間接性提高和降低學(xué)習(xí)率,來幫助梯度下降找到最小值點(diǎn)。更多學(xué)習(xí)率調(diào)度策略我們將在后續(xù)進(jìn)階內(nèi)容中繼續(xù)介紹。

3.小批量梯度下降與迭代收斂速度

小批量梯度下降不僅可以幫助損失函數(shù)跨越局部最小值點(diǎn),同時也能加快梯度下降的收斂速度。例如以0.02作為學(xué)習(xí)率、batch_size為50的情況下,測試梯度下降收斂過程:

# 設(shè)置初始參數(shù) np.random.seed(24) n = features.shape[1] w = np.random.randn(n, 1) w_norm = np.copy(w)# 記錄迭代過程損失函數(shù)取值變化 Loss_l = [] Loss_norm_l = []# 迭代次數(shù)/遍歷數(shù)據(jù)集次數(shù) epoch = 50np.random.seed(24) w = np.random.randn(3, 1) sgd_cal(Xtrain, w, ytrain, lr_gd, batch_size=1, epoch=3000, lr=0.02) #array([[ 0.76959334], # [-0.29175077], # [-0.17624047]])# 執(zhí)行迭代計算 for i in range(epoch):w = sgd_cal(features, w, labels, lr_gd, batch_size=50, epoch=1, lr=0.02)Loss_l.append(MSELoss(features, w, labels))w_norm = sgd_cal(features_norm, w_norm, labels, lr_gd, batch_size=50, epoch=1, lr=0.02)Loss_norm_l.append(MSELoss(features_norm, w_norm, labels))# 觀察計算結(jié)果 plt.plot(list(range(epoch)), np.array(Loss_l).flatten(), label='Loss_l') plt.plot(list(range(epoch)), np.array(Loss_norm_l).flatten(), label='Loss_norm_l') plt.xlabel('epochs') plt.ylabel('MSE') plt.legend(loc = 1)

在遍歷50次數(shù)據(jù)集的情況下就已經(jīng)能夠基本逼近全域最優(yōu)解,這說明局部規(guī)律的不一致性其實(shí)也將有助于提升模型收斂效率。同時我們也能發(fā)現(xiàn)數(shù)據(jù)歸一化也能夠有效提升小批量梯度下降的收斂速度。(小批量梯度下降和歸一化都能加快梯度下降收斂速度)

4.梯度下降組合優(yōu)化策略

當(dāng)然,無論是數(shù)據(jù)歸一化、學(xué)習(xí)率調(diào)度還是采用小批量梯度下降,這些方法并不互斥,我們完全可以組合進(jìn)行使用。

# 設(shè)置初始參數(shù) np.random.seed(24) n = features.shape[1] w = np.random.randn(n, 1) w_opt = np.copy(w)# 記錄迭代過程損失函數(shù)取值變化 Loss_l = [] Loss_opt_l = []# 迭代次數(shù)/遍歷數(shù)據(jù)集次數(shù) epoch = 100 w #array([[ 1.32921217], # [-0.77003345], # [-0.31628036]])# 執(zhí)行迭代計算 for i in range(epoch):w = w_cal(features, w, labels, lr_gd, lr = 0.2, itera_times = 1)Loss_l.append(MSELoss(features, w, labels))w_opt = sgd_cal(features_norm, w_opt, labels, lr_gd, batch_size=50, epoch=1, lr=0.5*lr_lambda(i))Loss_opt_l.append(MSELoss(features_norm, w_opt, labels))# 觀察計算結(jié)果 plt.plot(list(range(epoch)), np.array(Loss_l).flatten(), label='Loss_l') plt.plot(list(range(epoch)), np.array(Loss_opt_l).flatten(), label='Loss_norm_l') plt.xlabel('epochs') plt.ylabel('MSE') plt.legend(loc = 1)

Loss_opt_l[-1] #array([[0.03318614]]) Loss_l[-1] #array([[0.06004797]])

據(jù)此,我們不難發(fā)現(xiàn),在經(jīng)過一系列優(yōu)化手段處理之后的梯度下降過程,即使用歸一化進(jìn)行數(shù)據(jù)處理、采用小批量梯度下降、并且采用學(xué)習(xí)率調(diào)度方法來進(jìn)行參數(shù)迭代求解過程,效果會遠(yuǎn)遠(yuǎn)好于使用原始梯度下降算法來進(jìn)行求解,不僅收斂速度更快,并且最終也能夠收斂至一個更好的結(jié)果(更加逼近全域最小值點(diǎn)),這也就是優(yōu)化方法能夠讓梯度下降迭代過程“更好更快”收斂的直接體現(xiàn)。

當(dāng)然,在后續(xù)的梯度下降算法使用過程中,如無特殊要求,我們將默認(rèn)使用數(shù)據(jù)歸一化+學(xué)習(xí)率
衰減+小批量梯度下降算法來進(jìn)行求解。而更進(jìn)一步的,關(guān)于學(xué)習(xí)率衰減的其他策略及配合設(shè)置的初始學(xué)習(xí)率參數(shù),小批量梯度下降中的小批數(shù)據(jù)量等超參數(shù)的設(shè)置,我們將在后續(xù)使用過程中進(jìn)行更進(jìn)一步的探討。

總結(jié)

以上是生活随笔為你收集整理的Lesson 4.5 梯度下降优化基础:数据归一化与学习率调度的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。