Python BP算法模板

BP算法模板

神经网络结构

三大基本结构

请添加图片描述

权重(轴突、树突)

请添加图片描述

权重的矩阵表示

请添加图片描述

数值(胞体)

请添加图片描述

数值处理方式

sigmoid 函数

def __sigmoid(self,x):
    return 1 / (1 + np.exp(-x))

sigmoid 的导函数

def __sigmoid_prime(self,x):
    return x * (1 - x)

sigmoid 函数图像

请添加图片描述
其目的是将数值限制其大小输出。简单理解为一个阀门,当数值足够大时,标记为1。

核心运算

前向运算

def forward(self,X):
    self.Z.clear()
    X=np.array(X)
    self.Z.append(self.__sigmoid(np.dot(X,self.W[0])+self.B[0]))
    for i in range(2,len(self.Size)):
        self.Z.append(self.__sigmoid(np.dot(self.Z[-1],self.W[i-1])+self.B[i-1]))
    return self.Z[-1]

每个神经元的值乘以权重,累加到目标神经元中

反馈运算

def backward(self,X,Y,ans,Lambda ):
    dw=[]
    db=[]
    error = ans-Y
    delta = error * self.__sigmoid_prime(Y)
    dw.insert(0,np.dot(self.Z[-2].T, delta))
    db.insert(0,np.sum(delta, axis=0, keepdims=True))
    for i in range(1,len(self.Size)-2):
        delta = np.dot(delta, self.W[-i].T) * self.__sigmoid_prime(self.Z[-1-i])
        dw.insert(0,np.dot(self.Z[-2-i].T, delta))
        db.insert(0,np.sum(delta, axis=0, keepdims=True))
    delta = np.dot(delta, self.W[1].T) * self.__sigmoid_prime(self.Z[0])
    dw.insert(0,np.dot(X.T, delta))
    db.insert(0,np.sum(delta, axis=0, keepdims=True))
    for i in range(len(dw)):
        self.W[i]+=dw[i]*Lambda
        self.B[i]+=db[i]*Lambda
    return sum(error[0])

代码看起来有些凌乱,这里总结一下整体思路
请添加图片描述
针对每一个权重的调整策略,就是由
d w = 误差 × 右亮 × ( 1 − 右亮 ) × 左亮 × 原始权重 dw = 误差\times右亮\times(1-右亮)\times左亮\times原始权重 dw=误差×右亮×(1右亮)×左亮×原始权重
决定的。
这里重点说一下,原始公式要求是减法,但是考虑到误差的符号可以传递,那么在一开始的误差就做一下修改,改为误差的相反数,即 E r r o r = a n s − Y Error=ans-Y Error=ansY
一般情况下,神经网络还需要一个常量的节点参与,所以每个神经元都有一个常量的参数 B
对于 dB 的求法,其实就是误差梯度之和。
以上最重要的就是理解一下,这段代码的核心思路,具体细节还是要看代码。这里代码已经将正负调整过了,代码中看到的就是调整后的。
这里的Lambda 是学习力度,当获得一个新的知识点后,我们可以通过调整修改的力度。防止学傻了。

使用

Net=Neural([3,15,15,15,2])

这里传入一个结构列表,第一位代表输入层的结构,最后一位代表输出层结构,里面均是隐藏层的结构。


X,ans=Net.Format_Input([a,b,c],ans)

这里是根据输入层的结构个数,和输出层的结构个数,输入一个列表,做一下格式化。


Y=Net.forward(X)
E=Net.backward(X,Y,ans,0.01)

Y做为接收,获得输出层的输出结果,E做为误差值,目的是直观的感受训练的变化。


def creat(self):
    for i in range(1,len(self.Size)):
        self.W.append(np.random.randn(self.Size[i-1],self.Size[i]))
    for i in range(1,len(self.Size)):
        self.B.append(np.ones((1,self.Size[i])))

这里在网络训练之出,根据结构创建出整体框架,并随机赋值。
接下来我们也可以存储结构,因为一个网络知道结构后最重要的就是权重值,我们只需要把权重值存储一下,我们就可以接着上次继续运行了。

代码示例

聚类示例

import numpy as np
class Neural:
    def __init__(self,Size):
        self.Z=[]
        self.W=[]
        self.B=[]
        self.Size=Size
    def __sigmoid(self,x):
        return 1 / (1 + np.exp(-x))
    def __sigmoid_prime(self,x):
        return x * (1 - x)
    def Format_Input(self,NetIn,NetOut):
        return np.array([NetIn]),np.array([NetOut])
    def creat(self):
        for i in range(1,len(self.Size)):
            self.W.append(np.random.randn(self.Size[i-1],self.Size[i]))
        for i in range(1,len(self.Size)):
            self.B.append(np.ones((1,self.Size[i])))
        
    def forward(self,X):
        self.Z.clear()
        X=np.array(X)
        self.Z.append(self.__sigmoid(np.dot(X,self.W[0])+self.B[0]))
        for i in range(2,len(self.Size)):
            self.Z.append(self.__sigmoid(np.dot(self.Z[-1],self.W[i-1])+self.B[i-1]))
        return self.Z[-1]
    def backward(self,X,Y,ans,Lambda ):
        dw=[]
        db=[]
        error = ans-Y
        delta = error * self.__sigmoid_prime(Y)
        dw.insert(0,np.dot(self.Z[-2].T, delta))
        db.insert(0,np.sum(delta, axis=0, keepdims=True))
        for i in range(1,len(self.Size)-2):
            delta = np.dot(delta, self.W[-i].T) * self.__sigmoid_prime(self.Z[-1-i])
            dw.insert(0,np.dot(self.Z[-2-i].T, delta))
            db.insert(0,np.sum(delta, axis=0, keepdims=True))
        delta = np.dot(delta, self.W[1].T) * self.__sigmoid_prime(self.Z[0])
        dw.insert(0,np.dot(X.T, delta))
        db.insert(0,np.sum(delta, axis=0, keepdims=True))
        for i in range(len(dw)):
            self.W[i]+=dw[i]*Lambda
            self.B[i]+=db[i]*Lambda
        return sum(error[0])
