实验内容
The task is to build a single layer MLP network to classify the samples on MATLAB platform.
The first step is to train the network with training samples, and plot the classification line .
The second step is to test the trained—network with test samples, and figure out the classification line ,too.
The training samples and test samples have been given as follows.
Training samples:
P = [-0.5 -0.5 0.3 -0.1 0.2 0.0 0.6 0.8;
-0.5 0.5 -0.5 1.0 0.5 -0.9 0.8 -0.6];
T = [ 1 1 0 1 1 0 1 0 ]
Test samples:
P’=[-0.5 0.3 -0.9 0.4 -0.1 0.2 -0.6 0.8 0.1 -0.4;
-0.3 -0.8 -0.4 -0.7 0.4 -0.6 0.1 -0.5 -0.5 0.3]
T’=[ 1 0 1 0 1 0 1 0 0 1 ]
示例程序:
The reference program as follows:
clc;
clear;
% input the training samples and the corresponding classification.
P = [-0.5 -0.5 0.3 -0.1 0.2 0.0 0.6 0.8;
-0.5 0.5 -0.5 1.0 0.5 -0.9 0.8 -0.6];
T = [1 1 0 1 1 0 1 0 ];
%plot the samples
plotpv(P,T);
%build a MLP network.
net=newp([-1 1;-1 1],1);
handle=plotpc(net.iw{1},net.b{1});
%training the network with training samples and plot the classification line.
E=1;
while (sse(E)),
[net,Y,E]=adapt(net,P,T);
handle=plotpc(net.iw{1},net.b{1},handle);
end;
%test network with ten test samples.
testpoints=[-0.5 0.3 -0.9 0.4 -0.1 0.2 -0.6 0.8 0.1 -0.4;
-0.3 -0.8 -0.4 -0.7 0.4 -0.6 0.1 -0.5 -0.5 0.3];
a=sim(net,testpoints);
%plot the classify result .
figure;
plotpv(testpoints,a);
plotpc(net.iw{1},net.b{1});
实验方案
Python3.6
因为MLP的资料遍地都是,本文没有什么新颖之处,所以不再赘述。
多层感知机:MLP
多层感知机由感知机推广而来,最主要的特点是有多个神经元层。
多层感知机:MLP
多层感知机的一个重要特点就是多层,我们将第一层称之为输入层,最后一层称之有输出层,中间的层称之为隐层。MLP并没有规定隐层的数量,因此可以根据各自的需求选择合适的隐层层数。且对于输出层神经元的个数也没有限制。 MLP神经网络结构模型如下,本文中只涉及了一个隐层,输入只有三个变量[x1,x2,x3][x1,x2,x3]和一个偏置量bb,输出层有三个神经元。相比于感知机算法中的神经元模型对其进行了集成。
前向传播
前向传播指的是信息从第一层逐渐地向高层进行传递的过程。以下图为例来进行前向传播的过程的分析。
反向传播
基本的模型搭建完成后的,训练的时候所做的就是完成模型参数的更新。由于存在多层的网络结构,因此无法直接对中间的隐层利用损失来进行参数更新,但可以利用损失从顶层到底层的反向传播来进行参数的估计。(约定:小写字母—标量,加粗小写字母—向量,大写字母—矩阵)
实验结果
经过大约50000轮迭代,非常成功的收敛到极小值,从数据分布也看,超平面比较简单。
1 初始化权重:
Layer 1 :
[[-0.16595599 0.44064899 -0.99977125 -0.39533485]
[-0.70648822 -0.81532281 -0.62747958 -0.30887855]]
Layer 2 :
[[-0.20646505]
[ 0.07763347]
[-0.16161097]
[ 0.370439 ]]
2 最终权重:
Layer 1 :
[[ 2.20991726 2.84550996 -3.0260985 -5.09291135]
[-2.8026569 -2.90518023 2.44903329 3.95163548]]
Layer 2 :
[[ -3.41721513]
[ -4.02189943]
[ 5.27640864]
[ 10.3942392 ]]
实验总结
多层感知机可以解决线性可分问题。注意反向传播时复用每次差分结果。
程序
from numpy import exp, array, random, dot,newaxis,transpose,reshape,where,arange
from numpy import min,max,zeros
from matplotlib import pyplot as plt
import numpy as np
# Train samples
P = [[-0.5, -0.5, 0.3, -0.1, 0.2, 0.0, 0.6, 0.8],
[-0.5, 0.5, -0.5, 1.0, 0.5, -0.9, 0.8, -0.6]]
T = [1, 1, 0, 1, 1, 0, 1, 0]
# Test samples
P_ = [[-0.5, 0.3, -0.9, 0.4, -0.1, 0.2, -0.6, 0.8, 0.1, -0.4],
[-0.3, -0.8, -0.4, -0.7, 0.4, -0.6, 0.1, -0.5, -0.5, 0.3]]
T_ = [1, 0, 1, 0, 1, 0, 1, 0, 0, 1]
P, T, P_, T_ = list(map(array, [P, T, P_, T_]))
P, P_ = list(map(transpose, [P, P_]))
T, T_ = T[:, newaxis], T_[:,newaxis]
training_set_inputs = P
training_set_outputs = T
class NeuronLayer():
def __init__(self, number_of_neurons, number_of_inputs_per_neuron):
self.synaptic_weights = 2 * random.random((number_of_inputs_per_neuron, number_of_neurons)) - 1
class NeuralNetwork():
def __init__(self, layer1, layer2,testx,testy):
self.layer1 = layer1
self.layer2 = layer2
self.train_error=[[],[]]
self.test_error=[[],[]]
self.test_x=testx
self.test_y=testy
# sigmoid
def __sigmoid(self, x):
return 1 / (1 + exp(-x))
# sigmoid导数
def __sigmoid_derivative(self, sigmoid):
return sigmoid * (1 - sigmoid)
def train(self, training_set_inputs, training_set_outputs, number_of_training_iterations):
# plt.ion()
last_error=1e5
for iteration in range(number_of_training_iterations):
# 前向推理
output_from_layer_1, output_from_layer_2 = self.inference(training_set_inputs)
# 最后一层 残差
layer2_error = training_set_outputs - output_from_layer_2
layer2_delta = layer2_error * self.__sigmoid_derivative(output_from_layer_2)
# 隐层梯度
layer1_error = layer2_delta.dot(self.layer2.synaptic_weights.T)
layer1_delta = layer1_error * self.__sigmoid_derivative(output_from_layer_1)
# 调整量??
layer1_adjustment = training_set_inputs.T.dot(layer1_delta)
layer2_adjustment = output_from_layer_1.T.dot(layer2_delta)
# 更新
self.layer1.synaptic_weights += layer1_adjustment
self.layer2.synaptic_weights += layer2_adjustment
# 记录误差
error_sum=np.linalg.norm(layer2_error)
self.train_error[0].append(error_sum)
error_sum=np.linalg.norm(layer1_error)
self.train_error[1].append(error_sum)
error=self.test()
if abs(error-last_error)<1e-7:
break
else:
last_error=error
# plt.clf()
# draw_cost(self.train_error[1])
# plt.show()
# draw_cost(self.test_error[1])
# plt.show()
def test(self):
x,y=self.test_x,self.test_y
# x,y=reshape(x,(1,-1)),reshape(y,(1,-1))
output_from_layer_1, output_from_layer_2 = self.inference(x)
layer2_error = y - output_from_layer_2
layer2_delta = layer2_error * self.__sigmoid_derivative(output_from_layer_2)
layer1_error = layer2_delta.dot(self.layer2.synaptic_weights.T)
self.test_error[0].append(np.linalg.norm(layer1_error))
self.test_error[1].append(np.linalg.norm(layer2_error))
return self.test_error[1][-1]
# 前向传播
def inference(self, inputs):
output_from_layer1 = self.__sigmoid(dot(inputs, self.layer1.synaptic_weights))
output_from_layer2 = self.__sigmoid(dot(output_from_layer1, self.layer2.synaptic_weights))
return output_from_layer1, output_from_layer2
# 输出神经网络
def print_weights(self):
print('''Layer 1 :\n{0}
Layer 2 :\n{1}'''.format
(self.layer1.synaptic_weights,self.layer2.synaptic_weights))
def draw_image(x,y):
color=('r','b')
marker=('o','o')
for i in range(2):
indice=where(y==i)[0]
xi=x[indice]
# print(xi[:,:1],xi[:,1:])
plt.scatter(xi[:,0],xi[:,1],marker=marker[i],linewidths=0.1)
pass
def draw_cost(cost):
# plt.clf()
# print(cost)
plt.plot(np.arange(len(cost)),cost)
if __name__ == "__main__":
random.seed(1)
layer1 = NeuronLayer(4, 2)
layer2 = NeuronLayer(1, 4)
# try:
# np.load('w1.npy')
# layer1.synaptic_weights =np.load('w1.npy')
# # print('?')
# layer2.synaptic_weights=np.load('w2.npy')
# except Exception as e:
# repr(e)
neural_network = NeuralNetwork(layer1, layer2,P_,T_)
print("步骤 1 初始化权重: ")
neural_network.print_weights()
neural_network.train(training_set_inputs, training_set_outputs, 60000)
print("2 最终权重: ")
neural_network.print_weights()
np.save('w1.npy', layer1.synaptic_weights)
np.save('w2.npy', layer2.synaptic_weights)
print("预测: ")
hidden_state, output = neural_network.inference(array([0.6, 0.8]))
print(output)
# TODO 画图
min_x0,max_x0,min_x1,max_x1=min(P[:,0]),max(P[:,0]),min(P[:,1]),max(P[:,1])
print(min_x0,max_x0,min_x1,max_x1)
boundary_x=[]
for x1 in np.arange(min_x1-0.5,max_x1+0.5,0.01):
for x0 in np.arange(min_x0-0.5,max_x1+0.5,0.01):
x=np.array([x0,x1])
boundary_x.append(x)
boundary_x=np.array(boundary_x)
hidden_state, output = neural_network.inference(boundary_x)
output = (output // 0.5)
# print(output)
draw_image(boundary_x,output)
draw_image(P,T)
plt.savefig('boundary2.png')
# plt.show()
# draw_cost(neural_network.train_error[1])
# draw_cost(neural_network.test_error[1])
# plt.show()
# plt.savefig('cost_train.png')