BP神经网络以及python实现
BP神经网络多指多层前馈神经网络,运用梯度下降法,最小化误差。设神经网络最后输出
l
{l}
l维向量为
[
y
1
,
y
2
,
.
.
.
.
,
y
l
]
[y_{1},y_{2},....,y_{l}]
[y1,y2,....,yl],实际的输出为
[
y
^
1
,
y
^
2
.
.
.
,
y
^
l
]
[\hat{y}_1,\hat{y}_2...,\hat{y}_l]
[y^1,y^2...,y^l],输出层第
j
{j}
j个分量来自前一层的第
n
{n}
n个节点的权重是
w
n
j
{w_{nj}}
wnj,阈值是
θ
j
{\theta_j}
θj。
为使得
E
k
=
1
2
∑
i
=
1
l
(
y
^
i
−
y
i
)
2
{E_k=\frac{1}{2}\sum\limits_{i=1}^l(\hat{y}_i-y_i)^2}
Ek=21i=1∑l(y^i−yi)2最小,求偏导可得到
w
n
j
{w_{nj}}
wnj和
θ
j
{\theta_j}
θj要改变的值,
Δ
w
n
j
{\Delta w_{nj}}
Δwnj和
Δ
θ
j
{\Delta \theta_j}
Δθj。
Δ
w
n
j
=
η
g
j
b
n
{\Delta w_{nj}=\eta g_j b_n}
Δwnj=ηgjbn
g j = y ^ j ( 1 − y ^ j ) ( y j − y ^ j ) {g_j=\hat{y}_j(1-\hat{y}_j)(y_j-\hat{y}_j)} gj=y^j(1−y^j)(yj−y^j)
Δ
θ
j
=
−
η
g
j
{\Delta \theta_j=-\eta g_j}
Δθj=−ηgj
同理,下一层的权重和阈值设为
v
i
n
{v_{in}}
vin、
γ
n
{\gamma_n}
γn,要改变的值为
Δ
v
i
n
{\Delta v_{in}}
Δvin、
Δ
γ
n
{\Delta \gamma_n}
Δγn。
则
Δ
v
i
n
=
η
e
n
x
i
{\Delta v_{in}=\eta e_n x_i}
Δvin=ηenxi
e n = b n ( 1 − b n ) ∑ j = 1 l w n j g j {e_n=b_n (1-b_n)\sum\limits_{j=1}^{l}w_{nj}g_j} en=bn(1−bn)j=1∑lwnjgj
Δ γ n = − η e n {\Delta \gamma_n=-\eta e_n} Δγn=−ηen
python实现
- Neuron类(神经元)
激活函数采用 s i g m o i d = 1 1 + e − x {sigmoid=\frac{1}{1+e^{-x}}} sigmoid=1+e−x1
calE():用于计算 e n {e_n} en
import numpy as np
import math
def sigmoid(x):
return 1/(1+np.exp(-x))
def linearMul(x):
return x*(1-x)
class Neuron:
def __init__(self,dataLen):
self.input=np.ones(dataLen)
self.output=0
self.weight=np.random.uniform(0,0.1,dataLen)
self.value=0#threshold value
self.delta=0
self.addValue=0
def calOutput(self,inData):
self.input=inData
sigValue=np.dot(self.weight,self.input)-self.value
self.output=sigmoid(sigValue)
return self.output
def calDelta(self,standardValue):
return math.pow(self.output-standardValue,2)
def calE(self):
return self.weight*self.delta
def addW(self,layerName,standardValue,e,learningRate=0.01):
if layerName=="output":
self.delta=linearMul(self.output)*(standardValue-self.output)
if layerName=='hide':
self.delta=linearMul(self.output)*e
addTmp=learningRate*self.delta*np.array(self.input)
self.weight+=addTmp
self.value-=learningRate*self.delta
- networkLayer类(一层的神经网络)
用链表的结构链接
class networkLayer:
def __init__(self,numNode,dataLen):
self.nodeList=[Neuron(dataLen) for i in range(numNode)]
self.nextLayer=None
def sumE(self,num):
rel=0
for node in self.nodeList:
rel+=node.calE()[num]
return rel
def getOutput(self,inData):
rel=[]
for node in self.nodeList:
rel.append(node.calOutput(inData))
if self.nextLayer!=None:
return self.nextLayer.getOutput(rel)
return rel
def update(self,standardValue,learningRate):
cnt=0
name="output"
e=0
standardTmp=0
if self.nextLayer!=None:
name="hide"
self.nextLayer.update(standardValue,learningRate)
for node in self.nodeList:
if self.nextLayer!=None:
e=self.nextLayer.sumE(cnt)
else:
standardTmp=standardValue[cnt]
cnt=cnt+1
node.addW(name,standardTmp,e,learningRate)
- BpNetwork类
整个网络,由netwokLayer构成
class BpNetwork:
def __init__(self,layerNum):
self.layerList=[]
lastLayer=None
for i in range(1,len(layerNum)):
layerTmp=networkLayer(layerNum[i],layerNum[i-1])
if lastLayer!=None:
lastLayer.nextLayer=layerTmp
lastLayer=layerTmp
self.layerList.append(layerTmp)
def train(self,inputData,outputData,learningRate,updateTime):
index=[]
for i in range(0,len(inputData)):
index.append(i)
for j in range(0,updateTime):
np.random.shuffle(index)
for i in range(0,len(inputData)):
self.layerList[0].getOutput(inputData[index[i]])
self.layerList[0].update(outputData[index[i]],learningRate)
def predict(self,predictData):
rel=[]
for p in predictData:
rel.append(self.layerList[0].getOutput(p))
return rel