差分隐私代码实现系列(十二)

  • 写在前面的话
  • 回顾
  • 机器学习与差分隐私
  • 使用 Scikit-Learn 进行逻辑回归
  • 什么是模型?
  • 使用梯度下降训练模型
  • 梯度下降的单一步骤
  • 梯度下降算法
  • 梯度下降与差分隐私
  • 渐变剪切
  • 梯度的灵敏度
  • 噪音对训练的影响
  • 总结

写在前面的话

书上学来终觉浅,绝知此事要躬行

回顾

1、稀疏向量技术对数据集上的敏感度为1的查询流进行操作。它释放流中第一个通过测试的查询的标识,而不是其他任何内容。SVT的优点是,无论考虑多少查询,它都会产生固定的总隐私成本。

2、 在这种情况下,我们希望通过放弃对明显低于阈值的查询的数字答案,而仅报告这些查询确实低于阈值,从而获得本质的分析。(如果我们这样选择的话,我们也将能够获得阈值以上查询的数字值,而只需花费额外的费用)。该技术很简单:添加噪音并仅报告噪声值是否超过阈值。

3、该AboveThreshold算法通过有时返回错误的索引来保护差分隐私。有时,返回的索引可能用于结果未超过阈值的查询,有时,索引可能不是查询结果超过阈值的第一个索引。

4、为什么AboveThreshold做得更好?正如我们在指数机制中看到的那样,顺序组合将允许AboveThreshold发布比实际信息更多的信息。特别是,我们的算法的朴素版本可以释放每个超过阈值的查询的索引(不仅仅是第一个查询),加上嘈杂的查询答案本身,并且它仍然可以保留nϵn\epsilonnϵ-差分隐私。AboveThreshold隐瞒所有这些信息的事实允许对隐私成本进行更严格的分析。

机器学习与差分隐私

机器学习与差分隐私(认证鲁棒性和隐私保护)这篇博客中对两者之间的关系和发展进行了恰当的描述,大家感兴趣可以去看看。

《Deep Learning with Differential Privacy》中的MA也有不少博客对其进行分析,这里我也不多赘述。这篇博客主要是想通过代码从本质上来谈一谈机器学习和差分隐私之间的联系,而不是仅仅停留在论文中。

在本篇博客中,我们将探讨如何构建差分隐私机器学习分类器。

将重点介绍一种监督学习问题:给定一组标记的训练示例{(x1,y1),…,(xn,yn)}\{(x_1, y_1), \dots, (x_n, y_n)\}{(x1​,y1​),…,(xn​,yn​)},其中xix_ixi​称为特征向量,yiy_iyi​称为标签,训练一个模型θ\thetaθ,该模型可以预测训练集中不存在的新特征向量的标签。

每个xix_ixi​ 通常都是描述训练示例特征的实数向量,并且yiy_iyi​ 是从一组预定义的类(通常表示为整数)中提取的,可以从中得出示例。二进制分类器有两个类(通常为 1 和 0,或 1 和 -1)。

使用 Scikit-Learn 进行逻辑回归

为了训练模型,我们将使用一些可用的数据来构建一组训练示例(如前所述),但我们也会留出一些数据作为测试示例。

训练模型后,我们想知道它在训练集中不存在的示例上的工作效果如何,即在以前从未见过的新示例上效果良好的模型可以很好地进行分析。一个不能很好地进行分析的模型已经过度拟合了训练数据。

为了测试泛化,我们将使用测试示例,我们为它们提供了标签,因此我们可以通过要求模型对每个样本进行分类,然后将预测的类与数据集中的实际标签进行比较来测试模型的泛化准确性。

我们将数据拆分为包含 80% 示例的训练集和包含 20% 示例的测试集。

数据集如下:

划分过程如下:

%matplotlib inline
import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
import pandas as pd
import numpy as np
from collections import defaultdict# Some useful utilitiesdef laplace_mech(v, sensitivity, epsilon):return v + np.random.laplace(loc=0, scale=sensitivity / epsilon)def gaussian_mech(v, sensitivity, epsilon, delta):return v + np.random.normal(loc=0, scale=sensitivity * np.sqrt(2*np.log(1.25/delta)) / epsilon)def gaussian_mech_vec(v, sensitivity, epsilon, delta):return v + np.random.normal(loc=0, scale=sensitivity * np.sqrt(2*np.log(1.25/delta)) / epsilon, size=len(v))def pct_error(orig, priv):return np.abs(orig - priv)/orig * 100.0def z_clip(xs, b):return [min(x, b) for x in xs]def g_clip(v):n = np.linalg.norm(v, ord=2)if n > 1:return v / nelse:return vtraining_size = int(X.shape[0] * 0.8)X_train = X[:training_size]
X_test = X[training_size:]y_train = y[:training_size]
y_test = y[training_size:]y_test.shape


