主页 > 国内 >

周末AI课堂 核技巧 代码篇:机器学习你会遇到的“坑”

时间:2018-07-20

来源:互联网作者:编辑点击:

AI课堂开讲,就差你了!

很多人说,看了再多的文章,可是没有人手把手地教授,还是很难真正地入门AI。为了将AI知识体系以最简单的方式呈现给你,从这个星期开始,芯君邀请AI专业人士开设“周末学习课堂”——每周就AI学习中的一个重点问题进行深度分析,课程会分为理论篇和代码篇,理论与实操,一个都不能少!

来,退出让你废寝忘食的游戏页面,取消只有胡吃海塞的周末聚会吧。未来你与同龄人的差异,也许就从每周末的这堂AI课开启了!

读芯术读者交流群,请加小编微信号:zhizhizhuji。等你。后台回复“周末AI课堂”,查阅相关源代码

全文共2094字,预计学习时长5分钟

天气炎热,防暑降温措施要记得哦。

昨天,我们在《核技巧(理论篇)》中提到核技巧产生的动机是,在低维空间线性不可分的样本,经过映射到高维空间后就会变得线性可分,我们为了让样本线性可分,必须在高维空间中计算内积,而核技巧则会把高维空间的内积拉到低维空间来做,从而使得维数的升高不再是一个技术上的难题。

那么为什么低维空间线性不可分,而在高维空间就会线性可分呢?我们使用样例数据的可视化来说明这一点:

import matplotlib.pyplot as plt

import seaborn as snsfrom sklearn import datasetsX,y=datasets.make_circles(400,factor=.3,noise=.05,random_state=0)sns.set(style='darkgrid')fori,v,lin[[0,'r','class_0'],[1,'b','class_1']]: plt.scatter(X[y==i][:,0],X[y==i][:,1],c=v,label=l)plt.title('Sample data')plt.legend()plt.show()

这样的样本显然不是线性可分的,如果我们想用一条线来把不同类样本区分开,决策边界会类似于一个圆。但如果我们增加一个维度:

from mpl_toolkits.mplot3d import Axes3D

ax=Axes3D(plt.figure())fori,v,d,lin[[0,'r',0.5,'class_0'],[1,'b',0.6,'class_1']]: ax.scatter(X[y==i][:,0],X[y==i][:,1],\ [d]*X[y==i][:,0].shape[0],c=v,label=l)plt.legend() plt.show()

增加一个维度的效果就是,将某个类别从平面上拉出来,那么不同类的样本就会变得线性可分。

但我们选用核函数的效果不会这样简单,但是道理都是类似的,空间维度的升高,将会使样本变得更加稀疏,从而更有可能找到一个超平面,甚至可以找到无数个超平面。事实上,升高维度往往会出现无数个超平面,我们一般采用SVM+Kernel的方式来找出硬间隔最大的超平面,这也是SVM与Kernel经常放在一起讨论的原因之一。

我们可以利用Kernel PCA对样例数据做可视化,因为样例数据的特征有两个,而kernel PCA的原理是,先将原始特征映射到高维特征,然后再对核矩阵做特征值分解,我们选取不同的kernel对应的特征向量,相当于对kernel的效果直接进行了可视化:

from sklearn.decomposition import KernelPCA

X_new=KernelPCA(2,kernel='rbf',gamma=10).fit_transform(X)......

从上图可以看出Kernel PCA选取的特征向量已经使得样本线性可分。而普通的PCA并不会产生这样的效果。

虽然我们可以用Kernel PCA的方法获得高维空间的线性子空间(Kernel PCA的非线性体现在kernel ,而非特征值分解),但是我们更想看到的是在同一个特征空间,不同的kernel,以及kernel中不同的参数对决策边界的影响.我们就以SVM作为分类器,添加不同的kernel来观察决策边界。

不同的kernel会有不同的参数化,我们主要选择三种kernel:

•高斯核函数:

.(

是参数)

•多项式核:

.(d是多项式次数,

是参数)

•线性核:

.

我们采用的数据仍然是样例数据:

X,y=datasets.make_moons(200,noise=.2,random_state=0)

我们先尝试使用linear kernel,其实就是一个线性分类器,也没有多余的参数需要调试:

from sklearn.svm import SVC

#网格化def make_meshgrid(x,y,h=.02): x_min,x_max=x.min()-1,x.max()+1 y_min,y_max=y.min()-1,y.max()+1 xx,yy=np.meshgrid(np.arange(x_min,x_max,h), np.arange(y_min,y_max,h))return(xx,yy)X,y=datasets.make_moons(200,noise=0.2,random_state=0)#导入模型svc=SVC(kernel='linear')svc.fit(X,y)#用decision funtion的性质可视化决策边界xx,yy=make_meshgrid(X[:,0],X[:,1])Z=svc.decision_function(np.c_[xx.ravel(),yy.ravel()])Z = Z.reshape(xx.shape)#画图sns.set(style='white')plt.contourf(xx,yy,Z,cmap=plt.cm.RdBu)#绘制contour

for i,v,l in [[0,'r','class_0'],[1,'b','class_1']]:

