EigenGame:将主成份分析(PCA)作为一个博弈游戏

本文介绍了PCA(主成分分析)的基本原理和应用场景,并详细阐述了EigenGame——一种通过博弈学习寻找数据主成分的方法。文中对比了EigenGame与sklearn库PCA实现的差异,并提供了Python实现代码,展示了如何修正算法以获得一致的结果。
摘要由CSDN通过智能技术生成

EigenGame由两部分组成,“Eigen”意为特征,也是主成份分析(PCA)方法的核心。而"Game"则意为博弈论,是一种研究理性决策者之间的冲突与合作的数学模型。与本篇博客要介绍的EigenGame相关的论文主要有发表于ICLR2021的《EIGENGAME: PCA AS A NASH EQUILIBRIUM》与arXiv.org上公开预发表的《EigenGame Unloaded When playing games is better than optimizing》。这两篇论文的作者相同。

一、PCA简介

本人与PCA相关的博客见:

此处还想强调一点:PCA并没有把握一定能提高后续机器学习任务的效果,也没有把握能够防止过拟合问题。

PCA可以用来解决的问题【Andrew Ng曾在讲PCA时提到过】:

1)减少数据因为存储而造成的内存和硬盘的占用;
2)加速训练过程;
3)高维数据可视化。

假设原始数据集为 X ∈ R m × n \mathbf{X}\in \mathbb{R}^{m\times n} XRm×n,我们的目标是找到最佳的投影空间 W = [ w 1 , w 2 , . . . , w k ] ∈ R n × k \mathbf{W}=[\mathbf{w}_1, \mathbf{w}_2, ..., \mathbf{w}_k]\in \mathbb{R}^{n\times k} W=[w1,w2,...,wk]Rn×k,其中 w i \mathbf{w}_i wi是单位向量且 w i \mathbf{w}_i wi是单位向量且 w i \mathbf{w}_i wi w j ( i ≠ j ) \mathbf{w}_j(i\neq j) wj(i=j)正交,何为最佳的 W \mathbf{W} W?就是原始样本点投影到 W W W上之后,使得投影后的样本点方差最大。

我们先将原始数据集 X \mathbf{X} X零均值化为 U = { u 1 , u 2 , . . . , u n } \mathbf{U}=\{\mathbf{u_1}, \mathbf{u_2}, ..., \mathbf{u_n}\} U={u1,u2,...,un},其中, u i = x i − ∑ j = 1 n x j \mathbf{u_i}=\mathbf{x_i}-\sum_{j=1}^{n} \mathbf{x_j} ui=xij=1nxj

由于投影后均值为 0 \mathbf{0} 0,因此数据集 U \mathbf{U} U沿某一单位向量 w \mathbf{w} w投影后的总方差为:
1 n ∑ i = 1 n ( u i T w ) 2 = 1 n ∑ i = 1 n w T u i u i T w = w T [ 1 n ∑ i = 1 n u i u i T ] w \frac{1}{n}\sum_{i=1}^n (\mathbf{u}_i^{T}\mathbf{w})^2=\frac{1}{n}\sum_{i=1}^n \mathbf{w}^T\mathbf{u}_i \mathbf{u}_i^{T}\mathbf{w}= \mathbf{w}^T \left[\frac{1}{n}\sum_{i=1}^n \mathbf{u}_i \mathbf{u}_i^{T}\right]\mathbf{w} n1i=1n(uiTw)2=n1i=1nwTuiuiTw=wT[n1i=1nuiuiT]w

其中 1 n ∑ i = 1 n u i u i T = 1 n ∑ i = 1 n ( x i − 1 n ∑ j = 1 n x j ) ( x i − 1 n ∑ j = 1 n x j ) T \frac{1}{n}\sum_{i=1}^n \mathbf{u}_i \mathbf{u}_i^{T}=\frac{1}{n}\sum_{i=1}^n (\mathbf{x}_i -\frac{1}{n}\sum_{j=1}^{n}\mathbf{x}_j)(\mathbf{x}_i -\frac{1}{n}\sum_{j=1}^{n}\mathbf{x}_j)^T n1i=1nuiuiT=n1i=1n(xin1j=1nxj)(xin1j=1nxj)T就是原始数据集 X \mathbf{X} X的协方差矩阵(因为无偏估计的原因,一般协方差矩阵除以 n − 1 n-1 n1,这是用 n n n)。

