感知机原理
1.假设输入空间(特征空间)是
X
⊆
R
n
X\subseteq R^n
X⊆Rn输出空间是
y
=
(
+
1
,
−
1
)
y={{(+1, -1)}}
y=(+1,−1)表示实例的特征向量,对应于输入空间(特征空间)的点;输出
y
∈
Y
y\in Y
y∈Y
模型:公式表达如下:
f
(
x
)
=
s
i
g
n
(
w
x
+
b
)
f(x)=sign(wx+b)
f(x)=sign(wx+b)2.1
公式2.1称为感知机。其中w和b为感知机模型参数,。
w
∈
R
n
w\in R^n
w∈Rn叫做权值(weight)或权值向量(weight vector),
b
∈
R
b\in R
b∈R叫作偏置(bias),
w
∗
x
w*x
w∗x 表示w 和 x的内积。sign是符号函数,即:
s
i
g
n
(
x
)
=
{
+
1
x
≥
0
−
1
x
<
0
sign(x)=\left\{ \begin{array}{rcl} +1 & & x ≥ 0\\ -1 & & {x< 0} \end{array} \right.
sign(x)={+1−1x≥0x<0
2.感知机模型的性质
感知机是一种线性分类模型,属于判别模型。
3 感知机学习策略
3.1 数据集的线性可分性
给定数据集
T
=
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
,
⋯
,
(
x
N
,
y
N
)
,其中
x
i
∈
X
=
R
n
,
y
i
∈
Y
=
{
+
1
,
−
1
}
,
i
=
1
,
2
,
⋯
,
N
T={(x_1,y_1),(x_2,y_2),⋯,(x_N,y_N)},其中xi∈X=R^n, y_i∈Y=\{+1,−1\},i=1,2,⋯,N
T=(x1,y1),(x2,y2),⋯,(xN,yN),其中xi∈X=Rn,yi∈Y={+1,−1},i=1,2,⋯,N,如果存在某个超平面 S 满足:
w
⋅
x
+
b
=
0
w⋅x+b=0
w⋅x+b=0
能将数据集的正实例点和负实例点完全正确地划分到超平面的两侧,即对所有$ y_i=+1$ 的实例
x
i
x_i
xi,有$ w⋅xi+b>0$ ;对所有
y
i
=
−
1
y_i=−1
yi=−1 的实例
x
i
x_i
xi,有
w
⋅
x
i
+
b
<
0
w⋅xi+b<0
w⋅xi+b<0,则 称数据集 T 为线性可分数据集 ;否则,称数据集 T 线性 不可分。
在学习感知机模型中,需要确保数据集线性可分,才能够找到一个完全将正实例点和负实例点正确分开的分离超平面,即才能够确定感知机模型参数
w
,
b
w,b
w,b
习题2.1
题目:Minsky 与 Papert 指出:感知机因为是线性模型,所以不能表示复杂的函数,如异或 (XOR)。验证感知机为什么不能表示异或。
1.列出异或函数(XOR)的输入和输出;
2.使用图例法证明异或问题是线性不可分的;
3.使用反证法证明感知机无法表示异或。
4.解题步骤
(1)异或函数(XOR)的输入和输出
(2)对于异或函数(XOR),全部的输入与对应的输出如下:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# 使用Dataframe表示异或的输入与输出数据
x1 = [0, 0, 1, 1]
x2 = [0, 1, 0, 1]
y = [-1, 1, 1, -1]
x1 = np.array(x1)
x2 = np.array(x2)
y = np.array(y)
data = np.c_[x1, x2, y]
data = pd.DataFrame(data, index=None, columns=['x1', 'x2', 'y'])
data.head()
# 获取正类别(y=1)的数据
positive = data.loc[data['y'] == 1]
# 获取负类别(y=-1)的数据
negative = data.loc[data['y'] == -1]
plt.xlim(-0.5, 1.5)
plt.ylim(-0.5, 1.5)
plt.xticks([-0.5, 0, 1, 1.5])
plt.yticks([-0.5, 0, 1, 1.5])
plt.xlabel("x1")
plt.ylabel("x2")
# 绘制正、负样本点
plt.plot(positive['x1'], positive['x2'], "ro")
plt.plot(negative['x1'], negative['x2'], "bx")
plt.legend(['Positive', 'Negative'])
plt.show()
输出结果如下:
从上图可以看出,无法使用一条直线将两类样本分开,所以异或问题是线性不可分的
下一步,使用感知机模型进行测试
w
,
b
w,b
w,b
from sklearn.linear_model import Perceptron
import numpy as np
X_train = np.array([[1, 1], [1, 0], [0, 1], [0, 0]])
y = np.array([-1, 1, 1, -1])
perceptron_model = Perceptron()
perceptron_model.fit(X_train, y)
print("感知机模型的参数:w=", perceptron_model.coef_[
0], "b=", perceptron_model.intercept_[0])
输出结果如下:
感知机模型的参数:w= [0. 0.] b= 0.0
反证法:
s
i
g
n
(
x
)
=
{
+
1
x
≥
0
−
1
x
<
0
sign(x)=\left\{ \begin{array}{rcl} +1 & & x ≥ 0\\ -1 & & {x< 0} \end{array} \right.
sign(x)={+1−1x≥0x<0
假设咸知机模型可以表示异或问题,即满足异或函数(XOR)输入与输出的情况(见第 1 步 1 步 1步 )。假设 x 向量只有两个维度
x
1
,
x
2
x
1
,
x
2
x
1
,
x
2
x _1 , x_ 2 x_{1}, x_{2} x _1 ,x _2
x1,x2x1,x2x1,x2 :
根据
x
1
=
0
,
x
2
=
0
,
f
(
x
)
=
−
1
则
w
⋅
x
+
b
<
0
可得
b
<
0
根据 x 1 = 0 , x 2 = 0 , f ( x ) = − 1 则 w ⋅ x + b < 0 可得b<0
根据x1=0,x2=0,f(x)=−1则w⋅x+b<0可得b<0
2.
根据
x
1
=
0
,
x
2
=
1
,
f
(
x
)
=
1
,
则
w
2
+
b
>
0
结合
b
<
0
,
可得:
w
2
>
−
b
>
0
2.根据x _1 =0,x _2 =1,f(x)=1,则w _2 +b>0 结合b<0 ,可得:w_2>−b>0
2.根据x1=0,x2=1,f(x)=1,则w2+b>0结合b<0,可得:w2>−b>0
所以假设不成立,原命题成立,即感知机模型不能表示异或
习题2.2
解题步骤在上面的iris数据中已经体现。
import numpy as np
from matplotlib import pyplot as plt
%matplotlib tk
class Perceptron:
def __init__(self, X, Y, lr=0.001, plot=True):
"""
初始化感知机
:param X: 特征向量
:param Y: 类别
:param lr: 学习率
:param plot: 是否绘制图形
"""
self.X = X
self.Y = Y
self.lr = lr
self.plot = plot
if plot:
self.__model_plot = self._ModelPlot(self.X, self.Y)
self.__model_plot.open_in()
def fit(self):
# (1)初始化weight, b
weight = np.zeros(self.X.shape[1])
b = 0
# 训练次数
train_counts = 0
# 分类错误标识
mistake_flag = True
while mistake_flag:
# 开始前,将mistake_flag设置为False,用于判断本次循环是否有分类错误
mistake_flag = False
# (2)从训练集中选取x,y
for index in range(self.X.shape[0]):
if self.plot:
self.__model_plot.plot(weight, b, train_counts)
# 损失函数
loss = self.Y[index] * (weight @ self.X[index] + b)
# (3)如果损失函数小于0,则该点是误分类点
if loss <= 0:
# 更新weight, b
weight += self.lr * self.Y[index] * self.X[index]
b += self.lr * self.Y[index]
# 训练次数加1
train_counts += 1
print("Epoch {}, weight = {}, b = {}, formula: {}".format(
train_counts, weight, b, self.__model_plot.formula(weight, b)))
# 本次循环有误分类点(即分类错误),置为True
mistake_flag = True
break
if self.plot:
self.__model_plot.close()
# (4)直至训练集中没有误分类点
return weight, b
class _ModelPlot:
def __init__(self, X, Y):
self.X = X
self.Y = Y
@staticmethod
def open_in():
# 打开交互模式,用于展示动态交互图
plt.ion()
@staticmethod
def close():
# 关闭交互模式,并显示最终的图形
plt.ioff()
plt.show()
def plot(self, weight, b, epoch):
plt.cla()
# x轴表示x1
plt.xlim(0, np.max(self.X.T[0]) + 1)
# y轴表示x2
plt.ylim(0, np.max(self.X.T[1]) + 1)
# 画出散点图,并添加图示
scatter = plt.scatter(self.X.T[0], self.X.T[1], c=self.Y)
plt.legend(*scatter.legend_elements())
if True in list(weight == 0):
plt.plot(0, 0)
else:
x1 = -b / weight[0]
x2 = -b / weight[1]
# 画出分离超平面
plt.plot([x1, 0], [0, x2])
# 绘制公式
text = self.formula(weight, b)
plt.text(0.3, x2 - 0.1, text)
plt.title('Epoch %d' % epoch)
plt.pause(0.01)
@staticmethod
def formula(weight, b):
text = 'x1 ' if weight[0] == 1 else '%d*x1 ' % weight[0]
text += '+ x2 ' if weight[1] == 1 else (
'+ %d*x2 ' % weight[1] if weight[1] > 0 else '- %d*x2 ' % -weight[1])
text += '= 0' if b == 0 else ('+ %d = 0' %
b if b > 0 else '- %d = 0' % -b)
return text
X = np.array([[3, 3], [4, 3], [1, 1]])
Y = np.array([1, 1, -1])
model = Perceptron(X, Y, lr=1)
weight, b = model.fit()
输出结果: