1. 程式人生 > 實用技巧 >周志華西瓜書習題5.5

周志華西瓜書習題5.5

前言

這是第一次自己嘗試著把書上的程式碼去編寫成程式,但遺憾的是,沒有達到預想的結果

但是,我調了半天,終於調出來了,hahahahahahahaha

主要是犯了兩個重大錯誤:

1,只調eta2,卻忘記了調eta1,eta1要比eta2重要的多,

2,自己粗心,測試時居然用資料集X_train進行測試,而用y_test和測試集進行對比,我TM。。。。。。。。。。

第一次

第一次使用3.0a資料集,隱層有三個神經元,程式碼如下

'''
主要按照圖5.8的虛擬碼進行
使用資料集3.0a,兩個輸入一個輸出,對於資料集3.0,不知道怎麼把類別轉化為數字
使用的神經網路模型如下
         +++++++++++++++++++++++++
         +          O            +     輸出層  有一個閾值 theta
         +        / | \          +
         +       /  |  \         +     隱層到輸出層的三個權值 w
         +      /   |   \        +
         +     O    O    O       +     隱層    有三個閾值 gamma
         +                       +
         +  中間太難畫了,直接省略了  +     輸入層到隱層有三個權值 v
         +                       +
         +      O       O        +     輸入層
         +++++++++++++++++++++++++
''' import numpy as np import matplotlib.pyplot as plt import self_def #讀取資料集 data = np.loadtxt('watermelon_3a.csv',delimiter=',') X = data[:,1:3] y = data[:,3] #劃分資料集 from sklearn import model_selection X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.4, random_state=0) m,n
= np.shape(X_train) #引數初始化 theta = np.random.rand(1) #np.random.rand()可產生0到1內的隨機數 w = np.random.rand(3) gamma = np.random.rand(3) v = np.random.rand(3,2) eta1 = 0.1 eta2 = 0.2 #引數的歷史資料,用於檢視迭代情況 theta_history = np.zeros(m) w_history = np.zeros((m,3)) gamma_history = np.zeros((m,3)) v_history = np.zeros((3*m,2))
#訓練 for k in range(m): #計算三個隱層神經元的輸出 b = np.zeros(3) for h in range(3): b[h] = self_def.neuron_out1(X_train[k],v[h],gamma[h]) #輸出層神經元的輸出估計,式5.3 y_esti = self_def.neuron_out1(b,w,theta) #計算g,式5.10 g = y_esti*(1-y_esti)*(y_train[k]-y_esti) #計算e,式5.15 e = np.zeros(3) for h in range(3): e[h] = b[h]*(1-b[h])*(w[h]*g) # j = 1,5.15的求和式不必再計算 #計算5.11-5.14 delta_w = np.zeros(3) for h in range(3): delta_w[h] = eta1*g*b[h] delta_theta = -1*eta1*g #檢查一下 delta_v = np.zeros((3,2)) for h in range(3): for i in range(2): delta_v[h,i] = eta2*e[h]*X_train[k,i] delta_gamma = -1*eta2*e #引數更新 theta += delta_theta w += delta_w gamma += delta_gamma v += delta_v #記錄歷史資料 theta_history[k] = theta w_history[k] = w gamma_history[k] = gamma v_history[3*k:3*k+3] = v #訓練 mm = np.shape(X_test)[0] y_pred = np.zeros((mm,1)) for k in range(mm): #計算三個隱層神經元的輸出 for h in range(3): b[h] = self_def.neuron_out1(X_train[k],v[h],gamma[h]) #輸出層神經元的輸出估計,式5.3 y_esti = self_def.neuron_out1(b,w,theta) if y_esti >= 0.5: y_pred[k] = 1 #計算混淆矩陣 cfmat = np.zeros((2, 2)) for i in range(mm): if y_pred[i] == y_test[i] == 0: cfmat[0, 0] += 1 elif y_pred[i] == y_test[i] == 1: cfmat[1, 1] += 1 elif y_pred[i] == 0: cfmat[1, 0] += 1 elif y_pred[i] == 1: cfmat[0, 1] += 1 print(cfmat) #檢視迭代情況 t = np.arange(m) p1 = plt.subplot(411) p1.plot(t,theta_history) p2 = plt.subplot(412) w0 = np.ravel(w_history[:,0]) p2.plot(t,w0) w1 = np.ravel(w_history[:,1]) p2.plot(t,w1) w2 = np.ravel(w_history[:,2]) p2.plot(t,w2) p3 = plt.subplot(413) gamma0 = np.ravel(gamma_history[:,0]) p3.plot(t,gamma0) gamma1 = np.ravel(gamma_history[:,1]) p3.plot(t,gamma1) gamma2 = np.ravel(gamma_history[:,2]) p3.plot(t,gamma2) plt.show() print('end')

但是結果不怎麼樣,我感覺是因為資料量太小,啥也訓不出來,於是換資料集

第二次

資料集選用的是UCI資料集iris的一部分,共有100個,正例反例各50個

程式碼如下

