
使用這些基本 REST API 最佳實踐構建出色的 API
from keras.layers import Dense
model = Sequential()
model.add(Dense(4, input_dim=2,activation='relu'))
model.add(Dense(6, activation='relu'))
model.add(Dense(6, activation='relu'))
model.add(Dense(4, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model.fit(X_train, y_train, epochs=50, verbose=0)
如前面說過,只需幾個導入、幾行代碼就能創建和訓練一個模型,拿來解決分類問題幾乎能達到 100% 的準確率。我們的工作歸納起來就是根據選擇的模型結構,為模型提供超參數,比如網絡層的數量、每層的神經元數量、激活函數和訓練周期數量等等。下面我們來看看訓練的過程發生了什么,可以看到隨著訓練過程中,數據被正確地區分開了!
有了這些框架,這的確為我們節省了大量寫bugs(…) 的時間,讓我們的工作也更加流程化。然而,熟知神經網絡背后的工作原理,對于我們選擇模型架構、調參或優化模型都有莫大的幫助。
為了更深入的理解神經網絡的工作原理,本文將幫助大家理解一些在學習過程中可能會感到困惑的概念。我會盡量讓那些對代數和微積分不感冒的朋友讀著不那么痛苦,但是正如文章題目所示,本文主要講數學原理,所以會談論大量的數學,在這里先提個醒。
舉個例子,我們要解決一個數據集的二元分類問題,數據集如上所示。
數據點組成了兩個類別的圓圈狀,要區分這個數據,對很多傳統的機器學習算法來說都非常麻煩,但神經網絡可以很好地處理這個非線性分類問題。
為了解決這個問題,我們會使用如下圖所示結構的神經網絡,它有 5 個全連接層,每層有不同數量的神經元。對于隱藏層,我們會使用 ReLU 作為激活函數,在輸出層中使用 S 型函數。這是個相當簡單的結構,但也足夠解決我們的難題了。
我們首先來回答這個關鍵的問題:什么是神經網絡?它是一種在生物學啟發下創建的計算機程序,能夠學習知識,獨立發現數據中的關系。如圖 2 所示,神經網絡就是一系列的神經元排列在網絡層中,網絡層以某種方式連接在一起,從而相互之間實現溝通。
每個神經元會接受一系列的 x 值(從 1 到 n 的數字)作為輸入,計算預測的 y-hat 值。向量 x 實際上包含了訓練集中 m 個樣本中一個樣本的特征值。而且每個神經元會有它自己的一套參數,通常引用為 w(權重的列向量)和 b(偏差),在學習過程中偏差會不斷變化。在每次迭代中,神經元會根據向量 x 的當前權向量 x 計算它的加權平均值,再和偏差相加。最后,計算的結果會傳入一個非線性或函數 g 中。我在下面會提及一些最常見的激活函數。
現在,我們把范圍縮小一點,思考一下神經網絡的整個網絡層是怎么進行數學運算的。我們會利用單個神經元的計算知識,在整個層中進行向量化,將這些計算融合進矩陣方程中。為了讓數學符號一致,這些方程會寫給選定的網絡層。另外,下標的 i 符號標記了這一層的神經元順序。
還有一件重要的事:在我們為單個神經元寫方程時,我們使用 x 和 y-hat,它們分別表示特征列向量和預測值。當換成網絡層的通用符號時,我們使用向量 a —— 意指對應網絡層的激活。因此 x 向量是網絡層 0(輸入層)的激活。網絡層中的每個神經元都按照如下方程式執行相同的運算:
讓大家更清晰的看看,我們把第 2 層的公式寫下來:
你可以看到,對每個網絡層,我們必須執行一系列非常相似的運算。在這里使用 for 循環并不是非常高效,所以我們換成向量化來加快計算速度。首先,將權重 w 的水平向量堆放在一起,我們創建矩陣 W。同樣地,我們將網絡層中每個神經元的偏差堆放在一起,創建垂直向量 b。現在,我們可以順利地創建一個矩陣方程式了,從而一次性計算該網絡層的所有神經元。我們同樣寫下來用過的矩陣和向量的維度。
我們迄今所用的方程式只涉及了一個例子。在神經網絡的學習過程中,你通常要處理大量的數據,最高可達數百萬條。所以下一步就是在多個例子中實現向量化。假設我們的數據集有 m 個條目,每個有 nx 個特征。首先,我們將每一層的垂直向量 x,a 和 z 放在一起,分別創建矩陣 X,A 和 Z。然后,我們根據新創建的矩陣,重新編寫之前列出的方程式。
激活函數是神經網絡中最重要的部分之一。沒有激活函數,我們的神經網絡就只是一些線性函數的組合,那樣無非就是個線性函數而已。如果是這樣,模型的擴展性就很有限了,比邏輯回歸也強不到哪去。非線性部分能讓模型有更大的靈活性,在學習過程中也能創建復雜的函數。
此外,激活函數對模型的學習速度也有重大影響,而學習速度是選擇模型的主要標準之一。下圖顯示了一些常用的激活函數。當前,隱藏層中最常用的激活函數應該是 ReLU。在處理二元分類問題時,特別是想讓模型返回在 0 到 1 之間的值時,我們有時也會使用 S 型函數,特別是在輸出層中。
學習過程中基本信息源就是損失函數的值。通常來講,使用損失函數的目的就是展示我們離“理想”情況的差距。在我們這個例子中,我們使用了二元交叉熵,但根據我們處理的具體問題,可以使用不同的函數。我們所用的函數用如下公式表示,在學習過程中它的值的變化情況可視化動圖如下。它顯示了每次迭代中,損失函數的值在不斷下降,準確度的值也不斷增加。
學習過程就是不斷改變 W 和 b 參數的值,讓損失函數實現最小化。為了能實現這個目標,我們會借助微積分,使用梯度下降法來找到函數最小值。在每次迭代中,我們會計算損失函數偏導數相對于每個神經網絡參數的值。對于不太熟悉這種計算類型的人,我這里提示一下,導數能夠描述函數的斜率。正因如此,我們能夠知道該如何操作變量,從而在圖中向下移動。為了能讓大家直觀感受梯度下降的工作原理,我預備了一點小小的可視化,如下圖所示。你可以看到,隨著訓練批次增加,我們越來越靠近最小值。在我們的神經網絡中,也是同樣的工作方式——每次迭代計算出的梯度為我們顯示了應該向哪個方向移動。主要的不同之處是在我們的神經網絡中,我們有更多的參數可以調整。那么怎么計算如此復雜的導數呢?
反向傳播是一種算法,能讓我們計算非常復雜的梯度,比如我們這個例子中需要的梯度。神經網絡的參數按照如下公式進行調整。
在上面的方程式中,α 表示學習率——該超參數能讓我們控制調整幅度的大小。選擇學習率很關鍵,如果設置的太低,神經網絡會學習的非常慢;如果設置的太高,我們就無法達到損失的最小值。使用鏈式法則以及損失函數對于 W 和 b 的偏導數來計算出 dW 和 db,這二者的大小分別等于 W 和 b。下面第二張圖展示了神經網絡中的操作順序。我們可以清楚地看到正向傳播和反向傳播共同工作,優化損失函數。
希望本文能幫助你理解一些神經網絡背后的數學原理,掌握其中的數學基礎知識對于你使用神經網絡會大有幫助。雖然本文列出了一些重要內容,但它們也只是冰山一角。強烈建議你自己試著用一些簡單的框架寫一個小型的神經網絡,不要借助很高級的框架,這樣能加深你對機器學習的理解。
文章轉自微信公眾號@算法進階