Random Features for Large-Scale Kernel Machines阅读

       本文Random Features for Large-Scale Kernel Machines提出两种 randomized feature maps 来近似平移不变核 。
文 中 符 号   ′   表 示 转 置 文中符号\ ' \ 表示转置   

方法一方法二
试图从核函数的傅里叶变换中随机抽取正弦来组成以随机选择的分辨率使用随机移动的网格划分输入空间
映射是平滑的映射非平滑的
适合插值任务适合于近似依赖于数据点之间的L1距离的内核
采样自 p ( ω ) p(\omega) p(ω)

在这里插入图片描述
在这里插入图片描述

随机傅里叶特征

         随机特征,由随机傅里叶变换基 c o s ( w ′ x + b ) , 其 中 w ∈ R d , b ∈ R 是 随 机 变 量 cos(w'x+b),其中w\in R^d,b\in R 是随机变量 cos(wx+b),wRd,bR

其将数据点投影到随机选择的线上,然后使用正弦函数传递标量结果 (see Figure 1 and Algorithm 1)。从适当的分布中选取这些线的方向可以保证两个变换点的乘积将近似于所需的移位不变核。
在这里插入图片描述

Theorem 1 (Bochner [13])1

R d 上 的 一 个 连 续 的 核 k ( x , y ) = k ( x − y ) 如 果 是 正 定 的 R^d上的一个连续的核k(x,y)=k(x-y)如果是正定的 Rdk(x,y)=k(xy)2 当 且 仅 当 k ( δ ) 是 一 个 非 负 测 度 的 傅 里 叶 变 换 。 当且仅当k(δ)是一个非负测度的傅里叶变换。 k(δ) 如 果 平 移 不 变 核 k ( δ ) 被 相 应 地 缩 放 , B o c h n e r 定 理 保 证 了 它 的 F o u r i e r 变 换 p ( ω ) 是 一 个 相 应 的 概 率 分 布 。 如果平移不变核k(δ)被相应地缩放,Bochner定理保证了它的Fourier变换p(ω)是一个相应的概率分布。 k(δ)BochnerFourierp(ω)

令 ζ ω ( x ) = e j ω ′ x 令\zeta_\omega(x)=e^{j\omega'x} ζω(x)=ejωx
k ( x − y ) = ∫ R d p ( ω ) e j ω ′ ( x − y ) d ω = E w [ ζ ω ( x ) ζ ω ( y ) ∗ ] k(x-y)=\int_{R^d}p(\omega)e^{j\omega'(x-y)}d\omega =E_w[\zeta_\omega(x) \zeta_\omega(y)^*] k(xy)=Rdp(ω)ejω(xy)dω=Ew[ζω(x)ζω(y)]
所 以 当 w ∼ p , ζ ω ( x ) ζ ω ( y ) ∗ 是 k ( x , y ) 的 无 偏 估 计 所以当w\sim p,\zeta_\omega(x) \zeta_\omega(y)^* 是k(x,y)的无偏估计 wpζω(x)ζω(y)k(x,y)

由于概率分布p(ω)和核k(∆) 都是实的,当复指数替换为余弦时,积分(2)收敛。因此,我们可以令 z ω ( x ) = 2 c o s ( ω ′ x + b ) z_ω(x) = \sqrt{2} cos(ω'x+b) zω(x)=2 cos(ωx+b),以得到满足条件 E [ z ω ( x ) z ω ( y ) ] = k ( x , y ) E[z_ω(x)z_ω(y)] = k(x, y) E[zω(x)zω(y)]=k(x,y)的实值映射。 其 中 ω 取 自 分 布 p ( ω ) , b 取 自 [ 0 , 2 π ] 上 的 均 匀 分 布 。 \tiny其中ω取自分布p(ω),b取自[0,2\pi]上的均匀分布。 ωp(ω),b[0,2π] z ω ( x ) z ω ( y ) 的 期 望 值 k ( x , y ) 可 由 角 度 公 式 求 和 得 出 。 z_ω(x)z_ω(y)的期望值k(x,y)可由角度公式求和得出。 zω(x)zω(y)k(x,y)

我们可以通过将随机选择的D个zω连接到一个D维向量z中,并用√D对每个分量进行归一化来降低核估计的方差。内积 z ( x ) ′ z ( y ) = ∑ j = 1 D z w j ( x ) z w j ( y ) 是 z ω 的 样 本 平 均 值 z(x)'z(y)=\sum_{j=1}^D z_{w_j}(x)z_{w_j}(y)是z_ω的样本平均值 z(x)z(y)=j=1Dzwj(x)zwj(y)zω,因此是期望值(2)的较低方差近似值。
因为对于特定的x和y, z ω 的 边 界 在 − 2 和 + 2 之 间 z_ω的边界在-\sqrt2 和 +\sqrt2之间 zω2 +2 ,Hodeffding不等式保证了z(x)'z(y)和k(x,y)之间在D中的指数快速收敛:
P r [ ∣ z ( x ) 0 z ( y ) − k ( x , y ) ∣ ≥ ϵ ] ≤ 2 e x p ( − D ϵ 2 / 4 ) Pr [|z(x)0z(y) − k(x, y)| ≥ \epsilon] ≤ 2 exp(−D \epsilon^2/4) Pr[z(x)0z(y)k(x,y)ϵ]2exp(Dϵ2/4)

基于这一观察,可以对输入空间中的每一对点同时证明一个更有力的断言:
Claim 1:(傅里叶特征的一致收敛性)
设 M 是 直 径 为 d i a m ( M ) 的 R d 中 的 紧 子 集 。 然 后 , 对 于 映 射 z , 我 们 有 设M是直径为diam(M)的R^d中的紧子集。然后,对于映射z,我们有 Mdiam(M)Rdz
在这里插入图片描述

其 中 σ p 2 ( E p ( ω ′ ω ) ) 是 k 的 傅 里 叶 变 换 的 二 阶 矩 。 其中σ_p^2(E_p(ω'ω))是k的傅里叶变换的二阶矩。 σp2(Ep(ωω))k
这个断言的证明详见附录。
根据标准的傅里叶恒等式,标量 σ p 2 σ^2_p σp2等于k海森矩阵的迹在0处的值。它量化了核在原点处的曲率。
F o r t h e s p h e r i c a l G a u s s i a n k e r n e l , k ( x , y ) = e x p ( − γ ∣ ∣ x − y ∣ ∣ 2 ) , w e   h a v e   σ p 2 = 2 d γ . For the spherical Gaussian kernel, k(x, y) = exp(-γ||x-y||^2), we \ have \ σ^2_p = 2dγ. ForthesphericalGaussiankernel,k(x,y)=exp(γxy2),we have σp2=2dγ.

一点扩展:
对于非平移不变的kernel,可以通过平移不变的逐渐近似;
对于随机采样,可以通过QMC和正交采样等方式降低随机性和计算复杂度。

Random Binning Features 随机装箱特征

在这里插入图片描述

       以随机选择的分辨率且使用随机移动的网格划分输入空间,重复这个操作P次,并为输入点分配一个二进制位字符串,该字符串对应于其所在的存储单元(参见图2和算法2)。
因为它使用直线网格,这种映射非常适合只依赖于点对之间的L1距离的核。网格的构造使得两个点x和y被分配到同一个箱子的概率与k(x,y)成正比。一对变换点之间的内积与两个点组合在一起的次数成正比,因此是k(x,y)的无偏估计。

在这里插入图片描述
(左)该算法以随机选择的分辨率和使用随机移动的网格重复划分输入空间,然后得到每个点x的与分配给它的箱子关联的bit串z(x)。(右)描述这种划分的二元邻接矩阵的第ij个条目中的 z ( x i ) ′ z ( x j ) z(x_i)'z(x_j) z(xi)z(xj),此方法是核矩阵的无偏估计。

在这里插入图片描述
在这里插入图片描述

原因

Kernel machines:
给 定 { x n , y n } n = 1 N , 在 不 考 虑 偏 置 的 情 况 下 f = W T x 但 是 我 们 思 考 以 下 ( 图 一 : 深 蓝 色 , 浅 蓝 色 ) 的 二 分 类 问 题 : 左 侧 为 逻 辑 回 归 , 右 侧 为 核 方 法 中 著 名 的 非 线 性 支 持 向 量 机 给定\{x_n,y_n\}_{n=1}^N,在不考虑偏置的情况下\\ f=W^Tx\\ 但是我们思考以下(图一:深蓝色,浅蓝色)的二分类问题:\\ 左侧为逻辑回归,右侧为核方法中著名的非线性支持向量机 {xn,yn}n=1N,f=WTx()线
在这里插入图片描述

        Mercer’s theorem表明可以存在一个特征映射 φ : X → V \varphi:X\rightarrow V φ:XV
k ( x , y ) = < φ ( x ) , φ ( y ) > v k(x,y)=<\varphi(x),\varphi(y)>v k(x,y)=<φ(x),φ(y)>v

使 用 核 方 法 可 以 使 用 线 性 的 方 法 构 建 一 个 非 线 性 模 型 : f = ∑ n = 1 N a n k ( x , x n ) = < w , φ ( x ) > v 使用核方法可以使用线性的方法构建一个非线性模型:\\ f=\sum_{n=1}^Na_nk(x,x_n)=<w,\varphi(x)>v 使使线线f=n=1Nank(x,xn)=<w,φ(x)>v

但是许多和方法需要计算和操作N×N的协方差矩阵。在大数据领域,内核方法不一定可以扩展。
在这里插入图片描述

在原因部分提到了计算机难以支持核方法对大规模数据协方差矩阵的计算。由此引出Random features。构造一个“随机”映射Z使得:
在这里插入图片描述
即用z将数据映射到高维空间代替核函数隐性的映射到高维。

video : the theoretical guarantees of this approximatio
http://www.argmin.net/2017/12/05/kitchen-sinks/
机器学习有很多关于核函数的说法,核函数的定义和作用是什么?


参考:
https://gregorygundersen.com/blog/2019/12/23/random-fourier-features/
https://gregorygundersen.com/blog/2019/12/10/kernel-trick/
random feature map的SVM是不是和extreme learning machine很像
Random Features for Large-Scale Kernel Machines (Rahimi & Recht, 2007)
NIPS 网站 :https://neurips.cc/
NIPS 2017首日亮点全解读:四大获奖论文结果揭晓
获奖论文列表

什么是 bochner 技巧?
随机傅里叶特征(Random Fourier Features)
随机傅里叶特征(Random Fourier Features)
随机装箱算法(Random Binning Features)
添加链接描述

代码:

import numpy as np
import pandas as pd
df = pd.read_csv('adult_onehot.csv')
X = df.iloc[:200,:].values
def k(x,y):
    return np.exp(-np.linalg.norm(x-y)**2)
rows = []
for i in range(X.shape[0]):
    row=[]
    for j in range(X.shape[0]):
        row.append(k(X[i],X[j]))
    rows.append(np.hstack(row))    
K = np.vstack(rows)

D = 1000
W = np.random.randn(D,X.shape[1])
b = np.random.rand(D)

def z(x):
    return np.cos(W@x+b)
    
def zxzy(x,y):
    return 2.0/D*z(x).T@z(y)
rows = []
for i in range(X.shape[0]):
    row=[]
    for j in range(X.shape[0]):
        row.append(zxzy(X[i],X[j]))
    rows.append(np.hstack(row))    
Z = np.vstack(rows) # 按行顺序堆叠数组构成一个新的数组,dim=0

随机装箱算法相关论文
网站的幻灯片

https://github.com/qw3rtman/random-feature-maps

这里直接引用了以上链接的代码:

"""Random Fourier Feature"""

import numpy as np
from syllabus import Task

from .raw_array import make_raw
from .sample import KERNELS, sample, sample_1d


class RandomFourierFeature:
    """Random Fourier Feature
    Parameters
    ----------
    d : int
        Input space dimension
    D : int
        Feature space dimension
    W : RawArray or None
        If not None, used as the transformation matrix W instead of
        generating a new matrix
    b : RawArray or None
        If not None, used as the offset coefficients b
    kernel : char
        Kernel to use; 'G', 'L', or 'C'
    References
    ----------
    ..  [1] A. Rahimi, B. Recht, "Random Features for Large-Scale Kernel
        Machines"
    """

    def __init__(self, d, D, W=None, b=None, kernel='G', task=None):

        self.d = d
        self.D = D

        kernel = kernel.upper()
        if kernel not in ['G', 'L', 'C']:
            raise Exception('Invalid Kernel')
        self.kernel = kernel

        if W is None or b is None:
            self.__new(task)
        else:
            self.__load(W, b)

    def __load(self, W, b):
        """Load from existing RawArrays"""

        self.W = np.frombuffer(W, dtype=np.float32).reshape([self.D, self.d])
        self.b = np.frombuffer(b, dtype=np.float32)

    def __new(self, task):
        """Create new W and b"""

        if task is None:
            task = Task()
        task.start(name='Random Fourier Feature', desc=self.__str__())

        # Create feature
        self.create()

        task.done(
            self.W, self.b, desc="{desc} created".format(desc=self.__str__()))

    def mp_package(self):
        """Package into a multiprocessing-ready RawArray
        Returns
        -------
        (int, int, np.array, np.array)
            [0] input dimension (d)
            [1] output dimension (D)
            [2] W matrix (shape=(D, d))
            [3] b matrix (shape=(D))
        """

        if not hasattr(self, 'W_raw') or not hasattr(self, 'b_raw'):
            self.W_raw = make_raw(self.W)
            self.b_raw = make_raw(self.b)

        return (self.d, self.D, self.W_raw, self.b_raw)

    def create(self):
        """Create a d->D fourier random feature"""

        self.b = np.random.uniform(0, 2 * np.pi, self.D)

        if self.kernel == 'G':
            random_vectors = [
                np.random.normal(0, 1, self.d) for _ in range(self.D)]
            self.W = np.array([
                vector *
                (
                    sample_1d(KERNELS[self.kernel], [-10, 10]) /
                    np.linalg.norm(vector)
                )
                for vector in random_vectors
            ], dtype=np.float32)
        else:
            self.W = np.reshape(
                np.array([
                    sample(KERNELS[self.kernel], self.d)
                    for _ in range(self.D)], dtype=np.float32),
                (self.D, self.d))

    def transform(self, x):
        """Transform a vector using this feature
        Parameters
        ----------
        x : np.array (shape=(d))
            Array to transform; must be single dimension vector
        Returns
        -------
        x : np.array (shape=(D))
            Feature space transformation of x
        """
        return np.sqrt(2 / self.D) * np.cos(np.dot(self.W, x) + self.b)

    def __str__(self):
        """Get string representation
        Shown as "<d>-><D> Random Fourier Feature"
        """
        return (
            "{d}->{D} Random Fourier Feature"
            .format(d=self.d, D=self.D))
"""Random Binning Feature"""

import numpy as np
import math
from syllabus import Task
from .sample import sample, ft_laplacian
from .raw_array import make_raw


def get_p_set(args):
    """Generate one set of deltas (bin width) and mus (bin offset)
    Parameters
    ----------
    n : int
        Number of dimensions
    task : Task
        task parent
    Returns
    -------
    (np.array, np.array)
        [0] delta vector for this feature
        [1] mu vector for this feature
    """

    n, task = args

    delta_p = sample(ft_laplacian, n)
    mu_p = [np.random.uniform(0, delta_m) for delta_m in delta_p]

    if task is not None:
        task.done(silent=True)
    return (delta_p, mu_p)


class RandomBinningFeature:
    """Random Binning Feature
    Parameters
    ----------
    d : int
        Input space dimension
    D : int
        Feature space dimension; actual dimension is 128 * D binary array
    cores : int
        Number of cores to use for generation
    task : Task or none
        Task to register feature generation under
    """

    def __init__(self, d, D, delta=None, mu=None, cores=None, task=None):

        self.d = d
        self.D = D

        if delta is None or mu is None:
            self.__new(task, cores)
        else:
            self.__load(delta, mu)

    def __load(self, delta, mu):
        self.delta = np.frombuffer(
            delta, dtype=np.float32).reshape([self.D, self.d])
        self.mu = np.frombuffer(
            mu, dtype=np.float32).reshape([self.D, self.d])

    def __new(self, task, cores):

        if task is None:
            task = Task()
        task.start(name='Random Binning Feature', desc=self.__str__())

        gen = task.pool(
            get_p_set, [self.d for _ in range(self.D)],
            cores=cores, process=True, name='Random Binning Feature')

        self.delta = np.array([x[0] for x in gen], dtype=np.float32)
        self.mu = np.array([x[1] for x in gen], dtype=np.float32)

        task.done(
            self.delta, self.mu,
            desc="{desc} created".format(desc=self.__str__()))

    def mp_package(self):

        if not hasattr(self, 'delta_raw') or not hasattr(self, 'mu_raw'):
            self.delta_raw = make_raw(self.delta)
            self.mu_raw = make_raw(self.delta)

        return (self.d, self.D, self.delta_raw, self.mu_raw)

    def transform(self, x):
        """Transform a vector using this feature
        Parameters
        ----------
        x : np.array (shape=(d))
            Array to transform; must be a single dimension vector
        Returns
        -------
        x : np.array (shape=(D))
            Feature space transformation of x
        """
        ret = []
        for mu_p, delta_p in zip(self.mu, self.delta):
            tmp = [0 for i in range(128)]
            for x_i, mu, delta in zip(x, mu_p, delta_p):
                tmp[math.ceil((x_i - mu) / delta) % 128] += 1
            ret += tmp

        return 1 / np.sqrt(self.D) * np.array(ret, dtype=np.uint8)

    def __str__(self):
        """Get String representation
        Shown as "<d>-><D> Random Binning Feature"
        """
        return (
            "{d}->{D} Random Binning Feature"
            .format(d=self.d, D=self.D))

  1. 调和分析的经典定理。可参见W. Rudin. Fourier Analysis on Groups. Wiley Classics Library. Wiley-Interscience, New York, reprint edition edition, 1994. wiki ↩︎

  2. https://math.stackexchange.com/questions/2754657/conditions-for-a-nonnegative-fourier-transform
    https://en.wikipedia.org/wiki/Positive-definite_function_on_a_group ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值