'''
主要按照圖5.8的虛擬碼進行
使用資料集UCI中的iris的一個子資料集,四輸入一個輸出
使用的神經網路模型如下
         +++++++++++++++++++++++++
         +          O            +     輸出層  有一個閾值 theta_j     1
         +       // | \ \        +
         +     / /  |  \ \       +     隱層到輸出層的五個權值 w_hj     5*1
         +   /  /   |   \  \     +
         + O   O    O   O   O    +     隱層    有五個閾值 gamma_h     5
         +                       +
         +  中間太難畫了,直接省略了 +     輸入層到隱層有5*4個權值 v_hj    5*4
         +                       +
         +    O   O    O   O     +     輸入層
         +++++++++++++++++++++++++
'''

#以下是自己改程序序的過程 #2、把三個神經元改為五個神經元 #3、調節eta2的值 #4、引數不再隨機化賦值,改為賦指定值 #5、初始引數賦指定值,調節eta2 #6、將訓練過程和測試過程簡化為函式,見main_3 import numpy as np import matplotlib.pyplot as plt import self_def #讀取資料集 data = np.loadtxt('iris_2.csv',delimiter=',') X = data[:,0:4] y = data[:,4] #劃分資料集 from sklearn import model_selection X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.25, random_state=0) m,n = np.shape(X_train) #引數初始化 theta = np.random.rand(1) #np.random.rand()可產生0到1內的隨機數 w = np.random.rand(5) gamma = np.random.rand(5) v = np.random.rand(5,4) #引數賦指定值 theta = 0.5 w = np.arange(0,1,0.2) gamma = np.arange(0,1,0.2) for ii in range(5): v[ii] = np.arange(0,1,0.25) eta1 = 0.4 eta2 = 0.5 delta_w = np.zeros(5) delta_theta = 0 delta_v = np.zeros((5,4)) delta_gamma = 0 #引數的歷史資料,用於檢視迭代情況 theta_history = np.zeros(m) w_history = np.zeros((m,5)) gamma_history = np.zeros((m,5)) v_history = np.zeros((5*m,4)) #訓練 for k in range(m): #計算三個隱層神經元的輸出 b = np.zeros(5) for h in range(5): b[h] = self_def.neuron_out1(X_train[k],v[h],gamma[h]) #輸出層神經元的輸出估計,式5.3 y_esti = self_def.neuron_out1(b,w,theta) #計算g,式5.10 g = y_esti*(1-y_esti)*(y_train[k]-y_esti) #計算e,式5.15 e = np.zeros(5) for h in range(5): e[h] = b[h]*(1-b[h])*(w[h]*g) # j = 1,5.15的求和式不必再計算 #計算5.11-5.14 for h in range(5): delta_w[h] = eta1*g*b[h] delta_theta = -1*eta1*g #檢查一下 for h in range(5): for i in range(4): delta_v[h,i] = eta2*e[h]*X_train[k,i] delta_gamma = -1*eta2*e #引數更新 theta += delta_theta w += delta_w gamma += delta_gamma v += delta_v #記錄歷史資料 theta_history[k] = theta w_history[k] = w gamma_history[k] = gamma v_history[5*k:5*k+5] = v #預測 mm = np.shape(X_test)[0] y_pred = np.zeros((mm,1)) for k in range(mm): #計算三個隱層神經元的輸出 for h in range(5): b[h] = self_def.neuron_out1(X_test[k],v[h],gamma[h]) #輸出層神經元的輸出估計,式5.3 y_esti = self_def.neuron_out1(b,w,theta) #y_pred[k] = y_test[k] if y_esti >= 0.5: y_pred[k] = 1 #計算混淆矩陣 cfmat = np.zeros((2, 2)) for i in range(mm): if y_pred[i] == y_test[i] == 0: cfmat[0, 0] += 1 elif y_pred[i] == y_test[i] == 1: cfmat[1, 1] += 1 elif y_pred[i] == 0: cfmat[1, 0] += 1 elif y_pred[i] == 1: cfmat[0, 1] += 1 print(cfmat) print('end') # 檢視迭代情況 t = np.arange(m) p1 = plt.subplot(411) p1.plot(t, theta_history) plt.ylabel('theta') p2 = plt.subplot(412) w0 = np.ravel(w_history[:, 0]) plt.ylabel('w') p2.plot(t, w0) w1 = np.ravel(w_history[:, 1]) p2.plot(t, w1) w2 = np.ravel(w_history[:, 2]) p2.plot(t, w2) p3 = plt.subplot(413) gamma0 = np.ravel(gamma_history[:, 0]) plt.ylabel('gamma') p3.plot(t, gamma0) gamma1 = np.ravel(gamma_history[:, 1]) p3.plot(t, gamma1) gamma2 = np.ravel(gamma_history[:, 2]) p3.plot(t, gamma2) gamma3 = np.ravel(gamma_history[:, 3]) p3.plot(t, gamma3) plt.show()

結果

雖然準確率已經達到了100%,但是各個引數沒有趨於穩定,這跟標準BP演算法自身有很大的關係

心得

以下是自己改程序序的過程
#2、把三個神經元改為五個神經元
#3、調節eta2的值
#4、引數不再隨機化賦值,改為賦指定值,每次都使用不同的初值,肯定不方便觀察eta2對訓練結果的影響
#5、初始引數賦指定值,調節eta2
#6、跟著程式一步一步的走,發現eta1的作用遠比eta2大得多

進一步改進:簡化函式主體的結構,並作出 precision = f(eta1,eta2)的影象,尋找合適的eta1和eta2