BP(反向传播)两个小栗子---实现简单的BP神经网络及医疗数据诊断

例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()

实验结果:
在这里插入图片描述
在这里插入图片描述

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值