from random import randint as rand
Net=Neural([3,15,15,15,2])
Net.creat()
for i in range(1000000):
    #数据
    if rand(1,2)==1:
        a=rand(1,50)
        b=rand(20,30)
        c=rand(1,5)
        ans=[1,0]
    else:
        a=rand(51,100)
        b=rand(10,20)
        c=rand(6,8)
        ans=[0,1]
    #核心
    X,ans=Net.Format_Input([a,b,c],ans)
    Y=Net.forward(X)
    E=Net.backward(X,Y,ans,0.01)
    #验证
    if i%10000==0:
        print(i,"%.5f"%E)

这是一个聚类的神经网络,我们训练好网络后,我们可以走一遍,forward,获得输出,通过输出的特点去判断机器的决策结果。下面给出直观看出百分比的代码模块。

from random import randint as rand
Net=Neural([3,15,15,15,2])
Net.creat()
for i in range(100000):
    if rand(1,2)==1:
        a=rand(1,50)
        b=rand(20,30)
        c=rand(1,5)
        ans=[1,0]
    else:
        a=rand(51,100)
        b=rand(10,20)
        c=rand(6,8)
        ans=[0,1]
    X=np.array([[a,b,c]])
    Y=Net.forward(X)
    ans=np.array([ans])
    Net.backward(X,Y,ans,0.05)
    if i%10000==0:
        print(i,end=" ")
        cnt=0
        for i in range(100):
            if rand(1,2)==1:
                a=rand(1,50)
                b=rand(20,30)
                c=rand(1,5)
                ans=[1,0]
            else:
                a=rand(51,100)
                b=rand(10,20)
                c=rand(6,8)
                ans=[0,1]
            X=np.array([[a,b,c]])
            Y=Net.forward(X)
            if Y[0][0]>Y[0][1]:
                if ans==[1,0]:
                    cnt+=1
            else:
                if ans==[0,1]:
                    cnt+=1
        print(cnt)

比较大小示例

import numpy as np
class Neural:
    def __init__(self,Size):
        self.Z=[]
        self.W=[]
        self.B=[]
        self.Size=Size
    def __sigmoid(self,x):
        return 1 / (1 + np.exp(-x))
    def __sigmoid_prime(self,x):
        return x * (1 - x)
    def Format_Input(self,NetIn,NetOut):
        return np.array([NetIn]),np.array([NetOut])
    def creat(self):
        for i in range(1,len(self.Size)):
            self.W.append(np.random.randn(self.Size[i-1],self.Size[i]))
        for i in range(1,len(self.Size)):
            self.B.append(np.ones((1,self.Size[i])))
        
    def forward(self,X):
        self.Z.clear()
        X=np.array(X)
        self.Z.append(self.__sigmoid(np.dot(X,self.W[0])+self.B[0]))
        for i in range(2,len(self.Size)):
            self.Z.append(self.__sigmoid(np.dot(self.Z[-1],self.W[i-1])+self.B[i-1]))
        return self.Z[-1]
    def backward(self,X,Y,ans,Lambda ):
        dw=[]
        db=[]
        error = ans-Y
        delta = error * self.__sigmoid_prime(Y)
        dw.insert(0,np.dot(self.Z[-2].T, delta))
        db.insert(0,np.sum(delta, axis=0, keepdims=True))
        for i in range(1,len(self.Size)-2):
            delta = np.dot(delta, self.W[-i].T) * self.__sigmoid_prime(self.Z[-1-i])
            dw.insert(0,np.dot(self.Z[-2-i].T, delta))
            db.insert(0,np.sum(delta, axis=0, keepdims=True))
        delta = np.dot(delta, self.W[1].T) * self.__sigmoid_prime(self.Z[0])
        dw.insert(0,np.dot(X.T, delta))
        db.insert(0,np.sum(delta, axis=0, keepdims=True))
        for i in range(len(dw)):
            self.W[i]+=dw[i]*Lambda
            self.B[i]+=db[i]*Lambda
        return sum(error[0])
from random import randint as rand
Net=Neural([2,15,15,15,1])
Net.creat()
for i in range(1000000):
    #数据
    a=rand(1,50)
    b=rand(1,50)
    ans=[1] if a>b else [0]
    #核心
    X,ans=Net.Format_Input([a,b],ans)
    Y=Net.forward(X)
    E=Net.backward(X,Y,ans,0.01)
    #验证
    if i%10000==0:
        print(i,"%.5f"%E,end=" ")
        cnt=0
        for j in range(1000):
            a=rand(1,50)
            b=rand(1,50)
            ans=[1] if a>b else [0]
            X,ans=Net.Format_Input([a,b],ans)
            Y=Net.forward(X)
            if (Y[0][0]-ans)<0.1:
                cnt+=1
        print("%%%.2f"%(cnt/1000*100))

在这里插入图片描述
我们可以看到,这里训练的结果其实很乐观,我们把要求提的苛刻了一些,回出现%99.5-%100之间的波动,而且波动其实也不是很大。
或者我们调整一下学习力度,有可能是之前学的太慢了。
在这里插入图片描述

将学习力度,从0.01改为0.05,效果直接好了很多。

猜你喜欢

转载自blog.csdn.net/qq_35339563/article/details/130672401