度量学习系列(2):有监督度量学习

有监督度量学习算法利用输入点xx与目标标签yy作为来学习一个距离矩阵,这个距离矩阵拉近同类别的点(分类问题)或者目标值邻近的点(回归问题)的距离,并使不同类别或目标值相差大的点的互相远离。

1. 通用API

有监督的度量学习算法实质上利用了与scikit-learn相同的应用程序接口(API)。

1.1 输入数据

为了训练一个模型,我们需要两个array-like对象:XXyyXX应该为 n×mn \times m的2D数组,其中nn为样本的个数,mm为数据的维数。yy为大小为nn的一维数组,该数组包含XX中每个数据的类别标签(回归问题是为实数,例如度量学习核回归MLKR)。

下面给出用于度量学习的数据例子,数据中包含两种类别:狗与猫。

import numpy as np
X = np.array([[2.3, 3.6], [0.2, 0.5], [6.7, 2.1]])
y = np.array(['dog', 'cat', 'dog'])

注意:我们也可以利用数据预处理器来替代直接给出2D数组形式的输入,详情请查阅Preprocessor一节。

1.2 Fit, transform以及其它

有监督度量学习算法的目标是为了将数据转换到新空间中,在该空间中,同类别的两个数据点的距离会非常小,而不同类别的两个数据的距离则很大。为了得到这个转换矩阵,我们需要利用训练数据来fit度量学习器(例子:最近邻成分分析NCA)。

>>> from metric_learn import NCA
>>> nca = NCA(random_state=42)
>>> nca.fit(X, y)
NCA(init=None, max_iter=100, n_components=None, num_dims='deprecated',
  preprocessor=None, random_state=42, tol=None, verbose=False)

上面的代码块已经fit了度量学习器nca,现在我们可以将nca用于新的数据上。

首先,我们可以利用transform将数据转换到新的状态空间。下面给出转换两个数据到嵌入空间的例子:

>>> X_new = np.array([[9.4, 4.1], [2.1, 4.4]])
>>> nca.transform(X_new)
array([[ 5.91884732, 10.25406973],
       [ 3.1545886 ,  6.80350083]])

通过以上步骤,我们的度量学习器已经学到了数据点之间的距离,我们有以下两种使用它的途径:

  • 我们可以利用score_pairs返回两个数据点之间的距离:
>>> nca.score_pairs([[[3.5, 3.6], [5.6, 2.4]], [[1.2, 4.2], [2.1, 6.4]]])
array([0.49627072, 3.65287282])
  • 也可以利用get_metric函数返回两个数据点之间的距离:
>>> metric_fun = nca.get_metric()
>>> metric_fun([3.5, 3.6], [5.6, 2.4])
0.4962707194621285

注意:如果度量学习是学习马氏距离,我们可以利用get_mahalanobis_matrix得到学习到的矩阵。

>>> nca.get_mahalanobis_matrix()
array([[0.43680409, 0.89169412],
       [0.89169412, 1.9542479 ]])

2. 算法

2.1 LMNN

大边缘最近邻度量学习 Large Margin Nearest Neighbor Metric Learning (LMNN)

LMNN在kNN分类任务的前提下学习一个马氏距离度量。学习到的度量尝试保持同类别的K最近邻很近,并将不同类别的数据以大边缘隔离开来。该算法不对数据的分布作假设。

该距离是通过求解以下优化问题来学习得到的:
minLi,jηi,jL(xixj)2+ci,j,lηi,j(1yi,j)[1+L(xixj)2L(xixl)2]+min_{L}\sum_{i,j}\eta_{i,j}||L(x_i-x_j)||^2+c\sum_{i,j,l}\eta_{i,j}(1-y_{i,j})[1+||L(x_i-x_j)||^2-||L(x_i-x_l)||^2]_{+}
此处,xix_i为一数据点,xjx_jxix_i的一个具有相同标签的k最近邻点,xlx_l为所有其它不同标签的k最近邻点,ηi,jyi,j{0,1}\eta_{i,j},y_{i,j}\in \{0,1\}都是指标参数,ηi,j\eta_{i,j}表示xjx_j为与xix_i相同标签的k最近邻数,yi,j=0y_{i,j}=0表示xi,xjx_i,x_j属于不同的类别,[]+[·]_{+}表示损失函数Hinge Loss。

import numpy as np
from metric_learn import LMNN
from sklearn.datasets import load_iris

