道可道之機器學習(3) - 單隱藏層神經網路
系列回顧
道可道之機器學習(1) - 初探人工智慧
道可道之機器學習(2) - 透過數學看世界
數學先行
導數
牛兄踢了童子1腳,童子很生氣,但是李耳曾經交代過童子,如果牛兄惹童子不開心了,童子可以雙倍找李耳報仇(太上老君和牛兄相當有感情的),因此童子怒氣沖沖的踢了李耳2腳。李耳也生氣了,但是皇帝曾經交代過李耳,如果小孩子惹李耳不開心了,李耳可以三倍找皇帝報仇,因此李耳氣沖沖的跑到皇宮踢了皇帝6腳。全劇終。
導數的本質就是描述自變數發生變化後因變數跟著發生變化的幅度。在上面"牛踢童子-童子找李耳報仇"的問題中,自變數是"牛兄踢童子",值為1;因變數是童子踢李耳,值為2。
我們使用x代表牛踢童子的值,使用y表示童子因此而踢李耳的值,數學表達式:
繼續思考"童子踢李耳-李耳找皇帝報仇"的問題中,自變數是"童子踢李耳",值為2;因變數是"李耳踢皇上", 值為6。
使用z表示李耳踢皇上的值,數學表達式:
現在我們知道了李耳會因為童子被踢而被踢(變化幅度為2),皇帝會因為李耳被踢而被踢(變化幅度為3)。那麼可以推斷出皇帝會因為童子被踢而被踢(幅度為6)。如下是鏈式求導公式:
導數的本質已經端給了大家,至於各種五花八門的求導法則大家可以google一下,這裡就不在重複列舉了。
∑(累加)
英文寫法Sigma,中文讀音: 西格碼。代表累加,直接上數據公式:
單隱藏層BP神經網路擬合直線
皇上最近抽風了,覺得李耳練得丹更適合用來做裝飾。於是他下了聖旨,要李耳準備好丹爐,只要聖旨一下,李耳在十天之內必須練出規定顏色的丹,否則就奪去太上老君的稱號。這下李耳可鬱悶了,如果不限時間,李耳可以慢慢的練,先練10個小時看看顏色如果不對的話再重新練15小時、20小時這樣一直試,總會練出規定顏色的丹。可是皇帝限時了,這可咋辦呢。
李耳將之前練的10個丹拿了出來,煉丹時間(小時):x = [1, 2, 3, 6, 9, 11, 12, 13, 18, 20], 對應丹的顏色(將顏色從紅色到紫色映射到1-10內):y = [1, 1.2, 1.7, 2.9, 4, 5, 5, 6, 7.7, 8.5], 將數據在二維坐標系中畫了出來如下:
可以很直觀的看出在20小時內,煉丹的時間和顏色基本可以組成一個一次函數。因此他假設該函數為a = wx + b其中自變數x代表煉丹時間,因變數a代表預測出的丹的顏色,w和b正是李耳急切想要知道的常數。
李耳猜測了一下w和b的值,w=1 b=1。
怎樣判定李耳猜測的這一組值是否正確呢,顯然他需要一個可以量化的指標。"將計算出的值減去實際的值並且取其絕對值來得到每個預測值和真實值的誤差,最後將所有的誤差再加起來,值越小說明計算出的值與真實值越接近,說明我猜測的w,b值越靠譜; 反之值越大,說明計算出的值與真實值越不接近,說明我猜測的w,b值越不靠譜。"李耳終於想到了這個很靠譜的方法。得到了如下的函數,並命名為損失函數(代價函數), 使用loss表示。
李耳重複猜測->計算->再猜測->再計算。兩天後,他還是沒有得到一組w,b使得loss小到他滿意的程度,顯然這樣盲目的猜測w,b不太靠譜,需要找一個套路來快速的定位w,b。
"loss隨著w,b的變化而變化,要想快速定位loss的一個儘可能小的值,首先要知道loss隨w,b變化的規律,也就是w,b變化了,loss變化的幅度"。李耳想到這裡,幾天前他去踹皇帝的事情浮現在他腦子裡。
計算出loss對於w,b的導數: dloss/dw和dloss/db。 其中dloss/dw表示w每變化一個單位,loss變化的量;同樣的dlose/db表示b每變化一個單位,loss變化的量。首先給w和b的變化量定一個基調n。如果dloss/dw為正數,證明loss在w的這次變化後會增加,因此我們需要朝著相反的方向變化,w_next = w_current - n; 反之如果dloss/dw為負數,w_next = w_current + n。同理如果dloss/db為正數,b_next = b_current - n,如果dloss/db為負數,b_next = b_current + n。到這裡李耳已經定義了w和b的變化方向,具體w和b每次要變化多少呢,他繼續了如下的思考。
|dlose/dw|越大,證明w每變化一次lose變化的幅度也很大,可以理解為lose此時還有很大的縮小空間,這時w變化的幅度應該大一點以便於盡快的找到lose的最小值。|dlose/dw|越小,代表w變化一次lose變化很小了,基本趨於穩定了,這時候w變化的幅度應該更小一點防止不要超過了lose的最小值。同樣的道理適用於|dlose/db|。
現在思路已經很明確了,李耳先隨意給w和b賦值:w_current,b_current,然後使用歷史數據來計算loss值,並對其求導,再用導數算出新的w和b: w_next和b_next,這樣一輪結束。使用上一輪計算出的w和b的值:w_next和b_next,重複計算loss,計算導數,計算新的w和b,一直重複,直到loss足夠的小。
李耳歸納出了如下的數學表達式:
美滋滋的李耳開始計算dloss/dw和dloss/db,一個絕對值符號使得這兩個導數需要分情況討論了。李耳很不開心,決心要把絕對值符號去掉。那還等什麼,趕緊平方啊,完美解決問題!新的公式:
追隨李耳的腳步,我們重新捋一下使用BP神經網路解決問題的正確姿勢。
Step1: 準備數據。李耳收集了10個歷史數據(丹的顏色X和練丹時間Y)。
Step2: 定義模型。通過對歷史數據的分析,李耳定義了模型 y = wx+b
Step3: 定義損失函數。
經歷了定義和重新優化後,李耳的損失函數確定為平方誤差公式。loss = (y - a)^2
Step4: 對損失函數進行求導。使用鏈式求導法則分別求出dloss/dw和dloss/db。
Step5: 初始化w和b。李耳給他們賦值為1。
Step6: 前向求出損失函數的同時緩存y-a的值。
Step7: 使用Step6緩存的y-a的值算出dloss/dw和dlose/db。ps:多個數據取平均值。
Step8: 使用Step7求出來的導數算出新的w和b。
如果循環周期沒有結束,重複Step6、Step7和Step8.如果循環周期結束則輸出w和b。
向量化(使用矩陣來表示BP網路)
機器學習工具(numpy,matlab)都是以矩陣為基本單位來進行計算,因此李耳在實現代碼之前,需要使用矩陣來表示定義的BP網路,如下:
寫成python代碼如下(核心部分):
def oneLayerBPNet(): X_in, Y_out = X.reshape((1,-1)), Y.reshape((1,-1)) W,b,learnRate = np.array([[1]]), 1, 0.001 for _ in range(0,10000): Z = np.dot(W, X_in) + b loss_1 = Z - Y_out loss,dz = np.sum(np.square(loss_1)),2 * loss_1 b = b - learnRate * np.mean(dz) W = W - learnRate * np.mean(dz * X_in, axis = 1).T
文章中所有的代碼都是基於python實現,僅僅使用了matplotlib庫和numpy庫。
GitHub:FutureStories/aistudy
預告
下一篇文章帶大家一起實現一個多隱藏層的神經網路。
推薦閱讀:
※python3機器學習經典實例-第三章預測模型11
※Cousera deeplearning.ai筆記 — 深度神經網路(Deep neural network)
※過擬合與正則化
※機器學習演算法系列--生成模型與判別模型