-
Notifications
You must be signed in to change notification settings - Fork 0
/
privacy_engine_xl.py
187 lines (166 loc) · 6.76 KB
/
privacy_engine_xl.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
import torch
import opacus
from typing import List, Union
import os
def generate_noise(max_norm, parameter, noise_multiplier, noise_type, device):
"""
A noise generation function that can utilize different distributions for noise generation.
@param max_norm
The maximum norm of the per-sample gradients. Any gradient with norm
higher than this will be clipped to this value.
@param parameter
The parameter, based on which the dimension of the noise tensor
will be determined
@param noise_multiplier
The ratio of the standard deviation of the Gaussian noise to
the L2-sensitivity of the function to which the noise is added
@param noise_type
Sets the distribution for the noise generation.
See generate_noise for supported strings.
@param device
The device used for calculations and needed for tensor definition.
@return
a tensor of noise in the same shape as ``parameter``.
"""
if noise_multiplier > 0:
mean = 0
scale_scalar = noise_multiplier * max_norm
scale = torch.full(size=parameter.shape, fill_value=scale_scalar, dtype=torch.float32, device=device)
if noise_type.lower() in ["normal", "gauss", "gaussian"]:
dist = torch.distributions.normal.Normal(mean, scale)
elif noise_type.lower() in ["laplace", "laplacian"]:
dist = torch.distributions.laplace.Laplace(mean, scale)
elif noise_type.lower() in ["exponential"]:
rate = 1 / scale
dist = torch.distributions.exponential.Exponential(rate)
else:
dist = torch.distributions.normal.Normal(mean, scale)
noise = dist.sample()
return noise
return 0.0
# Server side Noise
def apply_noise(weights, batch_size, max_norm, noise_multiplier, noise_type, device, loss_reduction="mean", clipping=False):
"""
A function for applying noise to weights on the (intermediate) server side that utilizes the generate_noise function above.
@param weights
The weights to which to apply the noise.
@param batch_size
Batch size used for averaging.
@param max_norm
The maximum norm of the per-sample gradients. Any gradient with norm
higher than this will be clipped to this value.
@param noise_multiplier
The ratio of the standard deviation of the Gaussian noise to
the L2-sensitivity of the function to which the noise is added
@param noise_type
Sets the distribution for the noise generation.
See generate_noise for supported strings.
@param device
The device used for calculations and needed for tensor definition.
@param loss_reduction
The method of loss reduction.
currently supported: mean
"""
if isinstance(weights, dict):
weights = weights.values()
if max_norm == None:
max_norm = 1.0
for p in weights:
if clipping:
norm = torch.norm(p, p=2)
div_norm = max(1, norm/max_norm)
p /= div_norm
noise = generate_noise(max_norm, p, noise_multiplier, noise_type, device)
if loss_reduction == "mean":
noise /= batch_size
p += noise
# Client side Noise
class PrivacyEngineXL(opacus.PrivacyEngine):
"""
A privacy engine that can utilize different distributions for noise generation, based on opacus' privacy engine.
It gets attached to the optimizer just like the privacy engine from opacus.
@param module:
The Pytorch module to which we are attaching the privacy engine
@param batch_size
Training batch size. Used in the privacy accountant.
@param sample_size
The size of the sample (dataset). Used in the privacy accountant.
@param alphas
A list of RDP orders
@param noise_multiplier
The ratio of the standard deviation of the Gaussian noise to
the L2-sensitivity of the function to which the noise is added
@param max_grad_norm
The maximum norm of the per-sample gradients. Any gradient with norm
higher than this will be clipped to this value.
@param secure_rng
If on, it will use ``torchcsprng`` for secure random number generation. Comes with
a significant performance cost, therefore it's recommended that you turn it off when
just experimenting.
@param grad_norm_type
The order of the norm. For instance, 2 represents L-2 norm, while
1 represents L-1 norm.
@param batch_first
Flag to indicate if the input tensor to the corresponding module
has the first dimension representing the batch. If set to True,
dimensions on input tensor will be ``[batch_size, ..., ...]``.
@param target_delta
The target delta
@param loss_reduction
Indicates if the loss reduction (for aggregating the gradients)
is a sum or a mean operation. Can take values "sum" or "mean"
@param noise_type
Sets the distribution for the noise generation.
See generate_noise for supported strings.
@param **misc_settings
Other arguments to the init
"""
def __init__(
self,
module: torch.nn.Module,
batch_size: int,
sample_size: int,
alphas: List[float],
noise_multiplier: float,
max_grad_norm: Union[float, List[float]],
secure_rng: bool = False,
grad_norm_type: int = 2,
batch_first: bool = True,
target_delta: float = 1e-6,
loss_reduction: str = "mean",
noise_type: str="gaussian",
**misc_settings
):
import warnings
if secure_rng:
warnings.warn(
"Secure RNG was turned on. However it is not yet implemented for the noise distributions of privacy_engine_xl."
)
opacus.PrivacyEngine.__init__(
self,
module,
batch_size,
sample_size,
alphas,
noise_multiplier,
max_grad_norm,
secure_rng,
grad_norm_type,
batch_first,
target_delta,
loss_reduction,
**misc_settings)
self.noise_type = noise_type
def _generate_noise(self, max_norm, parameter):
"""
Generates a tensor of noise in the same shape as ``parameter``.
@param max_norm
The maximum norm of the per-sample gradients. Any gradient with norm
higher than this will be clipped to this value.
@param parameter
The parameter, based on which the dimension of the noise tensor
will be determined
@return
a tensor of noise in the same shape as ``parameter``.
"""
return generate_noise(max_norm, parameter, self.noise_multiplier, self.noise_type, self.device)