常见问题
什么是 Opacus?
Opacus 是一个库,它支持使用差分隐私训练 PyTorch 模型。它支持在客户端上只需最少的代码更改即可进行训练,对训练性能影响很小,并允许客户端在线跟踪任何给定时刻的隐私预算。请参阅这篇论文以了解有关 Opacus 的更多信息。
Opacus 是开源的吗?许可证是什么?
是的!Opacus 是开源的,可供公众使用,并根据 Apache 2.0 许可证授权。
如何报告错误或提问?
您可以通过提交 GitHub issue 来报告错误或提问。要提交 GitHub issue,请点击此处。
我想为 Opacus 贡献代码。我该怎么做?
感谢您对为 Opacus 贡献代码感兴趣!请在此处使用 GitHub 拉取请求提交您的贡献。请查看Opacus 贡献指南。
如果我在论文中使用 Opacus,该如何引用它?
如果您在论文中使用 Opacus,可以按以下方式引用:
@article{opacus,
title={Opacus: {U}ser-Friendly Differential Privacy Library in {PyTorch}},
author={Ashkan Yousefpour and Igor Shilov and Alexandre Sablayrolles and Davide Testuggine and Karthik Prasad and Mani Malek and John Nguyen and Sayan Ghosh and Akash Bharadwaj and Jessica Zhao and Graham Cormode and Ilya Mironov},
journal={arXiv preprint arXiv:2109.12298},
year={2021}
}
什么是 DP-SGD?
DP-SGD 是这篇论文中描述的算法;Opacus 是它的 PyTorch 实现。请参阅这篇博客文章以了解有关 DP-SGD 的更多信息。
如何附加隐私引擎?
使用 Opacus 进行训练就像实例化一个 PrivacyEngine 并将其附加到 optimizer 一样简单
# define your components as usual
model = Net()
optimizer = SGD(model.parameters(), lr=0.05)
data_loader = torch.utils.data.DataLoader(dataset, batch_size=1024)
# enter PrivacyEngine
privacy_engine = PrivacyEngine()
model, optimizer, data_loader = privacy_engine.make_private(
module=model,
optimizer=optimizer,
data_loader=data_loader,
noise_multiplier=1.1,
max_grad_norm=1.0,
)
# Now it's business as usual
PrivacyEngine 中的 secure_rng 参数是什么?
并非所有的伪随机数生成器 (RNG) 都是平等的。它们中的大多数(包括 Python 和 PyTorch 的默认生成器,它们基于梅森旋转法)无法支持加密应用程序所需的随机性质量。符合条件的 RNG 通常被称为加密安全 RNG (CSPRNG),CSPRNGs。Opacus 支持 torchcsprng 库提供的 CSPRNG。此选项通过将 secure_rng 设置为 True 来控制。
然而,使用 CSPRNG 会带来巨大的性能损失,因此我们通常建议您将 secure_rng 设置为 False 进行实验。一旦您确定了适用于您的应用程序的训练方案(即模型的架构、正确的超参数、训练时长等),那么我们建议您将其打开并从头开始再次训练,以便您的最终模型可以享受由此带来的安全性。
我的模型在默认隐私设置下不收敛。我该怎么办?
Opacus 有几个控制噪声量的设置,这会影响收敛。最重要的是 noise_multiplier,通常设置在 0.1 到 2 之间。在其他条件不变的情况下,高斯噪声的标准差与 noise_multiplier 成正比,这意味着将其缩小会使梯度计算更准确,但隐私性更差。
下一个要调整的参数是学习率。与非私有训练相比,Opacus 训练的模型以较小的学习率收敛(每次梯度更新都更嘈杂,因此我们希望采取更小的步骤)。
列表中的下一个是 max_grad_norm。它设置了一个阈值,Opacus 在此阈值之上裁剪梯度,从而损害收敛性。更深层次的模型受此阈值的影响较小,而线性模型如果其值未设置正确,可能会受到严重损害。
如果这些干预措施没有帮助(或者模型开始收敛但其隐私性不佳),那么是时候仔细研究模型架构或其组件了。[Papernot et al. 2019] 可以是一个很好的起点。
如何处理内存不足错误?
处理每样本梯度不可避免地会给您的内存带来更大的压力:毕竟,如果您想以 64 的批处理大小进行训练,您将需要保留 64 份参数梯度。要做的第一个健全性检查是确保您在“标准”训练(没有 DP)下不会内存不足。这应该保证您至少可以以 1 的批处理大小进行训练。然后,您可以像往常一样使用例如 nvidia-smi 检查您的内存使用情况,逐渐增加批处理大小,直到找到您的最佳点。请注意,这可能意味着您仍然以小批量大小进行训练,这有其自身的训练行为(即批次之间的方差更高)。使用更大的批处理大小可能是有益的。为此,我们构建了快速梯度裁剪和 virtual_step(请参阅常见问题中的什么是虚拟批处理大小)以使 DP-SGD 内存高效。
epsilon=1.1 到底是什么意思?delta 呢?
(epsilon, delta) 对量化了 DP-SGD 算法的隐私属性(参见博客文章)。使用 (epsilon, delta)-差分隐私 (DP) 训练的模型可以保护任何训练示例的隐私,无论该示例多么奇怪、不合适或完美。
形式上,(epsilon, delta)-DP 声明意味着在两个仅在一个示例上有所不同的数据集 D 和 D′ 上训练的模型 W 的输出概率是接近的:
这个声明延伸到该模型的所有下游用途:其推断、微调、蒸馏等。换句话说,如果 (epsilon, delta)-DP 属性符合您的隐私目标,那么发布整个模型——其架构、权重、激活函数——在隐私方面是没问题的。
从上面的表达式可以明显看出,epsilon 和 delta 扮演着不同的角色:epsilon 控制基线概率的乘性增加,而 delta 以相同的量提升所有概率。例如,如果您的基线场景(在 D′ 上训练的模型,不包含您的数据)将某个事件的概率指定为 0,那么在 D(包含您的数据)上观察到该事件的上限是 delta。因此,我们希望将 epsilon 定位为一个小常数,并将 delta 选择为微小。一个经验法则是将 delta 设置为小于训练数据集大小的倒数。
Epsilon 和 delta 是在优化器运行后事后计算的。实际上,对于每个 delta,都有一个 epsilon,取决于该 delta,使得运行满足 (epsilon, delta)-DP。调用 privacy_engine.get_epsilon(delta=delta) 在其第一个返回值中输出该 epsilon。
重要的是,(epsilon, delta)-DP 是对实际隐私损失的保守上限。有越来越多的证据表明,DP-SGD 算法可观测到的隐私损失可能显著更小。
批处理大小如何影响我的隐私预算?
假设批次是随机选择的,批处理大小的增加会增加采样率,从而增加隐私预算。这种效应可以通过选择更大的学习率(因为每个批次的梯度更好地近似于模型的真实梯度)和提前中止训练来抵消。
我的模型抛出了 IncompatibleModuleException。这是怎么回事?
您的模型很可能包含与 Opacus 不兼容的模块。这些模块中最突出的例子是批归一化类型。在验证您的模型之前,尝试使用 ModuleValidator.fix(model) 修复不兼容的模块,如此处所述。
什么是虚拟批处理大小?
Opacus 在底层计算并存储每样本梯度。这意味着,对于优化器期望的每个常规梯度,Opacus 将在每一步存储 batch_size 个每样本梯度。为了平衡峰值内存需求(与 batch_size ^ 2 成比例)和训练性能,我们使用虚拟批处理。通过虚拟批处理,我们可以将物理步骤(梯度计算)和逻辑步骤(噪声添加和参数更新)分开:使用更大的批次进行训练,同时保持低内存占用。有关无缝集成到您的训练代码中,请参阅批处理内存管理器。
什么是 alphas?
尽管我们使用 (epsilon, delta) 语言报告已使用的隐私预算,但在内部,我们使用 Rényi 差分隐私 (RDP) 来跟踪它 [Mironov 2017, Mironov 等人 2019]。简而言之,(alpha, epsilon)-RDP 界定了在单个元素上有所不同的任意两个数据集上机制输出分布的 alpha 阶 Rényi 散度。(alpha, epsilon)-RDP 声明是 epsilon-DP 的放宽,但保留了其许多重要属性,这些属性使得 RDP 特别适合 DP-SGD 的隐私分析。alphas 参数指示隐私引擎使用哪些 RDP 阶来跟踪隐私支出。
当隐私引擎需要为给定的 delta 使用 (epsilon, delta)-DP 来限制训练运行的隐私损失时,它会从 alphas 中搜索最佳阶。扩展阶列表的额外成本非常小。我们建议使用列表 [1 + x / 10.0 for x in range(1, 100)] + list(range(12, 64))。
调用 privacy_engine.get_epsilon(delta=delta) 返回一对值:一个 epsilon,使得训练运行满足 (epsilon, delta)-DP,以及一个最优阶 alpha。一个简单的诊断方法,用于确定 alphas 列表是否应该扩展,是查看返回的 alpha 值是否是 alphas 的两个边界值之一。