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=ans−Y
一般情况下,神经网络还需要一个常量的节点参与,所以每个神经元都有一个常量的参数 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,效果直接好了很多。