多层感知机(Multi Layer Perceptron, MLP)是由多个感知机层全连接组成的前馈神经网络,BP网络是指连接权调整采用了反向传播(Back Propagation)学习算法的前馈网络,可实现从输入到输出的非线性映射。
BP网络由前向传播与反向传播两个过程组成,前向传播是指由输入值预测输出值的过程,反向传播是指各输出层反向计算对损失函数的梯度进而迭代权重的过程。
BP网络可用于分类和回归问题,在回归问题中损失函数选取rmse等,在分类问题中损失函数选取交叉熵等,在输出层二分类问题选择sigmoid函数层进行映射,多分类问题选择softmax函数层进行映射。
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, ytrue = make_classification(n_samples=100, random_state=1)
X=np.hstack((X,np.ones([X.shape[0], 1])))#增加一列bias
X_train, X_test, y_train, y_test = train_test_split(X, ytrue,
random_state=1)
def sigmoid(z):
return 1 / (1.0 + np.exp(-np.clip(z,-100,10000)))
def sigmoid_Derivative(h):
return h*(1.0-h)#对应位置元素进行相乘,计算y的方差h(1-h)
整体思路:分别定义各层系数矩阵,向前传播计算输出值a,输入作为输出进行迭代;向后传播迭代参数
'''{param:
ni:input数据维数
nl:隐藏层数量(3)
nh:每层隐藏层包含神经元数量(列表形式存储)[2,3,4]
no:输出类别数}
'''
class BP:
#初始化神经网络
def _init_(self,ni,nl,nh,no):
self.input=ni
self.hidden=nh
self.output=no
self.layer=nl
#系数矩阵,列表存储第几层,size[i,]表示前一层输入神经元(bias+1),size[,i]表示后一层输出神经元(bias不需输出)
self.weight=[np.random.random(size=(i+1,o)) for i,o in zip([self.input]+self.hidden,self.hidden+[self.output]) ]
#神经元存储输入输出
self.cell_pre=[np.ones((pre+1,1)) for pre in [self.input]+self.hidden]
#前馈神经网络
def forward(self,x):
self.cell_pre[0]=x.reshape((len(x),1))
for i in range(len(self.cell_pre)-1):
z=self.weight[i].T@self.cell_pre[i]
o_new=sigmoid(z)
self.cell_pre[i+1][:-1,0]=o_new.reshape(1,len( self.cell_pre[i+1][:-1,0]))#bias只输入不输出
self.out_pre=sigmoid(self.weight[-1].T@self.cell_pre[-1])
return self.cell_pre,self.weight
#反向传播,根据链式法则计算,损失函数为交叉熵,先计算损失函数对输出层的梯度,而后向后传播
def backward_propagate(self,x,y,alpha):
out=self.forward(x)
#最后一层
# sigma=(self.out_pre-y)*sigmoid_Derivative(self.out_pre[-1]) 损失函数为rmse
sigma=self.out_pre-y
self.weight[-1]-=alpha*(self.cell_pre[-1]@sigma)
for j in range(1,len(self.cell_pre)):
sigma=((self.weight[-j][:-1,]*sigmoid_Derivative(self.cell_pre[-j])[:-1,]))@sigma #bias项连接drop
self.weight[-j-1]-=self.cell_pre[-j-1]@sigma.T
return self.weight
def train(self,cases,label,limit,alpha):
for l in range(limit):
# print('iterition:',l)
for k in range(0,len(cases)):#训练方法采用随机梯度下降进行计算
x = cases[k]
y = label[k]
self.weight=self.backward_propagate(x,y,alpha)
return self.weight
def predict(self,cases):
out=sigmoid(cases@self.weight[0])
out=np.hstack((out,np.ones([out.shape[0],1])))
for i in range(1,len(self.weight)):
out=sigmoid(out@self.weight[i])
if i !=len(self.weight)-1:
out=np.hstack((out,np.ones([out.shape[0],1])))
return np.round(out)
t=BP()
ni,nl,nh,no=20,4,[2,3,4,5],1
t._init_(ni,nl,nh,no)
w=t.train(X_train,y_train,500,0.01)
t.predict(X_train)
https://www.cnblogs.com/Finley/p/5946000.html
https://baike.baidu.com/item/%E5%89%8D%E9%A6%88%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C/7580523?fr=aladdin