神经网络入门(最通俗的理解神经网络)
先從回歸(Regression)問題說起。我在本吧已經(jīng)看到不少人提到如果想實現(xiàn)強(qiáng)AI,就必須讓機(jī)器學(xué)會觀察并總結(jié)規(guī)律的言論。具體地說,要讓機(jī)器觀察什么是圓的,什么是方的,區(qū)分各種顏色和形狀,然后根據(jù)這些特征對某種事物進(jìn)行分類或預(yù)測。其實這就是回歸問題。
如何解決回歸問題?我們用眼睛看到某樣?xùn)|西,可以一下子看出它的一些基本特征??墒怯嬎銠C(jī)呢?它看到的只是一堆數(shù)字而已,因此要讓機(jī)器從事物的特征中找到規(guī)律,其實是一個如何在數(shù)字中找規(guī)律的問題。
例:假如有一串?dāng)?shù)字,已知前六個是1、3、5、7,9,11,請問第七個是幾?
你一眼能看出來,是13。對,這串?dāng)?shù)字之間有明顯的數(shù)學(xué)規(guī)律,都是奇數(shù),而且是按順序排列的。
那么這個呢?前六個是0.14、0.57、1.29、2.29、3.57、5.14,請問第七個是幾?
這個就不那么容易看出來了吧!我們把這幾個數(shù)字在坐標(biāo)軸上標(biāo)識一下,可以看到如下圖形:
用曲線連接這幾個點,延著曲線的走勢,可以推算出第七個數(shù)字——7。
由此可見,回歸問題其實是個曲線擬合(Curve Fitting)問題。那么究竟該如何擬合?機(jī)器不可能像你一樣,憑感覺隨手畫一下就擬合了,它必須要通過某種算法才行。
假設(shè)有一堆按一定規(guī)律分布的樣本點,下面我以擬合直線為例,說說這種算法的原理。
其實很簡單,先隨意畫一條直線,然后不斷旋轉(zhuǎn)它。每轉(zhuǎn)一下,就分別計算一下每個樣本點和直線上對應(yīng)點的距離(誤差),求出所有點的誤差之和。這樣不斷旋轉(zhuǎn),當(dāng)誤差之和達(dá)到最小時,停止旋轉(zhuǎn)。說得再復(fù)雜點,在旋轉(zhuǎn)的過程中,還要不斷平移這條直線,這樣不斷調(diào)整,直到誤差最小時為止。這種方法就是著名的梯度下降法(Gradient Descent)。為什么是梯度下降呢?在旋轉(zhuǎn)的過程中,當(dāng)誤差越來越小時,旋轉(zhuǎn)或移動的量也跟著逐漸變小,當(dāng)誤差小于某個很小的數(shù),例如0.0001時,我們就可以收工(收斂, Converge)了。啰嗦一句,如果隨便轉(zhuǎn),轉(zhuǎn)過頭了再往回轉(zhuǎn),那就不是梯度下降法。
我們知道,直線的公式是y=kx+b,k代表斜率,b代表偏移值(y軸上的截距)。也就是說,k可以控制直線的旋轉(zhuǎn)角度,b可以控制直線的移動。強(qiáng)調(diào)一下,梯度下降法的實質(zhì)是不斷的修改k、b這兩個參數(shù)值,使最終的誤差達(dá)到最小。
求誤差時使用 累加(直線點-樣本點)^2,這樣比直接求差距 累加(直線點-樣本點) 的效果要好。這種利用最小化誤差的平方和來解決回歸問題的方法叫最小二乘法(Least Square Method)。
問題到此使似乎就已經(jīng)解決了,可是我們需要一種適應(yīng)于各種曲線擬合的方法,所以還需要繼續(xù)深入研究。
我們根據(jù)擬合直線不斷旋轉(zhuǎn)的角度(斜率)和擬合的誤差畫一條函數(shù)曲線,如圖:
從圖中可以看出,誤差的函數(shù)曲線是個二次曲線,凸函數(shù)(下凸, Convex),像個碗的形狀,最小值位于碗的最下端。如果在曲線的最底端畫一條切線,那么這條切線一定是水平的,在圖中可以把橫坐標(biāo)軸看成是這條切線。如果能求出曲線上每個點的切線,就能得到切線位于水平狀態(tài)時,即切線斜率等于0時的坐標(biāo)值,這個坐標(biāo)值就是我們要求的誤差最小值和最終的擬合直線的最終斜率。
這樣,梯度下降的問題集中到了切線的旋轉(zhuǎn)上。切線旋轉(zhuǎn)至水平時,切線斜率=0,誤差降至最小值。
切線每次旋轉(zhuǎn)的幅度叫做學(xué)習(xí)率(Learning Rate),加大學(xué)習(xí)率會加快擬合速度,但是如果調(diào)得太大會導(dǎo)致切線旋轉(zhuǎn)過度而無法收斂。 [學(xué)習(xí)率其實是個預(yù)先設(shè)置好的參數(shù),不會每次變化,不過可以影響每次變化的幅度。]
注意:對于凹凸不平的誤差函數(shù)曲線,梯度下降時有可能陷入局部最優(yōu)解。下圖的曲線中有兩個坑,切線有可能在第一個坑的最底部趨于水平。
微分就是專門求曲線切線的工具,求出的切線斜率叫做導(dǎo)數(shù)(Derivative),用dy/dx或f’(x)表示。擴(kuò)展到多變量的應(yīng)用,如果要同時求多個曲線的切線,那么其中某個切線的斜率就叫偏導(dǎo)數(shù)(Partial Derivative),用?y/?x表示,?讀“偏(partial)”。由于實際應(yīng)用中,我們一般都是對多變量進(jìn)行處理,我在后面提到的導(dǎo)數(shù)也都是指偏導(dǎo)數(shù)。
以上是線性回歸(Linear Regression)的基本內(nèi)容,以此方法為基礎(chǔ),把直線公式改為曲線公式,還可以擴(kuò)展出二次回歸、三次回歸、多項式回歸等多種曲線回歸。下圖是Excel的回歸分析功能。
在多數(shù)情況下,曲線回歸會比直線回歸更精確,但它也增加了擬合的復(fù)雜程度。
直線方程y=kx+b改為二次曲線方程y=ax^2+bx+c時,參數(shù)(Parameter)由2個(分別是k、b)變?yōu)?個(分別是a、b、c),特征(Feature)由1個(x)變?yōu)?個(x^2和x)。三次曲線和復(fù)雜的多項式回歸會增加更多的參數(shù)和特征。
前面講的是總結(jié)一串?dāng)?shù)字的規(guī)律,現(xiàn)實生活中我們往往要根據(jù)多個特征(多串?dāng)?shù)字)來分析一件事情,每個原始特征我們都看作是一個維度(Dimension)。例如一個學(xué)生的學(xué)習(xí)成績好壞要根據(jù)語文、數(shù)學(xué)、英語等多門課程的分?jǐn)?shù)來綜合判斷,這里每門課程都是一個維度。當(dāng)使用二次曲線和多變量(多維)擬合的情況下,特征的數(shù)量會劇增,特征數(shù)=維度^2/2 這個公式可以大概計算出特征增加的情況,例如一個100維的數(shù)據(jù),二次多項式擬合后,特征會增加到100*100/2=5000個。
下面是一張50*50像素的灰度圖片,如果用二次多項式擬合的話,它有多少個特征呢?——大約有3百萬!
它的維度是50*50=2500,特征數(shù)=2500*2500/2=3,125,000。如果是彩色圖片,維度會增加到原來的3倍,那么特征數(shù)將增加到接近3千萬了!
這么小的一張圖片,就有這么巨大的特征量,可以想像一下我們的數(shù)碼相機(jī)拍下來的照片會有多大的特征量!而我們要做的是從十萬乃至億萬張這樣的圖片中找規(guī)律,這可能嗎?
很顯然,前面的那些回歸方法已經(jīng)不夠用了,我們急需找到一種數(shù)學(xué)模型,能夠在此基礎(chǔ)上不斷減少特征,降低維度。
于是,“人工神經(jīng)網(wǎng)絡(luò)(ANN, Artificial Neural Network)”就在這樣苛刻的條件下粉墨登場了,神經(jīng)科學(xué)的研究成果為機(jī)器學(xué)習(xí)領(lǐng)域開辟了廣闊的道路。
神經(jīng)元
有一種假說:“智能來源于單一的算法(One Learning Algorithm)”。如果這一假說成立,那么利用單一的算法(神經(jīng)網(wǎng)絡(luò))處理世界上千變?nèi)f化的問題就成為可能。我們不必對萬事萬物進(jìn)行編程,只需采用以不變應(yīng)萬變的策略即可。有越來越多的證據(jù)證明這種假說,例如人類大腦發(fā)育初期,每一部分的職責(zé)分工是不確定的,也就是說,人腦中負(fù)責(zé)處理聲音的部分其實也可以處理視覺影像
下圖是單個神經(jīng)元(Neuron),或者說一個腦細(xì)胞的生理結(jié)構(gòu):
下面是單個神經(jīng)元的數(shù)學(xué)模型,可以看出它是生理結(jié)構(gòu)的簡化版,模仿的還挺像:
解釋一下:+1代表偏移值(偏置項, Bias Units);X1,X2,X2代表初始特征;w0,w1,w2,w3代表權(quán)重(Weight),即參數(shù),是特征的縮放倍數(shù);特征經(jīng)過縮放和偏移后全部累加起來,此后還要經(jīng)過一次激活運(yùn)算然后再輸出。激活函數(shù)有很多種,后面將會詳細(xì)說明。
舉例說明:
X1*w1+X2*w2+…+Xn*wn這種計算方法稱為加權(quán)求和(Weighted Sum)法,此方法在線性代數(shù)里極為常用。加權(quán)求和的標(biāo)準(zhǔn)數(shù)學(xué)符號是,不過為了簡化,我在教程里使用女巫布萊爾的符號表示,
剛好是一個加號和一個乘號的組合。
這個數(shù)學(xué)模型有什么意義呢?下面我對照前面那個 y=kx+b 直線擬合的例子來說明一下。
這時我們把激活函數(shù)改為Purelin(45度直線),Purelin就是y=x,代表保持原來的值不變。
這樣輸出值就成了 Y直線點 = b + X直線點*k,即y=kx+b。看到了吧,只是換了個馬甲而已,還認(rèn)的出來嗎?下一步,對于每個點都進(jìn)行這種運(yùn)算,利用Y直線點和Y樣本點計算誤差,把誤差累加起來,不斷地更新b、k的值,由此不斷地移動和旋轉(zhuǎn)直線,直到誤差變得很小時停住(收斂)。這個過程完全就是前面講過的梯度下降的線性回歸。
一般直線擬合的精確度要比曲線差很多,那么使用神經(jīng)網(wǎng)絡(luò)我們將如何使用曲線擬合?答案是使用非線性的激活函數(shù)即可,最常見的激活函數(shù)是Sigmoid(S形曲線),Sigmoid有時也稱為邏輯回歸(Logistic Regression),簡稱logsig。logsig曲線的公式如下:
還有一種S形曲線也很常見到,叫雙曲正切函數(shù)(tanh),或稱tansig,可以替代logsig。
下面是它們的函數(shù)圖形,從圖中可以看出logsig的數(shù)值范圍是0~1,而tansig的數(shù)值范圍是-1~1。
自然常數(shù)e
公式中的e叫自然常數(shù),也叫歐拉數(shù),e=2.71828…。e是個很神秘的數(shù)字,它是“自然律”的精髓,其中暗藏著自然增長的奧秘,它的圖形表達(dá)是旋渦形的螺線。
融入了e的螺旋線,在不斷循環(huán)縮放的過程中,可以完全保持它原有的彎曲度不變,就像一個無底的黑洞,吸進(jìn)再多的東西也可以保持原來的形狀。這一點至關(guān)重要!它可以讓我們的數(shù)據(jù)在經(jīng)歷了多重的Sigmoid變換后仍維持原先的比例關(guān)系。
e是怎么來的?e = 1 + 1/1! + 1/2! + 1/3! + 1/4! + 1/5! + 1/6! + 1/7! + … = 1 + 1 + 1/2 + 1/6 + 1/24 + 1/120+ … ≈ 2.71828 (!代表階乘,3!=1*2*3=6)
再舉個通俗點的例子:從前有個財主,他特別貪財,喜歡放債。放出去的債年利率為100%,也就是說借1塊錢,一年后要還給他2塊錢。有一天,他想了個壞主意,要一年算兩次利息,上半年50%,下半年50%,這樣上半年就有1塊5了,下半年按1塊5的50%來算,就有1.5/2=0.75元,加起來一年是:上半年1.5+下半年0.75=2.25元。用公式描述,就是(1+50%)(1+50%)=(1+1/2)^2=2.25元??墒撬窒?#xff0c;如果按季度算,一年算4次,那豈不是更賺?那就是(1+1/4)^4=2.44141,果然更多了。他很高興,于是又想,那干脆每天都算吧,這樣一年下來就是(1+1/365)^365=2.71457。然后他還想每秒都算,結(jié)果他的管家把他拉住了,說要再算下去別人都會瘋掉了。不過財主還是不死心,算了很多年終于算出來了,當(dāng)x趨于無限大的時候,e=(1+1/x)^x≈ 2.71828,結(jié)果他成了數(shù)學(xué)家。
e在微積分領(lǐng)域非常重要,e^x的導(dǎo)數(shù)依然是e^x,自己的導(dǎo)數(shù)恰好是它自己,這種巧合在實數(shù)范圍內(nèi)絕無僅有。
一些不同的稱呼:
e^x和e^-x的圖形是對稱的;ln(x)是e^x的逆函數(shù),它們呈45度對稱。
神經(jīng)網(wǎng)絡(luò)
好了,前面花了不少篇幅來介紹激活函數(shù)中那個暗藏玄機(jī)的e,下面可以正式介紹神經(jīng)元的網(wǎng)絡(luò)形式了。
下圖是幾種比較常見的網(wǎng)絡(luò)形式:
- 左邊藍(lán)色的圓圈叫“輸入層”,中間橙色的不管有多少層都叫“隱藏層”,右邊綠色的是“輸出層”。
- 每個圓圈,都代表一個神經(jīng)元,也叫節(jié)點(Node)。
- 輸出層可以有多個節(jié)點,多節(jié)點輸出常常用于分類問題。
- 理論證明,任何多層網(wǎng)絡(luò)可以用三層網(wǎng)絡(luò)近似地表示。
- 一般憑經(jīng)驗來確定隱藏層到底應(yīng)該有多少個節(jié)點,在測試的過程中也可以不斷調(diào)整節(jié)點數(shù)以取得最佳效果。
計算方法:
- 雖然圖中未標(biāo)識,但必須注意每一個箭頭指向的連線上,都要有一個權(quán)重(縮放)值。
- 輸入層的每個節(jié)點,都要與的隱藏層每個節(jié)點做點對點的計算,計算的方法是加權(quán)求和+激活,前面已經(jīng)介紹過了。(圖中的紅色箭頭指示出某個節(jié)點的運(yùn)算關(guān)系)
- 利用隱藏層計算出的每個值,再用相同的方法,和輸出層進(jìn)行計算。
- 隱藏層用都是用Sigmoid作激活函數(shù),而輸出層用的是Purelin。這是因為Purelin可以保持之前任意范圍的數(shù)值縮放,便于和樣本值作比較,而Sigmoid的數(shù)值范圍只能在0~1之間。
- 起初輸入層的數(shù)值通過網(wǎng)絡(luò)計算分別傳播到隱藏層,再以相同的方式傳播到輸出層,最終的輸出值和樣本值作比較,計算出誤差,這個過程叫前向傳播(Forward Propagation)。
前面講過,使用梯度下降的方法,要不斷的修改k、b兩個參數(shù)值,使最終的誤差達(dá)到最小。神經(jīng)網(wǎng)絡(luò)可不只k、b兩個參數(shù),事實上,網(wǎng)絡(luò)的每條連接線上都有一個權(quán)重參數(shù),如何有效的修改這些參數(shù),使誤差最小化,成為一個很棘手的問題。從人工神經(jīng)網(wǎng)絡(luò)誕生的60年代,人們就一直在不斷嘗試各種方法來解決這個問題。直到80年代,誤差反向傳播算法(BP算法)的提出,才提供了真正有效的解決方案,使神經(jīng)網(wǎng)絡(luò)的研究絕處逢生。
BP算法是一種計算偏導(dǎo)數(shù)的有效方法,它的基本原理是:利用前向傳播最后輸出的結(jié)果來計算誤差的偏導(dǎo)數(shù),再用這個偏導(dǎo)數(shù)和前面的隱藏層進(jìn)行加權(quán)求和,如此一層一層的向后傳下去,直到輸入層(不計算輸入層),最后利用每個節(jié)點求出的偏導(dǎo)數(shù)來更新權(quán)重。
為了便于理解,后面我一律用“殘差(error term)”這個詞來表示誤差的偏導(dǎo)數(shù)。
輸出層→隱藏層:殘差 = -(輸出值-樣本值) * 激活函數(shù)的導(dǎo)數(shù)
隱藏層→隱藏層:殘差 = (右層每個節(jié)點的殘差加權(quán)求和)* 激活函數(shù)的導(dǎo)數(shù)
如果輸出層用Purelin作激活函數(shù),Purelin的導(dǎo)數(shù)是1,輸出層→隱藏層:殘差 = -(輸出值-樣本值)
如果用Sigmoid(logsig)作激活函數(shù),那么:Sigmoid導(dǎo)數(shù) = Sigmoid*(1-Sigmoid)
輸出層→隱藏層:殘差 = -(Sigmoid輸出值-樣本值) * Sigmoid*(1-Sigmoid) = -(輸出值-樣本值)輸出值(1-輸出值)
隱藏層→隱藏層:殘差 = (右層每個節(jié)點的殘差加權(quán)求和)* 當(dāng)前節(jié)點的Sigmoid*(1-當(dāng)前節(jié)點的Sigmoid)
如果用tansig作激活函數(shù),那么:tansig導(dǎo)數(shù) = 1 - tansig^2
殘差全部計算好后,就可以更新權(quán)重了:
輸入層:權(quán)重增加 = 當(dāng)前節(jié)點的Sigmoid * 右層對應(yīng)節(jié)點的殘差 * 學(xué)習(xí)率
隱藏層:權(quán)重增加 = 輸入值 * 右層對應(yīng)節(jié)點的殘差 * 學(xué)習(xí)率
偏移值的權(quán)重增加 = 右層對應(yīng)節(jié)點的殘差 * 學(xué)習(xí)率
學(xué)習(xí)率前面介紹過,學(xué)習(xí)率是一個預(yù)先設(shè)置好的參數(shù),用于控制每次更新的幅度。
此后,對全部數(shù)據(jù)都反復(fù)進(jìn)行這樣的計算,直到輸出的誤差達(dá)到一個很小的值為止。
以上介紹的是目前最常見的神經(jīng)網(wǎng)絡(luò)類型,稱為前饋神經(jīng)網(wǎng)絡(luò)(FeedForward Neural Network),由于它一般是要向后傳遞誤差的,所以也叫BP神經(jīng)網(wǎng)絡(luò)(Back Propagation Neural Network)。
BP神經(jīng)網(wǎng)絡(luò)的特點和局限:
- BP神經(jīng)網(wǎng)絡(luò)可以用作分類、聚類、預(yù)測等。需要有一定量的歷史數(shù)據(jù),通過歷史數(shù)據(jù)的訓(xùn)練,網(wǎng)絡(luò)可以學(xué)習(xí)到數(shù)據(jù)中隱含的知識。在你的問題中,首先要找到某些問題的一些特征,以及對應(yīng)的評價數(shù)據(jù),用這些數(shù)據(jù)來訓(xùn)練神經(jīng)網(wǎng)絡(luò)。
- BP神經(jīng)網(wǎng)絡(luò)主要是在實踐的基礎(chǔ)上逐步完善起來的系統(tǒng),并不完全是建立在仿生學(xué)上的。從這個角度講,實用性 > 生理相似性。
- BP神經(jīng)網(wǎng)絡(luò)中的某些算法,例如如何選擇初始值、如何確定隱藏層的節(jié)點個數(shù)、使用何種激活函數(shù)等問題,并沒有確鑿的理論依據(jù),只有一些根據(jù)實踐經(jīng)驗總結(jié)出的有效方法或經(jīng)驗公式。
- BP神經(jīng)網(wǎng)絡(luò)雖然是一種非常有效的計算方法,但它也以計算超復(fù)雜、計算速度超慢、容易陷入局部最優(yōu)解等多項弱點著稱,因此人們提出了大量有效的改進(jìn)方案,一些新的神經(jīng)網(wǎng)絡(luò)形式也層出不窮。
文字的公式看上去有點繞,下面我發(fā)一個詳細(xì)的計算過程圖。
參考這個:http://www.myreaders.info/03_Back_Propagation_Network.pdf?我做了整理
這里介紹的是計算完一條記錄,就馬上更新權(quán)重,以后每計算完一條都即時更新權(quán)重。實際上批量更新的效果會更好,方法是在不更新權(quán)重的情況下,把記錄集的每條記錄都算過一遍,把要更新的增值全部累加起來求平均值,然后利用這個平均值來更新一次權(quán)重,然后利用更新后的權(quán)重進(jìn)行下一輪的計算,這種方法叫批量梯度下降(Batch Gradient Descent)。
推薦的入門級學(xué)習(xí)資源:
Andrew Ng的《機(jī)器學(xué)習(xí)》公開課:?https://class.coursera.org/ml
Coursera公開課筆記中文版(神經(jīng)網(wǎng)絡(luò)的表示):?http://52opencourse.com/139/coursera公開課筆記-斯坦福大學(xué)機(jī)器學(xué)習(xí)第八課-神經(jīng)網(wǎng)絡(luò)的表示-neural-networks-representation
Coursera公開課視頻(神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)):?http://52opencourse.com/289/coursera公開課視頻-斯坦福大學(xué)機(jī)器學(xué)習(xí)第九課-神經(jīng)網(wǎng)絡(luò)的學(xué)習(xí)-neural-networks-learning
斯坦福深度學(xué)習(xí)中文版:?http://deeplearning.stanford.edu/wiki/index.php/UFLDL教程
謝謝大家的支持。
今天先發(fā)個實際編程操作教程,介紹一下Matlab神經(jīng)網(wǎng)絡(luò)工具箱的用法,后面有空再加些深入點的知識。
關(guān)于Matlab的入門教程,參看這個帖子:http://tieba.baidu.com/p/2945924081
例1:我們都知道,面積=長*寬,假如我們有一組數(shù)測量據(jù)如下:
我們利用這組數(shù)據(jù)來訓(xùn)練神經(jīng)網(wǎng)絡(luò)。(在Matlab中輸入以下的代碼,按回車即可執(zhí)行)
p = [2 5; 3 6; 12 2; 1 6; 9 2; 8 12; 4 7; 7 9]’; % 特征數(shù)據(jù)X1,X2
t = [10 18 24 6 18 96 28 63]; % 樣本值
net = newff(p, t, 20); % 創(chuàng)建一個BP神經(jīng)網(wǎng)絡(luò) ff=FeedForward
net = train(net, p, t); % 用p,t數(shù)據(jù)來訓(xùn)練這個網(wǎng)絡(luò)
出現(xiàn)如下的信息,根據(jù)藍(lán)線的顯示,可以看出最后收斂時,誤差已小于10^-20。
你也許會問,計算機(jī)難道這樣就能學(xué)會乘法規(guī)則嗎?不用背乘法口訣表了?先隨便選幾個數(shù)字,試試看:
s = [3 7; 6 9; 4 5; 5 7]’; % 準(zhǔn)備一組新的數(shù)據(jù)用于測試
y = sim(net, s) % 模擬一下,看看效果
% 結(jié)果是:25.1029 61.5882 29.5848 37.5879
看到了吧,預(yù)測結(jié)果和實際結(jié)果還是有差距的。不過從中也能看出,預(yù)測的數(shù)據(jù)不是瞎蒙的,至少還是有那么一點靠譜。如果訓(xùn)練集中的數(shù)據(jù)再多一些的話,預(yù)測的準(zhǔn)確率還會大幅度提高。
你測試的結(jié)果也許和我的不同,這是因為初始化的權(quán)重參數(shù)是隨機(jī)的,可能會陷入局部最優(yōu)解,所以有時預(yù)測的結(jié)果會很不理想。
例2:下面測試一下擬合正弦曲線,這次我們隨機(jī)生成一些點來做樣本。
p = rand(1,50)*7 % 生成1行50個0~7之間的隨機(jī)數(shù)
t = sin(p) % 計算正弦曲線
s = [0:0.1:7]; % 生成0~7的一組數(shù)據(jù),間隔0.1,用于模擬測試
plot(p, t, ‘x’) % 畫散點圖
net = newff(p, t, 20); % 創(chuàng)建神經(jīng)網(wǎng)絡(luò)
net = train(net, p, t); % 開始訓(xùn)練
y = sim(net, s); % 模擬
plot(s, y, ‘x’) % 畫散點圖
從圖中看出,這次的預(yù)測結(jié)果顯然是不理想的,我們需要設(shè)置一些參數(shù)來調(diào)整。
下面的設(shè)置是一種標(biāo)準(zhǔn)的批量梯度下降法的配置。
% 創(chuàng)建3層神經(jīng)網(wǎng)絡(luò) [隱藏層10個節(jié)點->logsig, 輸出層1個節(jié)點->purelin] traingd代表梯度下降法
net = newff(p, t, 10, {‘logsig’ ‘purelin’}, ‘traingd’); % 10不能寫成[10 1]
% 設(shè)置訓(xùn)練參數(shù)
net.trainparam.show = 50; % 顯示訓(xùn)練結(jié)果(訓(xùn)練50次顯示一次)
net.trainparam.epochs = 500; % 總訓(xùn)練次數(shù)
net.trainparam.goal = 0.01; % 訓(xùn)練目標(biāo):誤差<0.01
net.trainParam.lr = 0.01; % 學(xué)習(xí)率(learning rate)
net = train(net, p, t); % 開始訓(xùn)練
注意:newff的第三個參數(shù)10不能寫成[10 1],否則就是4層網(wǎng)絡(luò),兩個隱藏層,分別是10個和1個節(jié)點。這個很容易弄錯。(輸出層的節(jié)點數(shù)程序會自動根據(jù)t的維度自動判斷,所以不用指定)
y = sim(net, s); % 模擬
plot(s, y, ‘x’) % 畫散點圖
這時的效果顯然更差了。
把精度調(diào)高一點看看。訓(xùn)練次數(shù)加到9999,誤差<0.001;學(xué)習(xí)率調(diào)到0.06,希望能加快點速度。
% 創(chuàng)建2層神經(jīng)網(wǎng)絡(luò) [隱藏層10個節(jié)點->logsig, 輸出層1個節(jié)點->purelin] traingd代表梯度下降法
net = newff(p, t, 10, {‘logsig’ ‘purelin’}, ‘traingd’);
% 設(shè)置訓(xùn)練參數(shù)
net.trainparam.show = 50; % 每間隔50次顯示一次訓(xùn)練結(jié)果
net.trainparam.epochs = 9999; % 總訓(xùn)練次數(shù)
net.trainparam.goal = 0.001; % 訓(xùn)練目標(biāo):誤差<0.001
net.trainParam.lr = 0.06; % 學(xué)習(xí)率(learning rate)
net = train(net, p, t); % 開始訓(xùn)練
標(biāo)準(zhǔn)的批量梯度下降法的速度確實夠慢,這次計算花了一分多鐘。
y = sim(net, s); % 模擬
plot(s, y, ‘x’) % 畫散點圖
效果比上次稍好一點。不過這條曲線顯得坑坑洼洼的很難看,這是一種過擬合(Overfitting)現(xiàn)象,與之相反的是欠擬合(Underfitting)。
先來解決速度問題,把traingd改為trainlm即可。trainlm使用LM算法,是介于牛頓法和梯度下降法之間的一種非線性優(yōu)化方法,不但會加快訓(xùn)練速度,還會減小陷入局部最小值的可能性,是Matlab的默認(rèn)值。
net = newff(p, t, 10, {‘logsig’ ‘purelin’}, ‘trainlm’);
… 后面的代碼不變
這個速度比較驚嘆了,1秒鐘之內(nèi)完成,只做了6輪計算,效果也好了一些。不過,LM算法也有弱點,它占用的內(nèi)存非常大,所以沒把其它算法給淘汰掉。
下面解決過擬合問題,把隱藏層的節(jié)點數(shù)目設(shè)少一點就行了。
net = newff(p, t, 3, {‘logsig’ ‘purelin’}, ‘trainlm’);
… 后面的代碼不變
這回終于達(dá)到滿意的效果了。(有時會出現(xiàn)局部最優(yōu)解,可以多試幾次)
如果節(jié)點數(shù)目太少,會出現(xiàn)欠擬合的情況。
關(guān)于隱藏層的節(jié)點個數(shù),一般是要憑感覺去調(diào)的。如果訓(xùn)練集的維數(shù)比較多,調(diào)節(jié)起來比較耗時間,這時可以根據(jù)經(jīng)驗公式上下浮動地去調(diào)整。
下面給出幾個經(jīng)驗公式供參考:
如果把輸出層改為logsig激活會是什么樣子呢?
net = newff(p, t, 3, {‘logsig’ ‘logsig’}); % 創(chuàng)建神經(jīng)網(wǎng)絡(luò)
net = train(net, p, t); % 開始訓(xùn)練
y = sim(net, s); % 模擬
plot(s, y, ‘x’) % 畫散點圖
可以看出,-1~0范圍之間的點都變?yōu)?了。使用logsig輸出時要想得到完整數(shù)值范圍的效果,必須先對數(shù)據(jù)進(jìn)行歸一化才行。
歸一化(Normalization),也叫標(biāo)準(zhǔn)化,就是把一堆數(shù)字按比例縮放到0~1或-1~1的范圍。
雖然用Purelin輸出可以不必歸一化,但歸一化能在一定程度上加快收斂速度,因此被許多教程定為訓(xùn)練前的必須步驟。
公式為:歸一值 = (當(dāng)前值x-最小值min)/(最大值max-最小值min)
如果限定了范圍,公式為:y = (ymax-ymin)*(x-xmin)/(xmax-xmin) + ymin;
0.1~0.9的范圍:(0.9-0.1)(x-min)/(max-min)(0.9-0.1)+0.1
把5, 2, 6, 3這四個數(shù)歸一化:
Matlab的歸一化命令為:mapminmax
注:網(wǎng)上的不少教程里用premnmx命令來歸一化,要注意Matlab版本R2007b和R2008b,premnmx在處理單列數(shù)據(jù)時有bug,Matlab已給出了警告,R2009a版才修正。因此推薦使用mapminmax。mapminmax的輸入輸出值和premnmx是行列顛倒的,使用時要注意代碼中是否添加轉(zhuǎn)置符號。
a = [5, 2, 6, 3];
b = mapminmax(a, 0, 1) % 歸一化到0~1之間
% b = 0.7500 0 1.0000 0.2500
c = mapminmax(a) % 歸一化到-1~1之間
% c = 0.5000 -1.0000 1.0000 -0.5000
反歸一化(Denormalization)就是按歸一化時的比例還原數(shù)值。
a = [5, 2, 6, 3];
[c,PS] = mapminmax(a); % PS記錄歸一化時的比例
mapminmax(‘reverse’, c, PS) % 利用PS反歸一化
% ans = 5 2 6 3
神經(jīng)網(wǎng)絡(luò)的歸一化(0~1范圍)代碼:
p = rand(1,50)*7; % 特征數(shù)據(jù)
t = sin(p); % 樣本值
s = [0:0.1:7]; % 測試數(shù)據(jù)
[pn, ps] = mapminmax(p, 0, 1); % 特征數(shù)據(jù)歸一化
[tn, ts] = mapminmax(t, 0, 1); % 樣本值歸一化
sn = mapminmax(‘a(chǎn)pply’, s, ps); % 測試數(shù)據(jù),按ps比例縮放
net = newff(pn, tn, [5 1], {‘logsig’ ‘logsig’}); % 創(chuàng)建神經(jīng)網(wǎng)絡(luò)
net = train(net, pn, tn); % 開始訓(xùn)練
yn = sim(net, sn); % 模擬
y = mapminmax(‘reverse’, yn, ts); % 按ps的比例還原
plot(s, y, ‘x’) % 畫散點圖
神經(jīng)網(wǎng)絡(luò)工具箱還有一個UI圖形操作界面,執(zhí)行nntool就可以打開。我覺得不如寫代碼方便,所以不怎么用。我提供一個相關(guān)的教程鏈接,有興趣的可以看一下:matlab神經(jīng)網(wǎng)絡(luò)工具箱創(chuàng)建神經(jīng)網(wǎng)絡(luò) -http://blog.新浪.com.cn/s/blog_8684880b0100vxtv.html (新浪替換成sina)
關(guān)于Sigmoid的由來,中文的網(wǎng)站上很少有提及的。下面簡單講一下,希望能給大家拓展一下思路。
PS: 這里的公式我都給出了求解過程,但如今這個年頭,用手工解題的人越來越少了,一般的方程用軟件來解就行了。
例如解Sigmoid微分方程,可以用Matlab去解:
dsolve(‘Dx=x*(1-x)’)
% ans = 1/(1+exp(-t)*C1)
如果想得到求解的步驟或更詳細(xì)的信息,推薦使用Wolfram:http://www.wolframalpha.com
在Wolfram的搜索框輸入 x’=x(1-x) 即可。
logsig
Sigmoid函數(shù)(S形函數(shù),Logistic Function)是受統(tǒng)計學(xué)模型的啟發(fā)而產(chǎn)生的激活函數(shù)。
基于生物學(xué)的神經(jīng)元激活函數(shù)是這樣的:
參看:http://eprints.pascal-network.org/archive/00008596/01/glorot11a.pdf
實踐證明了基于統(tǒng)計學(xué)的Sigmoid函數(shù)激活效果要比基于生物學(xué)的模型好,而且計算起來很方便,所以說不能以機(jī)器和人的相似度為標(biāo)準(zhǔn)來判斷AI算法的好壞。
Sigmoid函數(shù)原先是個描述人口增長的數(shù)學(xué)模型,1838提出,給出的是導(dǎo)數(shù)形式(概率密度)。人口增長規(guī)律:起初階段大致是指數(shù)增長;然后逐漸開始變得飽和,增長變慢;達(dá)到成熟時幾乎停止增長;整個過程形如一條S型曲線。
導(dǎo)數(shù)的形式知道了,那么它的原函數(shù)是什么樣子呢?已知導(dǎo)數(shù)求原函數(shù),用統(tǒng)計學(xué)的話來講,即根據(jù)概率密度函數(shù)(PDF)求累積分布函數(shù)(CDF),不定積分(Indefinite Integral)就是專門用來做這個的工具。
根據(jù)不定積分的知識可知,由于常數(shù)項是可變的,所以存在無數(shù)個原函數(shù)的可能。讓我們先用圖解法看一下:既然導(dǎo)數(shù)是函數(shù)曲線的斜率,那么可以把一定數(shù)值范圍內(nèi)的斜率,都畫成一根根的短斜線,組成斜率場(Slope Fields, Direction Fields),然后根據(jù)這些斜線的走勢,畫出積分曲線。
Matlab可以用quiver命令來畫斜率場。
從上圖中可以看出,在y軸的0~1之間是個分水嶺,0和1處的方向趨于水平。下面放大0~1的范圍看看是什么樣子的。
看到了吧,我們要的Logistic Sigmoid就在這里呢。
下面給出符號求解的過程:
tansig
雙曲正切函數(shù)(雙極S形函數(shù), tanh, Hyperbolic Tangent),讀tanch,18世紀(jì)就已經(jīng)出現(xiàn)了。它的定義是:tanh(x)=sinh(x)/cosh(x),可以由著名的歐拉公式(Euler’s formula)推導(dǎo)出來。
用tanh作激活函數(shù),收斂比較快,效果比Logistic函數(shù)還要好。
歐拉公式: i是虛數(shù)(Imaginary Number)單位,它的定義是: (即i^2 = -1)
題外話:根據(jù)上面的公式變換,可以得出史上最美的數(shù)學(xué)公式:?,數(shù)學(xué)中最神秘的5個符號e、i、π、1和0,全包含在里面了。
求tanh的導(dǎo)數(shù):
logsig和tansig的關(guān)系:
from:?https://blog.csdn.net/lyl771857509/article/details/78990215
總結(jié)
以上是生活随笔為你收集整理的神经网络入门(最通俗的理解神经网络)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IntelliJ IDEA 常用设置
- 下一篇: 卷积神经网络CNN总结