鍵.png)
使用這些基本 REST API 最佳實(shí)踐構(gòu)建出色的 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)
如前面說過,只需幾個(gè)導(dǎo)入、幾行代碼就能創(chuàng)建和訓(xùn)練一個(gè)模型,拿來解決分類問題幾乎能達(dá)到 100% 的準(zhǔn)確率。我們的工作歸納起來就是根據(jù)選擇的模型結(jié)構(gòu),為模型提供超參數(shù),比如網(wǎng)絡(luò)層的數(shù)量、每層的神經(jīng)元數(shù)量、激活函數(shù)和訓(xùn)練周期數(shù)量等等。下面我們來看看訓(xùn)練的過程發(fā)生了什么,可以看到隨著訓(xùn)練過程中,數(shù)據(jù)被正確地區(qū)分開了!
有了這些框架,這的確為我們節(jié)省了大量寫bugs(…) 的時(shí)間,讓我們的工作也更加流程化。然而,熟知神經(jīng)網(wǎng)絡(luò)背后的工作原理,對(duì)于我們選擇模型架構(gòu)、調(diào)參或優(yōu)化模型都有莫大的幫助。
為了更深入的理解神經(jīng)網(wǎng)絡(luò)的工作原理,本文將幫助大家理解一些在學(xué)習(xí)過程中可能會(huì)感到困惑的概念。我會(huì)盡量讓那些對(duì)代數(shù)和微積分不感冒的朋友讀著不那么痛苦,但是正如文章題目所示,本文主要講數(shù)學(xué)原理,所以會(huì)談?wù)摯罅康臄?shù)學(xué),在這里先提個(gè)醒。
舉個(gè)例子,我們要解決一個(gè)數(shù)據(jù)集的二元分類問題,數(shù)據(jù)集如上所示。
數(shù)據(jù)點(diǎn)組成了兩個(gè)類別的圓圈狀,要區(qū)分這個(gè)數(shù)據(jù),對(duì)很多傳統(tǒng)的機(jī)器學(xué)習(xí)算法來說都非常麻煩,但神經(jīng)網(wǎng)絡(luò)可以很好地處理這個(gè)非線性分類問題。
為了解決這個(gè)問題,我們會(huì)使用如下圖所示結(jié)構(gòu)的神經(jīng)網(wǎng)絡(luò),它有 5 個(gè)全連接層,每層有不同數(shù)量的神經(jīng)元。對(duì)于隱藏層,我們會(huì)使用 ReLU 作為激活函數(shù),在輸出層中使用 S 型函數(shù)。這是個(gè)相當(dāng)簡(jiǎn)單的結(jié)構(gòu),但也足夠解決我們的難題了。
我們首先來回答這個(gè)關(guān)鍵的問題:什么是神經(jīng)網(wǎng)絡(luò)?它是一種在生物學(xué)啟發(fā)下創(chuàng)建的計(jì)算機(jī)程序,能夠?qū)W習(xí)知識(shí),獨(dú)立發(fā)現(xiàn)數(shù)據(jù)中的關(guān)系。如圖 2 所示,神經(jīng)網(wǎng)絡(luò)就是一系列的神經(jīng)元排列在網(wǎng)絡(luò)層中,網(wǎng)絡(luò)層以某種方式連接在一起,從而相互之間實(shí)現(xiàn)溝通。
每個(gè)神經(jīng)元會(huì)接受一系列的 x 值(從 1 到 n 的數(shù)字)作為輸入,計(jì)算預(yù)測(cè)的 y-hat 值。向量 x 實(shí)際上包含了訓(xùn)練集中 m 個(gè)樣本中一個(gè)樣本的特征值。而且每個(gè)神經(jīng)元會(huì)有它自己的一套參數(shù),通常引用為 w(權(quán)重的列向量)和 b(偏差),在學(xué)習(xí)過程中偏差會(huì)不斷變化。在每次迭代中,神經(jīng)元會(huì)根據(jù)向量 x 的當(dāng)前權(quán)向量 x 計(jì)算它的加權(quán)平均值,再和偏差相加。最后,計(jì)算的結(jié)果會(huì)傳入一個(gè)非線性或函數(shù) g 中。我在下面會(huì)提及一些最常見的激活函數(shù)。
現(xiàn)在,我們把范圍縮小一點(diǎn),思考一下神經(jīng)網(wǎng)絡(luò)的整個(gè)網(wǎng)絡(luò)層是怎么進(jìn)行數(shù)學(xué)運(yùn)算的。我們會(huì)利用單個(gè)神經(jīng)元的計(jì)算知識(shí),在整個(gè)層中進(jìn)行向量化,將這些計(jì)算融合進(jìn)矩陣方程中。為了讓數(shù)學(xué)符號(hào)一致,這些方程會(huì)寫給選定的網(wǎng)絡(luò)層。另外,下標(biāo)的 i 符號(hào)標(biāo)記了這一層的神經(jīng)元順序。
還有一件重要的事:在我們?yōu)閱蝹€(gè)神經(jīng)元寫方程時(shí),我們使用 x 和 y-hat,它們分別表示特征列向量和預(yù)測(cè)值。當(dāng)換成網(wǎng)絡(luò)層的通用符號(hào)時(shí),我們使用向量 a —— 意指對(duì)應(yīng)網(wǎng)絡(luò)層的激活。因此 x 向量是網(wǎng)絡(luò)層 0(輸入層)的激活。網(wǎng)絡(luò)層中的每個(gè)神經(jīng)元都按照如下方程式執(zhí)行相同的運(yùn)算:
讓大家更清晰的看看,我們把第 2 層的公式寫下來:
你可以看到,對(duì)每個(gè)網(wǎng)絡(luò)層,我們必須執(zhí)行一系列非常相似的運(yùn)算。在這里使用 for 循環(huán)并不是非常高效,所以我們換成向量化來加快計(jì)算速度。首先,將權(quán)重 w 的水平向量堆放在一起,我們創(chuàng)建矩陣 W。同樣地,我們將網(wǎng)絡(luò)層中每個(gè)神經(jīng)元的偏差堆放在一起,創(chuàng)建垂直向量 b。現(xiàn)在,我們可以順利地創(chuàng)建一個(gè)矩陣方程式了,從而一次性計(jì)算該網(wǎng)絡(luò)層的所有神經(jīng)元。我們同樣寫下來用過的矩陣和向量的維度。
我們迄今所用的方程式只涉及了一個(gè)例子。在神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)過程中,你通常要處理大量的數(shù)據(jù),最高可達(dá)數(shù)百萬條。所以下一步就是在多個(gè)例子中實(shí)現(xiàn)向量化。假設(shè)我們的數(shù)據(jù)集有 m 個(gè)條目,每個(gè)有 nx 個(gè)特征。首先,我們將每一層的垂直向量 x,a 和 z 放在一起,分別創(chuàng)建矩陣 X,A 和 Z。然后,我們根據(jù)新創(chuàng)建的矩陣,重新編寫之前列出的方程式。
激活函數(shù)是神經(jīng)網(wǎng)絡(luò)中最重要的部分之一。沒有激活函數(shù),我們的神經(jīng)網(wǎng)絡(luò)就只是一些線性函數(shù)的組合,那樣無非就是個(gè)線性函數(shù)而已。如果是這樣,模型的擴(kuò)展性就很有限了,比邏輯回歸也強(qiáng)不到哪去。非線性部分能讓模型有更大的靈活性,在學(xué)習(xí)過程中也能創(chuàng)建復(fù)雜的函數(shù)。
此外,激活函數(shù)對(duì)模型的學(xué)習(xí)速度也有重大影響,而學(xué)習(xí)速度是選擇模型的主要標(biāo)準(zhǔn)之一。下圖顯示了一些常用的激活函數(shù)。當(dāng)前,隱藏層中最常用的激活函數(shù)應(yīng)該是 ReLU。在處理二元分類問題時(shí),特別是想讓模型返回在 0 到 1 之間的值時(shí),我們有時(shí)也會(huì)使用 S 型函數(shù),特別是在輸出層中。
學(xué)習(xí)過程中基本信息源就是損失函數(shù)的值。通常來講,使用損失函數(shù)的目的就是展示我們離“理想”情況的差距。在我們這個(gè)例子中,我們使用了二元交叉熵,但根據(jù)我們處理的具體問題,可以使用不同的函數(shù)。我們所用的函數(shù)用如下公式表示,在學(xué)習(xí)過程中它的值的變化情況可視化動(dòng)圖如下。它顯示了每次迭代中,損失函數(shù)的值在不斷下降,準(zhǔn)確度的值也不斷增加。
學(xué)習(xí)過程就是不斷改變 W 和 b 參數(shù)的值,讓損失函數(shù)實(shí)現(xiàn)最小化。為了能實(shí)現(xiàn)這個(gè)目標(biāo),我們會(huì)借助微積分,使用梯度下降法來找到函數(shù)最小值。在每次迭代中,我們會(huì)計(jì)算損失函數(shù)偏導(dǎo)數(shù)相對(duì)于每個(gè)神經(jīng)網(wǎng)絡(luò)參數(shù)的值。對(duì)于不太熟悉這種計(jì)算類型的人,我這里提示一下,導(dǎo)數(shù)能夠描述函數(shù)的斜率。正因如此,我們能夠知道該如何操作變量,從而在圖中向下移動(dòng)。為了能讓大家直觀感受梯度下降的工作原理,我預(yù)備了一點(diǎn)小小的可視化,如下圖所示。你可以看到,隨著訓(xùn)練批次增加,我們?cè)絹碓娇拷钚≈怠T谖覀兊?a href="http://cnzze.cn/blog/wx-comprehensive-overview-of-neural-network-models/">神經(jīng)網(wǎng)絡(luò)中,也是同樣的工作方式——每次迭代計(jì)算出的梯度為我們顯示了應(yīng)該向哪個(gè)方向移動(dòng)。主要的不同之處是在我們的神經(jīng)網(wǎng)絡(luò)中,我們有更多的參數(shù)可以調(diào)整。那么怎么計(jì)算如此復(fù)雜的導(dǎo)數(shù)呢?
反向傳播是一種算法,能讓我們計(jì)算非常復(fù)雜的梯度,比如我們這個(gè)例子中需要的梯度。神經(jīng)網(wǎng)絡(luò)的參數(shù)按照如下公式進(jìn)行調(diào)整。
在上面的方程式中,α 表示學(xué)習(xí)率——該超參數(shù)能讓我們控制調(diào)整幅度的大小。選擇學(xué)習(xí)率很關(guān)鍵,如果設(shè)置的太低,神經(jīng)網(wǎng)絡(luò)會(huì)學(xué)習(xí)的非常慢;如果設(shè)置的太高,我們就無法達(dá)到損失的最小值。使用鏈?zhǔn)椒▌t以及損失函數(shù)對(duì)于 W 和 b 的偏導(dǎo)數(shù)來計(jì)算出 dW 和 db,這二者的大小分別等于 W 和 b。下面第二張圖展示了神經(jīng)網(wǎng)絡(luò)中的操作順序。我們可以清楚地看到正向傳播和反向傳播共同工作,優(yōu)化損失函數(shù)。
希望本文能幫助你理解一些神經(jīng)網(wǎng)絡(luò)背后的數(shù)學(xué)原理,掌握其中的數(shù)學(xué)基礎(chǔ)知識(shí)對(duì)于你使用神經(jīng)網(wǎng)絡(luò)會(huì)大有幫助。雖然本文列出了一些重要內(nèi)容,但它們也只是冰山一角。強(qiáng)烈建議你自己試著用一些簡(jiǎn)單的框架寫一個(gè)小型的神經(jīng)網(wǎng)絡(luò),不要借助很高級(jí)的框架,這樣能加深你對(duì)機(jī)器學(xué)習(xí)的理解。
文章轉(zhuǎn)自微信公眾號(hào)@算法進(jìn)階
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)