NeurIPS 2020 | 隐私保护的 Bandit 算法

NeurIPS 2020 | 隐私保护的 Bandit 算法

【作者按】本文首发于 MindSpore 微信公众号[1],现整理转发至本专栏,方便读者查阅。

简介

老虎机(Bandit)问题是强化学习中一类重要的问题,由于它定义简洁且有大量的理论分析,因此被广泛应用于新闻推荐,医学试验等实际场景中。随着人类进入大数据时代,用户对自身数据的隐私性日益重视,这对机器学习算法的设计提出了新的挑战。为了在保护隐私的情况下解决 Bandit 这一经典问题,我们提出了基于本地差分隐私的 Bandit 算法,论文[2]已被 NeurIPS 2020 录用,代码[3]已基于 MindSpore 开源首发。

更新:基于 Numpy 的代码 v1.1.0 已经发布!基于 MindSpore 的代码参见 v1.0.0 版本。

本文将先简单介绍 Bandit 问题和本地差分隐私的相关背景,然后介绍基于本地差分隐私的 Bandit 算法,最后通过一个简单的电影推荐场景来验证 LDP LinUCB 算法(这部分实验是对原论文的一个补充)。

老虎机问题(Bandit Problem)

大家都有过这样的经历,在我们刷微博或是读新闻的时候,经常会看到一些系统推荐的内容,这些推荐的内容是根据用户对过往推荐内容的点击情况以及阅读时长等反馈来产生的。在这个过程里,系统事先不知道用户对各种内容的偏好,通过不断地与用户进行交互(推荐内容 — 得到反馈),来慢慢学习到用户的偏好特征,不断提高推荐的精准性,从而最大化用户的价值,这就是一个典型的 Bandit 问题。

Bandit 问题有 context-free 和 contextual 两种常见的设定,下面给出它们具体的数学定义。

【Context-Free Bandit】 假设给定一个动作集合 \mathcal{X},玩家跟环境的交互过程按轮进行。在每一轮 t,玩家基于之前所有的观测结果选择一个动作 x_t\in\mathcal{X} 去执行,然后从环境观测到一个损失值 f_t(x_t),如此往复(有些文献中定义成 reward,那么 reward 的负数就对应此处的损失值)。我们定义累积 regret 函数为 \max_{x\in\mathcal{X}} \mathbb{E} [\sum_{t=1}^T (f_t(x_t)-f_t(x))],问题目标是设计一个算法使得累积 regret 最小。其中 f_t(x_t) 既可以是 adversarial 也可以是 stochastic(只需让 f_t(x_t)=f(x_t)+q_tq_t 是独立同分布的零均值噪声)。

【Contextual Bandit】 顾名思义,Contextual Bandit 这类算法在做决策时考虑了上下文的信息,因而更加适合实际的个性化推荐场景。形式化地说,在每一轮 t ,系统观测到当前用户 u_t 和每一个候选物品的联合特征的集合 \mathcal{X}_{t}(即上下文信息),然后基于之前所有的观测结果选择一个候选物品 x_t\in\mathcal{X_{t}}(由于联合特征 x_t 和候选物品一一对应,故此处用 x_t 代替)去推荐,并观测到一个奖励值 y_t。通常,y_t 可以建模成 g(x_t^\top \theta^*)+\eta_t,其中 \theta^* 是待学习的真实参数,\eta_t 是零均值噪声,g 是某个形式已知的函数。同样地,我们可以定义累积 regret 函数为 Reg^T=\sum_{t=1}^T [g(x_{t,*}^\top \theta^*)-g(x_t^\top \theta^*)],其中 x_{t,*}=\arg\max_{x\in\mathcal{X}_t}g(x^\top \theta^*),问题目标是设计一个算法使得累积 regret 最小。

本地差分隐私(LDP)

传统的差分隐私技术(Differential Privacy,DP)是将用户数据集中到一个可信的数据中心,在数据中心对用户数据进行匿名化使其符合隐私保护的要求后,再分发给下游使用,我们将其称之为中心化差分隐私。但是,一个绝对可信的数据中心很难找到,因此人们提出了本地差分隐私技术(Local Differential Privacy,LDP),它直接在客户端进行数据的隐私化处理后再提交给数据中心,彻底杜绝了数据中心泄露用户隐私的可能。

本地差分隐私的定义:假设 \varepsilon,\delta 是正实数,算法 Q:C\rightarrow Z 被称为满足 (\varepsilon,\delta)-LDP,如果对任意两个数据 x,x’\in C 和任意子集 U\subset Z\text{Pr}[Q(x)\in U]\le e^\varepsilon \text{Pr}[Q(x’)\in U]+\delta。特别地,如果 Q 满足 (\varepsilon,0)-LDP,我们简称为 \varepsilon-LDP。

