-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0dc125a
commit 6bcbdf6
Showing
30 changed files
with
21,131 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import torch | ||
import torch.nn.functional as F | ||
|
||
|
||
class FGM: | ||
def __init__(self, model, emb_name='embedding.'): | ||
self.model = model | ||
self.emb_backup = {} # restore embedding parameters | ||
self.epsilon = 1.0 | ||
self.emb_name = emb_name | ||
|
||
def train(self, input_data, labels, optimizer): | ||
''' define process of training here according to your model define | ||
''' | ||
pass | ||
|
||
def train_bert(self, token, segment, mask, labels, optimizer, attack=False): | ||
''' a advertisement training demo for bert | ||
''' | ||
outputs = self.model(token, segment, mask) | ||
loss = F.cross_entropy(outputs, labels) | ||
loss.backward() | ||
|
||
if attack: | ||
self.attack_embedding() | ||
outputs = self.model(token, segment, mask) | ||
loss = F.cross_entropy(outputs, labels) | ||
# self.model.zero_grad() # compute advertise samples' grad only | ||
loss.backward() | ||
self.restore_embedding() # recover | ||
optimizer.step() | ||
self.model.zero_grad() | ||
|
||
return outputs, loss | ||
|
||
def attack_embedding(self, backup=True): | ||
''' add add disturbance in embedding layer you want | ||
''' | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
if backup: # store parameter | ||
self.emb_backup[name] = param.data.clone() | ||
|
||
self._add_disturbance(name, param) # add disturbance | ||
|
||
def restore_embedding(self): | ||
'''recover embedding backup before | ||
''' | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
assert name in self.emb_backup | ||
param.data = self.emb_backup[name] | ||
self.emb_backup = {} | ||
|
||
def _add_disturbance(self, name, param): | ||
''' add disturbance | ||
''' | ||
norm = torch.norm(param.grad) | ||
if norm != 0: | ||
r_at = self.epsilon * param.grad / norm | ||
param.data.add_(r_at) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import numpy as np | ||
import torch.nn.functional as F | ||
|
||
|
||
class FGSM: | ||
def __init__(self, model, epsilon=0.05, emb_name='embedding.'): | ||
self.model = model | ||
self.emb_backup = {} | ||
self.epsilon = epsilon | ||
self.emb_name = emb_name | ||
|
||
def train(self, input_data, labels, optimizer): | ||
''' define process of training here according to your model define | ||
''' | ||
pass | ||
|
||
def train_bert(self, token, segment, mask, labels, optimizer, attack=False): | ||
''' add disturbance in training | ||
''' | ||
outputs = self.model(token, segment, mask) | ||
loss = F.cross_entropy(outputs, labels) | ||
loss.backward() | ||
|
||
if attack: | ||
self.attack_embedding() | ||
outputs = self.model(token, segment, mask) | ||
loss = F.cross_entropy(outputs, labels) | ||
# self.model.zero_grad() # compute advertise samples' grad only | ||
loss.backward() | ||
self.restore_embedding() # recover | ||
optimizer.step() | ||
self.model.zero_grad() | ||
|
||
return outputs, loss | ||
|
||
def attack_param(self, name, param): | ||
# r_at = epsilon * sign(grad) | ||
r_at = self.epsilon * np.sign(param.grad) | ||
param.data.add_(r_at) | ||
|
||
def attack_embedding(self, backup=True): | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
if backup: | ||
self.emb_backup[name] = param.data.clone() | ||
# attack embedding | ||
self.attack_param(name, param) | ||
|
||
def restore_embedding(self): | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
assert name in self.emb_backup | ||
param.data = self.emb_backup[name] | ||
self.emb_backup = {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import torch | ||
import torch.nn.functional as F | ||
|
||
|
||
|
||
class FreeAT: | ||
def __init__(self, model, epsilon=0.8, k=3, emb_name='embedding.'): | ||
self.model = model | ||
self.emb_backup = {} | ||
self.epsilon = epsilon | ||
self.K = k # attack times | ||
self.emb_name = emb_name # embedding layer name want to attack | ||
self.backup_emb() | ||
|
||
def train(self, input_data, labels, optimizer): | ||
''' define process of training here according to your model define | ||
''' | ||
pass | ||
|
||
def train_bert(self, token, segment, mask, labels, optimizer, attack=True): | ||
''' add disturbance in training | ||
''' | ||
outputs = self.model(token, segment, mask) | ||
loss = F.cross_entropy(outputs, labels) | ||
loss.backward() | ||
|
||
if attack: | ||
for t in range(self.K): | ||
outputs = self.model(token, segment, mask) | ||
self.model.zero_grad() | ||
loss = F.cross_entropy(outputs, labels) | ||
loss.backward() | ||
optimizer.step() | ||
self.attack_emb(backup=False) # accumulate projected disturb in embedding | ||
|
||
return outputs, loss | ||
|
||
def attack_param(self, name, param): | ||
'''add disturbance | ||
FreeAT Format: | ||
r[t+1] = r[t] + epsilon * sign(grad) | ||
r_at = epsilon * np.sign(param.grad) | ||
''' | ||
norm = torch.norm(param.grad) | ||
if norm != 0: | ||
r_at = self.epsilon * param.grad / norm | ||
param.data.add_(r_at) | ||
param.data = self.project(name, param.data) | ||
|
||
def project(self, param_name, param_data): | ||
''' projected disturbance like disturb cropping inside the pale (-eps, eps) | ||
''' | ||
r = param_data - self.emb_backup[param_name] # compute disturbance | ||
if torch.norm(r) > self.epsilon: # disturbance cropping inside the pale (-eps, eps) | ||
r = self.epsilon * r / torch.norm(r) | ||
return self.emb_backup[param_name] + r | ||
|
||
def attack_emb(self, backup=False): | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
if backup: # backup embedding | ||
self.emb_backup[name] = param.data.clone() | ||
self.attack_param(name, param) | ||
|
||
def backup_emb(self): | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
self.emb_backup[name] = param.data.clone() | ||
|
||
def restore_emb(self): | ||
'''recover embedding''' | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
assert name in self.emb_backup | ||
param.data = self.emb_backup[name] | ||
self.emb_backup = {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import torch | ||
import torch.nn.functional as F | ||
|
||
|
||
class PGD: | ||
def __init__(self, model, epsilon=1.0, alpha=0.3, k=3, emb_name='embedding.'): | ||
self.model = model | ||
self.emb_backup = {} | ||
self.grad_backup = {} | ||
self.epsilon = epsilon | ||
self.alpha = alpha | ||
self.K = k # PGD attack times | ||
self.emb_name = emb_name | ||
|
||
def train(self, input_data, labels, optimizer): | ||
''' define process of training here according to your model define | ||
''' | ||
pass | ||
|
||
def train_bert(self, token, segment, mask, labels, optimizer, attack=True): | ||
''' a advertisement training demo for bert | ||
''' | ||
outputs = self.model(token, segment, mask) | ||
loss = F.cross_entropy(outputs, labels) | ||
loss.backward() | ||
|
||
if attack: | ||
self.backup_grad() | ||
for t in range(self.K): | ||
self.attack_embedding(backup=(t == 0)) | ||
if t != self.K - 1: | ||
self.model.zero_grad() | ||
else: | ||
self.restore_grad() | ||
outputs = self.model(token, segment, mask) | ||
loss = F.cross_entropy(outputs, labels) | ||
loss.backward() | ||
self.restore_embedding() # recover embedding | ||
optimizer.step() | ||
self.model.zero_grad() | ||
|
||
return outputs, loss | ||
|
||
def attack_param(self, name, param): | ||
'''add disturbance | ||
PGD: r = epsilon * grad / norm(grad) | ||
''' | ||
norm = torch.norm(param.grad) | ||
if norm != 0 and not torch.isnan(norm): | ||
r_at = self.alpha * param.grad / norm | ||
param.data.add_(r_at) | ||
param.data = self.project(name, param.data) | ||
|
||
def project(self, param_name, param_data): | ||
''' projected disturbance like parameter cropping inside the pale | ||
''' | ||
r = param_data - self.emb_backup[param_name] | ||
if torch.norm(r) > self.epsilon: | ||
r = self.epsilon * r / torch.norm(r) | ||
return self.emb_backup[param_name] + r | ||
|
||
def attack_embedding(self, backup=False): | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
if backup: # backup embedding | ||
self.emb_backup[name] = param.data.clone() | ||
self.attack_param(name, param) | ||
|
||
def backup_embedding(self): | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
self.emb_backup[name] = param.data.clone() | ||
|
||
def restore_embedding(self): | ||
'''recover embedding''' | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and self.emb_name in name: | ||
assert name in self.emb_backup | ||
param.data = self.emb_backup[name] | ||
self.emb_backup = {} | ||
|
||
def backup_grad(self): | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and param.grad is not None: | ||
self.grad_backup[name] = param.grad.clone() | ||
|
||
def restore_grad(self): | ||
'''recover grad back upped | ||
''' | ||
for name, param in self.model.named_parameters(): | ||
if param.requires_grad and name in self.grad_backup: | ||
param.grad = self.grad_backup[name] |
Oops, something went wrong.