大白話5分鐘帶你走進人工智慧-第九節梯度下降之函式最優化演算法和梯度下降程式碼過程解析(4)

LHBlog發表於2019-04-11

                                                                                    第九節梯度下降之函式最優化演算法(4)

上一節中我們介紹了梯度下降的兩種方式,批量梯度下降和隨機梯度下降的兩種方式,介紹了其具體的梯度下降的方式。本節的話,我們介紹一種函式最優化的演算法。以後一聽到函式最優化演算法,就理解它就是一個工具,交給它一個函式,我給你找到它的最小值在哪。只有函式有最小值,才會有這種梯度下降的方式。

所以我們引入區域性最優解和全域性最優解。雖然對於之前講的線性迴歸,以及未來講的邏輯迴歸來講,它只有一個最小值,但是對於深度神經網路來說,它是有很多個極小值的。那麼有這麼多的極小值,對於每一個極小值,我們都叫一個local最小值,區域性最小值。而在最深的谷底叫做全域性最小值。

那麼梯度下降能找到全域性最優解嗎?不一定。對於凸函式來說,通過梯度下降法只能找到一個最優解。即全域性最優解,如果函式並不是凸函式,那麼函式定義域上存在多個最優解,使用梯度下降演算法找到的最優解並不能保證是全域性最優解,這樣的解就有可能是區域性最優解。這個是沒有辦法突破的一個問題,所以在非凸函式這種有多個區域性最優解的函式中,使用任何我們們現在已知的這種梯度下降的這種方式,並且可以實踐的,找全域性最優解的方式要麼就是計算複雜度太高,要麼就是壓根找不到。

那該怎麼辦呢,其實可以通過你多隨機幾次,你看它能找到谷底,完全取決於它上來初始化的位置在哪了,所以通常會使用多次初始化的方式,比如我初始化五次,我得到五個區域性最優解,你拿最小的區域性最優解來用,相對來說你至少沒找到最差的一個區域性最優解。通過更合理的初始化方式,是一個讓它更大概率的落在比較深的谷底,這個也是我們們在學深度學習的時候要學的一些內容,目的也是為了防止梯度彌散梯度消失。所以多次隨機之後找到的區域性最優解也不是一個不可以接受的這麼一個結果。但對於這種梯度下降法,它是還有一個缺陷的,比如下圖:

你通常認為在一個凸函式的時候,越平緩的地方離最優解越近,但是有一些函式它會有這個plateau(高原)。比如青藏高原就是它明明很高,但是它又很平,這會兒梯度下降就會陷入一個坑裡,走不動了,所以梯度下降,對於這種情況也是它的弱項。我們看下梯度下降的程式碼實現:

import numpy as np
from sklearn.linear_model import LinearRegression
#構造 100個x

X = 2 * np.random.rand(100, 1)
# 模擬出100個y
y = 4 + 3 * X + np.random.randn(100, 1)
# 例項化出一個 線性迴歸器 是個物件
lin_reg = LinearRegression()
lin_reg.fit(X, y)
print(lin_reg.intercept_, lin_reg.coef_)

X_new = np.array([[0], [2]])
print(lin_reg.predict(X_new))

 

解釋下上面程式碼:X = 2 * np.random.rand(10000, 1)  構造一百個X。y = 4 + 3 * X + np.random.randn(10000, 1)在幹什麼?模擬出一百個Y。我們們從import ,sklearn.linear_model import LinearRegression  匯入線性迴歸。所有的sklearn裡邊的這種迴歸分類的這種東西,這種工具基本都是這麼用的。就是首先通過LinearRegression這個類建立出一個物件,相當於實力化出一個線性迴歸器,然後這些物件有它自己的屬性,其中就有一個fit,這是它的成員函式fit,fit原始碼如下:

                         def fit(self, X, y, sample_weight=None)

這個函式,需要你傳進一個X,傳進一個Y,還可以傳一個sample_weight代表這條資料的重要性,你可以去把一些資料給設的重要一些,設的不重要一些,通常不傳它。那麼一個X,傳一個Y,按理說你想你訓練模型就丟給這個演算法一個訓練集,然後就可以了,我們fit完了之後,在這個物件裡面會產生兩個新的屬性,一個叫intercept,代表截距,一個叫coefficient,代表係數,其中intercept是B或者W0, coefficient所有的W。

問:對於我們們這個例子裡面有幾個intercept? 對於任何例子中有幾個intercept?coefficient有幾個?

答:intercept都是隻有一個,coefficient在這個例子裡是一個,在其它的例子裡面是你X有多少列就會有多少個W,它會把所有的coefficient按照對應的W給列出來。我們先執行一下程式碼,得出結果是截距(intercept)是3.72和引數(coefficient是)3.2,跟我們原始的4和3差不太多是吧?因為我們只有一百個X而且還是一樣的,那麼接下來當來一條新資料怎麼預測? 實際上我們就是用lin_reg,就是我通過LinearRegression這個類建立的物件,並且訓練完了之後,物件本身模型就存在這個物件裡了。你呼叫它的predict函式再把新的資料丟進去,它就會把新的資料的預測結果給返回來,那麼

                          X_new = np.array([[0], [2]])