λ = w T Σ w \lambda=\mathbf{w}^T\mathbf{\Sigma} \mathbf{w} λ=wTΣw
其中, λ = 1 n ∑ i = 1 n ( x i T w ) 2 , Σ = 1 n ∑ i = 1 n x i x i T \lambda=\frac{1}{n}\sum_{i=1}^n (\mathbf{x}_i^{T}\mathbf{w})^2,\mathbf{\Sigma}=\frac{1}{n} \sum_{i=1}^{n} \mathbf{x}_i \mathbf{x}_i^{T} λ=n1i=1n(xiTw)2,Σ=n1i=1nxixiT

上式两边同时左乘 w \mathbf{w} w,注意到 w w T = 1 \mathbf{w}\mathbf{w}^T=1 wwT=1(单位向量),则有

λ w = Σ w \lambda \mathbf{w}=\mathbf{\Sigma} \mathbf{w} λw=Σw
所以 w \mathbf{w} w是矩阵 Σ \mathbf{\Sigma} Σ的特征值所对应的特征向量。

欲使投影后的总方差最大,即 λ \lambda λ最大, 可知最佳的投影向量 w w w是特征值 λ \lambda λ最大时对应的特征向量,因此,当我们将 w w w设置为与具有最大的特征值向量相等时,方差会达到最大值。这个特征向量被称为第一主成分。

在这里插入图片描述

二、EigenGame

论文《EigenGame Unloaded When playing games is better than optimizing》中第一个公式给出EigenGame的核心思想:通过设计一个多智能体的博弈学习系统,达到最终的纳什均衡(Nash equilibrium);此时,每个智能体则是按特征值大小排序的特征向量

在这里插入图片描述
上面公式右边第一项 v ^ i T Σ v ^ i = λ i \hat{v}_i^T\Sigma \hat{v}_i=\lambda_i v^iTΣv^i=λi,也即第 i i i大的特征值。第二项度量了第 i i i个特征向量与前面第 j j j个特征向量的方向一致程度,第 i i i个向量与前面第 j j j个向量越一致,第二项的值越大,垂直时为最小值0。整个公式右边,期望第 i i i个特征向量在尽量与它前面特征向量垂直的同时,使得它对应的特征值最大。每个智能体被赋予这样一条规则,将公式(1)作为学习目标函数,最后就能学到数据集的top-k特征向量。

两篇论文总共给出三个相关的EigenGame算法。三个算法实现功能一样,主要是计算过程串行(Algorithm1 EIgenGame R-sequential)并行(Algorithm 2 EigenGame R),以及Alogrithm 1 μ − \mu- μEigenGame R实现了将整个数据切分成小batch来训练。
在这里插入图片描述
在这里插入图片描述

注意:经过验证,按照上面算法伪代码实现与sklean库里的PCA结果不一致。以Algorithm 1 μ − \mu- μEigenGame R算法为例, reward ← X t m T X t m v ^ i \text{reward} \leftarrow X_{tm}^{T} X_{tm}\hat{v}_i rewardXtmTXtmv^i中的 X t m T X t m X_{tm}^{T}X_{tm} XtmTXtm表示一个batch大小为 n ′ ′ n'' n数据集的方差,准确公式应该为 Σ m = 1 n ′ ′ ( X t m − X m e a n ) T ( X t m − X m e a n ) \Sigma_{m}=\frac{1}{n''}(X_{tm}-X_{mean})^{T}(X_{tm}-X_{mean}) Σm=n1(XtmXmean)T(XtmXmean)。然后, reward ← Σ v ^ i \text{reward} \leftarrow \Sigma\hat{v}_i rewardΣv^i, penalties ← ∑ j < i < v ^ i , Σ v ^ j > v ^ j \text{penalties} \leftarrow \sum_{j<i}<\hat{v}_i, \Sigma \hat{v}_j>\hat{v}_j penaltiesj<i<v^i,Σv^j>v^j。总之一句,PCA标准过程:1)数据去中心化;2)利用中心化的数据计算协方差(要除以数据的个数)。

