PrivacyEngine(module, batch_size, sample_size, alphas, noise_multiplier, max_grad_norm, secure_rng=False, batch_first=True, target_delta=1e-06, loss_reduction='mean', **misc_settings)¶
The main component of Opacus is the
To train a model with differential privacy, all you need to do is to define a
PrivacyEngineand later attach it to your optimizer before running.
This example shows how to define a
PrivacyEngineand to attach it to your optimizer.
>>> import torch >>> model = torch.nn.Linear(16, 32) # An example model >>> optimizer = torch.optim.SGD(model.parameters(), lr=0.05) >>> privacy_engine = PrivacyEngine(model, batch_size, sample_size, alphas=range(2,32), noise_multiplier=1.3, max_grad_norm=1.0) >>> privacy_engine.attach(optimizer) # That's it! Now it's business as usual.
Module) – The Pytorch module to which we are attaching the privacy engine
int) – Training batch size. Used in the privacy accountant.
int) – The size of the sample (dataset). Used in the privacy accountant.
float) – The ratio of the standard deviation of the Gaussian noise to the L2-sensitivity of the function to which the noise is added
bool) – If on, it will use
torchcsprngfor secure random number generation. Comes with a significant performance cost, therefore it’s recommended that you turn it off when just experimenting.
bool) – 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, ..., ...].
float) – The target delta
str) – Indicates if the loss reduction (for aggregating the gradients) is a sum or a mean operation. Can take values “sum” or “mean”
**misc_settings – Other arguments to the init
Attaches the privacy engine to the optimizer.
Attaches to the
PrivacyEnginean optimizer object,and injects itself into the optimizer’s step. To do that it,
Validates that the model does not have unsupported layers.
Adds a pointer to this object (the
PrivacyEngine) inside the optimizer.
Moves optimizer’s original
4. Monkeypatches the optimizer’s
step()function to call
step()on the query engine automatically whenever it would call
Optimizer) – The optimizer to which the privacy engine will attach
Detaches the privacy engine from optimizer.
To detach the
PrivacyEnginefrom optimizer, this method returns the model and the optimizer to their original states (i.e. all added attributes/methods will be removed).
Computes the (epsilon, delta) privacy budget spent so far.
This method converts from an (alpha, epsilon)-DP guarantee for all alphas that the
PrivacyEnginewas initialized with. It returns the optimal alpha together with the best epsilon.
Takes a step for the privacy engine.
You should not call this method directly. Rather, by attaching your
PrivacyEngineto the optimizer, the
PrivacyEnginewould have the optimizer call this method for you.
ValueError – If the last batch of training epoch is greater than others. This ensures the clipper consumed the right amount of gradients. In the last batch of a training epoch, we might get a batch that is smaller than others but we should never get a batch that is too large
Moves the privacy engine to the target device.
device]) – The device on which Pytorch Tensors are allocated. See: https://pytorch.org/docs/stable/tensor_attributes.html#torch.torch.device
This example shows the usage of this method, on how to move the model after instantiating the
>>> model = torch.nn.Linear(16, 32) # An example model. Default device is CPU >>> privacy_engine = PrivacyEngine(model, batch_size, sample_size, alphas=range(5,64), noise_multiplier=0.8, max_grad_norm=0.5) >>> device = "cuda:3" # GPU >>> model.to(device) # If we move the model to GPU, we should call the to() method of the privacy engine (next line) >>> privacy_engine.to(device)
Takes a virtual step.
Virtual batches enable training with arbitrary large batch sizes, while keeping the memory consumption constant. This is beneficial, when training models with larger batch sizes than standard models.
Imagine you want to train a model with batch size of 2048, but you can only fit batch size of 128 in your GPU. Then, you can do the following:
>>> for i, (X, y) in enumerate(dataloader): >>> logits = model(X) >>> loss = criterion(logits, y) >>> loss.backward() >>> if i % 16 == 15: >>> optimizer.step() # this will call privacy engine's step() >>> optimizer.zero_grad() >>> else: >>> optimizer.virtual_step() # this will call privacy engine's virtual_step()
The rough idea of virtual step is as follows:
loss.backward()repeatedly stores the per-sample gradients for all mini-batches. If we call
Ntimes on mini-batches of size
B, then each weight’s
.grad_samplefield will contain
NxBgradients. Then, when calling
step(), the privacy engine clips all
NxBgradients and computes the average gradient for an effective batch of size
NxB. A call to
optimizer.zero_grad()erases the per-sample gradients.
2. By calling
Bper-sample gradients for this mini-batch are clipped and summed up into a gradient accumulator. The per-sample gradients can then be discarded. After
Niterations (alternating calls to
virtual_step()), a call to
step()will compute the average gradient for an effective batch of size
The advantage here is that this is memory-efficient: it discards the per-sample gradients after every mini-batch. We can thus handle batches of arbitrary size.
Resets clippers status.
Clipper keeps internal gradient per sample in the batch in each
forwardcall of the module, they need to be cleaned before the next round.
If these variables are not cleaned the per sample gradients keep being concatenated accross batches. If accumulating gradients is intented behavious, e.g. simulating a large batch, prefer using