多层感知器是在感知器的基础上多元化,原来只是用一个感知器,但是单个感知器因为是单输出,所以只能进行二分类的操作,他并不能进行类似异或问题的求解,再次基础上前辈们提出了多层感知器。
如上图所示,{a11,a12,a13}所代表的是第一层的神经元,{a21,a22}所代表的是第二层的神经元,图中的w代表的是权重。
与单层感知器不同的是这里在前层神经元权重求和后,还有进行一次非线性激活函数激活,最后得到的就是该神经元的值。
如上所示,其中f就是其中的激活函数,激活函数有类似sigmoid函数、tanh函数以及ReLU函数和它的改进Leaky ReLu函数。
MLP多层感知器算法的前馈部分就是这一步,以次遍历到最后的输出。
到此为止为前馈操作,接下来是反馈操作,前馈和反馈之间还存在一个损失函数。
此处损失函数代表的是目标值和结果值之间的差距多大。所以反馈操作的目的就是减小该损失函数的结果值。
根据刚才的神经网络图,进行改进。
根据链式求导法则
在这里我们把激活函数定义为sigmoid函数。
在这里可以看出,sigmoid函数f(z)的导数是f(z)*(1-f(z))
这就可以得出从输出层到隐藏层的导数,
从隐藏层到输入层:
(连式求导)
同理可得出别的导数。
然后用所求出的导数去更新权重。
用MLP多层感知器算法求解异或问题。
import numpy as np
import matplotlib.pyplot as plt
rate=0.1 #学习率
sample_num=4 #样本数据量
class my_mlp:
def __init__(self, input_size, hidden_size, output_size):
self.w1 = np.random.normal(size=(hidden_size, input_size))#输入层到隐藏层
self.w2 = np.random.normal(size=(hidden_size,output_size))#隐藏层到输出层
self.b1 = np.random.normal(size=(hidden_size))
self.b2 = np.random.normal(size=(output_size))
self.h_out = np.zeros(1)
self.out = np.zeros(1)
@staticmethod
def sigmoid(x):
'''sigmoid函数作为激活函数'''
return 1 / (1 + np.exp(-x))
@staticmethod
def d_sigmoid(x):
'''相对误差对输出和隐含层求导'''
return x * (1 - x)
def forward(self,input):
self.h_out = my_mlp.sigmoid(np.dot(input, self.w1)+self.b1)
self.out = my_mlp.sigmoid(np.dot(self.h_out, self.w2)+self.b2)
def backpropagation(self,input,output,lr=rate):
self.forward(input)
L2_delta=(output-self.out) * my_mlp.d_sigmoid(self.out)
L1_delta = L2_delta.dot(self.w2.T) * my_mlp.d_sigmoid(self.h_out)
d_w2 = rate * self.h_out.T.dot(L2_delta)
d_w1 = rate * input.T.dot(L1_delta)
self.w2 += d_w2
self.w1 += d_w1
d_b2 = np.ones((1,sample_num)).dot(L2_delta)
d_b1 = np.ones((1,sample_num)).dot(L1_delta)
self.b2 += rate*d_b2.reshape(d_b2.shape[0]*d_b2.shape[1],)
self.b1 += rate*d_b1.reshape(d_b1.shape[0]*d_b1.shape[1],)
if __name__ == '__main__':
mlp=my_mlp(2,2,1)
# x_data x1,x2
x_data = np.array([[0, 0],
[0, 1],
[1, 0],
[1, 1]])
# y_data label
y_data = np.array([[0],
[1],
[1],
[0]])
for i in range(15000):
mlp.backpropagation(x_data,y_data)
out=mlp.out # 更新权值
if i % 500 == 0:
plt.scatter(i, np.mean(np.abs(y_data - out)))
#print('当前误差:',np.mean(np.abs(y_data - out)))
plt.title('Error Curve')
plt.xlabel('iteration')
plt.ylabel('Error')
plt.show()
print('输入层到隐含层权值:\n',mlp.w1)
print('输入层到隐含层偏置:\n',mlp.b1)
print('隐含层到输出层权值:\n',mlp.w2)
print('隐含层到输出层偏置:\n',mlp.b2)
print('输出结果:\n',out)
print('忽略误差近似输出:')
for i in out:
print(0 if i<=0.5 else 1)
结果: