簡單BP神經網路的python實現
阿新 • • 發佈:2019-01-01
貼上一個前兩天寫的不用框架實現隨機梯度下降的GitHub連結吧,具體說明可以看裡面的文件。
============================18.6.3 update=======================================
儘管神經網路已經有了很完備並且好用的框架,而且BP神經網路又是其中比較簡單低效的一種,但是出於學習的目的來實現一下這個神經網路還是有意義的吧我想。
下面程式用到了iris資料集,為了方便畫圖先用PCA對資料進行了降維。同時對分類結果進行了標籤化,針對神經網路的特點,用三個神經元作為輸出來表示三個不同的分類,程式碼如下:
最終分類結果的準去率評分達到了0.983,但是可以在下面的圖中看到,綠色和藍色點的邊界部分存在著過擬合的問題,這個問題日後慢慢解決嘍..import math import random from sklearn.decomposition import PCA from sklearn.cross_validation import train_test_split import matplotlib.pyplot as plt import matplotlib as mpl import numpy as np from sklearn.metrics import accuracy_score def trtype(s):#定義類別轉換函式 types = {'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2} return types[s] data = np.loadtxt('iris.data',delimiter=',',converters={4:trtype})#讀入資料,第五列轉換為類別012 x,y = np.split(data,(4,),axis=1)#切分data和label pca=PCA(n_components=2) x=pca.fit_transform(x)#為方便繪圖,對x進行PCA降維至二維 #劃分測試集和訓練集 def label_tr(y):#標籤轉換,將一維標籤轉換為三維 l = {0:[1,0,0],1:[0,1,0],2:[0,0,1]} ys = [] for i in range(len(y)): ys.append(l[int(y[i])]) return np.array(ys) def inv_label_tr(y_1d):#標籤轉換逆過程 y_pres = [] for i in range(y_1d.shape[0]): for j in range(3): if (y_1d[i][j]==1): y_lable = j y_pres.append(y_lable) return np.array(y_pres) y = label_tr(y) #劃分資料 x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=1, train_size=0.6) random.seed(0) def rand(a, b):#隨機數函式 return (b - a) * random.random() + a def make_matrix(m, n, fill=0.0):#矩陣生成函式 mat = [] for i in range(m): mat.append([fill] * n) return mat def sigmoid(x):#啟用函式 return 1.0 / (1.0 + math.exp(-x)) def sigmoid_derivative(x):#啟用函式求導 return x * (1 - x) class BPNeuralNetwork:#BP神經網路類 def __init__(self):#初始化 self.input_n = 0 self.hidden_n = 0 self.output_n = 0 self.input_cells = [] self.hidden_cells = [] self.output_cells = [] self.input_weights = [] self.output_weights = [] self.input_correction = [] self.output_correction = [] def setup(self, ni, nh, no): #初始化輸入、隱層、輸出元數 self.input_n = ni + 1 self.hidden_n = nh self.output_n = no # 初始化神經元 self.input_cells = [1.0] * self.input_n self.hidden_cells = [1.0] * self.hidden_n self.output_cells = [1.0] * self.output_n # 初始化權重矩陣 self.input_weights = make_matrix(self.input_n, self.hidden_n) self.output_weights = make_matrix(self.hidden_n, self.output_n) # 初始化權重 for i in range(self.input_n): for h in range(self.hidden_n): self.input_weights[i][h] = rand(-0.2, 0.2) for h in range(self.hidden_n): for o in range(self.output_n): self.output_weights[h][o] = rand(-2.0, 2.0) # 初始化偏置 self.input_correction = make_matrix(self.input_n, self.hidden_n) self.output_correction = make_matrix(self.hidden_n, self.output_n) def predict(self, inputs): # 啟用輸入層 for i in range(self.input_n - 1): self.input_cells[i] = inputs[i] # 啟用隱層 for j in range(self.hidden_n): total = 0.0 for i in range(self.input_n): total += self.input_cells[i] * self.input_weights[i][j] self.hidden_cells[j] = sigmoid(total) # 啟用輸出層 for k in range(self.output_n): total = 0.0 for j in range(self.hidden_n): total += self.hidden_cells[j] * self.output_weights[j][k] self.output_cells[k] = sigmoid(total) return self.output_cells[:] def back_propagate(self, case, label, learn, correct): # 反向傳播 self.predict(case) # 求輸出誤差 output_deltas = [0.0] * self.output_n for o in range(self.output_n): error = label[o] - self.output_cells[o] output_deltas[o] = sigmoid_derivative(self.output_cells[o]) * error # 求隱層誤差 hidden_deltas = [0.0] * self.hidden_n for h in range(self.hidden_n): error = 0.0 for o in range(self.output_n): error += output_deltas[o] * self.output_weights[h][o] hidden_deltas[h] = sigmoid_derivative(self.hidden_cells[h]) * error # 更新輸出權重 for h in range(self.hidden_n): for o in range(self.output_n): change = output_deltas[o] * self.hidden_cells[h] self.output_weights[h][o] += learn * change + correct * self.output_correction[h][o] self.output_correction[h][o] = change # 更新輸入權重 for i in range(self.input_n): for h in range(self.hidden_n): change = hidden_deltas[h] * self.input_cells[i] self.input_weights[i][h] += learn * change + correct * self.input_correction[i][h] self.input_correction[i][h] = change # 求全域性誤差 error = 0.0 for o in range(len(label)): error += 0.5 * (label[o] - self.output_cells[o]) ** 2 return error def train(self, cases, labels, limit=10000, learn=0.05, correct=0.1): #訓練神經網路 for j in range(limit): error = 0.0 for i in range(len(cases)): label = labels[i] case = cases[i] error += self.back_propagate(case, label, learn, correct) def fit(self,x_test):#離散預測函式用於輸出資料 y_pre_1d = [] for case in x_test: y_pred = self.predict(case) for i in range(len(y_pred)): if (y_pred[i] == max(y_pred)): y_pred[i] = 1 else: y_pred[i] = 0 y_pre_1d.append(y_pred) return inv_label_tr(np.array(y_pre_1d)) def fit2(self,x_test):#連續預測函式用於畫圖 y_pre_1d = [] for case in x_test: w = np.array([0,1,2]) y_pred = self.predict(case) y_pre_1d.append(np.array(y_pred).dot(w.T)) return np.array(y_pre_1d) if __name__ == '__main__':#主函式 nn = BPNeuralNetwork() nn.setup(2, 5, 3)#初始化 nn.train(x_train, y_train, 100000, 0.05, 0.1)#訓練 y_pre_1d = nn.fit(x_test)#測試 y_test_1d = inv_label_tr(y_test) print accuracy_score(y_pre_1d,y_test_1d)#列印測試精度 #畫圖 mpl.rcParams['font.sans-serif'] = [u'SimHei'] mpl.rcParams['axes.unicode_minus'] = False cm_light = mpl.colors.ListedColormap(['#FFA0A0', '#A0FFA0', '#A0A0FF']) cm_dark = mpl.colors.ListedColormap(['#AAAAFF', '#FFAAAA','#AAFFAA']) x1_min, x1_max = x[:, 0].min(), x[:, 0].max() # 第0列的範圍 x2_min, x2_max = x[:, 1].min(), x[:, 1].max() # 第1列的範圍 x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j] # 生成網格取樣點 grid_test = np.stack((x1.flat, x2.flat), axis=1) # 測試點 grid_hat = nn.fit2(grid_test)#預測結果 grid_hat = grid_hat.reshape(x1.shape) # 使之與輸入的形狀相同 plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light) plt.scatter(x[:, 0], x[:, 1], c=y, edgecolors='k', s=50, cmap=cm_dark) plt.title(u'BPNN二特徵分類', fontsize=15) plt.show() print grid_hat.shape