plt.scatter(X[y==i][:,0],X[y==i][:,1],c=v,label=l)#plt.title('KernelPCA with Gussian Kernel')plt.legend()plt.show()

如图,红蓝色逐渐变浅的分界线就是我们的决策边界,而且颜色越深,代表着离决策边界越远,说明了属于某一类的概率也就越大。

同理,我们采用高斯核和线性核,只需要改变SVC类的kernel参数:

svc=SVC(kernel='rbf',gamma=0.5)#高斯核

svc=SVC(kernel='poly',degree=3,gamma=10,coef0=2)#多项式核

直观看来,高斯核和多项式核的表现要优于线性核,这是意料之中的事情,因为样本在特征空间的分布就不是线性可分。但有两个问题没有解决:

•多项式核(

)和高斯核(

),哪一个更好?

•高斯核和多项式核都有着一些参数,调节参数会对决策边界产生什么影响?

针对第一个问题,我们将两种核在测试集的上表现做对比:

fromsklearn.model_selectionimportcross_validate

.....clfs=dict(Linear=SVC(kernel='linear'), Polynomial=SVC(kernel='poly',degree=3,gamma=10,coef0=2), Gussian=SVC(kernel='rbf',gamma=0.5))test_mse=[]kernels=[]forname,clfinclfs.items(): clf_dict=cross_validate(clf,X,y,cv=5,scoring='accuracy') test_mse.append(clf_dict['test_score'].mean()) kernels.append(name)......

从图中可以看出,高斯核和多项式核的性能远远好于线性核,准确率提升了10%,但多项式核(

)和高斯核(

)两者却不相上下。

调节参数会使得性能变得更好么?这其实就是我们的第二个问题。我们试着对高斯核采用不同的参数,一方面用参数离散的变化来观察决策边界的变化,另一方面用参数连续的变化来观察测试集上的表现。

......

gammas=[0.5,5,50,500]plt.figure()fork,jin enumerate(gammas): clf=SVC(kernel='rbf',gamma=j) clf.fit(X,y) Z=clf.decision_function(np.c_[xx.ravel(),yy.ravel()]) Z = Z.reshape(xx.shape) plt.subplot(len(gammas)/2,len(gammas)/2,k+1) plt.contourf(xx,yy,Z,cmap=plt.cm.RdBu)fori,v,lin[[0,'r','class_0'],[1,'b','class_1']]: plt.scatter(X[y==i][:,0],X[y==i][:,1],c=v,label=l) plt.title('$\gamma=$%s'%j)plt.legend()plt.show()

我们可以看到随着

的增大,决策边界变得越来越复杂,最终我们的contour不再是大片的区域,而是精确覆盖每一个点。从理论上来说,这与我们高斯核函数的形式有关,

,如果我们换一种写法:

就会发现,高斯核函数就可以被解释为:均值为

,标准差为

的关于

的高斯分布。

越大,其实标准差

越小,那么钟形曲线就会变得越尖,代表着

集中于

附近,所以我们的决策边界对于每一个样本都会变得非常集中。

可是决策边界如此精确的覆盖了每一个点,很可能是过拟合的表现,我们紧接着来进行第二步:用参数的连续变化集,去观察测试集上的表现。

......

gammas=np.linspace(1,50,100)

test_mse=[]

train_mse=[]

foriingammas:

clf=SVC(kernel='rbf',gamma=i)

clf_dict=cross_validate(clf,X,y,cv=5,scoring='accuracy')

test_mse.append(clf_dict['test_score'].mean())

train_mse.append(clf_dict['train_score'].mean())

......

从图中可以发现,测试集上的准确率越来越小,而训练集上的准确率却越来越大,说明随着

的增大,决策边界越来越复杂,泛化能力却在越来越低,过大的

会导致分类器严重的过拟合。我们在挑选合适的参数时,就可以针对性的画出训练集和测试集上的误差分析图来分析。

读芯君开扒

课堂TIPS

•高斯核是广泛使用的核函数,它又被叫做径向基函数(radial basis function,RBF),可以理解为一种模板匹配,其被

理解为两个样本的距离,而距离又是相似度的度量,而负指数形式则是对相似度高的样本赋予较大的权重。一般的,我们没有先验知识的情况下,就会采用高斯核函数尝试。

•无论采用哪种核函数,我们都需要计算样本的内积矩阵,也就说明,随着样本量的增大,计算会越来越慢,这也是添加kernel的学习器面临的限制。而SVM中,只需要计算支持向量(support vector),这也是核技巧常见于SVM的原因之一。

• 文中只对RBF的参数性能进行了分析,主要是为了简单,因为RBF只有一个参数,多项式核函数的参数有三个,我们需要进行网格搜索。

• 分类问题中,我们还可以在拥有正则化项的Logistic Regression上添加kernel;回归问题中,我们可以在岭回归上添加kernel。原则上来说,满足于表示定理的优化函数,都可以通过添加kernel完成线性学习器到非线性学习器的转变。

留言 点赞 发个朋友圈

我们一起探讨AI落地的最后一公里

作者:唐僧不用海飞丝

如需转载,请后台留言,遵守转载规范

上一篇:台积电发布2018年Q2财报:净利润24亿美元 下一篇:没有了
热门文章 更多>>