1. Minsky与Papert指出:感知机是线性模型,所以不能表示复杂的函数,如异或(XOR).验证感知机为什么不能表示异或。
首先写出异或函数对应的输入输出:
y | ||
1 | 1 | -1 |
1 | -1 | +1 |
-1 | 1 | +1 |
-1 | -1 | -1 |
我们可以可视化上述实例及其标签:
import numpy as np
import matplotlib.pyplot as plt
x = np.array([[1,1],[1,-1],[-1,1],[-1,-1]])
y = np.array([-1,1,1,-1])
plt.scatter(x[:,0],x[:,1],c=y)
plt.xlabel('x1')
plt.ylabel('x2')
plt.ylim(-2,2)
plt.xlim(-2,2)
plt.xticks([-2,-1,0,1,2])
plt.yticks([-2,-1,0,1,2])
plt.title('XOR')
plt.show()
显然异或问题是线性不可分的,感知机算法无法用一条直线把两类样本点完全分开。
2. 模仿上一节中的例题,构建从训练数据集求解感知机模型的例子。
import numpy as np
from sklearn.linear_model import Perceptron
X_train = np.array([[3,3],[4,3],[1,1]])
y_train = np.array([1,1,-1])
#初始化感知机模型
perceptron_model = Perceptron()
#训练
perceptron_model.fit(X_train,y_train)
#打印学好的参数
print("w:",perceptron_model.coef_,"\nb:",perceptron_model.intercept_,"\n")
#在训练集上进行预测
res = perceptron_model.predict(X_train)
print(res)
3. 证明以下定理:样本集线性可分的充要条件是正实例点集所构成的凸壳与负实例点集所构成的凸壳互不相交。
在2维情况下,凸壳可用下面的图形来表示:
其中向量A,B,C,D,F可以看作是集合S中的元素,他们围成的整个多边形区域就是集合S的凸壳Conv(S),区域内所有的点或者向量都是Conv(S)中的元素。
线性可分的定义:
4. 思考感知机模型假设空间是什么?模型复杂度体现在哪?、
假设空间 {f|f=wx+b},即特征空间中的所有线性分类器。
模型的复杂度主要体现在实例特征向量的维度d上或者特征数量上。
5. 已知训练数据集D,其正实例点是x1=(3,3)T,x2=(4,3)T,负实例点是x3=(1,1)T:
1)试调用sklearn.linear_model 的Perceptron模块,对训练数据集进行分类,并对比不同学习率对模型学习速度及结果的影响。
Perceptron模块/对象主要的方法或属性:
import numpy as np
from sklearn.linear_model import Perceptron
X_train = np.array([[3,3],[4,3],[1,1]])
y_train = np.array([1,1,-1])
#初始化感知机模型
perceptron_model = Perceptron()
#训练
perceptron_model.fit(X_train,y_train)
#打印学好的参数和迭代次数
print("w:",perceptron_model.coef_,"\nb:",perceptron_model.intercept_,"\nn_iter:",perceptron_model.n_iter_,"\n")
#在训练集上进行预测
res = perceptron_model.predict(X_train)
print(res)
#计算在训练集上的准确率
acc = perceptron_model.score(X_train,y_train)
print('correct accuracy:{:.0%}'.format(acc))
Perceptron模块/对象主要的参数:
设定tol=1e-3,max_iter=1000:
perceptron_model = Perceptron(tol=1e-3,max_iter=1000)
设置学习率:
perceptron_model = Perceptron(eta0=0.5,tol=1e-3,max_iter=1000)
w,b变成了原来的0.5倍。
perceptron_model = Perceptron(eta0=0.1,tol=1e-3,max_iter=1000)
w,b变成了原来的0.1倍。
改变学习率虽然w,b变了,但是他们之间的比例没有变,即表示的分离超平面是不变的,说明改变学习率对最终的结果没有影响,对收敛的速度会有影响。
原因在于,我们w,b的初始值为0,根据更新规则:
不管更新多少次,因为初始值为0,w,b都可以表示为的倍数,而分离超平面的方程是wx+b=0,因为w,b都为的倍数,所以可以约掉,因此表示的分离超平面是不变的,说明改变学习率对最终的结果没有影响。如果w,b的初始值不为0,那么改变学习率对最终的结果是有影响的。
正则化:
可以选择使用l1或l2正则化,或者混合正则化()
正则化是为了防止过拟合(减小权值/参数),L1正则化会使权重/参数更稀疏;L2正则化会使权重/参数更均匀。
perceptron_model = Perceptron(penalty="l1",eta0=1,tol=1e-3,max_iter=1000)
perceptron_model = Perceptron(penalty="l2",eta0=1,tol=1e-3,max_iter=1000)
正则化系数控制惩罚或约束力度,过小无约束效力;过大约束太狠,可能会出现欠拟合(模型过于简单,参数会变得很小)。
perceptron_model = Perceptron(penalty="l2",alpha=0.0001,eta0=1,tol=1e-3,max_iter=1000)
perceptron_model = Perceptron(penalty="l2",alpha=0.1,eta0=1,tol=1e-3,max_iter=1000)
2) 用python 自编程实现感知机模型,对训练数据集进行分类,并对比误分类点选择次序不同对最终结果的影响。可采用函数式编程或面向对象的编程。
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
class MyPerceptron:
def __init__(self):
self.w=None
self.b=0
self.l_rate=1
def fit(self,X_train,y_train):
#用样本点的特征数更新初始w,如x1=(3,3)T,有两个特征,则self.w=[0,0]
#尽量使用二维数组来表示行向量/列向量
self.w=np.zeros(X_train.shape[1]).reshape(-1,1)
i=0
while i 0] = 1
res = res.reshape(xx.shape) # 转型为网格的形状
# 绘制决策边界
plt.contourf(xx, yy, res, alpha=0.5, cmap=ListedColormap(('red', 'blue')))
# 添加图例 注释
plt.xlabel('x1')
plt.ylabel('x2')
# 绘制数据点
for i, j in enumerate(np.unique(label)):
plt.scatter(X[label == j, 0], X[label == j, 1], c=ListedColormap(('red', 'blue'))(i),
label=str(j))
plt.legend()
plt.show()
def main():
# 构造训练数据集
X_train=np.array([[3,3],[4,3],[1,1]])
y_train=np.array([1,1,-1])
# 构建感知机对象,对数据集继续训练
perceptron=MyPerceptron()
perceptron.fit(X_train,y_train)
print(perceptron.w)
print(perceptron.b)
# 结果图像绘制
#draw(X_train,perceptron.w,perceptron.b)
visual(X_train,perceptron.w,perceptron.b,y_train)
if __name__=="__main__":
main()
3) 对比传统感知机算法及其对偶形式的运行速度。