Skip to content

Commit 2800fd8

Browse files
authored
feat: LOKT attack method (#58)
* feat: simple tcgan for lokt * fix: trainer error * feat: lokt trainer * feat: raw lokt attacker * feat: lokt * lokt readme * fix: name error in lokt * fix: lokt error & lokt attack script
1 parent 3e9e9c4 commit 2800fd8

15 files changed

Lines changed: 1014 additions & 20 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ The reason why we developed this toolbox is that the research line of **MI** suf
4545

4646
## :memo: Model Inversion Attacks
4747

48-
|Method|Paper|Publication|Whitebox or Blackbox|Key Characteristics|
48+
|Method|Paper|Publication|Scenario|Key Characteristics|
4949
|:-:|:-:|:-:|:-:|:-:|
5050
|[DeepInversion](./src/modelinversion/attack/DeepInversion/)|Dreaming to Distill: Data-Free Knowledge Transfer via DeepInversion|[CVPR'2020](https://openaccess.thecvf.com/content_CVPR_2020/html/Yin_Dreaming_to_Distill_Data-Free_Knowledge_Transfer_via_DeepInversion_CVPR_2020_paper.html)|whitebox|student-teacher, data-free|
5151
|[GMI](./src/modelinversion/attack/GMI/)|The Secret Revealer: Generative Model-Inversion Attacks Against Deep Neural Networks|[CVPR'2020](https://openaccess.thecvf.com/content_CVPR_2020/html/Zhang_The_Secret_Revealer_Generative_Model-Inversion_Attacks_Against_Deep_Neural_Networks_CVPR_2020_paper.html)|whitebox|the first GAN-based MIA, instance-level|
@@ -58,6 +58,7 @@ The reason why we developed this toolbox is that the research line of **MI** suf
5858
|[C2FMI](./src/modelinversion/attack/C2FMI/)|C2FMI: Corse-to-Fine Black-box Model Inversion Attack|[TDSC'2023](https://ieeexplore.ieee.org/abstract/document/10148574)|whitebox, blackbox|gradient-free, two-stage|
5959
|[Lomma](./src/modelinversion/attack/Lomma/)|Re-Thinking Model Inversion Attacks Against Deep Neural Networks|[CVPR'2023](https://openaccess.thecvf.com/content/CVPR2023/html/Nguyen_Re-Thinking_Model_Inversion_Attacks_Against_Deep_Neural_Networks_CVPR_2023_paper.html)|blackbox|special loss, model augmentation|
6060
|[RLBMI](./src/modelinversion/attack/RLBMI/)|Reinforcement Learning-Based Black-Box Model Inversion Attacks|[CVPR'2023](https://openaccess.thecvf.com/content/CVPR2023/html/Han_Reinforcement_Learning-Based_Black-Box_Model_Inversion_Attacks_CVPR_2023_paper.html)|blackbox|reinforcement learning|
61+
|[LOKT](./src/modelinversion/attack/Lokt/)|Label-Only Model Inversion Attacks via Knowledge Transfer|[NeurIPS'2023](https://openreview.net/forum?id=NuoIThPPag)|blackbox|surrogate models, label-only|
6162

6263

6364

attack_scripts/lokt.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import sys
2+
sys.path.append('.')
3+
sys.path.append('./src')
4+
sys.path.append('./src/modelinversion')
5+
6+
from modelinversion.attack.Lokt.attacker import LoktAttackConfig, LoktAttacker
7+
from development_config import get_dirs
8+
9+
if __name__ == '__main__':
10+
dirs = get_dirs('lokt')
11+
cache_dir, result_dir, ckpt_dir, dataset_dir = dirs['work_dir'], dirs['result_dir'], dirs['ckpt_dir'], dirs['dataset_dir']
12+
13+
# target name support: vgg16, ir152, facenet64, facenet
14+
target_name = 'vgg16'
15+
# eval name support: vgg16, ir152, facenet64, facenet
16+
eval_name = 'facenet'
17+
# gan target name support: vgg16
18+
gan_target_name = 'vgg16'
19+
# dataset name support: celeba
20+
dataset_name = 'celeba'
21+
# gan dataset name support: celeba, ffhq, facescrub
22+
gan_dataset_name = 'celeba'
23+
24+
surrogate_names = ['densenet121', 'densenet161', 'densenet169']
25+
26+
batch_size = 64
27+
target_labels = list(range(0, 10))
28+
device = 'cuda:2'
29+
30+
config = LoktAttackConfig(
31+
target_name=target_name,
32+
eval_name=eval_name,
33+
ckpt_dir=ckpt_dir,
34+
result_dir=result_dir,
35+
dataset_dir=dataset_dir,
36+
cache_dir=cache_dir,
37+
dataset_name=dataset_name,
38+
device=device,
39+
gan_target_name=gan_target_name,
40+
gan_dataset_name=gan_dataset_name,
41+
surrogate_names = surrogate_names
42+
)
43+
44+
attacker = LoktAttacker(config)
45+
46+
attacker.attack(batch_size, target_labels)
47+
48+
attacker.evaluation(200, knn=True, feature_distance=True, fid=True)
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import sys
2+
sys.path.append('.')
3+
sys.path.append('./src')
4+
sys.path.append('./src/modelinversion')
5+
6+
import os
7+
8+
import torch
9+
from torch.utils.data import DataLoader
10+
from torchvision.datasets import ImageFolder
11+
from torchvision.transforms import ToTensor
12+
from modelinversion.attack.Lokt.gan_trainer import LoktGANTrainArgs, LoktGANTrainer
13+
from development_config import get_dirs
14+
15+
from modelinversion.foldermanager import FolderManager
16+
os.environ["CUDA_VISIBLE_DEVICES"] = '1'
17+
if __name__ == '__main__':
18+
batch_size = 64
19+
20+
target_name = 'vgg16'
21+
dataset_name = 'celeba'
22+
device = 'cuda'
23+
24+
dirs = get_dirs('lokt_gan')
25+
cache_dir, result_dir, ckpt_dir, dataset_dir = dirs['work_dir'], dirs['result_dir'], dirs['ckpt_dir'], dirs['dataset_dir']
26+
dataset = ImageFolder(dataset_dir, transform=ToTensor())
27+
epoch_num = 300
28+
29+
# trainloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
30+
31+
train_args = LoktGANTrainArgs(
32+
dataset_name=dataset_name,
33+
batch_size=batch_size,
34+
epoch_num=epoch_num,
35+
device=device,
36+
target_name=target_name,
37+
class_loss_start_iter=15000
38+
)
39+
40+
folder_manager = FolderManager(ckpt_dir, dataset_dir, cache_dir, result_dir, None)
41+
42+
trainer = LoktGANTrainer(train_args, folder_manager)
43+
44+
trainer.train()
45+
# trainer.prepare_training()
46+
# trainer.G.load_state_dict(torch.load('checkpoints/lokt/lokt_celeba_vgg16_G.pt')['state_dict'])
47+
z = torch.randn((8, 128), device=device)
48+
c = torch.arange(0, 8, device=device, dtype=torch.long)
49+
img = trainer.G(z, c)
50+
import torchvision
51+
torchvision.utils.save_image(img, 'aa.png', normalize=True, nrow = 4)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import sys
2+
sys.path.append('.')
3+
sys.path.append('./src')
4+
sys.path.append('./src/modelinversion')
5+
6+
import os
7+
8+
import torch
9+
from torch.utils.data import DataLoader
10+
from torchvision.datasets import ImageFolder
11+
from torchvision.transforms import ToTensor
12+
from modelinversion.attack.Lokt.surrogate_trainer import LoktSurrogateTrainArgs, LoktSurrogateTrainer
13+
from development_config import get_dirs
14+
from modelinversion.models import *
15+
16+
from modelinversion.foldermanager import FolderManager
17+
os.environ["CUDA_VISIBLE_DEVICES"] = '1'
18+
19+
if __name__ == '__main__':
20+
21+
model_name = 'densenet121'
22+
23+
dirs = get_dirs(f'lokt_surrogate_{model_name}')
24+
cache_dir, result_dir, ckpt_dir, dataset_dir, defense_ckpt_dir = dirs['work_dir'], dirs['result_dir'], dirs['ckpt_dir'], dirs['dataset_dir'], dirs['defense_ckpt_dir']
25+
26+
folder_manager = FolderManager(ckpt_dir, dataset_dir, cache_dir, result_dir, defense_ckpt_dir, 'no_defense')
27+
28+
29+
dataset_name = 'celeba'
30+
epoch_num = 200
31+
lr = 0.01
32+
device = 'cuda'
33+
batch_size = 256
34+
35+
train_args = LoktSurrogateTrainArgs(
36+
model_name,
37+
dataset_name,
38+
epoch_num,
39+
device=device,
40+
target_name='vgg16',
41+
target_dataset_name='celeba',
42+
)
43+
44+
model = get_model(model_name, dataset_name, device=device, backbone_pretrain=True)
45+
46+
optimizer = torch.optim.SGD(model.parameters(), lr=lr,
47+
momentum=0.9, weight_decay=5e-4)
48+
scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max = epoch_num)
49+
50+
trainer = LoktSurrogateTrainer(train_args, folder_manager=folder_manager, model=model, optimizer=optimizer, lr_scheduler=scheduler)
51+
52+
trainset = trainer.get_trainset()
53+
54+
trainloader = DataLoader(trainset, batch_size, shuffle=True)
55+
56+
trainer.train(trainloader, None)

src/modelinversion/attack/GMI/gan_trainer.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ def _gradient_penalty(self, real: torch.Tensor, fake: torch.Tensor):
7070

7171
def train_dis_step(self, batch) -> OrderedDict:
7272
args = self.args
73+
74+
batch = batch[0].to(args.device)
7375
bs = len(batch)
7476
z = torch.randn(bs, args.z_dim).to(args.device)
7577

@@ -90,7 +92,7 @@ def train_dis_step(self, batch) -> OrderedDict:
9092

9193
def train_gen_step(self, batch) -> OrderedDict:
9294
args = self.args
93-
bs = len(batch)
95+
bs = len(batch[0])
9496
z = torch.randn(bs, args.z_dim).to(args.device)
9597

9698
fake = self.G(z)

src/modelinversion/attack/KEDMI/gan_trainer.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ def softXEnt(self, input, target):
8181

8282
def train_dis_step(self, batch) -> OrderedDict:
8383
args = self.args
84+
85+
batch = batch[0].to(args.device)
8486
bs = len(batch)
8587
z = torch.randn(bs, args.z_dim).to(args.device)
8688

@@ -114,6 +116,7 @@ def train_dis_step(self, batch) -> OrderedDict:
114116

115117
def train_gen_step(self, batch) -> OrderedDict:
116118
args = self.args
119+
batch = batch[0].to(args.device)
117120
bs = len(batch)
118121
z = torch.randn(bs, args.z_dim).to(args.device)
119122

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import os
2+
from dataclasses import dataclass, field
3+
4+
from ...foldermanager import FolderManager
5+
from ..PLGMI.attacker import PLGMIAttackConfig, PLGMIAttacker
6+
from ...models import *
7+
8+
@dataclass
9+
class LoktAttackConfig(PLGMIAttackConfig):
10+
surrogate_names: list = field(default_factory=lambda: ['vgg16'])
11+
12+
@dataclass
13+
class LoktAttacker(PLGMIAttacker):
14+
15+
def __init__(self, config: LoktAttackConfig) -> None:
16+
self._tag = f'{config.dataset_name}_{config.target_name}_{config.gan_dataset_name}_{config.gan_target_name}'
17+
super().__init__(config)
18+
self.config: LoktAttackConfig
19+
20+
self.surrogate_models = []
21+
22+
23+
def prepare_attack(self):
24+
super().prepare_attack()
25+
26+
config = self.config
27+
folder_manager = self.folder_manager
28+
29+
self.surrogate_models = []
30+
31+
for S_name in config.surrogate_names:
32+
surrogate_model = get_model(S_name, config.dataset_name, device=config.device)
33+
# folder_manager.load_target_model_state_dict(surrogate_model, config.dataset_name, S_name, device=config.device)
34+
folder_manager.load_state_dict(surrogate_model, ['lokt', f'{S_name}_{config.dataset_name}_{self.config.target_name}_{self.config.defense_type}.pt'], device=config.device)
35+
surrogate_model.eval()
36+
self.surrogate_models.append(surrogate_model)
37+
38+
def get_loss(self, fake, iden):
39+
aug_list = self.config.attack_transform
40+
41+
inv_loss = 0
42+
43+
for S in self.surrogate_models:
44+
out1 = S(aug_list(fake)).result
45+
out2 = S(aug_list(fake)).result
46+
47+
inv_loss += self.loss_fn(out1, iden) + self.loss_fn(out2, iden)
48+
return inv_loss / len(self.surrogate_models)
49+
50+
def attack_step(self, iden):
51+
return super().attack_step(iden)

0 commit comments

Comments
 (0)