前言
上一篇文章讲了神经网络反向传播方法实现,现在我们把它具体的应用到项目中去。
代码段
- 我们选取sklearn中的医疗数据,作为我们实验对象。
# -*- coding: utf-8 -*-
import numpy as np
from sklearn import datasets
import sklearn
import matplotlib.pyplot as plt
input_dim = 2 #
output_dim = 2 #
eplison = 0.01 #
reg_lambda = 0.01 #
#计算损失函数
def calculate_loss(model, X, y):
'''损失函数'''
#1.使用model中的参数
num_examples = len(X)
w1, b1, w2, b2, w3, b3 = model['w1'], model['b1'], model['w2'], model['b2'], model['w3'], model['b3']
#2.使用正向传播计算预测值
z1 = X.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
a2 = np.tanh(z2)
z3 = a2.dot(w3) + b3
exp_scores = np.exp(z3)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
#3.计算损失函数
corect_logrpobs = -np.log(probs[range(num_examples), y])
data_loss = np.sum(corect_logrpobs)
#4.对损失值进行归一化
data_loss += reg_lambda / 2 * (np.sum(np.square(w1)) + np.sum(np.square(w2)) + np.sum(np.square(w3)))
return 1. / num_examples * data_loss
def predict(model, X):
'''预测函数'''
#1.向前传播
w1, b1, w2, b2, w3, b3 = model['w1'], model['b1'], model['w2'], model['b2'], model['w3'], model['b3']
# 2.使用正向传播计算预测值
z1 = X.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
a2 = np.tanh(z2)
z3 = a2.dot(w3) + b3
exp_scores = np.exp(z3)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
#2.returen 具有最大类别概率
return np.argmax(probs, axis=1)
def ANN_model(X, y, nn_hdim):
'''
人工神经网络模型函数
:param X:
:param y:
:param nn_hdim: 隐层的神经元结点
:return:
'''
num_indim = len(X)
model = {
}#模型存储定义
#1.随机初始化网络中的权重参数w1,w2和偏置b1,b2
np.random.seed(0)
w1 = np.random.randn(input_dim, nn_hdim) / np.sqrt(input_dim)
b1 = np.zeros((1, nn_hdim))
w2 = np.random.randn(nn_hdim, nn_hdim) / np.sqrt(nn_hdim)
b2 = np.zeros((1, nn_hdim))
w3 = np.random.randn(nn_hdim, output_dim) / np.sqrt(nn_hdim)
b3 = np.zeros((1, output_dim))
num_passes = 20000 #梯度下降迭代次数
#2.批量梯度下降算法BSGD
for i in range(0, num_passes):
# 2.使用正向传播计算预测值
z1 = X.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
a2 = np.tanh(z2)
z3 = a2.dot(w3) + b3
exp_scores = np.exp(z3)
probs = exp_scores / np.sum(exp_scores, axis=1, keepdims=True)
#4.向后传播
delta4 = probs #得到预测值
delta4[range(num_indim), y] -= 1 #预测值减去实际值
delta3 = delta4.dot(w3.T) * (1 - np.power(a2, 2))
delta2 = delta3.dot(w2.T) * (1 - np.power(a1, 2))
dw3 = (a2.T).dot(delta4) #w2的导数
db3 = np.sum(delta4, axis=0, keepdims=True) #b3 的导数
dw2 = a1.T.dot(delta3) #w1的导数
db2 = np.sum(delta3, axis=0, keepdims=True) #b2 的导数
dw1 = (X.T).dot(delta2)
db1 = np.sum(delta2, axis=0, keepdims=True) #b1 的导数
#5.添加正则化项
dw1 += reg_lambda * w1
dw2 += reg_lambda * w2
dw3 += reg_lambda * w3
#根据梯度下降算法更新权重
w1 += -eplison * dw1
b1 += -eplison * db1
w2 += -eplison * dw2
b2 += -eplison * db2
w3 += -eplison * dw3
b3 += -eplison * db3
#把新的参数写入model字典中进行记录
model = {
'w1':w1, 'b1': b1, 'w2': w2, 'b2': b2, 'w3': w3, 'b3': b3}
if i % 1000 == 0:
print('Loss after iteration {}: {}' .format(i, calculate_loss(model, X, y)))
return model
def plot_decision_boundary(pred_func, data, labels):
'''绘制分类边界函数'''
#设置最大值和最小值并增加0.5边界(0.5 padding)
x_min, x_max = data[:, 0].min() - 0.5, data[:, 0].max() + 0.5
y_min, y_max = data[:, 1].min() - 0.5, data[:, 1].max() + 0.5
h = 0.01 #点阵间距
#生成一个点阵网格,点阵间距为h
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)
#绘制分类结果z
plt.contourf(xx, yy, z, cmap=plt.cm.Blues, alpha=0.2)
plt.scatter(data[:, 0], data[:, 1], s=40, c=labels, cmap=plt.cm.Reds, edgecolors='black')
plt.show()
print('end')
print('begin')
X, y = datasets.make_moons(300, noise=0.25) #300个数据点, 噪声设定0.25
hidden_3_model = ANN_model(X, y, 3)
plot_decision_boundary(lambda x:predict(hidden_3_model, x), X, y)
plt.title('Hidden Layer size 3')
实验效果图:
训练数据调参过程:
通过训练过程的可视化展示,我们能够发现训练效果还是不错的。
之前学到过增加隐藏层结点的数量相当于是在集合空间中增加一个超几何平面,增加一层隐层相当于是在已经用平面划分好的空间中进行二次划分,以此类推。4
- 使用中间层节点数目更多的隐藏作为人工神经网络的节点。
使用不同的节点数目训练模型:
效果图如下:
当你看到这里是不是和我一样对深度学习更加痴迷呢。
就着这个例子我在下面将给出反向传播的四个过程,我更加在意过程是怎么实现的:
方程 | 含义 |
---|---|
δ L = ∇ a ⊙ f ‘ ( z L ) \delta^L=\nabla_a\odot f^{`}(z^L) δL=∇a⊙f‘(zL) | BP1输出层误差 |
δ l = ( ( w l ) T δ l + 1 ) ⊙ ( f ‘ ( z l ) ) \delta^l=((w^l)^T\delta^{l+1})\odot(f^`(z^l)) δl=((wl)Tδl+1)⊙(f‘(zl)) | BP2第 l l l层误差 |
∂ L ∂ b i l = δ i l \frac{\partial{L}}{\partial{b_i^l}}= \delta_i^l ∂bil∂L=δil | BP3损失函数关于偏置的偏导 |
∂ L ∂ w i , j l = a j l − 1 δ i l \frac{\partial{L}}{\partial{w_{i,j}^l}}= a_{j}^{l-1}\delta_i^l ∂wi,jl∂L=ajl−1δil | BP4损失函数关于权值的偏导 |
- BP1输出层误差
根据定义, δ i L \delta_i^L δiL为输出层误差,又因为 a l = f ( z l ) a^l=f(z^l) al=f(zl),对损失函数求导可得:
δ i L = ∂ L ∂ z i L = ∂ L ∂ a i L ∂ a i L ∂ z i L = ∂ L ∂ a i L ∂ f ( z i L ) z i L = ∂ L ∂