前馈型BP神经网络(python)

BP神经网络的算法流程:
在这里插入图片描述
算法步骤
步骤1:初始化权重
每二个神经元之间的网络连接权重 被初始化为一个很小的随机数,同时每个神经元有一个偏置 也被初始化为一个随机数。对每个输入样本 按步骤2进行处理。
步骤2:向前传播输入
根据训练样本 提供网络的输人层,通过计算得到每个神经元的输出。都由其输入的线性组合得到,具体公式为:
步骤3:反向误差传播
由步骤2一路向前,最终在输出层得到实际输出,可以通过与预期输出相比较得到每个输出单元 的误差, 如公式 (for each output unit calculate its error term)所示, 是输出单元 的预期输出。得到的误差需要从后向前传播,前面一层单元 的误差可以通过和它连接的后面一层的所有单元k的误差计算所得,用公式: (for each hidden unit )依次得到最后一个隐含层到第一个隐含层每个神经元的误差。
步骤4:网络权重与神经元偏置调整
计算得到的所有神经元的误差,然后统一调整网络权重和神经元的阈值。
调整网络权重的方法是从输入层与第一隐含层的连接权重开始,依次向后进行,每个连接权重 用公式 = + = +( ) 进行调整。
神经元偏置的调整方法是对每个神经元 用公式: = + = +( ) 更新。
步骤5:判断结束
对于每个样本,如果最终的输出误差小于可接受的范围或者迭代次数t达到了一定的阈值,则选取下一个样本,转到步骤2重新继续执行。否则,迭代次数加1,然后转向步骤2继续使用当前样本进行训练。

举例:
已知一个前馈型神经网络例子如下图所示。设学习率l为0.9,当前的训练样本为x={1,0,1},而且预期分类标号为1,同时,下表给出了当前该网络的各个连接权值和神经元偏置。求该网络在当前训练样本下的训练过程 。
在这里插入图片描述
python代码实现:

import numpy as np
import random
import math
import matplotlib.pyplot as plt

##初始化权重矩阵,N为输入层的神经元个数,n为输出层的神经元个数
def init(N,n):
    C = []
    for i in range(N):
        c = []
        for j in range(n):
            a = np.random.uniform(-1,1)
            c.append(a)
        C.append(c)
    return C

##每一层的总输入和输出
def cal_s(W,N,n,X,c):
    Q = []
    for i in range(n):##对第i列
        s=0
        for j in range(N):##对第j行
            s =s+W[j][i]*X[j]
        s+=c[i]
        q = 1/(1+math.e**(-s))
        Q.append(q)
    return Q

## 计算输出层的能量函数E
def cal_e2(Q,T,n):
    E = []
    for i in range(n):
        e = Q[i]*(1-Q[i])*(T[i]-Q[i])
        E.append(e)
    return E


##计算隐含层的能量函数E1
def cal_e1(Q, W, E, n):
    E1 = []
    for i in range(n):
        s = 0
        for j in range(len(E)):
            s = s + W[i][j] * E[j]
        e1 = Q[i] * (1 - Q[i]) * s
        E1.append(e1)
    return E1


##调整权重矩阵
def fit_W(W,N,n,E,Q,l):
    for i in range(N):
        for j in range(n):
            W[i][j]=W[i][j]+l*E[j]*Q[i]
    return W

##调整阈值
def fit_c(c,E,n,l):
    for i in range(n):
        c[i] += l*E[i]
    return c


N = 3 ##输入层神经元数
n = 2 ##隐含层神经元数
m = 1 ##输出层神经元数
##初始化第一层权重函数W1,第二层权重函数W2,阈值函数c1,c2(在-1到1中随机取值)
W1 = init(N,n)
W2 = init(n,m)
c1 = (np.random.random(n)-0.5)*2
c2 = (np.random.random(m)-0.5)*2

X = [1,0,1]
T = [1]
l = 0.9
t = 500##迭代次数

Y =[]
for i in range(1,t+1):
    #print("第",i,"次迭代:")
    ##计算隐藏层的输出Q1,输出层的输出Q2
    Q1 = cal_s(W1,N,n,X,c1)
    Q2 = cal_s(W2,n,m,Q1,c2)
    #print(Q1,Q2)

    ##计算输出层的误差
    E2 = cal_e2(Q2,T,m)
    E1 = cal_e1(Q1,W2,E2,n)
    #print(E2,E1)

    ##调整权重矩阵
    W1 = fit_W(W1,N,n,E1,X,l)
    #print(W1)
    W2 = fit_W(W2,n,m,E2,Q1,l)
    #print(W2)

    ##调整阈值
    c1 = fit_c(c1,E1,n,l)
    c2 = fit_c(c2,E2,m,l)
    #print(c1,c2)

    Y.append(E2[0])
plt.plot(Y)
plt.show()

运行结果:
在这里插入图片描述

代码改进:

import numpy as np
import scipy.special as sp
import math
import matplotlib.pyplot as plt

# 函数:前向传播
# 函数:后向传播
# 函数:读取数据---初始化数据
# 函数:初始化w b
# 超参数:输入节点数,输出节点数,隐藏层节点数

class net:
    def __init__(self,iteration,rate,input_data,label,input_num=3,hidden_num=2,output_num=1):
        """initialize variable and run train funtion"""
        self.w1=np.random.rand(hidden_num,input_num)*2-1
        self.w2=np.random.rand(output_num,hidden_num)*2-1
        self.b1=np.random.rand(hidden_num,1)*2-1
        self.b2=np.random.rand(output_num,1)*2-1

        self.input_num=input_num
        self.output_num=output_num
        self.hidden_num=hidden_num
        self.iteration=iteration
        self.rate=rate

        self.E=[]

        # self.activate_function= lambda x:sp.expit(x)

        self.input_data=input_data
        self.label=np.reshape(label,(output_num,1))

        for i in range(self.iteration):
            self.train(self.input_data,self.label)
        print("finish")

    def activate_function(self, data):
        """activate funciton for matrix"""
        """ arg: data:example :np.ndarray (not list) """
        shape=data.shape
        s= list(map(lambda x: 1 / (1 + math.exp(-x)),data))
        return np.reshape(s,shape)

    def train(self,input_data,label):
        """train data"""
        """ arg: input_data: train_data_X label: train_data_Y """
        input_data = np.reshape(input_data,(self.input_num,1))#np.reshape(data,(a,b))把data变换(a,b)的维度

        hidden_inputs = np.dot(self.w1,input_data)+self.b1#np.dot(X,Y) 矩阵X Y相乘
        hidden_output = self.activate_function(hidden_inputs)

        output_input=np.dot(self.w2,hidden_output)+self.b2
        final=self.activate_function(output_input)

        E2=abs(final-label)
        self.E.append(E2[0][0])
        E1=np.dot(self.w2.T,E2)*hidden_output*(1-hidden_output)

        self.w2+=self.rate*hidden_output.T*E2
        self.w1+=self.rate*input_data.T*E1
        self.b1+=self.rate*E1
        self.b2+=self.rate*E2

    def query(self,input_data):
        """query text_data"""
        input_data = np.reshape(input_data,(self.hidden_num,1))#np.reshape(data,(a,b))把data变换(a,b)的维度

        hidden_inputs = np.dot(self.w1,input_data)+self.b1#np.dot(X,Y) 矩阵X Y相乘
        hidden_output = self.activate_function(hidden_inputs)

        output_input=np.dot(self.w2,hidden_output)+self.b2
        final=self.activate_function(output_input)
        return final

a=net(500,0.9,[1,0,1],[1])

print(a.E[-1])

plt.plot(a.E)
plt.show()