''' 11行神经网络① 层数可变,多类 ''' import numpy as np import matplotlib.pyplot as plt class BPNN(object): def __init__(self, neurals, epsilon=0.01, lamda=0.01): if not isinstance(neurals, list): raise '出错:参数 neurals 必须是 list 类型' self.neurals = neurals # 各层神经元数目,如:[3,10,8,2] self.size = len(neurals) self.epsilon = epsilon # 学习速率 self.lamda = lamda # 正则化强度 self.w = [np.random.randn(i,j) for i,j in zip(neurals[:-1], neurals[1:])] + [None] self.b = [None] + [np.random.randn(1,j) for j in neurals[1:]] self.l = [None] * self.size self.l_delta = [None] * self.size self.probs = None # 前向传播 def forward(self, X): self.l[0] = X for i in range(1, self.size-1): self.l[i] = np.tanh(np.dot(self.l[i-1], self.w[i-1]) + self.b[i]) # tanh 函数 self.l[-1] = np.exp(np.dot(self.l[-2], self.w[-2]) + self.b[-1]) self.probs = self.l[-1] / np.sum(self.l[-1], axis=1, keepdims=True) # 后向传播 def backward(self, y): self.l_delta[-1] = np.copy(self.probs) self.l_delta[-1][range(self.n_samples), y] -= 1 for i in range(self.size-2, 0, -1): self.l_delta[i] = np.dot(self.l_delta[i+1], self.w[i].T) * (1 - np.power(self.l[i], 2)) # tanh 函数的导数 # 更新权值、偏置 def update(self): self.b[-1] -= self.epsilon * np.sum(self.l_delta[-1], axis=0, keepdims=True) for i in range(self.size-2, -1, -1): self.w[i] -= self.epsilon * (np.dot(self.l[i].T, self.l_delta[i+1]) + self.lamda * self.w[i]) if i == 0: break self.b[i] -= self.epsilon * np.sum(self.l_delta[i], axis=0) # 计算损失 def calculate_loss(self, y): loss = np.sum(-np.log(self.probs[range(self.n_samples), y])) loss += self.lamda/2 * np.sum([np.sum(np.square(wi)) for wi in self.w[:-1]]) # 可选 loss *= 1/self.n_samples # 可选 return loss # 拟合 def fit(self, X, y, n_iter=1000, print_loss=True): self.n_samples = X.shape[0] # 样本大小(样本数目) for i in range(n_iter): self.forward(X) self.backward(y) self.update() if not print_loss: continue if i%100 == 0: print(self.calculate_loss(y)) # 预测 def predict(self, x): self.forward(x) return np.argmax(self.probs, axis=1) def plot_decision_boundary(clf, X, y): # Set min and max values and give it some padding x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5 y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5 h = 0.01 # Generate a grid of points with distance h between them xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) # Predict the function value for the whole gid Z = clf.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # Plot the contour and training examples plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral) plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Spectral) def test1(): X = np.array([[0,0,1],[0,1,1],[1,0,1],[1,1,1]]) #y = np.array([0,1,1,0]) # 两类 y = np.array([0,1,2,3]) # 多类 # bpnn = BPNN([3, 10, 8, 1]) bpnn = BPNN([3, 10, 8, 4]) bpnn.fit(X, y, n_iter=1000) print('训练结果:', bpnn.predict(X)) def test2(): from sklearn.datasets import make_moons from sklearn.linear_model import LogisticRegressionCV X, y = make_moons(200, noise=0.20) plt.scatter(X[:,0], X[:,1], s=40, c=y, cmap=plt.cm.Spectral) plt.show() clf = LogisticRegressionCV() clf.fit(X, y) plot_decision_boundary(clf, X, y) plt.show() #nn = BPNN([2,5,4,2]) nn = BPNN([2,4,2]) nn.fit(X, y, n_iter=1000) plot_decision_boundary(nn, X, y) plt.show() if __name__ == '__main__': #test1() test2()