iris_data = load_iris()
X = iris_data['data']
Y = iris_data['target']

lmnn = LMNN(k=5, learn_rate=1e-6)
lmnn.fit(X, Y, verbose=False)

参考文献:
[1] Weinberger et al. Distance Metric Learning for Large Margin Nearest Neighbor Classification. JMLR 2009
[2] Wikipedia entry on Large Margin Nearest Neighbor

2.2 NCA

近邻成分分析 Neighborhood Components Analysis (NCA)

NCA是一个距离度量学习算法,该度量算法旨在提升最近邻分类器的精确度(与传统欧式距离相比较)。算法直接最大化训练集上留一法KNN评价器的随机变量。它也可以用来学习一个低张维度的线性转换矩阵,用于数据可视化和快速分类。

利用分解M=LTL\mathbf{M}=\mathbf{L}^T\mathbf{L},并定义概率pijp_{ij},此概率通过xix_i的邻居xjx_j来对其进行正确分类的概率,如下通过马氏距离意义下的softmax似然值表示:

pij=exp(LxiLxj22)liexp(LxiLxl22),pii=0 p_{i j}=\frac{\exp \left(-\left\|\mathbf{L} \mathbf{x}_{i}-\mathbf{L} \mathbf{x}_{j}\right\|_{2}^{2}\right)}{\sum_{l \neq i} \exp \left(-\left\|\mathbf{L} \mathbf{x}_{i}-\mathbf{L} \mathbf{x}_{l}\right\|_{2}^{2}\right)}, \quad p_{i i}=0
对每一个与xix_i近邻的数据点,我们将上式计算的概率加和得到xix_i被正确分类的最终概率:
pi=j:ji,yj=yipij p_{i}=\sum_{j: j \neq i, y_{j}=y_{i}} p_{i j}
优化问题变为找到矩阵L\mathbf{L}使得所有数据点的正确分类概率和最大:
L=argmaxipi \mathbf{L}=\operatorname{argmax} \sum_{i} p_{i}

import numpy as np
from metric_learn import NCA
from sklearn.datasets import load_iris

iris_data = load_iris()
X = iris_data['data']
Y = iris_data['target']

nca = NCA(max_iter=1000)
nca.fit(X, Y)

参考文献:

[1] Goldberger et al. Neighbourhood Components Analysis. NIPS 2005
[2] Wikipedia entry on Neighborhood Components Analysis

2.3 LFDA

局部Fisher差别分析 Local Fisher Discriminant Analysis (LFDA)

LFDA是一个线性的有监督降维方法。该算法对于多模态问题特别有效,所谓的多模态就是一个或多个类别在状态空间中包含多个独立的聚集。LFDA的核心优化问题是一个广义特征值求解问题。

该算法定义Fisher局部的类内、类间散布矩阵S(ω)/S(ω)\mathbf{S}^{(\omega)}/\mathbf{S}^{(\omega)}

S(w)=12i,j=1nWij(w)(xixj)(xixj)TS(b)=12i,j=1nWij(b)(xixj)(xixj)T \begin{aligned} \mathbf{S}^{(w)} &=\frac{1}{2} \sum_{i, j=1}^{n} W_{i j}^{(w)}\left(\mathbf{x}_{i}-\mathbf{x}_{j}\right)\left(\mathbf{x}_{i}-\mathbf{x}_{j}\right)^{T} \\ \mathbf{S}^{(b)} &=\frac{1}{2} \sum_{i, j=1}^{n} W_{i j}^{(b)}\left(\mathbf{x}_{i}-\mathbf{x}_{j}\right)\left(\mathbf{x}_{i}-\mathbf{x}_{j}\right)^{T} \end{aligned}