构建二元分类器的一种简单方法是使用逻辑回归。

scikit-learn 库有一个用于执行逻辑回归的内置模块,称为LogisticRegression,并且很容易使用我们的数据构建模型。

from sklearn.linear_model import LogisticRegression
model = LogisticRegression().fit(X_train,y_train)
model


接下来,我们可以使用模型的predict方法预测测试集的标签。

model.predict(X_test)


那么,我们的模型正确了多少个测试示例呢?我们可以将预测的标签与数据集中的实际标签进行比较;如果我们将正确预测的标签数量除以测试示例的总数,我们可以测量正确分类的示例的百分比。

np.sum(model.predict(X_test) == y_test)/X_test.shape[0]


我们的模型为测试集中 84% 的示例预测了正确的标签。对于此数据集,这是一个相当不错的结果。

什么是模型?

模型到底是什么?它如何编码用于进行预测的信息?

有许多不同类型的模型,但我们将在这里探讨的是线性模型。对于具有kkk维特征向量x1,…,xkx_1, \dots, x_kx1​,…,xk​的未标记示例,线性模型通过首先计算数量来预测标签:

w1x1+⋯+wkxk+biasw_1 x_1 + \dots + w_k x_k + bias w1​x1​+⋯+wk​xk​+bias
然后取它的符号(即,如果上面的数量为负,我们预测标签-1;如果它是正的,我们预测1)。

然后,模型本身可以由包含值w1,…,wkw_1, \dots, w_kw1​,…,wk​和biasbiasbias值的向量表示。该模型被称为线性的,因为我们在预测标签时计算的数量是1次的多项式(即线性)。值w1,…,wkw_1, \dots, w_kw1​,…,wk​ 通常称为模型的权重或系数,biasbiasbias通常称为偏差项或截距。

这实际上也是scikit-learn表示其逻辑回归模型的方式!我们可以使用模型的coef_属性来检查已训练模型的权重:

model.intercept_[0], model.coef_[0]


请注意,我们将始终具有与特征xix_ixi​完全相同的权重数量wiw_iwi​,因为我们必须将每个特征乘以相应的权重。这意味着我们的模型具有与我们的特征向量完全相同的维度。

现在我们有了一种方法来获取权重和偏差项,我们可以实现自己的函数来执行预测:

def predict(xi, theta, bias=0):label = np.sign(xi @ theta + bias)return labelnp.sum(predict(X_test, model.coef_[0], model.intercept_[0]) == y_test)/X_test.shape[0]


我们在这里将偏差术语设置为可选,因为在许多情况下,没有它也可以做得很好。为了让事情变得更简单,我们不会费心在自己的算法中训练偏差项。

使用梯度下降训练模型

训练过程实际上是如何运作的?scikit-learn库有一些非常复杂的算法,但我们也可以通过实现一个简单的称为梯度下降的算法来做到这一点。

**大多数机器学习的训练算法都是根据损失函数定义的,它指定了一种测量模型在预测时有多"坏"的方法。**训练算法的目标是最小化损失函数的输出,具有低损失的模型将擅长预测。

机器学习领域已经开发了许多不同的常用损失函数。对于每个正确预测的示例,简单的损失函数可能返回 0,对于每个错误预测的示例返回 1;当损失变为 0 时,这意味着我们已经正确预测了每个示例的标签。

二元分类中比较常用的损失函数称为逻辑损失,逻辑损失为我们提供了一个衡量标准,即我们距离预测正确标签还有多远(这比简单的0 vs 1方法更具信息性)。

逻辑损失由以下 Python 函数实现:

def loss(theta, xi, yi):exponent = - yi * (xi.dot(theta))return np.log(1 + np.exp(exponent))

我们可以使用损失函数来衡量特定模型的好坏。让我们用一个权重都为零的模型来尝试一下。这个模型不太可能很好地工作,但它是一个起点,我们可以从中训练出更好的模型。