三、python实现注意

3.1 sklearn PCA结果

  • 加载手写数字数据集
import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets

digits = datasets.load_digits()
X = digits.data
y = digits.target
  • 利用sklearn.decomposition.PCA计算基准结果
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,random_state=666)
from sklearn.decomposition import PCA

pca = PCA(n_components=10)
pca.fit(X_train)
X_train_reduction = pca.transform(X_train)
X_test_reduction = pca.transform(X_test)
pca.explained_variance_

前10个特征向量对应的特征值如下:
在这里插入图片描述

3.2 EigenGame结果

此处给出三个关于EigenGame的结果

3.2.1 EigenGame基本代码

本博客以最简的串行计算方式,来实现EigenGame

import numpy as np

def sample_spherical(npoints, ndim=3):
    vec = np.random.randn(ndim, npoints)
    vec /= np.linalg.norm(vec, axis=0)
    return vec

def update_eigenvector(M, parents, d):
    """
    Follow Algorithm 1
    """
    v_i = sample_spherical(1, d)  # want d x 1
    lr = 0.001
    t_i = 10000 # TEMP
    # precompute rewards upfront for each vector of parents
    rewards_j = [np.matmul(M, v_j) for v_j in parents]
    for i in range(t_i):
        reward_i = np.matmul(M, v_i)  # n x 1
        penalty = np.zeros((reward_i.shape))
        for r_j in rewards_j:
            p = float(np.dot(reward_i.T, r_j) / np.dot(r_j.T, r_j))
            penalty += p * r_j

        delta_vi = 2.0 * (reward_i - penalty)

        reimann_projection = delta_vi - float(np.dot(delta_vi.T, v_i)) * v_i

        v_prime = v_i + lr * reimann_projection
        
        v_i = v_prime / np.linalg.norm(v_prime, axis=0)

    return v_i, parents
3.2.2 论文算法中原始作法: X T X X^TX XTX
M = np.dot(X_train.T, X_train)
parents = []
for i in range(10):
    v_new, parents = update_eigenvector(M, parents, d=64)
    print(np.dot(np.dot(v_new.T, M), v_new))
    parents.append(v_new)

在这里插入图片描述
发现结果与sklearn基准结果相差很远。

3.2.3 第二种: 1 n X T X \frac{1}{n}X^TX n1XTX
M = np.dot(X_train.T, X_train)/len(X_train)
parents = []
for i in range(10):
    v_new, parents = update_eigenvector(M, parents, d=64)
    print(np.dot(np.dot(v_new.T, M), v_new))
    parents.append(v_new)

在这里插入图片描述
我们发现,第一位貌似多余了,从第二个开始,与sklearn基准结果对上了。

3.2.3 第三种: 1 n ( X − X m e a n ) T ( X − X m e a n ) \frac{1}{n}(X-X_{mean})^T(X-X_{mean}) n1(XXmean)T(XXmean)
X_mean = np.mean(X_train, axis=0)
X_zero = X_train - X_mean
M = np.dot(X_zero.T, X_tzero)/len(X_zero)
parents = []
for i in range(10):
    v_new, parents = update_eigenvector(M, parents, d=64)
    print(np.dot(np.dot(v_new.T, M), v_new))
    parents.append(v_new)

在这里插入图片描述
我们发现,结果与sklearn基准结果一致。

最后把特征向量Plot出来与sklearn的基准结果进行比较,发现除了有些向量正负号相反外,基本重合。
在这里插入图片描述

by windSeS 2021-5-27

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

windSeS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值