這裡面傳了幾條資料進去?傳的是一條還是兩條?實際上是兩條,雖然受限於我們們程式碼的書寫方式,它二維陣列就是矩陣,實際上它輸入的是這麼一個東西。

                                                 \begin{bmatrix} [0]\\ [2] \end{bmatrix}

兩行一列的矩陣。代表是兩條資料,而每條資料因為只有一個維度。對於0,它的預測結果其實就是0×3.2+3.72,預測結果應該是3.72。而對於2的預測結果就應該是2×3.21+3.72。

問:predict快還是fit快?

答:應該是fit快,按理說,任何模型都會發生這兩步,先predict再fit.當我再執行一遍模型時,模型結果又變了,為什麼變了?因為你隨機產生的訓練集變了。加上如下程式碼,放在構建X之前。

                             np.random.seed(1)

seed(1)裡面我隨便寫個數進去,這裡寫成1,以後我每次執行這程式碼運算的都是不變。這個就是你在調參的時候都會把這個東西給定死,否則你不知道是你引數影響你模型變好了,還是訓練過程中的一些隨機過程影響你這個結果變好了。通常會願意把它定死。

問:這個背後到底是用的解析解求的還是用的梯度下降求得呢?

           答:我們知道梯度下降一般會有超引數,那麼我們的程式碼裡超引數又在哪?你發現你在fit的過程中,是不是隻讓你傳了X和Y,沒有傳其他引數的地方了?實際上在你建立物件的時候,會有一些超引數,在lin_reg裡面它基本上沒有讓我們去設定額外的超引數,但是在其他的演算法裡面是有的。lin_reg的原始碼:

           def __init__(self, fit_intercept=True, normalize=False, copy_X=True,n_jobs=1):

fit_intercept,是否要把截距給加上? 如果你把它置為false,你訓練出來就一個W,什麼樣的情況下會和現在情況等價?當把你訓練集通通的加一個W0等於1,這樣你再設成false和fit_intercept直接設成true是一模一樣的結果。

問:無論是解析解,還是梯度下降。重運算量的事物在哪?

答:肯定是fit,predict只是簡單的一個相乘相加就完事了,這個是我們想要的機器學習架構,有一些演算法是反過來的,它fit階段就把它存下來就好了,predict階段才會去計算。比如KNN演算法,它實際上是一個分類演算法,來一個新的資料,它去比較跟你訓練集上的每一條資料誰更像?離誰更像哪條資料,你想它fit階段做了什麼? 什麼事也沒幹。直到你拿到這條新資料之後,你才能去逐條的跟每一個原來的過去的訓練集裡的資料去比較。所以它的大部分運送量是不是都在predict的階段?所以實際上predict階段非常的冗餘,那麼為什麼我們不想要這種情況?想一下,你訓練模型的架構,是有具備大規模算力的系統,是在你的中心節點上訓練的,而客戶端使用你的系統,使用你的AI的成果,實際上是使用你提前訓練好的模型。比如國產手機前置AI雙攝拍人更美功能,它使用的時候,實際上儲存在手機本地的就是一組權重值,是你提前訓練好的模型預存在你手機裡的,而不是需要你先拍一千張自己的照片越拍越美。它是提前已經訓練好凍結住的模型,它認為最合適了,預製到手機裡是一組權重,那麼手機要乾的什麼?其實就是一個類似相乘相加的工作,把它給都搞出來,所以我們希望我們的訓練架構苦多累沒關係,你讓我用的時候能達到實時運算就可以了,要做到 儘量把大規模的運算往中間節點放,提前準備好模型。

截止目前為止,你已經對人工智慧應用有一個相對的自己的概念了,比如前陣AlphaGo火爆所有媒體眼球的時候,大家想象中的就是計算機很厲害,它再在你下一步棋的時候,其實它已經把所有的可能性想象到了,這個是媒體的腦洞,我們們的算力根本不可能達到,讓它把所有的步驟算出來,遠遠達不到,你想的容易覺得計算機運算的快,它運算的再快,隨著指數級上升,這個東西很快它也就飽和了,能理解嗎?AlphaGo找到的也都是一系列的區域性最優解,遠沒有那麼暴力,我們們的計算機的算力遠沒有那麼暴力,然後另外一個就是AlphaGo知不知道它在下圍棋?其實真的不知道。計算機永遠是一個大的計算器,至少在當前通用型人工智慧沒有實現之前,我們們現在的人工智慧,你會發現它是一個更高效的幫你算數的機器,而更智慧的應用是從深度神經網路開始的,深度神經網路所謂的智慧,也不是說它真的有思想了,而只是中間它的隱藏層能自動幫你組合出新的特徵來,這新的特徵什麼意思?人類已經沒法理解了,它就是一種純粹的數值上的特徵。

下一節中我們將講解歸一化的各種方式和必要性。

 

相關文章