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