一个简单的引导问题
假设我们有以下两种标签的二维数据,标签分别为-1/1,我们想通过训练到一条直线将它们很好的分开。
这条直线可能是以下这样。
当然也可能是以下这样。
甚至可能是斜率为负的直线。我们发现,有很多这样的直线可以将它们分开(这里举例是一个简单的例子)
那么,我们如何通过训练找到其中一条直线,可以将两类很好的分开呢?这里可以用感知机的方法,这个例子是学习感知机最熟悉的配方。
感知机的基本理解
- 单层感知器(Single Layer Perceptron)是最简单的神经网络。它包含输入层和输出层,而输入层和输出层是直接相连的。
- 与最早提出的MP模型不同,神经元突触权值可变,因此可以通过一定规则进行学习。可以快速、可靠地解决线性可分的问题。
- 感知机的组成,单层感知器由一个线性组合器和一个二值阈值元件组成。
可以理解为:输入-分别加权-计算加权结果-加权结果通过一个step function转换为不同标签的过程。
规定step function对加权结果的映射作用为:
在理解以上的基础上,我们还需要知道感知机是一个监督学习的过程,只适用于二进制神经元。
介绍训练过程前,我们规定
学习信号=期望输出-实际输出
这里我们可以理解为真实结果/标签与我们当前训练结果/训练标签的差距。
训练过程其实是一个不断调整权重的过程,这里权重就是分界线的系数。
了解以上,训练过程如下:
1. 初始话权重向量w0,可以设置为随机数等。但是要位于【-1,1】之间。
2. 指定学习率lr,介于(0,1)间。注意学习率过小,收敛速度较慢。但是如果较大,容易在达到期望输出时产生波动。
3. 开始以下迭代
3.1 计算学习信号 R = D(期望输出)-F(W'X)(训练输出)
3.2 计算权重调整 deltaW = lr*(D-R')*X
3.3 更新权重 W0 = W0+deltaW
4.不断训练直到训练输出==期望输出,或者正确率达到某个条件。
求解那个简单的实例
运用感知机,我们对之前提到的二分类问题进行分类,代码如下:
Python Version
## 感知机模型实例
import numpy as np
import matplotlib.pyplot as plt
def perceptron(X,Y,weight,train_nums,lr):
# 在训练次数内,进行以下迭代
for nums in range(train_nums):
# 计算当前权重下的线性加权结果
current_outcome = X.dot(weight)
# 将当前线性加权结果进行sigmod
current_outcome = np.sign(current_outcome)
# 根据实际输出与期望输出的差值调整权重
delatW = lr*(Y-current_outcome.T).dot(X)
# 调整权重
weight = weight+delatW
print(current_outcome)
# 判断训练输出结果和期望输出结果是否相同
if (Y == current_outcome).all():
break
return weight
if __name__ == "__main__":
# 设置训练集
X = np.array([[1,4,3],[1,5,4],[1,4,5],[1,1,1],[1,2,1],[1,3,2]])
Y = np.array([1,1,1,-1,-1,-1])
# 设置训练次数和学习率,初始权重([-1,1])
train_nums = 100
lr = 0.1
np.random.seed(4)
weight = 2*(np.random.random(3)-0.5)
# 开始训练
W = perceptron(X,Y,weight,train_nums,lr)
# 输出分界线并绘图
x1 = np.array([1,6])
x2 = (-W[1]/W[2])*x1-W[0]/W[2]
plt.plot(x1,x2)
plt.plot(X[:,1][0:3],X[:,2][0:3],'ro')
plt.plot(X[:,1][3:6],X[:,2][3:6],'b*')
plt.show()
迭代过程:
[1. 1. 1. 1. 1. 1.]
[-1. -1. -1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1.]
[-1. -1. 1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1.]
[-1. -1. -1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[1. 1. 1. 1. 1. 1.]
[-1. -1. 1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. -1. -1. 1.]
[-1. -1. 1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. -1. -1. 1.]
[-1. -1. 1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. -1. -1. 1.]
[-1. -1. 1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. -1. -1. 1.]
[-1. -1. 1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. -1. -1. 1.]
[-1. -1. 1. -1. -1. -1.]
[1. 1. 1. 1. 1. 1.]
[ 1. 1. 1. -1. -1. 1.]
[-1. 1. 1. -1. -1. -1.]
[ 1. 1. 1. -1. -1. 1.]
[ 1. 1. 1. -1. -1. -1.]
Matlab Version
lr = 0.2;
w0 = 2*(rand(3,1)-0.5);
X = [1 4 3;1 5 4;1 4 5;1 1 1; 1 2 1;1 3 2];
Y = [1,1,1,-1,-1,-1];
for nums = 1:100
current_out = X*w0;
deltaW = lr*(Y-current_out')*X;
w0 = w0 + deltaW';
disp(current_out)
if current_out == Y
break
end
end