为支持向量机设计内核(异或)

21
我的问题是“如何为学习问题设计核函数?” 在支持向量机和核机器的书籍中,作者提供了一些核函数的例子(例如多项式核、高斯核和文本核),但他们要么只提供结果的图片而不具体说明核函数,要么笼统地声称“可以构建有效的核函数”。我对为新问题设计核函数的流程很感兴趣。
最简单的例子可能是学习异或运算,这是一个在实数平面上嵌入的最小非线性数据集(4个点)。如何设计一个自然(且非平凡)的核函数来线性分离这些数据?
作为一个更复杂的例子(见Cristianini,《SVM入门》第6.2节),如何设计一个核函数来学习棋盘图案?Cristianini称这张图片是“使用高斯核导出的”,但他使用了多个核函数,并以未指定的方式进行组合和修改。
如果这个问题过于宽泛,无法在此处回答,那么我希望得到一个构建这样一个核函数的参考资料,尽管我更喜欢这个例子相对简单。

你是否已经使用SVM实现了异或逻辑门? - user11528241
6个回答

9

问: "如何为学习问题设计核函数?"

答: "非常小心地"

对于想要获得最准确的预测模型的人来说,尝试使用通常的嫌疑人(线性、多项式、RBF)并使用最有效的一个确实是明智的建议。值得一提的是,SVMs经常被批评为似乎有许多需要根据经验调整的参数。所以至少你不是孤单的。

如果你真的想为一个特定的问题设计一个核函数,那么你是对的,这本身就是一个机器学习问题。它被称为“模型选择问题”。我自己在这方面并不是专家,但对我来说,关于核方法最好的洞察力来源是Rasumussen和Williams的书“高斯过程”(它可以在网上免费获取),特别是第4章和第5章。很抱歉我不能说更多,只能说“阅读这本数学丰富的大书”,但这是一个复杂的问题,他们做了一个非常好的解释。


1
你很幸运,我不怕数学 :) 更好的是,这本书的竞赛内容都在线上。 - JeremyKun
1
@Bean 我认为这类问题最好在 http://metaoptimize.com/qa/ 上提出。那里是一个更小的社区,但有很多机器学习专家。 - Stompchicken

6
(对于那些不熟悉机器学习中核函数的使用的人来说,核函数就是将输入向量(构成数据集的数据点)映射到高维空间,也称为“特征空间”。然后,支持向量机在这个转换后的空间中找到具有最大间隔(超平面和支持向量之间的距离)的分离超平面。)
好的,首先使用已知可与SVM分类器一起使用以解决感兴趣的问题的核函数。在这种情况下,我们知道带有训练过的SVM的径向基函数(RBF)核干净地分离XOR。您可以用以下方式在Python中编写RBF函数:
def RBF():
    return NP.exp(-gamma * NP.abs(x - y)**2)

在其中,gamma是1 /特征数量(数据集中的列数),而x、y是笛卡尔对。

(径向基函数模块也在scipy.interpolate.Rbf中)

第二,如果你想要构建自己的核函数来解决分类/回归问题,而不仅仅使用现有的核函数,我建议先研究如何选择核函数以及这些函数内部的参数如何影响分类器性能。与SVM/SVC一起常用的小组核函数是最好的起点。该组包括以下内容(除了RBF):

  • 线性核函数

  • 多项式

  • sigmoid


我们如何提前确定内核是否“干净地分离”任何东西?肯定有比民间传说和试错更多的原则。您是在说我们用线性/多项式/ Sogmoid 内核的某些组合来近似最佳内核吗?因为即使我们限制自己只使用一类内核,这听起来也像一个机器学习问题。 - JeremyKun
这里,核心功能并不依靠于数据分离,而是将数据投影到一个更高维的特征空间中。其次,我提到了一项简单的经验研究而非"民间传说"。例如,进行这样一个简单的研究:同一组数据,相同的SVM参数和核函数选择是唯一可调参数;来衡量最简单的核函数对SVM分类器性能的影响。 - doug
你说,“从已知可行的内核开始”,这听起来像是民间传说。而内核的重点就是通过该投影将数据分离,否则就不会有分离的超平面。我的问题是是否有任何理论原因选择线性/多项式/ Sigmoid / RBF 内核来解决给定问题,并且如何组合它们以适应问题的任何已知(空间)属性。你的答案是“经验研究”,这实际上只是一种花哨的方式来说猜测和检查。 - JeremyKun
考虑到您的问题在某些方面比较通用,我认为Doug的回答没有任何问题。将已知可以解决某些类型问题的所有内核作为参数传递给网格搜索是一个完全可行的方法,也许可以像他在评论中建议的那样使用同一算法(SVC)进行嵌套交叉验证,只更改内核。 - MyCarta

1
我的方法是研究数据:我如何分离XOR问题中的点?当我开始学习机器学习和支持向量机时,我做的就是拿一个玩具问题,手工画图,并尝试分离类别。当我第一次看到XOR问题时,我发现下面左侧的两个紫色点具有相同符号的X和Y,一个为负数,一个为正数,而两个绿色点具有相反的符号。因此,对于绿色点,X和Y的平方和将为0(或在初始问题中有些噪声时非常小),而对于紫色点,则为2(或接近2)。因此,添加第三个坐标Z = np.sqrt(np.square(X + Y))将很好地分离这两组。

3D before 3D after

顺便提一句,如果你考虑到在这种情况下np.sqrt(np.square(X + Y))本质上与np.abs(X + Y)相同,那么Zdoug的rbf的表述并没有太大的差异。

我无法获取Crisitanini的论文,但我会以类似的方式解决这个问题,从一个玩具版本开始(顺便说一句,棋盘代码要感谢doug):

checkerboard

这里可能的直觉是黑色方块的行和列索引之和始终为偶数,而白色方块的行和列索引之和始终为奇数,因此在这个简单版本中添加类似于 (row_index + col_index) % 2 的第三维即可解决问题。在更大、更复杂的棋盘数据集中,比如我在网上找到的这个:

Cristianini-like?

事情并不那么简单,但也许可以级联聚类来找到16个聚类的平均X和Y位置(或许使用medoids clustering),然后应用“模数核技巧”的一个版本?

免责声明,我没有处理过大量分类问题,到目前为止,我发现在制作复杂问题的玩具版本时,通常会获得关于可能有效解决方案的“数字”直觉。

最后,正如在doug的答案评论中发布的那样,我并不认为像他那样采用经验方法研究所有可能内核的性能有任何问题,通过将它们传递给嵌套交叉验证中的网格搜索,并仅更改内核。您可以通过在转换后的特征空间中绘制相应的边距来增加该方法的可靠性:例如,对于rbf,使用Doug提出的方程式(以及Sebastian Raschka的例程这里的cell 13)。

更新于2017年10月27日 在我的slack频道上的一次交谈中,另一位地球物理学家问我,如果XOR门设计为0和1而不是-1和1(后者类似于勘探地球物理学中的经典问题),这种情况会怎样。

如果我要处理XOR门并且没有rbf核的知识,那么在这种情况下,我会将问题转化为这些问题的坐标,并尝试找到一种变换方法。

XOR_II

我最初的观察是,O位于x=y线上,X位于x=-y线上,因此差异x-y在一个情况下为0(或略微带有噪声),在另一个情况下为+/-1。绝对值可处理符号,因此Z = np.abs(X-Y) 可以工作。顺便提一下,这非常类似于doug'srbf = np.exp(-gamma * np.abs(x - y)**2)(另一个支持他回答的原因);实际上,他的rbf是更通用的解决方案,在所有异或情况下都有效。


0

我正在寻找一些多项式核函数的实例,偶然发现了这篇文章。如果你还在寻找的话,有几件事情可能会对你有所帮助,比如这个工具包(http://www2.fml.tuebingen.mpg.de/raetsch/projects/shogun),它使用多核学习,你可以选择各种核方法,然后学习将为问题选择最佳方法,因此你不必自己去尝试。

另外一个更简单传统的方法是使用交叉验证和不同的核方法来找到最佳方法。

希望这能对你或其他阅读核方法相关内容的人有所帮助。


不幸的是,我一直在寻找数学上的理由,而不是经验上的原因。到目前为止,我还没有找到一个,所以我已经将其归结为应用数学和任意参数的祸根。 - JeremyKun

0
一个简单的核函数可以解决XOR问题,其表达式为: $(x,y) \rightarrow (x,y,xy)$
这与@MyCarta提供的解决方案有关,因为 $(x+y)^2 = x^2 + xy + y^2$
然而,与原点的距离$x^2 + y^2$对于区分四个象限是无关紧要的,因此我们可以安全地忽略它并得到一个更简单的表达式。
下面是应用这种核函数的示例。

enter image description here

显然,边界超平面是$z=0$,等价于$xy=0$,对应于二维空间中的水平轴和垂直轴,即$y=0$和$x=0$。
对于单极情况,将边界向两个方向平移半个单位就足够了,得到双曲线$\left(x-\frac{1}{2}\right)\left(y-\frac{1}{2}\right) = 0$。
所需的项,$x$、$y$和$xy$,都包含在二次多项式核函数中,但其他项是不必要的。因此,这个简化的三维核函数可以更容易地进行可视化。

0

XOR问题不是线性可分的,因此例如使用SVM - 使用多项式核函数

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

import sklearn
from sklearn.metrics import classification_report
from sklearn.svm import SVC
from sklearn.model_selection import train_test_split

# generate the XOR data
##    excluding OR
##    input_data = np.array([[0, 0], [0, 1], [1, 0], [1, 1]], int)
##    output_data = np.array([[0], [1], [1], [0]], int)

##Using the following code, we will create a simple dataset that has the form of an XOR gate using the logical_xor function from NumPy, where 100 samples will be assigned the class label 1 and 100 samples will be assigned the class label -1, respectively:

np.random.seed(0)
X_xor = np.random.randn(200, 2)
y_xor = np.logical_xor(X_xor[:, 0] > 0, X_xor[:, 1] > 0)
y_xor = np.where(y_xor, 1, -1)

plt.scatter(X_xor[y_xor==1, 0], X_xor[y_xor==1, 1],
             c='b', marker='x', label='1')
plt.scatter(X_xor[y_xor==-1, 0], X_xor[y_xor==-1, 1],
    c='r', marker='x', label='1')
plt.show()

# construct the training and testing split by taking 75% of the data for training
# and 25% for testing
(trainData, testData, trainLabels, testLabels) = train_test_split(X_xor, y_xor, test_size=0.25,
    random_state=42)

# train the linear SVM model, evaluate it, and show the results
##print("[RESULTS] SVM w/ Linear Kernel")
##model = SVC(kernel="linear")
##model.fit(trainData, trainLabels)
##print(classification_report(testLabels, model.predict(testData)))
##print("")

# train the SVM + poly. kernel model, evaluate it, and show the results
print("[RESULTS] SVM w/ Polynomial Kernel")
model = SVC(kernel="poly", degree=2, coef0=1)
model.fit(trainData, trainLabels)
print(classification_report(testLabels, model.predict(testData)))

这里注释了线性核 - 可以取消注释以查看错误核使用的结果... 或者可以使用rbf_Kernel(例如这里)- 使用Kernel Trick(在链接中概述为拉格朗日对偶问题)... 还有这里是SVM的几个限制(除了SVM无法在实时数据流中通过新点获得新知识之外 - 与感知器相比 - SVM需要重新学习)

P.S. sklearn仍然似乎是更方便的多类和多标签分类库


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接