可以看到,当 \varepsilon\delta 越小,说明 Q(x)Q(x’) 相似性越高,隐私保护程度也越好。

通常来说,对数据加噪声可以满足 LDP,两种常用的加噪声的方法:高斯噪声和拉普拉斯噪声。

给定一个函数 h:C\rightarrow \mathbb{R}^d高斯机制定义为 h(x)+\mathcal{N}^d(0,\sigma^2),其中 \sigma^2=\frac{2\Delta^2}{\varepsilon^2}\ln \frac{1.25}{\delta}\Delta:= \max \| h(x)-h(x') \|_2拉普拉斯机制定义为 h(x)+\text{Laplace}^d(s/\varepsilon),其中 s:= \max \| h(x)-h(x') \|_1

可以证明,高斯机制能满足 (\varepsilon,\delta)-LDP 性质,拉普拉斯机制能满足 \varepsilon-LDP 性质。因此,下文主要考虑 (\varepsilon,\delta)-LDP 性质,将算法中的高斯机制替换成拉普拉斯机制可以得到对应的 \varepsilon-LDP 性质。

隐私保护的 Bandit 算法

Context-Free Bandit

假定我们有一个非隐私保护的 Bandit 算法 \mathcal{A},根据高斯机制,如果直接在每一轮回传的损失值 f_t(x_t) 上注入噪声,那么该算法就可以满足 (\varepsilon,\delta)-LDP 性质。 假设 f_t(x) 是有界的,即 \forall x\in \mathcal{X}, t\in [T], |f_t(x)|\le B,那么满足 (\varepsilon,\delta)-LDP 的 Bandit 算法可以写成如下形式:

我们可以证明,上述算法有如下的性能:

【定理】 假设非隐私保护的 Bandit 算法 \mathcal{A} 的 regret 上界是 B\cdot Reg_{\mathcal{A}}^T,那么算法 1 有如下理论保证: \forall x\in \mathcal{X}\mathbb{E}\left[\sum_{t=1}^T f_t(x_t)-f_t(x)\right] \le \tilde{\mathcal{O}}\left(\frac{B\ln (T/\delta)}{\varepsilon}\cdot Reg_{\mathcal{A}}^T\right)

根据上述定理,我们只需将任一非隐私保护的算法按照算法 1 进行改造,就立即可以得到对应的隐私保护版本的算法,且它的累积 regret 的理论上界和非隐私算法只相差一个 \varepsilon 因子,因此算法 1 具有很强的通用性。 我们将损失函数满足不同凸性和光滑性条件下的 regret 简单罗列如下:

上述算法和结论可以扩展到每一轮能观测多个动作损失值的情况,感兴趣的可以参见论文

Contextual Bandit

这里我们只介绍一类最简单的线性的情况:g 函数是恒等变换,即 y_t=x_t^\top \theta^*+\eta_t。LinUCB 是一个解决这种 linear contextual bandit 的经典算法。在 LinUCB 算法中,每一轮需要传输的是更新量是 x_t x_t^\topy_tx_t,我们通过给这些变量加高斯噪声就可以保证 (\varepsilon,\delta)-LDP,我们称之为 LDP LinUCB 算法,具体过程如下:

【定理】 依照至少为 1-\alpha 的概率,LDP LinUCB 算法的 regret 满足如下关系:Reg^T \le \tilde{\mathcal{O}}\left(\sqrt{\log\frac{1}{\delta}\log\frac{1}{\alpha}}\frac{(dT)^{3/4}}{\varepsilon}\right)

上述算法和结论可以扩展到 g 不是恒等变换的情况,感兴趣的可以参见论文

场景模拟:电影推荐

MovieLens 是一个包含多个用户对多部电影评分的公开数据集,我们可以用它来模拟电影推荐。 我们通过 src/dataset.py[3]来构建环境:我们从数据集中抽取一部分有电影评分数据的用户,然后将评分矩阵通过 SVD 分解来补全评分数据,并将分数归一化到 [-1,+1]。在每次交互的时候,系统随机抽取一个用户,推荐算法获得特征,并选择一部电影进行推荐,MovieLensEnv 会在打分矩阵中查询该用户对电影对评分并返回,从而模拟用户给电影打分。

class MovieLensEnv:
    def observation(self):    # Random select a user and return its feature.
        sampled_user = random.randint(0, self._data_matrix.shape[0] - 1)
        self._current_user = sampled_user
        return Tensor(self._feature[sampled_user])
    def current_rewards(self):    # Rewards for current user.
        return Tensor(self._approx_ratings_matrix[self._current_user])

LDP LinUCB 的算法位于 src/linucb.py,参数如下,分别对应算法中的 \tilde V_t, \tilde u_t, \tilde\theta_t

import mindspore.nn as nn

