BP神经网络python代码详细解答(来自原文翻译)
翻譯如下
**
**
? ? ? ? 注: Scratch是一款由麻省理工學院(MIT) 設計開發的一款面向少年的簡易編程工具。這里寫鏈接內容 ? ? ? ? 本文翻譯自“IMPLEMENTING A NEURAL NETWORK FROM SCRATCH IN PYTHON – AN INTRODUCTION”,原文鏈接為這里寫鏈接內容。并且,我在這里給出原文數學公式的推導和對原文一些概念的修正;
? ? ? ? 在這里,我將展示一種簡單的三層神經網絡,我不會詳細推導出與本文有關的所有數學公式,我將我的想法以一種直觀的形式展示出來,我也會提供一些相關鏈接,來讓讀者能更好的理解本文的細節。
我認為,你們對于基本的微積分知識和機器學習的概念有一定的認識。同樣你們應該能理解分類和回歸的概念,如果你們能夠理解最優化的概念,如梯度下降法的原理,那就更好了。如果你對本文的概念都不了解,你同樣可以發現這篇文章還是很有意思的。
但是為什么用scratch來實現神經網絡 ,即使你在以后采用其他軟件平臺如PyBrain,僅僅用scratch 做一次神經網絡都是非常有價值的,他幫助你理解神經網絡的運作原理,這種原理對于建立模型是至關重要的。
我要指出的是這里的代碼例子不是非常高效,但是他容易理解,在以后的文章中,我將用Theano.展示一種更加高效的神經網絡。
產生一組數據
? ? ? ? 讓我們產生一組數據來開始,幸運的是scikit-learn 有非常有用的數據發生器,我們沒有必要自己寫代碼來產生數據了。我們用make_moons function.來 出數據
? ? ? ? 我們得到兩類數據,分別以紅點和藍點畫出,你可以認為藍色的點代表男性病人,紅點代表女性病人,X,Y軸分別代表治療措施。我們的目標是訓練機器分類器,讓機器來分類,然后給出想X,Y的坐標。需要指出的是這些數據不是線性可分的。我們不能用一條直線來將這兩組數據分成兩類。這就意味著,像Logistic Regression這樣的算法不能用于這樣數據的分類,除非你采用對于分類比較好的,手動非線性回歸(如多項式回歸)算法,
事實上,神經網絡的一個優勢就是你沒有必要擔心特征的收集,隱藏層就會自動學習特征。
LOGISTIC REGRESSION(邏輯斯提克回歸)
為了證明這一點,我們來訓練Logistic Regression 分類器,輸入X,Y值和輸出分類(0 or 1)
import numpy as np from sklearn import datasets, linear_model import matplotlib.pyplot as pltdef generate_data():np.random.seed(0)X, y = datasets.make_moons(200, noise=0.20)return X, ydef visualize(X, y, clf):# plt.scatter(X[:, 0], X[:, 1], s=40, c=y, cmap=plt.cm.Spectral)# plt.show()plot_decision_boundary(lambda x: clf.predict(x), X, y)plt.title("Logistic Regression")def plot_decision_boundary(pred_func, X, y):# Set min and max values and give it some paddingx_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5h = 0.01# Generate a grid of points with distance h between themxx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))# Predict the function value for the whole gidZ = pred_func(np.c_[xx.ravel(), yy.ravel()])Z = Z.reshape(xx.shape)# Plot the contour and training examplesplt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)plt.show()def classify(X, y):clf = linear_model.LogisticRegressionCV()clf.fit(X, y)return clf? ? ? ? 圖片顯示,分類邊界已經被Logistic Regression classifier畫出,他將數據盡其所能按直線分成兩類,但是他不能捕捉月亮形狀的數據。
TRAINING A NEURAL NETWORK(訓練一種神經網絡)
? ? ? ? 我們將建立一個三層神經網絡,這個網絡包括一個輸入層,一個輸出層和一個隱藏層。輸入層的節點數(2)由數據的維度確定(數據時二維的,包括X,Y的坐標 ),輸出層的節點數(2)由所分的種類確定(我們只有兩類數據,我們實際上可以只設置一個輸出節點來預測0或者1,但是當設置兩個節點時,該神經網絡可以擴展,使該網絡可以計算更多的分類),輸入層只要輸入X,Y的坐標,輸出層要輸出兩種分類的概率。
? ? ? ? 我們可以設置隱藏層的節點數,隱藏層的節點數越多,分類的效果越好。但是這樣做的代價也比較大,首先,該網絡的在預測是需要學習的參數就比較多,導致計算量的增加。其次,大量的參數也容易導致過擬合。怎樣去確定隱藏層的規模呢? 盡管有一些大致的規則和建議,更多時候取決于實際問題的情況。隱藏層的節點數更多時候是一個藝術的問題而不是一個科學的問題,我們將改變隱藏層的 節點數來看看輸出 的效果
我們需要為隱藏層選取一個激活函數,這個激活函數將層的輸入值轉化為輸出值,非線性的激活函數允許我們完成非線性的預測,激活函數一般選取,tanh, the sigmoid function, or ReLUs. /font>
? ? ? ? 我們將使用tanh,tanh在很多情況下表現都很好。這些函數都有一個很好的優點,即他們的導數可以用他們的原函數來表示。例如 這樣的函數非常有用,因為我們只需要計算一次函數值,然后再次利用函數值來得到他的導數值
? ? ? ? 因為我們希望該網絡最后輸出概率,所以我們將輸出層的激活函數選為 softmax,softmax可以將原始數據轉化為概率,如果你對logistic function 比較熟悉的話你可以把它看做logistic function 的推廣。
? ? ? ? 譯者說明:本神經網絡在算法本質上是BP 神經網絡,但是他與一般的BP網又存在不同點:
? ? ? ? 1. 一般教科書上的BP網都采用同一個激活函數,下文的代碼中,隱藏層的激活函數為tanh ,輸出層的激活函數為softmax.為什么采用softmax 作為輸出層的激活函數,我會在下文中進行說明。
HOW OUR NETWORK MAKES PREDICTIONS (我們的網絡如何預測)
? ? ? ?我們的網絡采用前饋神經網絡,即一串矩陣相乘,然后再利用我們之前定義的激活函數。如果x是一個二維數組,輸入到神經網絡,輸出值為 同樣是二維數據。
\begin{aligned} z_1 & = xW_1 + b_1 \ a_1 & = \tanh(z_1) \ z_2 & = a_1W_2 + b_2 \ a_2 & = \hat{y} = \mathrm{softmax}(z_2) \end{aligned}
zi 是第i層的輸入值,ai是第i層通過激活函數的輸出值,w1,b1,w2,b2,為該神經網絡的參數,這些參數同對數據的學習來不斷的修正(w1為輸入層和隱藏層之間的權矩陣,b1為隱藏層的偏置,w2為隱藏層和輸出層之間的權矩陣,b1為輸出層的偏置)。你也可以認為他是各層之間的轉換矩陣。通過對上面矩陣相乘我們可以看出各個矩陣的維度,如果我們在隱藏層設置500個節點,那么
? ? ? ?? ? ? ?
? ? ? ? 現在你可以看出,如果我們增加隱藏層的節點,我們將需要更多的參數
LEARNING THE PARAMETERS
? ? ? ?通過最小化誤差來不斷的修正各層的參數(w1,b1,w2,b2,)。但是如何定義誤差呢,我們把這個函數叫作誤差損失函數;關于softmax 函數的誤差函數叫做叫做交叉熵損失(也叫做log似然代價函數),如果我們有N個訓練例子和C個人分類,那么log似然代價函數如下, 是我們的預測值(計算值),而y是標簽值,(目標值)
? ? ? ? ? ? ? ?
? ? ? ?這個公式看起來非常復雜,但是他只是將所有例子的誤差加起來,如果我們預測分類不正確,y 是(目標值),是預測值(計算值),如果這兩個值相差越大,則誤差函數就越大。通過訓練數據最大化似然函數,來最小化誤差,同時不斷修正網絡參數。
? ? ? ? 我們可以用梯度下降法來,尋求最小值,我將常用的梯度下降法,也叫采用固定學習速度的批量梯度下降法。他的變種是隨機梯度下降法和 minibatch gradient descent,表現都很好,如果你對這種算法感興趣,你可以嘗試一下各種算法。
? ? ? ?輸入時,梯度下降法需要輸入梯度,(),損失函數的向量導數。為了計算梯度我們運用著名的BP算法。該算法是一種計算梯度的有效算法。我不想展示BP算法的的求導細節。
? ? ? ? 譯者注釋:
1.BP 神經網絡求導細節請看這里這里寫鏈接內容這是一篇非常好的文章還有這篇這里寫鏈接內容
2.在下面代碼中還涉及到softmax的求導,這里寫鏈接內容請好好看看上面三篇文章,你就對BP 算法有比較深刻的認識。
? ? ? ?通過誤差反向傳播算法,我們可以得到如下公式(相信我,下面的公式是正確的)
? ? ? ?? ? ? ?? ? ? ?
? ? ? ? 譯者注釋:那我就將推導上面所有公式!!!
BP算法
1.0
? ? ? ?? 表示第 L-1層的第i個神經元連接到第層的第j個神經元的連接權重;
? ? ? ?? ? 表示第L層的第i個神經元的輸入
? ? ? ?
? ? ? ?? ? 表示第L層的第i個神經元的輸出
? ? ? ?
? ? ? ?? ? 表示輸出層的激活函數,在本文中,激活函數為softmax函數。
2.0
代價函數為最大似然函數,如下: 是我們的預測值(計算值),而y是標簽值,(目標值)
? ? ? ? ? ? ? ?
3.0
首先,將第L層第i個神經元中產生的錯誤對第i層的倒數定義為
? ? ? ? ? ? ? ?
方程一(計算損失函數對輸出層某個節點輸入值的導數)
方程2(由后往前,計算損失函數對前一層某個節點輸入值的導數):
方程3(計算損失函數對最靠近當前層與當前層某個權值的偏導數):
方程4(計算損失函數對當前層某個偏置的偏導數):
4.0
BP算法偽代碼
1,輸入數據
2,初始化權值和偏置我w,b
3,前向傳播
3,計算損失函數對輸出層某個節點輸入值的偏導數
4,計算損失函數對隱藏層某個節點輸入值的偏導數
5,計算損失函數對各層各個節點的權值,和偏置的梯度,采用梯度下降法最小化似然函數
在這里我們已經清楚BP算法的的原理,我們要感謝這里寫鏈接內容這位博主,他用精細化的數學語言向我們展示了BP算法。他的推到有點問題,我已經在我的文章中糾正了。
但是要理解下面的代碼,有一個很重要的問題就是softmax函數求導的問題,這里我們將探討這個問題。
1. softmax函數及其求導;我們要感謝這里寫鏈接內容內容這位博主,他用精細化的數學語言向我們展示了softmax求導算法。
softmax的函數
其中,表示第L層(通常是最后一層)第j個神經元的輸入,表示第L層第j個神經元的輸出,e表示自然常數。注意看,表示了第L層所有神經元的輸入之和。
softmax函數最明顯的特點在于:它把每個神經元的輸入占當前層所有神經元輸入之和的比值,當作該神經元的輸出。這使得輸出更容易被解釋:神經元的輸出值越大,則該神經元對應的類別是真實類別的可能性更高。
另外,softmax不僅把神經元輸出構造成概率分布,而且還起到了歸一化的作用,適用于很多需要進行歸一化處理的分類問題。
由于softmax在ANN算法中的求導結果比較特別,分為兩種情況。希望能幫助到正在學習此類算法的朋友們。求導過程如下所示:
二次代價函數在訓練ANN時可能會導致訓練速度變慢的問題。那就是,初始的輸出值離真實值越遠,訓練速度就越慢。這個問題可以通過采用交叉熵代價函數來解決。其實,這個問題也可以采用另外一種方法解決,那就是采用softmax激活函數,并采用log似然代價函數(log-likelihood cost function)來解決。
log似然代價函數的公式為:
在上一篇博文“交叉熵代價函數”中講到,二次代價函數在訓練ANN時可能會導致訓練速度變慢的問題。那就是,初始的輸出值離真實值越遠,訓練速度就越慢。這個問題可以通過采用交叉熵代價函數來解決。其實,這個問題也可以采用另外一種方法解決,那就是采用softmax激活函數,并采用log似然代價函數(log-likelihood cost function)來解決。
log似然代價函數的公式為:
下面為羅干注釋的代碼
# -*- coding: utf-8 -*- """ Created on Sun Feb 12 14:57:00 2017@author: Denny Britz @Translater:luogan 羅干 @luogan has make some coment on the code @ 我愛婷婷和臭臭 """import numpy as np from sklearn import datasets, linear_model import matplotlib.pyplot as pltclass Config:nn_input_dim = 2 #數組輸入的維度是2(x,y兩個坐標當然是二維啊)nn_output_dim = 2#數組輸出的維度是2(分為兩類當然是二維啊) epsilon = 0.01 # 梯度下降學習步長reg_lambda = 0.01 # 修正的指數?def generate_data():np.random.seed(0)#偽隨機數的種子0,當然也可以是1,2啊X, y = datasets.make_moons(200, noise=0.20)#產生200個數據,噪聲誤差為0.2return X, ydef visualize(X, y, model):plot_decision_boundary(lambda x:predict(model,x), X, y)#好好看這個代碼,函數名字做參數哦plt.title("Logistic Regression")def plot_decision_boundary(pred_func, X, y):#把X的第一列的最小值減掉0.5賦值給x_min,把X的第一列的最大值加0.5賦值給x_maxx_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5h = 0.01# 根據最小最大值和一個網格距離生成整個網格,就是在圖上細分好多個點,畫分類邊界的時候要用這些點xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))Z = pred_func(np.c_[xx.ravel(), yy.ravel()])Z = Z.reshape(xx.shape)plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral)plt.show()def predict(model, x):#這是字典啊W1, b1, W2, b2 = model['W1'], model['b1'], model['W2'], model['b2']z1 = x.dot(W1) + b1# 輸入層向隱藏層正向傳播a1 = np.tanh(z1) # 隱藏層激活函數使用tanh = (exp(x) - exp(-x)) / (exp(x) + exp(-x))z2 = a1.dot(W2) + b2# 隱藏層向輸出層正向傳播exp_scores = np.exp(z2)#這兩步表示輸出層的激活函數為softmax函數哦probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)return np.argmax(probs, axis=1)def build_model(X, y, nn_hdim, num_passes=20000, print_loss=False):num_examples = len(X)np.random.seed(0)#初始化權值和偏置W1 = np.random.randn(Config.nn_input_dim, nn_hdim) / np.sqrt(Config.nn_input_dim)b1 = np.zeros((1, nn_hdim))W2 = np.random.randn(nn_hdim, Config.nn_output_dim) / np.sqrt(nn_hdim)b2 = np.zeros((1, Config.nn_output_dim))model = {}for i in range(0, num_passes):z1 = X.dot(W1) + b1# 輸入層向隱藏層正向傳播a1 = np.tanh(z1)# 隱藏層激活函數使用tanh = (exp(x) - exp(-x)) / (exp(x) + exp(-x))z2 = a1.dot(W2) + b2# 隱藏層向輸出層正向傳播exp_scores = np.exp(z2)#這兩步表示輸出層的激活函數為softmax函數哦probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)delta3 = probs#下面這才是delta3,為損失函數對z2求偏導數,y-y^delta3[range(num_examples), y] -= 1dW2 = (a1.T).dot(delta3)#損失函數對w2的偏導數db2 = np.sum(delta3, axis=0, keepdims=True)#損失函數對b2的偏導數delta2 = delta3.dot(W2.T) * (1 - np.power(a1, 2))#損失函數對z1的偏導數dW1 = np.dot(X.T, delta2)#損失函數對w1的偏導數db1 = np.sum(delta2, axis=0)#損失函數對b1的偏導數#個人認為下面兩行代碼完全沒有必要存在dW2 += Config.reg_lambda * W2#w2梯度增量的修正 屁話dW1 += Config.reg_lambda * W1#w1梯度增量的修正 屁話#更新權值和偏置W1 += -Config.epsilon * dW1b1 += -Config.epsilon * db1W2 += -Config.epsilon * dW2b2 += -Config.epsilon * db2model = {'W1': W1, 'b1': b1, 'W2': W2, 'b2': b2}return modeldef main():X, y = generate_data()model = build_model(X, y, 8)visualize(X, y, model)if __name__ == "__main__":main()#2017.3.20 羅干注釋于同濟大學圖書館[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yTVs91UX-1596200021425)(https://img-blog.csdn.net/20170320100022990?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHVvZ2FudHRjYw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]
在這里首先要感謝dennybritz這里是dennybritz的github
(High-school dropout. Google Brain, Stanford, Berkeley. Into Startups, Deep Learning. Writing at wildml.com and dennybritz.com. Lived in 日本 and ??)
操,高中輟學都這么屌,還上了斯坦福,和伯克利。
dennybritz在GitHub上分享了他的代碼和文章。我的這篇博客就是對dennybritz原文的翻譯,但是他的文章中沒有BP網絡和softmax函數的求導。
我在這篇文章中插入數學推導,主要參考這里天才的博客這位天才的文章,為了讓讀者更好的理解BP,我就直接引用了。
特碼的,搞神經網絡,畢業都延期了,不過也是值得的
未完待續,我還會修改的
總結
以上是生活随笔為你收集整理的BP神经网络python代码详细解答(来自原文翻译)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python 程序开机自启动,亲测可用
- 下一篇: tf.dynamic_stitch 和