基于sympy的python实现三层BP神经网络算法

#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
写一个三层的BP神经网络(3,2,1),3是输入数据的维度,隐层设置节点数为2,1是因为每个观测的target都是一个标量即只有一个数;
1.随机生成两个随机矩阵作为三个层之间的连接权值,注意矩阵大小设置;设定误差阈值等参数
2.使用i=random.randint(0,len(x)-1)随机产生一个样品的输入及target
3.使用权值w1,w2,sigmoid函数、diffsigmoid函数计算隐层和输出层的输入,输出
4.利用上面的随机样品的实际输出和期望输出之差e,用e求偏导de/dwho、de/dwih
5.梯度下降法更新权值w1,w2
6.再次计算全局误差,若满足设定的误差阈值,返回当前权值;否则重算
"""
print(__doc__)
import random
from sympy import *
import numpy as np
import pandas as pd
data=pd.read_csv("wenzi.csv",header='infer')
data=np.mat(data)
x=data[:, :3]
y=data[:, 3]

#激活函数
def sigmoid(x):
    return ( 1/(1+np.exp(-x)) )
#激活函数的导函数
def diffsigmoid(x):
    return (1- 1/(1+np.exp(-x)) )*( 1/(1+np.exp(-x)) )

def upgrade_w1_w2(): #i是随机选取的一个样本
    erro=0.01 #误差
    n_iter=500 #迭代次数
    learnrate=0.1 #学习率

global w1,w2,b1,b2
w1= 0.5 * np.random.rand(2,3) - 0.1
b1= 0.5 * np.random.rand(2,1) - 0.1
w2= 0.5 * np.random.rand(1,2) - 0.1
b2= 0.5 * np.random.rand(1,1) - 0.1


"""
随机抽取一个样本计算两个偏导de/dwih 、de/dwoh
"""
i=random.randint(0,len(x)-1)
obs =np.array(x[i] )

hidden_input_1=np.dot(w1[0],obs.T) - b1[0]
hidden_input_2=w1[1].dot(obs.T)-b1[1]

hidden_output_1=sigmoid(hidden_input_1)
hidden_output_2=sigmoid(hidden_input_2)

hidden_output_array=[float(hidden_output_1),float(hidden_output_2)]

outlayer_input=np.dot(w2[0] ,(hidden_output_array)) - b2[0] #输出层只有一个节点
outlayer_output=sigmoid(outlayer_input)

expect_output=y[i]
loss=expect_output - outlayer_output
sigma_t_k_1=-(expect_output-sigmoid(outlayer_input)) * diffsigmoid(outlayer_input)

A=sigma_t_k_1 * hidden_output_array #de/dwho
print("sigma_t_k_1\n",sigma_t_k_1)
print('隐层的输出向量',hidden_output_array )
a=np.array(sum(-(sigma_t_k_1)))

print("sum(-(sigma_t_k_1)* w1) * obs",a*w1[0] * obs )

B1=diffsigmoid(hidden_input_1) * a* w1[0] * obs

B2=diffsigmoid(hidden_input_2) * a* w1[1] * obs

"""
计算全局误差
"""

while True:
    for j in range(len(x)):
        obs =x[j]
        hidden_input_1=np.mat(w1[0]).dot(obs.T) - b1[0] #隐层第一个节点上的输入
        hidden_input_2=np.mat(w1[1]).dot(obs.T) - b1[1] #隐层第二个节点上的输入
        hidden_output_1=sigmoid(hidden_input_1) #隐层第一个节点上的输出
        hidden_output_2=sigmoid(hidden_input_2) #隐层第二个节点上的输出
        hidden_output_array=[float(hidden_output_1),float(hidden_output_2)]
        outlayer_input_1=w2[0].dot(hidden_output_array)-b2[0] #输出层的输入
        outlayer_output_1=sigmoid(outlayer_input_1) #输入层的输出
        expect_output=y[i] #期望输出就是每个观测的target数值
        totalloss= [] #建立空列表用以求和
        loss=expect_output - outlayer_output_1 #loss是每个观测的期望输出与实际输出的差
        totalloss.append(loss) #
        totalloss=np.array(totalloss) #把列表转化为数组才能进行点乘
    
    
    """
    如果全局误差大于阈值就要更新权重
    """
    if 0.5*totalloss.dot(totalloss) > erro:
        print("误差大于给定的阈值")
    
    new_w2_0=w2[0]-learnrate* (sigma_t_k_1 * hidden_output_array)
    new_w2=new_w2_0
    w2=new_w2
    
    new_w1_0=np.array(w1[0]-learnrate*B1)
    new_w1_1=np.array(w1[1]-learnrate*B2)
    w1=np.vstack((new_w1_0,new_w1_1))
    
    print("误差大于阈值时的全局损失; ",0.5*totalloss.dot(totalloss))
    print("误差大于阈值时的实际输出",sigmoid(outlayer_output_1))
    print("误差大于阈值时的w1权值矩阵:\n",w1)
    print("误差大于阈值时的w2权值矩阵:\n",w2)
    
    """
    如果全局误差小于阈值就返回目前权
    """
    if 0.5*totalloss.dot(totalloss)<= erro:
        print("\n误差满足要求!")
        w1=np.mat(w1)
        print("到更新的w1矩阵",w1 )
        
        print("得到更新的w2矩阵",w2)
        
        print("全局损失; ",0.5*totalloss.dot(totalloss))
        break
    
    upgrade_w1_w2() #调用函数
    
    def classfier(test):
        obs =test[0:,:3]
        hi_1=np.mat(w1[0]).dot(obs.T) - b1[0]
        hi_2=np.mat(w1[1]).dot(obs.T) - b1[1]
        ho_1=sigmoid(hi_1)
        ho_2=sigmoid(hi_2)
        hidden_output_array=[float(hi_1),float(hi_2)]
        outlayer_input_1=w2[0].dot(hidden_output_array)-b2[0]
        outlayer_output_1=sigmoid(outlayer_input_1)
        print("经过最终神经网络训练后,输出层的实际输出:", outlayer_output_1)
        if outlayer_output_1>0.45:
            print("该测试样本和0.9代表的类别更接近")
        if outlayer_output_1<0.45:
            print("该测试样本和0.1代表的类别更接近")
        if outlayer_output_1==0.45:
            print("该测试样本可被任意归为两个类别之一")
    
    classfier(np.mat([[1.82,1.54,0]]))
    #这里的测试样本[[2.08,1.56,0]]是我从原先14个样本中挑选的,训练集有13个,留了1个作为测试,该样本的target的确是0.1
    #说明我们训练出的BP神经网络模型有可信度,训练集如下图所示,最后一列是target目标值

任何程序错误,以及技术疑问或需要解答的,请添加

基于sympy的python实现三层BP神经网络算法_第1张图片

你可能感兴趣的:(python,神经网络,算法)