theta = np.zeros(X_train.shape[1])
loss(theta, X_train[0], y_train[0])


我们通常通过简单地对训练数据中所有示例的损失进行平均来衡量我们的模型在整个训练集上有多好。

在本例中,我们弄错了每个示例,因此整个训练集上的平均损失正好等于我们上面计算的损失,仅举一例。

np.mean([loss(theta, x_i, y_i) for x_i, y_i in zip(X_train, y_train)])


我们训练模型的目标是将损失降至最低。所以关键问题是:我们如何修改模型以减小损失?

梯度下降是一种通过根据损失的梯度更新模型来使损失变小的方法。

梯度就像一个多维导数:对于具有多维输入的函数(如上面的损失函数),梯度体现函数的输出相对于输入的每个维度的变化速度。

如果梯度在特定维度中为正,则意味着如果我们增加该维度的模型权重,则该函数的值将增加;我们希望损失减少,因此我们应该通过朝着梯度的反方向来修改我们的模型,即做与梯度相反的事情。由于我们沿梯度相反的方向移动模型,因此这称为梯度下降。

当我们迭代地执行这个下降过程的许多步骤时,我们慢慢地越来越接近模型,从而最大限度地减少损失。此算法称为梯度下降。让我们看看这在Python中看起来如何;首先,我们将定义梯度函数。

def gradient(theta, xi, yi):exponent = yi * (xi.dot(theta))return - (yi*xi) / (1+np.exp(exponent))

梯度下降的单一步骤

接下来,让我们执行梯度下降的单个步骤。我们可以将gradient函数应用于训练数据中的单个示例,这应该为我们提供足够的信息来改进该示例的模型。我们通过从当前theta模型中减去梯度来"下降"梯度。

theta = theta - gradient(theta, X_train[0], y_train[0])
theta


现在,如果我们从训练数据中调用相同的示例,则其标签被正确预测!这意味着我们的更新确实改进了模型,因为它现在能够对此示例进行分类。

y_train[0], predict(theta, X_train[0])


我们将多次测量模型的准确性,因此让我们定义一个用于测量准确性的帮助器函数。它的工作方式与上述 sklearn 模型的精度测量相同。我们可以通过降低一个示例的梯度来使用它在theta上,看看我们的模型在测试集上有多好。

def accuracy(theta):return np.sum(predict(X_test, theta) == y_test)/X_test.shape[0]accuracy(theta)


我们改进的模型现在可以正确预测测试集的 75% 的标签!这是一个很好的进步,我们已经大大改进了模型。

梯度下降算法

我们需要进行两项更改才能得出基本的梯度下降算法。首先,我们上面的单个步骤仅使用了训练数据中的单个示例;我们希望在更新模型时考虑整个训练集,以便改进所有示例的模型。其次,我们需要执行多次迭代,以尽可能接近最小化损失。

**我们可以通过计算所有训练示例的平均梯度来解决第一个问题,并将其用于下降步骤,而不是我们之前使用的单例梯度。**我们的avg_grad函数计算整个训练示例数组和相应标签的平均梯度。

def avg_grad(theta, X, y):grads = [gradient(theta, xi, yi) for xi, yi in zip(X, y)]return np.mean(grads, axis=0)avg_grad(theta, X_train, y_train)

为了解决第二个问题,我们将定义一个迭代算法,该算法将梯度降序多次。

def gradient_descent(iterations):theta = np.zeros(X_train.shape[1])for i in range(iterations):theta = theta - avg_grad(theta, X_train, y_train)return thetatheta = gradient_descent(10)
accuracy(theta)


经过10次迭代,我们的模型达到了近78%的准确率,还不错!

我们的梯度下降算法看起来很简单(确实如此!)但不要让它的简单性愚弄你,这种基本方法是最近在大规模深度学习中取得的许多成功背后的原因,我们的算法在设计上非常接近于在流行的机器学习框架中实现的算法,如Tensorflow。

请注意,我们没有完全达到我们之前训练的 sklearn 模型的 84% 准确率。别担心,我们的算法绝对有能力做到这一点!我们只需要更多的迭代,以接近最小的损失。

通过100次迭代,我们越来越接近82%的准确率。