class LinUCB(nn.Cell):
    def __init__(self, context_dim, epsilon=100, delta=0.1, alpha=0.1, T=1e5):
    ...
        # Parameters
        self._V = Tensor(np.zeros((context_dim, context_dim), dtype=np.float32))
        self._u = Tensor(np.zeros((context_dim,), dtype=np.float32))
        self._theta = Tensor(np.zeros((context_dim,), dtype=np.float32))

每来一个用户,LDP LinUCB 算法根据用户和电影的联合特征 x 基于当前的模型来选择最优的电影 a_max 做推荐,并传输带噪声的更新量(算法中的 x_tx_t^\top+B_ty_tx_t+\xi_t):

import mindspore.nn as nn

class LinUCB(nn.Cell):
...
    def construct(self, x, rewards):    # Compute the perturbed gradients for parameters.
        # Choose optimal action
        x_transpose = self.transpose(x, (1, 0))
        scores_a = self.squeeze(self.matmul(x, self.expand_dims(self._theta, 1)))
        scores_b = x_transpose * self.matmul(self._Vc_inv, x_transpose)
        scores_b = self.reduce_sum(scores_b, 0)
        scores = scores_a + self._beta * scores_b
        max_a = self.argmax(scores)
        xa = x[max_a]
        xaxat = self.matmul(self.expand_dims(xa, -1), self.expand_dims(xa, 0))
        y = rewards[max_a]
        y_max = self.reduce_max(rewards)
        y_diff = y_max - y
        self._current_regret = float(y_diff.asnumpy())
        self._regret += self._current_regret

        # Prepare noise
        B = np.random.normal(0, self._sigma, size=xaxat.shape)
        B = np.triu(B)
        B += B.transpose() - np.diag(B.diagonal())
        B = Tensor(B.astype(np.float32))
        Xi = np.random.normal(0, self._sigma, size=xa.shape)
        Xi = Tensor(Xi.astype(np.float32))

        # Add noise and update parameters
        return xaxat + B, xa * y + Xi, max_a

系统收到更新量之后,更新模型参数如下:

import mindspore.nn as nn

class LinUCB(nn.Cell):
...
    def server_update(self, xaxat, xay):    # Update parameters with perturbed gradients.
        self._V += xaxat
        self._u += xay
        self.inverse_matrix()
        theta = self.matmul(self._Vc_inv, self.expand_dims(self._u, 1))
        self._theta = self.squeeze(theta)

实验结果

我们测试不同的 \varepsilon 对累积 regret 对影响:

x 轴:交互轮数;y 轴:累积 regret

可以看到,当固定隐私变量 \varepsilon 的时候,累积 regret 随着时间增加得越来越缓慢,意味着推荐的电影和用户最喜欢的电影越来越接近,即推荐变得越来越精准。 同时,随着 \varepsilon 的减小,隐私保护程度越好,但性能也会有所下降。 由于测试用的数据量较小,因此此处 \varepsilon 设定的比较大。在真实商用场景中的数据量会远远大于此处模拟用的数据量,届时可以把 \varepsilon 设定到 10 以下。

接着我们测试了 LDP LinUCB 和非隐私保护 LinUCB 的累积 regret 的比较(LinUCB 的累积 regret 是 \tilde{\mathcal{O}}(\sqrt{T}) ):

x 轴:交互轮数;y 轴:累积 regret 除以“根号T”

可以看到 LDP LinUCB 的累积 regret 增长速度和 \sqrt{T} 近似,说明 LDP LinUCB 近乎是最优的算法。这也提示我们,论文中给出的 LDP LinUCB 的理论上界 \tilde{\mathcal{O}}(T^{3/4}/\varepsilon) 也许可以进一步改进到 \tilde{\mathcal{O}}(T^{1/2}/\varepsilon)

相关代码已上线 MindSpore Model Zoo,感兴趣的可自行体验。


最后,打个小广告,我们正在招 2-3 名实习生,如果您感兴趣,欢迎点击如下链接了解:

本专栏的微信公众号是 notes-for-ai,欢迎订阅及时获取最新内容的推送。

参考

  1. ^"MindSpore 首发:隐私保护的 Bandit 算法,实现电影推荐." MindSpore 微信公众号. Jan 19, 2021. https://mp.weixin.qq.com/s/DxqJvwmYUwRiF-T7ZbcDmg
  2. ^Kai Zheng, Tianle Cai, Weiran Huang, Zhenguo Li, Liwei Wang. "Locally Differentially Private (Contextual) Bandits Learning." Advances in Neural Information Processing Systems. 2020. https://arxiv.org/abs/2006.00701
  3. ^abLDP LinUCB 代码 https://github.com/huang-research-group/LDPbandit2020
编辑于 2023-01-17 01:49・IP 属地上海

文章被以下专栏收录