周志华《机器学习》课后习题(第五章):神经网络
作者 |?我是韓小琦
鏈接 |?https://zhuanlan.zhihu.com/p/47616848
5.1 試述將線性函數??用作神經元激活函數的缺陷。
答:
使用線性函數作為激活函數時,無論是在隱藏層還是在輸出層(無論傳遞幾層),其單元值(在使用激活函數之前)都還是輸入??的線性組合,這個時候的神經網絡其實等價于邏輯回歸(即原書中的對率回歸,輸出層仍然使用Sigmoid函數)的,若輸出層也使用線性函數作為激活函數,那么就等價于線性回歸 。
5.2 試述使用圖 5.2(b) 激活函數的神經元與對率回歸的聯系。
答:
使用Sigmoid激活函數,每個神經元幾乎和對率回歸相同,只不過對率回歸在??時輸出為1,而神經元直接輸出??。
5.3 對于圖 5.7 中的??,試推導出 BP 算法中的更新公式 (5.13)。
答:
?,因?只在計算??時用上,所以??,其中?,所以??,即得原書中5.13式。
5.4 試述式 (5.6) 中學習率的取值對神經網絡訓練的影響。
答:
用一張網上找到的圖來說明吧。
簡單說就是學習率太高會導致誤差函數來回震蕩,無法收斂;而學習率太低則會收斂太慢,影響訓練效率。
在原書p104也提到過。
5.5 試編程實現標準 BP 算法和累積 BP 算法,在西瓜數據集 3.0 上分別用這兩個算法訓練一個單隱層網絡,并進行比較。
答:
標準 BP 算法和累積 BP 算法在原書(P105)中也提到過,就是對應標準梯度下降和隨機梯度下降,差別就是后者每次迭代用全部數據計算梯度,前者用一個數據計算梯度。
代碼在:
https://github.com/han1057578619/MachineLearning_Zhouzhihua_ProblemSets/tree/master/ch5--%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/5.5-5.6
具體兩種情況的結果如下圖:可以看出來gd的成本函數收斂過程更加穩定,而sgd每次迭代并不一定向最優方向前進,但總體方向是收斂的,且同樣是迭代200次,最后結果相差不大,但由于sgd每次迭代只使用一個樣本,計算量大幅度下降,顯然sgd的速度會更快。
ps.關于隨機梯度下降的實現,好像有兩種方式,一種是每次將樣本打亂,然后遍歷所有樣本,而后再次打亂、遍歷;另一種是每次迭代隨機抽取樣本。這里采取的是后一種方式,貌似兩種方式都可以。
此外,BP神經網絡代碼在以前學吳恩達老師深度學習課程的時候就寫過,這次整理了一下正好放上來,所以很多代碼和課程代碼類似,添加了應用多分類的情況的代碼。下面的5.6題也一并在這里實現。
5.6 試設計一個 BP 改進算法,能通過動態調整學習率顯著提升收斂速度。編程實現該算法,并選擇兩個 UCI 數據集與標準 BP 算法進行實驗比較。
答:
動態調整學習率有很多現成的算法,RMSProp、Adam、NAdam等等。也可以手動實現一個簡單指數式衰減?,??是一個超參。這里代碼實現了Adam,下面
代碼和5.5一同實現,同樣在:
https://github.com/han1057578619/MachineLearning_Zhouzhihua_ProblemSets/tree/master/ch5--%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/5.5-5.6
這里只嘗試了sklearn 中自帶的iris數據集試了一下。同樣學習率下,兩者訓練時損失函數如下:
可以明顯看出adam的速度更快的。
5.7 根據式 (5.18)和 (5.19) ,試構造一個能解決異或問題的單層 RBF 神經網絡。
答:
這里可以使用X = array([[1, 0], [0, 1], [0, 0], [1, 1]]),y = array([[1], [1], [0], [0]])作為數據,訓練一個RBF神經網絡。
這里使用均方根誤差作為損失函數;輸出層和書上一致,為隱藏層的線性組合,且另外加上了一個偏置項(這是書上沒有)。
代碼在:
''' 這里使用均方根誤差作為損失函數的RBF神經網絡。 ''' import numpy as np import matplotlib.pyplot as pltdef RBF_forward(X_, parameters_):m, n = X_.shapebeta = parameters_['beta']W = parameters_['W']c = parameters_['c']b = parameters_['b']t_ = c.shape[0]p = np.zeros((m, t_)) # 中間隱藏層的激活值 對應書上5.19式x_c = np.zeros((m, t_)) # 5.19式中 x - c_{i}for i in range(t_):x_c[:, i] = np.linalg.norm(X_ - c[[i],], axis=1) ** 2p[:, i] = np.exp(-beta[0, i] * x_c[:, i])a = np.dot(p, W.T) + breturn a, p, x_cdef RBF_backward(a_, y_, x_c, p_, parameters_):m, n = a_.shapegrad = {}beta = parameters_['beta']W = parameters_['W']da = (a_ - y_) # 損失函數對輸出層的偏導 ,這里的a其實對應著 輸出層的y_hatdw = np.dot(da.T, p_) / mdb = np.sum(da, axis=0, keepdims=True) / mdp = np.dot(da, W) # dp即損失函數對隱藏層激活值的偏導dbeta = np.sum(dp * p_ * (-x_c), axis=0, keepdims=True) / massert dbeta.shape == beta.shapeassert dw.shape == W.shapegrad['dw'] = dwgrad['dbeta'] = dbetagrad['db'] = dbreturn graddef compute_cost(y_hat_, y_):m = y_.shape[0]loss = np.sum((y_hat_ - y) ** 2) / (2 * m)return np.squeeze(loss)def RBF_model(X_, y_, learning_rate, num_epochs, t):''':param X_::param y_::param learning_rate: 學習率:param num_epochs: 迭代次數:param t: 隱藏層節點數量:return:'''parameters = {}np.random.seed(16)# 定義中心點,本來這里的中心點應該由隨機采用或者聚類等非監督學習來獲得的,這里為了簡單就直接定義好了parameters['beta'] = np.random.randn(1, t) # 初始化徑向基的方差parameters['W'] = np.zeros((1, t)) # 初始化parameters['c'] = np.random.rand(t, 2)parameters['b'] = np.zeros([1, 1])costs = []for i in range(num_epochs):a, p, x_c = RBF_forward(X_, parameters)cost = compute_cost(a, y_)costs.append(cost)grad = RBF_backward(a, y_, x_c, p, parameters)parameters['beta'] -= learning_rate * grad['dbeta']parameters['W'] -= learning_rate * grad['dw']parameters['b'] -= learning_rate * grad['db']return parameters, costsdef predict(X_, parameters_):a, p, x_c = RBF_forward(X_, parameters_)return aX = np.array([[1, 0], [0, 1], [0, 0], [1, 1]]) y = np.array([[1], [1], [0], [0]]) #parameters, costs = RBF_model(X, y, 0.003, 10000, 8)plt.plot(costs) plt.show()print(predict(X, parameters))# 梯度檢驗 # parameters = {} # parameters['beta'] = np.random.randn(1, 2) # 初始化徑向基的方差 # parameters['W'] = np.random.randn(1, 2) # 初始化 # parameters['c'] = np.array([[0.1, 0.1], [0.8, 0.8]]) # parameters['b'] = np.zeros([1, 1]) # a, p, x_c = RBF_forward(X, parameters) # # cost = compute_cost(a, y) # grad = RBF_backward(a, y, x_c, p, parameters) # # # parameters['b'][0, 0] += 1e-6 # # a1, p1, x_c1 = RBF_forward(X, parameters) # cost1 = compute_cost(a1, y) # print(grad['db']) # # print((cost1 - cost) / 1e-6)最后輸出是:
[[ 9.99944968e-01][ 9.99881045e-01]
[ 8.72381056e-05]
[ 1.26478454e-04]]
感覺,分類的時候在輸出層使用sigmoid作為激活函數也可以。
5.8 從網上下載或自己編程實現 SOM 網絡,并觀察其在西瓜數據集 3.0α上產生的結果。
答:
花了挺長時間看,寫完代碼的發現結果和預期有點不太符合,先暫時放一下吧還是...代碼不完整就不放了。
這里提一個迷惑了我很久的一點,有些博客說SOM神經網絡的聚類類別不需要自己定義,其實是不對的,SOM神經網絡輸出聚類類別是需要自己定義,每個輸出節點對應著一個類別,通過計算樣本和輸出節點的權重向量的相似度來確定樣本屬于哪個類別(節點);輸入節點的數量和樣本的維度一樣(和BP網絡相同);輸出的節點常常是以二維矩陣(這里可以是正方形也可以多邊形等)或者一維直線的形式,每一個輸出節點對應著一個權重向量和輸入節點實現全連接。
想了解SOM建議參考下面幾個鏈接:
https://www.jianshu.com/p/41fc86728928
https://github.com/KeKe-Li/tutorial/blob/master/assets/src/SOM/SOM.md
https://www.cs.bham.ac.uk/~jxb/NN/l16.pdf
5.9* 試推導用于 Elman 網絡的 BP 算法.
答:
Elman 網絡在西瓜書原書上說的是“遞歸神經網絡”,但是在網上找資料說的
“遞歸神經網絡”是空間維度的展開,是一個樹結構。“循環神經網絡”是時間維度的展開,代表信息在時間維度從前往后的的傳遞和積累。
從書上p111描述來看感覺更像“循環神經網絡”。最近時間不多(lan..),就不去啃原論文了。關于“循環神經網絡”或者遞歸神經網絡的BP可以參考下面鏈接。
1、零基礎入門深度學習(5) - 循環神經網絡?,網上大神寫了。
https://zybuluo.com/hanbingtao/note/541458
另外關于循環神經網絡也可以看看吳恩達老師的深度學習課程“序列模型”那部分。
5.10 從網上下載或自己編程實現一個卷積神經網絡并在手寫字符識別數據 MNIST 上進行實驗測試。
答:
正好前段時間做過Kaggle上手寫數字識別的題目。這里正好放上來,CNN是用Tensorflow實現的,之前看吳恩達老師深度學習課程的時候也拿numpy實現過(課程作業),等以后有時間再整理放上來吧。
https://github.com/han1057578619/kaggle_competition/tree/master/Digit_Recogniz
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯AI基礎下載(pdf更新到25集)機器學習的數學基礎專輯獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/yFQV7am本站qq群1003271085,加入微信群請掃碼喜歡文章,點個在看 與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的周志华《机器学习》课后习题(第五章):神经网络的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【深度学习】Coursera的Tenso
- 下一篇: 周志华《机器学习》课后习题解析(第一章)