但是,当我们要求如此多的迭代时,该算法需要很长时间才能运行。更糟糕的是,我们越接近最小化损失,就越难改进,所以我们在100次迭代后可能会达到82%的准确率,但可能需要1000次迭代才能达到84%。

这指出了机器学习的根本紧张关系,**一般来说,更多的训练迭代可以提高准确性,但更多的迭代需要更多的计算时间。**大多数用于使大规模深度学习变得实用的"技巧"实际上都是为了加快梯度下降的每次迭代,以便在相同的时间内执行更多的迭代。

还有一件有趣的事情需要注意:损失函数的值确实会随着我们执行的梯度下降的每次迭代而下降 。

因此,随着我们执行更多的迭代,我们慢慢地接近最小化损失。另请注意,训练和测试损失彼此非常接近,这表明我们的模型不会过度拟合训练数据。

def gradient_descent_log(iterations):theta = np.zeros(X_train.shape[1])for i in range(iterations):theta = theta - avg_grad(theta, X_train, y_train)print(f'Training loss: {np.mean(loss(theta, X_train, y_train))}')print(f'Testing loss: {np.mean(loss(theta, X_test, y_test))}\n')return thetagradient_descent_log(5);

梯度下降与差分隐私

我们如何使上述算法差分隐私?我们希望设计一种算法来确保训练数据的差分隐私,以便最终模型不会显示有关单个训练示例的任何信息。

算法中唯一使用训练数据的部分是梯度计算。使算法具有差分隐私的一种方法是在每次迭代时在更新模型之前向梯度本身添加噪声。这种方法通常称为噪声梯度下降,因为我们直接将噪声添加到梯度中。

我们的梯度函数是一个向量值函数,因此我们可以使用gaussian_mech_vec它来向其输出添加噪声:

def noisy_gradient_descent(iterations, epsilon, delta):theta = np.zeros(X_train.shape[1])sensitivity = '???'for i in range(iterations):grad = avg_grad(theta, X_train, y_train)noisy_grad = gaussian_mech_vec(grad, sensitivity, epsilon, delta)theta = theta - noisy_gradreturn theta

上面的代码只缺少一个部分,**梯度函数的灵敏度是多少?**回答这个问题是算法工作的核心困难。

这里有两个主要挑战。

首先,梯度是平均查询的结果,它是每个示例的许多梯度的平均值

正如我们之前所看到的,最好将此类查询拆分为总和查询和计数查询。这并不难做到,我们可以计算每个示例梯度的总和,而不是它们的平均值,并在以后除以噪声计数。

其次,我们需要绑定每个示例梯度的灵敏度。

有两种基本方法:我们可以分析梯度函数本身(就像我们在之前的查询中所做的那样)来确定其最坏情况下的全局灵敏度,或者我们可以通过剪裁梯度函数的输出来强制执行灵敏度(就像我们在样本和聚合中所做的那样)。

我们将从第二种方法开始,通常称为渐变剪切 。因为它在概念上更简单,并且在其应用程序中更通用。

渐变剪切

回想一下,当我们实现采样和聚合时,我们通过剪裁其输出,对灵敏度未知的函数fff强制执行所需的灵敏度。fff的敏感度为:

