例1 :实现简单的BP神经网络
****代码流程****
输入(Input):输入层输入向量
向前传播 (Feed Forward)
输出层误差(Output Error)
反向传播误差(Back propagate Error):
隐藏层误差 输出(Output):
输出损失函数的偏置
import numpy as np
import pprint
pp=pprint.PrettyPrinter(indent=4)
# 定义神经网络的模型架构[input,hidden,output]
network_sizes=[3,4,2]
# 初始化该神经网络的参数
sizes=network_sizes # 网络大小
num_layers=len(sizes) # 层数
biases=[np.random.randn(h,1) for h in sizes[1:]] #偏置
# [1:]表示去掉列表中第一个元素,对后面的元素进行操作
# [:-1]从第一项到最后一项
weights=[np.random.randn(y,x) for x,y in zip(sizes[:-1],sizes[1:])] #权重
# zip函数作用:将可迭代对象作为参数,将对象中对应的元素打包成一个元组,然后返回由这些元组组成的列表
'''
返回损失函数的偏导,损失函数使用MSE(均方误差)
L=1/2(network_y-real_y)^2
delta_L=network_y-real_y
'''
def loss_der(network_y,real_y):
return (network_y-real_y)
''' 激活函数用sigmoid '''
def sigmoid(z):
return 1.0/(1.0+np.exp(-z))
''' sigmoid函数的导数 derivative of sigmoid'''
def sigmoid_der(z):
return sigmoid(z)*(1-sigmoid(z))
'''
根据损失函数,C通过反向传播算法返回
return a tuple "(nabla_b,nabla_w)" representing the gradient for
the cost function C_x."nabla_b" and "nabla_w" are layer-by-layer lists
of numpy arrays,similar to "self.biases"and"self.weights"
'''
# 初始化网络参数的导数,权重w的偏导和偏置b的偏导
# np.zeros是指返回一个给定形状和类型的用0填充的数组,shape 读取矩阵长度
def backprop(x,y):
delta_w=[np.zeros(w.shape) for w in weights]
delta_b=[np.zeros(b.shape) for b in biases]
# 向前传播 feed forward
activation= x # 把输入的数据作为第一次激活值
activations=[x] #存储网络的激活值
zs=[] #存储网络的加权输入值 (z=wx+b)
for w,b in zip(weights,biases):
z=np.dot(w,activation)+b
activation=sigmoid(z)
activations.append(activation)
zs.append(z)
# 反向传播 back propagation
# BP1 计算输出层误差
delta_L=loss_der(activations[-1],y)*sigmoid_der(zs[-1])
# BP3 损失函数在输出层关于偏置的偏导
delta_b[-1]=delta_L
# BP4 损失函数在输出层关于权值的偏导
delta_w[-1]=np.dot(delta_L, activations[-2].transpose())
delta_l=delta_L
for l in range(2,num_layers):
# BP2 计算第l层误差
z=zs[-1]
sp=sigmoid_der(z)
delta_l = np.dot(weights[-l + 1].transpose(), delta_l) * sp
# BP3 损失函数在第l层关于偏置的偏导
delta_b[-1]=delta_l
# BP4 损失函数在l层关于权值的偏导
delta_w[-1]=np.dot(delta_l,activations[-l-1].transpose())
return (delta_w,delta_b)
# 生成数据进行训练
'''
输入(input):输入层输入向量
向前传播(feed forward)
输出层误差(output error)
反向传播误差(back propagate error):隐藏层误差
输出(output):输出损失函数的偏置
'''
training_x=np.random.rand(3).reshape(3,1)
training_y=np.array([0,1]).reshape(2,1)
print("training data x:\n{},\n training data y:\n{}".format(training_x,training_y))
delta_w, delta_b=backprop(training_x,training_y)
print("delta_w:\n{},\n delta_b:\n{}".format(delta_w, delta_b))
运行结果:
例2 :医疗数据诊断
from sklearn import linear_model
from sklearn import datasets
import sklearn
import numpy as np
import matplotlib.pyplot as plt
# matplotlib是画图软件包
# # 创建数据
# def generate_data():
# ''' seed()方法改变随机数生成器的种子,可以在调用其他随机模块函数之前调用此函数'''
# np.random.seed(0)
# X,Y=datasets.make_moons(200,noise=0.20)#200个数据点,噪声设定为0.2
# return X,Y
# # 读取数据并显示
# data,labels=generate_data() # 读取数据
# plt.scatter(data[:,0],data[:,1],s=50,c=labels,cmap=plt.cm.Spectral,edgecolors="#313131")
# plt.title("Medical data")
# plt.show()
class Config: #定义的常数值
input_dim=2 #输入的维度
output_dim=2 #输出的维度
epsilon=0.01 #梯度下降学习速度
reg_lambda=0.01 #正则化强度
def generate_data():#用于生成数据的函数
np.random.seed(0)
# 用make_moons生成数据集
X,y=datasets.make_moons(200,noise=0.20)#200个数据点,噪声设定为0.2
return X,y
def display_model(model):
print("W1 {}: \n{}\n".format(model['W1'].shape,model['W1']))
print("b1 {}: \n{}\n".format(model['b1'].shape,model['b1']))
print("W2 {}: \n{}\n".format(model['W2'].shape,model['W2']))
print("b1 {}: \n{}\n".format(model['b2'].shape,model['b2']))
# 绘制分类边界图
def plot_decision_boundary(pred_func,data,labels):
#设置最大值和最小值并增加0.5的边界(0.5padding)
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)
# 绘制轮廓和训练样本
plt.contourf(xx,yy,z,cmap=plt.cm.Spectral,alpha=0.2) #透明度alpha=0.2
plt.scatter(data[:,0],data[:,1],s=40,c=labels,cmap=plt.cm.Spectral)
# plt.show()
'''损失函数'''
def calculate_loss(model,X,y):
num_examples=len(X) #训练集大小
W1,b1,W2,b2=model['W1'],model['b1'],model['W2'],model['b2']
# 正向传播计算预测值
z1=X.dot(W1)+b1
a1=np.tanh(z1)
z2=a1.dot(W2)+b2
exp_scores=np.exp(z2)
probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)
# 计算损失值
corect_logprobs=-np.log(probs[range(num_examples),y])
data_loss=np.sum(corect_logprobs)
# 对损失值进行归一化
data_loss+=Config.reg_lambda/2 * \
(np.sum(np.square(W1))+np.sum(np.square(W2)))
return 1./num_examples * data_loss
'''预测函数'''
def predict(model,x):
W1,b1,W2,b2=model['W1'],model['b1'],model['W2'],model['b2']
# 向前传播
z1=x.dot(W1)+b1
a1=np.tanh(z1)
z2=a1.dot(W2)+b2
exp_scores=np.exp(z2)
probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)
return np.argmax(probs,axis=1)
'''网络学习函数,并返回网络
nn_hdim:隐层的神经元节点(隐层数目)
num_passes:梯度下降迭代次数
print_loss:是否显示损失函数值
'''
def ANN_modle(X,y,nn_hdim,num_passes=20000,print_loss=False):
num_examples=len(X) #训练的数据集
model={}#模型存储定义
# 随机初始化参数
np.random.seed(0)
W1=np.random.randn(Config.input_dim,nn_hdim)/np.sqrt(Config.input_dim)
b1=np.zeros((1,nn_hdim))
W2=np.random.randn(nn_hdim,Config.output_dim)/np.sqrt(nn_hdim)
b2=np.zeros((1,Config.output_dim))
display_model({'W1':W1,'b1':b1,'W2':W2,'b2':b2})
# 批量梯度下降法
for i in range(0,num_passes+1):
# 向前传播
z1=X.dot(W1)+b1 # M_200*2 .* M_2*3 --> M_200*3
a1=np.tanh(z1)
z2=a1.dot(W2)+b2 # M_200*3 .* M_3*2 --> M_200*2
exp_scores=np.exp(z2)
probs=exp_scores / np.sum(exp_scores,axis=1,keepdims=True)
# 向后传播
delta3=probs #得到预测值
delta3[range(num_examples),y]-=1 #预测值减去实际值
delta2=delta3.dot(W2.T)*(1-np.power(a1,2))
dW2=(a1.T).dot(delta3) #w2的导数
db2=np.sum(delta3,axis=0,keepdims=True) #b2的导数
dW1=np.dot(X.T,delta2) # W1的导数
db1=np.sum(delta2,axis=0) #b1的导数
# 添加正则化项
dW1 +=Config.reg_lambda*W1
dW2 +=Config.reg_lambda*W2
#根据梯度下降更新权重
W1+=-Config.epsilon * dW1
b1+=-Config.epsilon * db1
W2+=-Config.epsilon * dW2
b2+=-Config.epsilon * db2
#把新参数加入模型当中
model={'W1':W1,'b1':b1,'W2':W2,'b2':b2}
if print_loss and i %1000==0:
print("Loss after iteration %i:%f"%(i,calculate_loss(model,X,y)))
return model
# 创建数据并进行网络训练
data,labels=generate_data()
model=ANN_modle(data,labels,3,print_loss=3)
# 创建三个神经元的隐藏层
print(display_model(model))
plot_decision_boundary(lambda x:predict(model,x),data,labels)
plt.title("hidden Layer size 3")
plt.show()
实验结果: