补充一个,使用precomputed模式的时候,参与计算kernel的数据集必须同时包含测试集和训练集,不然会出现预测失误。下面给两个例子,
一个是直接传递外部核函数给svm:
# coding=utf-8
import numpy as np
from sklearn import svm, datasets
from matplotlib.pylab import plt
if __name__ == "__main__":
# 定义数据集
X_train = np.array([[0.3, 0.4], [0, 0], [1, 1], [1.1, 1.1]])
y_train = [0, 0, 1, 1]
X_test = np.array([[0.2, 0.2], [0, 3], [1, -1], [5, 5]])
y_test = [0, 1, 0, 1]
# 测试1
def my_kernel(X, Y): # 自定义核函数
return np.dot(X, Y.T)
clf = svm.SVC(kernel=my_kernel)
clf.fit(X_train, y_train)
result = clf.predict(X_test)
print(result)
得到结果为:
[0 1 0 1]
第二个例子,在外部计算好核,测试集和训练集的核分别计算:
# coding=utf-8
import numpy as np
from sklearn import svm, datasets
from matplotlib.pylab import plt
if __name__ == "__main__":
# 定义数据集
X_train = np.array([[0.3, 0.4], [0, 0], [1, 1], [1.1, 1.1]])
y_train = [0, 0, 1, 1]
X_test = np.array([[0.2, 0.2], [0, 3], [1, -1], [5, 5]])
y_test = [0, 1, 0, 1]
# 测试2:外部核计算
clf = svm.SVC(kernel='precomputed')
gram = np.dot(X_train, X_train.T) # linear kernel computation,先在外部计算核
clf.fit(gram, y_train)
gram_test = np.dot(X_test, X_test.T)
result = clf.predict(gram_test)
print(result)
得到结果为:
[0 0 1 1]
跟预期的不一样!预期是[0, 1, 0, 1],结果却是[0, 0, 1, 1]
我们再仔细看一下sklearn的说明:
参与计算kernel的数据集必须同时包含 测试集和 训练集
正解是什么呢?是这样:
clf = svm.SVC(kernel='precomputed')
gram = np.dot(X_train, X_train.T) # linear kernel computation,先在外部计算核
clf.fit(gram, y_train)
# 当用precomputed模式的时候,测试集和训练集都要包含在kernel里面。
gram_test = np.dot(X_test, X_train.T)
result = clf.predict(gram_test)
print(result)
如代码所示,预测的时候,要把测试集X和训练集X同时丢到卷积核里面做运算
补充:
本文所用的核函数为gram matrix,相关参考如下Gram Matrix实际上可看做是feature之间的偏心协方差矩阵(即没有减去均值的协方差矩阵),在feature map中,每一个数字都来自于一个特定滤波器在特定位置的卷积,因此每个数字就代表一个特征的强度,而Gram计算的实际上是两两特征之间的相关性,哪两个特征是同时出现的,哪两个是此消彼长的等等,同时,Gram的对角线元素,还体现了每个特征在图像中出现的量,因此,Gram有助于把握整个图像的大体风格。有了表示风格的Gram Matrix,要度量两个图像风格的差异,只需比较他们Gram Matrix的差异即可。