此处,
Wij(w)={0yiyjAi,j/nlyi=yjAi,j(1/n1/nl)yi=yj \begin{aligned} W_{i j}^{(w)}=\left\{\begin{array}{cc}{0} & {y_{i} \neq y_{j}} \\ {\mathbf{A}_{i, j} / n_{l}} & {y_{i}=y_{j}} \\ {\mathbf{A}_{i, j}\left(1 / n-1 / n_{l}\right)} & {y_{i}=y_{j}}\end{array}\right.\end{aligned}

Ai,j\mathbf{A}_{i,j}为接近矩阵A\mathbf{A}(i,j)(i,j)个元素,A\mathbf{A}可以根据局部缩放方法来计算。

因此,学习问题变成推导LFDA变换矩阵TLFDA\mathbf{T}_{LFDA}
TLFDA=argmaxT[tr((TTS(w)T)1TTS(b)T)] \mathbf{T}_{L F D A}=\arg \max _{\mathbf{T}}\left[\operatorname{tr}\left(\left(\mathbf{T}^{T} \mathbf{S}^{(w)} \mathbf{T}\right)^{-1} \mathbf{T}^{T} \mathbf{S}^{(b)} \mathbf{T}\right)\right]

得到的变换矩阵T\mathbf{T}可保证同类中邻近的数据靠的更近,不同类中的数据离的更远,但是不能保证同类中离的远的数据靠近。

import numpy as np
from metric_learn import LFDA
from sklearn.datasets import load_iris

iris_data = load_iris()
X = iris_data['data']
Y = iris_data['target']

lfda = LFDA(k=2, dim=2)
lfda.fit(X, Y)

参考文献:

[1] Sugiyama. Dimensionality Reduction of Multimodal Labeled Data by Local Fisher Discriminant Analysis. JMLR 2007
[2] Tang. Local Fisher Discriminant Analysis on Beer Style Clustering.

2.4 MLKR

核回归度量学习 Metric Learning for Kernel Regression (MLKR)

MLKR是一个有监督度量学习算法,该算法通过直接最小化留一法回归误差来学习一个距离函数。MLKR可以被看作为一个有监督版本的PCA,能用于降维和高维数据可视化。

理论上,MLKR也能应用于许多不同形式的核函数和距离度量。此处,我们利用高斯核函数与马氏距离。一个高斯核函数如下所示:

kij=12πσexp(d(xi,xj)σ2) k_{i j}=\frac{1}{\sqrt{2 \pi} \sigma} \exp \left(-\frac{d\left(\mathbf{x}_{i}, \mathbf{x}_{j}\right)}{\sigma^{2}}\right)

此处,d(,)d(·,·)为某一测度下的距离平方,此处该测度为马氏距离,为d(xi,xj)A(xixj)d(x_i,x_j)||\mathbf{A}(x_i-x_j)||A\mathbf{A}为推导出的分解矩阵为:M=ATA\mathbf{M}=\mathbf{A}^T\mathbf{A}

σ2\sigma^2可以归并到d()d(·)中,此处我们简单的设σ2=1\sigma^2=1。我们利用以下在训练样本上的累积留一法二次回归误差作为损失函数:

L=i(yiy^i)2 \mathcal{L}=\sum_{i}\left(y_{i}-\hat{y}_{i}\right)^{2}

此处,预测y^i\hat{y}_i是由核回归器得到的:
y^i=jiyjkijjikij \hat{y}_{i}=\frac{\sum_{j \neq i} y_{j} k_{i j}}{\sum_{j \neq i} k_{i j}}

from metric_learn import MLKR
from sklearn.datasets import load_iris

iris_data = load_iris()
X = iris_data['data']
Y = iris_data['target']

mlkr = MLKR()
mlkr.fit(X, Y)

参考文献:

[1] Weinberger et al. Metric Learning for Kernel Regression. AISTATS 2007

2.5 有监督版本的弱监督度量学习算法

每一个弱监督度量学习算法都有一个对应的有监督版本*_Supervised,其中,相似元组从标签信息中生成并传递给底层算法。

对于成对的学习者(参见“成对学习”),使用metric_learn.constraints.positive_negative_pair函数采样成对(数据集中两个点的元组)和成对标签(int,表示这两个点是相似的(+1)还是不同的(-1))。为了对(标签+1的)正对进行抽样,该方法将对来自同一标签的所有样本进行抽样,并从中随机抽取一对样本。为了对负对(标签-1)进行抽样,该方法将查看来自不同类的所有样本,并随机抽取其中的一对样本。该方法将尝试构建num_constraints正对和num_constraints负对,但有时它找不到足够的一个,因此强制same_length=True将返回两个lenghts的最小值。
使用四元组学习器(见基于四元组的学习)以监督的方式,积极的和消极的对采样如上和连接,这样我们有一个3维四元组的数组,其中每个成套的一分之二点来自同一个类,最后两个点来自不同的类(事实上类似最后两点应该低于前两个点)。

from metric_learn import MMC_Supervised
from sklearn.datasets import load_iris

iris_data = load_iris()
X = iris_data['data']
Y = iris_data['target']

mmc = MMC_Supervised(num_constraints=200)
mmc.fit(X, Y)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章