∣f(x)−f(x′)∣\lvert f(x) - f(x') \rvert ∣f(x)−f(x′)∣
使用参数bbb进行剪裁后,这将变为:

∣clip(f(x),b)−clip(f(x′),b)∣\lvert \mathsf{clip}(f(x), b) - \mathsf{clip}(f(x'),b) \rvert ∣clip(f(x),b)−clip(f(x′),b)∣
在最坏的情况下,clip(f(x),b)=b\mathsf{clip}(f(x), b) = bclip(f(x),b)=b和clip(f(x′),b)=0\mathsf{clip}(f(x'),b) = 0clip(f(x′),b)=0,因此裁剪结果的灵敏度正好是bbb(剪裁参数的值)。

我们可以使用相同的技巧来绑定梯度函数的L2灵敏度。

我们需要定义一个函数来"裁剪"向量,使其在所需范围内具有 L2 范数。我们可以通过缩放向量来实现这一点:如果我们按元素除以向量的L2范数,那么生成的向量的L2范数将为1。

如果我们想针对特定的剪切参数bbb,我们可以将缩放的向量乘以bbb以将其放大以具有 L2 范数bbb。

我们希望避免修改已经将 L2 范数低于bbb的向量;在这种情况下,我们只返回原始向量。我们可以与参数ord=2一起使用np.linalg.norm来计算向量的 L2 范数。

def L2_clip(v, b):norm = np.linalg.norm(v, ord=2)if norm > b:return b * (v / norm)else:return v

现在,我们已准备好分析裁剪渐变的灵敏度。我们将梯度表示为∇(θ;X,y)\nabla(\theta; X, y)∇(θ;X,y)(对应于我们的 Python 代码gradient):

∥L2_clip(∇(θ;X,y),b)−L2_clip(∇(θ;X′,y))∥2\lVert \mathsf{L2\_clip}( \nabla (\theta; X, y), b) - \mathsf{L2\_clip}( \nabla (\theta; X', y)) \rVert_2 ∥L2_clip(∇(θ;X,y),b)−L2_clip(∇(θ;X′,y))∥2​
在最坏的情况下,L2_clip(∇(θ;X,y),b)\mathsf{L2\_clip}( \nabla (\theta; X, y), b)L2_clip(∇(θ;X,y),b)的 L2 范数为bbb和L2_clip(∇(θ;X′,y))\mathsf{L2\_clip}( \nabla (\theta; X', y))L2_clip(∇(θ;X′,y))全为零 - 因此差分的 L2 范数等于bbb。因此,剪切渐变的 L2 灵敏度受剪切参数bbb的限制!

现在,我们可以继续计算裁剪梯度的总和,并根据我们通过裁剪强制执行的 L2 灵敏度bbb添加噪声。

def gradient_sum(theta, X, y, b):gradients = [L2_clip(gradient(theta, x_i, y_i), b) for x_i, y_i in zip(X,y)]return np.sum(gradients, axis=0)

现在,我们已准备好完成噪声梯度下降算法。要计算噪声平均梯度,我们需要:

1、根据噪声的灵敏度将噪声添加到梯度的总和中bbb

2、计算训练示例数的噪声计数(灵敏度 1)

3、将 (1) 中的噪声和除以 (2) 中的噪声计数

def noisy_gradient_descent(iterations, epsilon, delta):theta = np.zeros(X_train.shape[1])sensitivity = 5.0noisy_count = laplace_mech(X_train.shape[0], 1, epsilon)for i in range(iterations):grad_sum        = gradient_sum(theta, X_train, y_train, sensitivity)noisy_grad_sum  = gaussian_mech_vec(grad_sum, sensitivity, epsilon, delta)noisy_avg_grad  = noisy_grad_sum / noisy_counttheta           = theta - noisy_avg_gradreturn thetatheta = noisy_gradient_descent(10, 0.1, 1e-5)
accuracy(theta)


此算法的每次迭代都满足(ϵ,δ)(\epsilon, \delta)(ϵ,δ)-差分隐私,我们执行一个额外的查询来确定满足ϵ\epsilonϵ-差分隐私的噪声计数。

如果我们执行kkk迭代,则通过顺序组合,算法满足(kϵ+ϵ,kδ)(k\epsilon + \epsilon, k\delta)(kϵ+ϵ,kδ)-差分隐私。我们还可以使用高级组合来分析总隐私成本;更好的是,我们可以将算法转换为 Rényi 差分隐私或零集中差分隐私,并获得隐私成本的严格限制。

梯度的灵敏度

我们之前的方法非常通用,因为它不对梯度的行为做出任何假设。

然而,有时我们确实对梯度的行为有所了解。特别是,一大类有用的梯度函数(包括我们在这里使用的逻辑损失的梯度)是利普希茨连续,这意味着它们具有有界的全局灵敏度。从形式上讲,可以证明:

If∥xi∥2≤bthen∥∇(θ;xi,yi)∥2≤b\text{If}\; \lVert x_i \rVert_2 \leq b\; \text{then}\; \lVert \nabla(\theta; x_i, y_i) \rVert_2 \leq b If∥xi​∥2​≤bthen∥∇(θ;xi​,yi​)∥2​≤b
这一事实允许我们裁剪训练示例的值(即梯度函数的输入),而不是梯度函数的输出,并获得梯度的L2灵敏度的边界。

裁剪训练示例而不是梯度有两个优点。首先,估计训练数据的比例(从而选择一个好的裁剪参数)通常比估计训练期间将要计算的梯度的尺度更容易。

其次,它在计算上更有效:我们可以裁剪一次训练示例,并在每次训练模型时重用裁剪的训练数据。使用渐变剪切,我们需要在训练期间修剪每个梯度。

此外,我们不再被迫计算每个示例的梯度,以便我们可以裁剪它们,相反,我们可以一次计算所有梯度,这可以非常有效地完成(这是机器学习中常用的技巧,但我们不会在这里讨论它)。

但请注意,许多有用的损失函数,特别是那些从深度学习中的神经网络派生的函数,没有有界的全局灵敏度。对于这些损耗函数,我们被迫使用渐变裁剪。

我们可以通过对算法进行一些简单的修改来裁剪训练示例而不是梯度。首先,我们在开始训练之前使用L2_clip裁剪训练示例。其次,我们只需删除用于裁剪渐变的代码即可。

def gradient_sum(theta, X, y, b):gradients = [gradient(theta, x_i, y_i) for x_i, y_i in zip(X,y)]return np.sum(gradients, axis=0)
def noisy_gradient_descent(iterations, epsilon, delta):theta = np.zeros(X_train.shape[1])sensitivity = 5.0noisy_count = laplace_mech(X_train.shape[0], 1, epsilon)clipped_X = [L2_clip(x_i, sensitivity) for x_i in X_train]for i in range(iterations):grad_sum        = gradient_sum(theta, clipped_X, y_train, sensitivity)noisy_grad_sum  = gaussian_mech_vec(grad_sum, sensitivity, epsilon, delta)noisy_avg_grad  = noisy_grad_sum / noisy_counttheta           = theta - noisy_avg_gradreturn thetatheta = noisy_gradient_descent(10, 0.1, 1e-5)
accuracy(theta)


可以对该算法进行许多改进,这可以提高隐私成本和准确性。许多都来自机器学习文献。一些示例包括:

1、通过将每次迭代ϵ\epsilonϵ作为算法的一部分,将总隐私成本限定为ϵ\epsilonϵ。

2、通过高级组合定理、RDP 或 zCDP 为大量迭代提供更好的组合。

3、小型分组:使用一小部分训练数据而不是整个训练集来计算每次迭代的梯度(这减少了计算梯度所需的计算)。

4、与minibatching相结合的平行组合定理。

5、随机抽样批次与小批次相结合。

6、其他超参数,如学习速率η\etaη。

噪音对训练的影响

到目前为止,我们已经看到迭代次数对我们获得的模型的准确性有很大的影响,因为更多的迭代可以让你更接近最小的损失。

由于我们的差分隐私算法会在梯度上增加噪声,这也会影响准确性,噪声会导致我们的算法在训练期间向错误的方向移动,并且实际上会使模型变得更糟。

可以合理地预期,ϵ\epsilonϵ的值越小,模型的精度就越低(因为这是我们迄今为止看到的每个差分隐私算法的趋势)。

这是事实,但也有一个稍微更微妙的权衡,这是由于我们在执行算法的多次迭代时需要考虑的组成:更多的迭代意味着更大的隐私成本。

在标准梯度下降算法中,迭代次数越多,通常会产生更好的模型。在我们的差分隐私版本中,更多的迭代可能会使模型变得更糟,因为我们必须为每次迭代使用较小的ϵ\epsilonϵ,因此噪声的规模会上升。在差分隐私机器学习中,在使用的迭代次数和添加的噪声规模之间取得适当的平衡是很重要的(有时是非常具有挑战性的)。

让我们做一个小实验,看看ϵ\epsilonϵ 的设置如何影响模型的准确性。我们将为ϵ\epsilonϵ的多个值训练一个模型,每次使用 20 次迭代,并根据训练时使用的ϵ\epsilonϵ值绘制每个模型的准确性图。

delta = 1e-5epsilons = [0.001, 0.003, 0.005, 0.008, 0.01, 0.03, 0.05, 0.08, 0.1]
thetas   = [noisy_gradient_descent(10, epsilon, delta) for epsilon in epsilons]
accs     = [accuracy(theta) for theta in thetas]
plt.xlabel('Epsilon')
plt.ylabel('Accuracy')
plt.plot(epsilons, accs);


该图显示,ϵ\epsilonϵ的非常小的值会导致模型的精度大大降低。请记住,我们在绘图中指定的ϵ\epsilonϵ是每次迭代ϵ\epsilonϵ,因此组合后的隐私成本要高得多。

总结

1、梯度下降是一种通过根据损失的梯度更新模型来使损失变小的方法。梯度就像一个多维导数:对于具有多维输入的函数(如上面的损失函数),梯度体现函数的输出相对于输入的每个维度的变化速度。如果梯度在特定维度中为正,则意味着如果我们增加该维度的模型权重,则该函数的值将增加;我们希望损失减少,因此我们应该通过朝着梯度的反方向来修改我们的模型,即做与梯度相反的事情。由于我们沿梯度相反的方向移动模型,因此这称为梯度下降。

2、一般来说,更多的训练迭代可以提高准确性,但更多的迭代需要更多的计算时间。大多数用于使大规模深度学习变得实用的"技巧"实际上都是为了加快梯度下降的每次迭代,以便在相同的时间内执行更多的迭代。

3、我们的目的是使得最终模型不会显示有关单个训练示例的任何信息。算法中唯一使用训练数据的部分是梯度计算。使算法具有差分隐私的一种方法是在每次迭代时在更新模型之前向梯度本身添加噪声。这种方法通常称为噪声梯度下降,因为我们直接将噪声添加到梯度中。

4、这里有两个主要挑战。首先,梯度是平均查询的结果,它是每个示例的许多梯度的平均值。正如我们之前所看到的,最好将此类查询拆分为总和查询和计数查询。这并不难做到,我们可以计算每个示例梯度的总和,而不是它们的平均值,并在以后除以噪声计数。其次,我们需要绑定每个示例梯度的灵敏度。有两种基本方法:我们可以分析梯度函数本身(就像我们在之前的查询中所做的那样)来确定其最坏情况下的全局灵敏度,或者我们可以通过剪裁梯度函数的输出来强制执行灵敏度(就像我们在样本和聚合中所做的那样)。

5、渐变剪裁算法的每次迭代都满足(ϵ,δ)(\epsilon, \delta)(ϵ,δ)-差分隐私,我们执行一个额外的查询来确定满足ϵ\epsilonϵ-差分隐私的噪声计数。如果我们执行kkk迭代,则通过顺序组合,算法满足(kϵ+ϵ,kδ)(k\epsilon + \epsilon, k\delta)(kϵ+ϵ,kδ)-差分隐私。我们还可以使用高级组合来分析总隐私成本;更好的是,我们可以将算法转换为 Rényi 差分隐私或零集中差分隐私,并获得隐私成本的严格限制。

6、我们之前的方法非常通用,因为它不对梯度的行为做出任何假设。然而,有时我们确实对梯度的行为有所了解。特别是,一大类有用的梯度函数(包括我们在这里使用的逻辑损失的梯度)是利普希茨连续,这意味着它们具有有界的全局灵敏度。

7、裁剪训练示例而不是梯度有两个优点。首先,估计训练数据的比例(从而选择一个好的裁剪参数)通常比估计训练期间将要计算的梯度的尺度更容易。其次,它在计算上更有效:我们可以裁剪一次训练示例,并在每次训练模型时重用裁剪的训练数据。使用渐变剪切,我们需要在训练期间修剪每个梯度。此外,我们不再被迫计算每个示例的梯度,以便我们可以裁剪它们,相反,我们可以一次计算所有梯度,这可以非常有效地完成(这是机器学习中常用的技巧,但我们不会在这里讨论它)。

8、可以合理地预期,ϵ\epsilonϵ的值越小,模型的精度就越低(因为这是我们迄今为止看到的每个差分隐私算法的趋势)。这是事实,但也有一个稍微更微妙的权衡,这是由于我们在执行算法的多次迭代时需要考虑的组成:更多的迭代意味着更大的隐私成本。在标准梯度下降算法中,迭代次数越多,通常会产生更好的模型。在我们的差分隐私版本中,更多的迭代可能会使模型变得更糟,因为我们必须为每次迭代使用较小的ϵ\epsilonϵ,因此噪声的规模会上升。在差分隐私机器学习中,在使用的迭代次数和添加的噪声规模之间取得适当的平衡是很重要的(有时是非常具有挑战性的)。

【机器学习与差分隐私代码实现】差分隐私代码实现系列(十二)相关推荐

  1. java死锁业务场景_【深入浅出多线程系列十二】:什么是死锁?(场景+代码示例)...

    在学习Java的道路上,是否路过多线程时总让你很迷惘:很不巧,我也是,而使我们感到很迷惘主要原因都源于没有对概念的深深的理解和实践.所以我决定漫步Java多线程,同你一起会会多线程. 多线程系列 多线 ...

  2. 深入理解机器学习:从理论到算法-习题全解之第十二章:凸学习问题

  3. 【链接攻击,差分攻击,去标识化代码实现】差分隐私代码实现系列(二)

    差分隐私代码实现系列(二) 写在前面的话 去识别化(De-identification) 数据处理 去识别化操作 链接攻击 Karrie特别吗? 我们可以重新识别多少人? 聚合(Aggregation ...

  4. 隐私计算之差分隐私-Laplace机制

    1 背景 在这个信息膨胀的大数据智能时代,如何安全获取与使用个人的相关数据,渐渐成为迫切需要解决的问题.基于大数据的人工智能应用层出不穷,每个人都感觉自己在被时刻的跟踪,感觉在整个网络面前没有丝毫的隐 ...

  5. 【差分隐私入门】差分隐私系统学习记录 (一)

    The Algorithmic Foundations of Differential Privacy (一) 写在前面的话 The Promise of Differential Privacy B ...

  6. 差分进化算法_差分进化算法

    差分进化算法(Differential Evolution Algorithm,DE)是一种高效的全局优化算法.是一种模拟生物进化的随机模型,通过反复迭代,使得那些适应环境的个体被保存了下来.它的进化 ...

  7. 差分数组 and 树上差分

    差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易 ...

  8. 机器学习算法一览(附python和R代码)

     机器学习算法一览(附python和R代码) 来源:数据观 时间:2016-04-19 15:20:43 作者:大数据文摘 "谷歌的无人车和机器人得到了很多关注,但我们真正的未来却在于能 ...

  9. ML之Validation:机器学习中模型验证方法的简介、代码实现、案例应用之详细攻略

    ML之Validation:机器学习中模型验证方法的简介.代码实现.案例应用之详细攻略 目录 模型验证方法的简介 1.Hold-out验证 2.K-折交叉验证 3.自助重采样 模型验证方法的代码实现 ...

最新文章

  1. 黄聪:DEDECMS系统栏目、文章页面、分页面伪静态和域名301重定向详细方法
  2. Win8下的SAP安装初体验
  3. [批处理]使用Log.io监控日志变化
  4. 利用Serverless Kubernetes和Kaniko快速自动化构建容器镜像
  5. 多租户saas 架构_实战复盘:toB产品的多租户架构设计
  6. php7 viewmodel,【初念科技】| php框架实例: Laravel之Model Observer模型
  7. 千万不要错过云计算兴起的时代
  8. Linux卸载JDK的方法
  9. 基于二叉链表的二叉树最大宽度的计算
  10. Java学习手册:JDBC中getString()方法与getObject()方法有什么区别?
  11. 计算机桌面维护的相关知识,电脑维护知识
  12. python源码中明明没有逻辑代码 为什么还能执行呢
  13. java duplicate_java中出现duplicate local variable
  14. 中国石油大学(北京)-《机器人设计》第一阶段在线作业
  15. matlab用摄像头拍照,matlab调用摄像头拍照
  16. 解决:Activiti7与SpringBoot整合时,默认生成的activiti数据库中只有17张表,无另外8张历史表
  17. 极米H3S和坚果J10S对比,5000元投影仪到底哪个好?
  18. 【积跬步以至千里】Markdownpad2报错: Html Rendering Error:An error occurred with the HTML rendering component。
  19. MySQL定位慢查询步骤
  20. 【Activiti工作流】5. 简单请假流程

热门文章

  1. NTA高性能Flow负载均衡及其应用
  2. TypeScript入门教程 之 模板字符串
  3. Design-patterns-JS:用JavaScript实现23种设计模式
  4. DreamFacotry 第6章 将业务逻辑集成到DreamFactory API中
  5. 容器编排技术 -- Google Computer Engine入门
  6. Spring Batch示例教程
  7. RIP报文封装、OSPF封装、OSPF——cost值
  8. leaflet 结合 Echarts4 实现散点图(附源码下载)
  9. MongoDB 安装与基本命令
  10. windows git密码 删除