神經(jīng)網(wǎng)絡(luò)是機器學(xué)習(xí)領(lǐng)域中最強大、應(yīng)用最廣泛的算法之一。乍一看,神經(jīng)網(wǎng)絡(luò)似乎是個黑盒子;輸入層將數(shù)據(jù)輸入到“隱藏層”中,經(jīng)過一個魔術(shù)之后,我們可以看到輸出層提供的信息。然而,理解隱藏層在做什么是神經(jīng)網(wǎng)絡(luò)實現(xiàn)和優(yōu)化的關(guān)鍵步驟。 在我們理解神經(jīng)網(wǎng)絡(luò)的道路上,我們將回答三個問題:
什么是神經(jīng)網(wǎng)絡(luò)?我們將要考慮的神經(jīng)網(wǎng)絡(luò)被嚴(yán)格地稱為人工神經(jīng)網(wǎng)絡(luò),顧名思義,它是基于科學(xué)對人腦結(jié)構(gòu)和功能的了解。 簡單地說,神經(jīng)網(wǎng)絡(luò)被定義為一種計算系統(tǒng),它由許多簡單但高度互聯(lián)的元素或節(jié)點組成,稱為“神經(jīng)元”,這些元素或節(jié)點被組織成層,利用外部輸入的動態(tài)狀態(tài)響應(yīng)處理信息。在這種結(jié)構(gòu)的上下文中,輸入層將模式引入到神經(jīng)網(wǎng)絡(luò)中,輸入層為輸入數(shù)據(jù)中出現(xiàn)的每個組件都有一個神經(jīng)元,并與網(wǎng)絡(luò)中出現(xiàn)的一個或多個隱藏層進行通信;之所以稱為“隱藏”,是因為它們不構(gòu)成輸入或輸出層。在隱藏層中,所有的處理實際上都是通過一個以權(quán)重和偏差(通常稱為W和b)為特征的連接系統(tǒng)進行的:接收輸入,神經(jīng)元計算加權(quán)和添加偏差并根據(jù)結(jié)果和一個預(yù)設(shè)激活函數(shù)(最常見的一個是sigmoid,σ),它決定是否應(yīng)該“fired”或激活。之后,神經(jīng)元將信息傳遞到下游的其他連接的神經(jīng)元,這個過程被稱為“forward pass”。在這個過程的最后,最后一個隱藏層被連接到輸出層,輸出層對于每個可能需要的輸出都有一個神經(jīng)元。 2層神經(jīng)網(wǎng)絡(luò)的基本結(jié)構(gòu) Wi:相應(yīng)連接的權(quán)重。注意:計算網(wǎng)絡(luò)中存在的層數(shù)時,不包括輸入層。 神經(jīng)網(wǎng)絡(luò)如何工作?現(xiàn)在我們已經(jīng)了解了神經(jīng)網(wǎng)絡(luò)基本結(jié)構(gòu)的外觀,我們將繼續(xù)解釋它是如何工作的。為了做到這一點,我們需要解釋我們可以包含在網(wǎng)絡(luò)中的不同類型的神經(jīng)元。 我們要解釋的第一種神經(jīng)元是Perceptron。即使它的使用已經(jīng)在今天衰退,了解它們?nèi)绾喂ぷ鲗槲覀兲峁╆P(guān)于更多現(xiàn)代神經(jīng)元如何運作的良好線索。 感知器使用函數(shù)通過將二進制變量的矢量映射到單個二進制輸出來學(xué)習(xí)二元分類器,并且它還可以用于監(jiān)督學(xué)習(xí)。在這種情況下,感知器遵循以下步驟:
我們也可以把感知器函數(shù)寫成這樣: 注意:b是偏差,相當(dāng)于-threshold,wx是w的點積,是矢量,其中分量是權(quán)重,x是由輸入組成的矢量。 該算法最突出的一點是,我們可以改變權(quán)重和偏差,以獲得不同的決策模型。我們可以給這些輸入賦予更多的權(quán)重,這樣如果它們是正的,就會有利于我們想要的輸出。另外,因為偏差可以理解為輸出1的難易程度的度量,如果我們想讓期望的輸出或多或少發(fā)生,我們可以降低或提高它的值。如果我們注意這個公式,我們可以觀察到一個大的正向偏差會使輸出1變得非常容易;然而,負的偏見將使輸出1的任務(wù)變得非常不可能。 因此,感知器可以分析不同的數(shù)據(jù),并根據(jù)設(shè)定的偏好做出決定。事實上,創(chuàng)建更復(fù)雜的網(wǎng)絡(luò)是有可能的,包括更多的感知器層,每一層都取前一層的輸出并加權(quán),做出越來越復(fù)雜的決定。 如果感知器能很好地做出復(fù)雜的決定,為什么我們還需要其他類型的神經(jīng)元呢?包含感知器的網(wǎng)絡(luò)的一個缺點是,甚至在只有一個感知器中,權(quán)重或偏壓的小變化,也會嚴(yán)重地改變從0到1的輸出,反之亦然。我們真正想要的是通過引入權(quán)重或偏差的小修改來逐漸改變我們網(wǎng)絡(luò)的行為。這就是一種更現(xiàn)代的神經(jīng)元派上用場的地方:Sigmoid神經(jīng)元。Sigmoid neurons和感知器的主要區(qū)別在于輸入和輸出可以是0到1之間的任意連續(xù)值。在考慮權(quán)重w和偏差b的情況下,將sigmoid函數(shù)應(yīng)用到輸入中,得到輸出結(jié)果。為了更直觀的理解,我們可以這樣寫: 所以,輸出的公式是: 如果我們對這個函數(shù)進行數(shù)學(xué)分析,我們可以得到我們的函數(shù)σ 的圖形,如下所示,并得出結(jié)論:當(dāng)z很大且正數(shù)時,函數(shù)達到其最大漸近值1; 但是,如果z很大且為負,則函數(shù)達到其最小漸近值0.這里是sigmoid函數(shù)變得非常有趣的地方,因為它具有中等的z值,函數(shù)采用平滑且接近線性的形狀。在此間隔中,權(quán)重(Δwj)或偏差(Δbj)的微小變化將在輸出中產(chǎn)生微小變化; 我們所期待的行為是感知器的改進。 z = np.arange(-10, 10, 0.3)sigm = 1 / (1 + np.exp(-z))plt.plot(z, sigm, color = 'mediumvioletred', linewidth= 1.5)plt.xlabel('Z', size = 14, alpha = 0.8)plt.ylabel('σ(z)', size = 14, alpha = 0.8)a = plt.title('Sigmoid Function', size = 14)a = a.set_position([.5, 1.05]) 我們知道一個函數(shù)的導(dǎo)數(shù)是y值相對于變量x的變化速率的度量,在這種情況下,變量y是我們的輸出變量x是權(quán)重和偏差的函數(shù)。我們可以利用這一點,用導(dǎo)數(shù)來計算輸出的變化,特別是偏導(dǎo)數(shù)(關(guān)于w和關(guān)于b的)。在sigmoid函數(shù)中,導(dǎo)數(shù)將被縮減為計算:f(z)*(1-f(z))。 這里有一個簡單的Python代碼,可以用來建模一個sigmoid函數(shù): '''Build a sigmoid function to map any value to a value between zero and one\n',Refers to case of logistic function defined by: s(z) = 1/(1+e^-z)which derivative is bell shape. derivative is equal to f(z)*(1-f(z))'''def sigmoid(x, deriv = False): if deriv == True: return x*(1-x) return 1/(1+np.exp(-x)) 我們剛剛解釋了我們網(wǎng)絡(luò)中每個神經(jīng)元的功能,現(xiàn)在,我們可以檢查其余神經(jīng)元是如何工作的。將來自一層的輸出用作下一層的輸入的神經(jīng)網(wǎng)絡(luò)稱為前饋,特別是因為不涉及循環(huán)并且信息僅pass forward而從不返回。 假設(shè)我們有一個訓(xùn)練集,我們想要使用一個3層神經(jīng)網(wǎng)絡(luò),我們也使用上面看到的sigmoid神經(jīng)??元來預(yù)測某個特征。根據(jù)我們對神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)的解釋,需要首先將權(quán)重和偏差分配給一層??中的神經(jīng)元與下一層中的神經(jīng)元之間的連接。通常,偏差和權(quán)重都在突觸矩陣中隨機初始化。如果我們在python中編碼神經(jīng)網(wǎng)絡(luò),我們可以使用Numpy函數(shù)np.random.random 生成高斯分布(其中均值等于0,標(biāo)準(zhǔn)差為1)。 #Create Synapsis matrixsyn0 = 2+np.random.random((3,4)) -1syn1 = 2+np.random.random((4,1)) -1 之后,我們將從前饋步驟開始構(gòu)建神經(jīng)網(wǎng)絡(luò),以計算預(yù)測輸出; 換句話說,我們只需要構(gòu)建網(wǎng)絡(luò)中涉及的不同層:
我們還需要迭代訓(xùn)練集以讓網(wǎng)絡(luò)學(xué)習(xí)。為此,我們將添加for 循環(huán)。 #For loop iterate over the training setfor i in range(60000): #First layer is the input layer0 = X #Second layer can be obtained with the multiplication of each layer #and its synapsis and then running sigmoid function layer1 = sigmoid(np.dot(layer0, syn0)) #Do the same with l1 and its synapsis layer2 = sigmoid(np.dot(layer1,syn1)) 到目前為止,我們已經(jīng)創(chuàng)建了神經(jīng)網(wǎng)絡(luò)的基本結(jié)構(gòu):不同的層,神經(jīng)元之間連接的權(quán)重和偏差,以及sigmoid 函數(shù)。但這些都沒有解釋神經(jīng)網(wǎng)絡(luò)如何在預(yù)測數(shù)據(jù)集中的模式方面做得如此出色。這就是我們最后一個問題。 為什么神經(jīng)網(wǎng)絡(luò)能夠?qū)W習(xí)?機器學(xué)習(xí)算法的主要優(yōu)勢在于它們每次預(yù)測輸出時都能學(xué)習(xí)和改進。但他們能學(xué)到什么意味著什么呢?在神經(jīng)網(wǎng)絡(luò)的背景下,它意味著定義神經(jīng)元之間連接的權(quán)重和偏差變得更加精確; 最后,選擇權(quán)重和偏差,例如來自網(wǎng)絡(luò)的輸出近似于所有訓(xùn)練輸入的實際值y(x)。 那么,為了讓我們知道是否需要繼續(xù)尋找更精確的參數(shù),我們?nèi)绾瘟炕覀兊念A(yù)測與實際值的距離?為了這個目標(biāo),我們需要計算一個誤差,或者換句話說,定義一個成本函數(shù)(成本函數(shù)不是預(yù)測網(wǎng)絡(luò)正確輸出的誤差;換句話說,這就是預(yù)期和預(yù)期輸出的差值)。在神經(jīng)網(wǎng)絡(luò)中,最常用的是二次成本函數(shù),也稱為均方誤差,公式定義為: w和b分別表示網(wǎng)絡(luò)中的所有權(quán)重和偏差。n是訓(xùn)練輸入的總數(shù)。a是輸出,而x是輸入。Σ是所有訓(xùn)練輸入的總和。 該函數(shù)優(yōu)于線性誤差,因為在神經(jīng)網(wǎng)絡(luò)中,權(quán)重和偏差的微小變化不會使正確輸出的數(shù)量發(fā)生任何變化; 因此,使用二次函數(shù),其中較大的差值對成本函數(shù)的影響比小的差異更有助于確定如何修改這些參數(shù)。 另一方面,我們可以看到,對于所有訓(xùn)練輸入,我們的成本函數(shù)隨著輸出更接近實際值y而變小。我們算法的主要目標(biāo)是通過找到一組權(quán)重和偏差來使這個成本函數(shù)最小化,以使其盡可能小。實現(xiàn)這一目標(biāo)的主要工具是一種名為Gradient Descent的算法。 那么,我們應(yīng)該回答的下一個問題是如何最大限度地降低成本函數(shù)。從微積分中,我們知道函數(shù)可以具有全局最大值和/或最小值,即函數(shù)實現(xiàn)其可以具有的最大值或最小值。我們也知道獲得這一點的一種方法是計算導(dǎo)數(shù)。但是,當(dāng)我們有一個帶有兩個變量的函數(shù)時,很容易計算,但在神經(jīng)網(wǎng)絡(luò)的情況下,它們包含許多變量,這使得這個計算很難完成。 讓我們看一下隨機函數(shù),如下圖: 我們可以看到這個函數(shù)具有全局最小值。正如我們之前所說,我們可以計算導(dǎo)數(shù)以計算最小值的位置,或者我們可以采用另一種方法。我們可以從一個隨機點開始嘗試沿箭頭方向做一個小的移動,我們在數(shù)學(xué)上說,在x方向上移動Δx,在y方向上移動Δy,并計算我們的函數(shù)ΔC的變化。因為方向的變化率是函數(shù)的導(dǎo)數(shù),我們可以將函數(shù)的變化表示為: 在這里,我們將從函數(shù)梯度的微積分中定義: 函數(shù)的梯度:具有偏導(dǎo)數(shù)的向量 現(xiàn)在,我們可以將函數(shù)中的更改重寫為: C的梯度將函數(shù)C的變化與(x,y)的變化聯(lián)系起來 現(xiàn)在,我們可以看到當(dāng)我們選擇參數(shù)的某個變化時,成本函數(shù)會發(fā)生什么。我們選擇向任何方向移動的數(shù)量稱為學(xué)習(xí)率,它定義了我們向全局最小化移動的速度。如果我們選擇一個非常小的數(shù)字,我們需要做出太多的動作來達到這一點; 但是,如果我們選擇一個非常大的數(shù)字,我們就有可能超越這一點而永遠無法達到它。所以挑戰(zhàn)在于選擇足夠小的學(xué)習(xí)率。選擇學(xué)習(xí)率后,我們可以更新我們的權(quán)重和偏見,并采取另一種行動; 我們在每次迭代中重復(fù)的過程。 因此,簡而言之,梯度下降通過重復(fù)計算梯度?C,然后更新權(quán)重和偏差,并試圖找到最小化值來實現(xiàn)。這就是神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)的方式。 有時候,計算梯度可能非常復(fù)雜。然而,有一種方法可以加速這種計算,叫做隨機梯度下降法。這是通過估算梯度?C通過計算梯度而不是隨機選擇的小樣本訓(xùn)練的輸入。然后,將這些小樣本平均起來,就能很好地估計出真實的梯度,加速梯度下降,從而學(xué)習(xí)得更快。 但是我們?nèi)绾斡嬎愠杀竞瘮?shù)的梯度呢?這是另一個算法的地方:反向傳播。該算法的目標(biāo)是計算關(guān)于任何權(quán)重w和任何偏差b的成本函數(shù)的偏導(dǎo)數(shù);實際上,這意味著計算從最終層開始的誤差矢量,然后將其傳播回以更新權(quán)重和偏差。我們需要回去的原因是成本是網(wǎng)絡(luò)輸出的函數(shù)。我們可以觀察公式。 反向傳播算法給出的四個基本公式,可用于實現(xiàn)神經(jīng)網(wǎng)絡(luò) 反向傳播算法僅針對一個訓(xùn)練示例計算成本函數(shù)的梯度。因此,我們需要將反向傳播與學(xué)習(xí)算法相結(jié)合,例如隨機梯度下降,以便計算所有訓(xùn)練集的梯度。 現(xiàn)在,我們?nèi)绾螌⑺鼞?yīng)用于python中的神經(jīng)網(wǎng)絡(luò)?在這里,我們可以逐步看到計算結(jié)果: #Compute the error by checking how far the prediction #is from the real value. l2_error = y - l2 #multiply error rate by result of sigmoide on l2 to get derivative #from output #Delta will be use to reduce error rate of prediction when update syn #FORMULA 1 l2_delta = l2_error*sigmoid(l2, deriv=True) #How much l1 contributed to error in l2. Multiply #layer2_delta with syn1 transpose. l1_error = l2_delta.dot(syn1.T) #get delta for l1 l1_delta = l1_error * sigmoid(l1, deriv=True) #Update our synapse rates to reduce the error rate every iteration #Multiply each layer by a delta #*BACKPROPAGATION* syn1 += l1.T.dot(l2_delta) syn0 += l0.T.dot(l1_delta) 最后現(xiàn)在我們可以將我們在算法方面看到的所有這些公式和概念放在一起,看看我們?nèi)绾螌崿F(xiàn)的:
當(dāng)然,還有更多的概念、實現(xiàn)和改進,可以對神經(jīng)網(wǎng)絡(luò)進行改進,這些神經(jīng)網(wǎng)絡(luò)已經(jīng)在過去的幾年里越來越廣泛地被使用。但我希望本文能告訴你什么是神經(jīng)網(wǎng)絡(luò),它是如何工作的,以及它是如何利用梯度下降和反向傳播學(xué)習(xí)的。 |
|