├── utils
├── __init__.py
└── util.py
├── .idea
├── .name
├── vcs.xml
├── sshConfigs.xml
├── deployment.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── webServers.xml
└── workspace.xml
├── create_backdoor_data
└── Dynamic
│ ├── networks
│ ├── __init__.py
│ ├── lenet.py
│ ├── blocks.py
│ ├── vgg.py
│ ├── mobilenet.py
│ ├── mobilenetv2.py
│ ├── googlenet.py
│ ├── resnext.py
│ ├── dpn.py
│ ├── densenet.py
│ ├── shufflenet.py
│ ├── efficientnet.py
│ ├── resnet.py
│ ├── senet.py
│ ├── pnasnet.py
│ ├── preact_resnet.py
│ ├── models.py
│ └── shufflenetv2.py
│ └── create_dynamic_backdoor_data.py
├── backdoor.png
├── models
├── __init__.py
├── selector.py
├── wresnet.py
├── resnet.py
└── lenet.py
├── networks
├── blocks.py
└── models.py
├── README.md
├── config.py
├── train.py
└── data_loader.py
/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | backdoor_unlearning.py
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backdoor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zaixizhang/CBD/HEAD/backdoor.png
--------------------------------------------------------------------------------
/models/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Data:2020/7/3 20:58
3 | # @Author:lyg
4 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/sshConfigs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/deployment.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/webServers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/lenet.py:
--------------------------------------------------------------------------------
1 | '''LeNet in PyTorch.'''
2 | import torch.nn as nn
3 | import torch.nn.functional as F
4 |
5 | class LeNet(nn.Module):
6 | def __init__(self):
7 | super(LeNet, self).__init__()
8 | self.conv1 = nn.Conv2d(3, 6, 5)
9 | self.conv2 = nn.Conv2d(6, 16, 5)
10 | self.fc1 = nn.Linear(16*5*5, 120)
11 | self.fc2 = nn.Linear(120, 84)
12 | self.fc3 = nn.Linear(84, 10)
13 |
14 | def forward(self, x):
15 | out = F.relu(self.conv1(x))
16 | out = F.max_pool2d(out, 2)
17 | out = F.relu(self.conv2(out))
18 | out = F.max_pool2d(out, 2)
19 | out = out.view(out.size(0), -1)
20 | out = F.relu(self.fc1(out))
21 | out = F.relu(self.fc2(out))
22 | out = self.fc3(out)
23 | return out
24 |
--------------------------------------------------------------------------------
/networks/blocks.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from torch import nn
3 |
4 |
5 | class Conv2dBlock(nn.Module):
6 | def __init__(self, in_c, out_c, ker_size=(3, 3), stride=1, padding=1, batch_norm=True, relu=True):
7 | super(Conv2dBlock, self).__init__()
8 | self.conv2d = nn.Conv2d(in_c, out_c, ker_size, stride, padding)
9 | if batch_norm:
10 | self.batch_norm = nn.BatchNorm2d(out_c, eps=1e-5, momentum=0.05, affine=True)
11 | if relu:
12 | self.relu = nn.ReLU(inplace=True)
13 |
14 | def forward(self, x):
15 | for module in self.children():
16 | x = module(x)
17 | return x
18 |
19 |
20 | class DownSampleBlock(nn.Module):
21 | def __init__(self, ker_size=(2, 2), stride=2, dilation=(1, 1), ceil_mode=False, p=0.0):
22 | super(DownSampleBlock, self).__init__()
23 | self.maxpooling = nn.MaxPool2d(kernel_size=ker_size, stride=stride, dilation=dilation, ceil_mode=ceil_mode)
24 | if p:
25 | self.dropout = nn.Dropout(p)
26 |
27 | def forward(self, x):
28 | for module in self.children():
29 | x = module(x)
30 | return x
31 |
32 |
33 | class UpSampleBlock(nn.Module):
34 | def __init__(self, scale_factor=(2, 2), mode="bilinear", p=0.0):
35 | super(UpSampleBlock, self).__init__()
36 | self.upsample = nn.Upsample(scale_factor=scale_factor, mode=mode)
37 | if p:
38 | self.dropout = nn.Dropout(p)
39 |
40 | def forward(self, x):
41 | for module in self.children():
42 | x = module(x)
43 | return x
44 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/blocks.py:
--------------------------------------------------------------------------------
1 | from torch import nn
2 | import torch
3 |
4 | class Conv2dBlock(nn.Module):
5 |
6 | def __init__(self, in_c, out_c, ker_size=(3,3), stride=1, padding=1, batch_norm=True, relu=True):
7 | super(Conv2dBlock, self).__init__()
8 | self.conv2d = nn.Conv2d(in_c, out_c, ker_size, stride, padding)
9 | if(batch_norm):
10 | self.batch_norm = nn.BatchNorm2d(out_c, eps=1e-5, momentum=0.05, affine=True)
11 | if relu:
12 | self.relu = nn.ReLU(inplace=True)
13 |
14 |
15 | def forward(self, x):
16 | for module in self.children():
17 | x = module(x)
18 | return x
19 |
20 |
21 | class DownSampleBlock(nn.Module):
22 | def __init__(self, ker_size=(2,2), stride=2, dilation=(1,1), ceil_mode=False, p=0.0):
23 | super(DownSampleBlock, self).__init__()
24 | self.maxpooling = nn.MaxPool2d(kernel_size=ker_size, stride=stride, dilation=dilation, ceil_mode=ceil_mode)
25 | if(p):
26 | self.dropout = nn.Dropout(p)
27 | def forward(self, x):
28 | for module in self.children():
29 | x = module(x)
30 | return x
31 |
32 | class UpSampleBlock(nn.Module):
33 | def __init__(self, scale_factor=(2, 2), mode='bilinear', p=0.0):
34 | super(UpSampleBlock, self).__init__()
35 | self.upsample = nn.Upsample(scale_factor=scale_factor, mode=mode)
36 | if(p):
37 | self.dropout = nn.Dropout(p)
38 |
39 | def forward(self, x):
40 | for module in self.children():
41 | x = module(x)
42 | return x
43 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/vgg.py:
--------------------------------------------------------------------------------
1 | '''VGG11/13/16/19 in Pytorch.'''
2 | import torch
3 | import torch.nn as nn
4 |
5 |
6 | cfg = {
7 | 'VGG11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
8 | 'VGG13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
9 | 'VGG16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
10 | 'VGG19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
11 | }
12 |
13 |
14 | class VGG(nn.Module):
15 | def __init__(self, vgg_name):
16 | super(VGG, self).__init__()
17 | self.features = self._make_layers(cfg[vgg_name])
18 | self.classifier = nn.Linear(512, 10)
19 |
20 | def forward(self, x):
21 | out = self.features(x)
22 | out = out.view(out.size(0), -1)
23 | out = self.classifier(out)
24 | return out
25 |
26 | def _make_layers(self, cfg):
27 | layers = []
28 | in_channels = 3
29 | for x in cfg:
30 | if x == 'M':
31 | layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
32 | else:
33 | layers += [nn.Conv2d(in_channels, x, kernel_size=3, padding=1),
34 | nn.BatchNorm2d(x),
35 | nn.ReLU(inplace=True)]
36 | in_channels = x
37 | layers += [nn.AvgPool2d(kernel_size=1, stride=1)]
38 | return nn.Sequential(*layers)
39 |
40 |
41 | def test():
42 | net = VGG('VGG11')
43 | x = torch.randn(2,3,32,32)
44 | y = net(x)
45 | print(y.size())
46 |
47 | # test()
48 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/mobilenet.py:
--------------------------------------------------------------------------------
1 | '''MobileNet in PyTorch.
2 |
3 | See the paper "MobileNets: Efficient Convolutional Neural Networks for Mobile Vision Applications"
4 | for more details.
5 | '''
6 | import torch
7 | import torch.nn as nn
8 | import torch.nn.functional as F
9 |
10 |
11 | class Block(nn.Module):
12 | '''Depthwise conv + Pointwise conv'''
13 | def __init__(self, in_planes, out_planes, stride=1):
14 | super(Block, self).__init__()
15 | self.conv1 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=in_planes, bias=False)
16 | self.bn1 = nn.BatchNorm2d(in_planes)
17 | self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
18 | self.bn2 = nn.BatchNorm2d(out_planes)
19 |
20 | def forward(self, x):
21 | out = F.relu(self.bn1(self.conv1(x)))
22 | out = F.relu(self.bn2(self.conv2(out)))
23 | return out
24 |
25 |
26 | class MobileNet(nn.Module):
27 | # (128,2) means conv planes=128, conv stride=2, by default conv stride=1
28 | cfg = [64, (128,2), 128, (256,2), 256, (512,2), 512, 512, 512, 512, 512, (1024,2), 1024]
29 |
30 | def __init__(self, num_classes=10):
31 | super(MobileNet, self).__init__()
32 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False)
33 | self.bn1 = nn.BatchNorm2d(32)
34 | self.layers = self._make_layers(in_planes=32)
35 | self.linear = nn.Linear(1024, num_classes)
36 |
37 | def _make_layers(self, in_planes):
38 | layers = []
39 | for x in self.cfg:
40 | out_planes = x if isinstance(x, int) else x[0]
41 | stride = 1 if isinstance(x, int) else x[1]
42 | layers.append(Block(in_planes, out_planes, stride))
43 | in_planes = out_planes
44 | return nn.Sequential(*layers)
45 |
46 | def forward(self, x):
47 | out = F.relu(self.bn1(self.conv1(x)))
48 | out = self.layers(out)
49 | out = F.avg_pool2d(out, 2)
50 | out = out.view(out.size(0), -1)
51 | out = self.linear(out)
52 | return out
53 |
54 |
55 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CBD
2 | Official Inplementation of CVPR23 paper "Backdoor Defense via Deconfounded Representation Learning"
3 |
4 | Deep neural networks (DNNs) are recently shown to be vulnerable to backdoor attacks, where attackers embed hidden backdoors in the DNN model by injecting a few poisoned examples into the training dataset. While extensive efforts have been made to detect and remove backdoors from backdoored DNNs, it is still not clear whether a backdoor-free clean model can be directly obtained from poisoned datasets. In this paper, we first construct a causal graph to model the generation process of poisoned data and find that the backdoor attack acts as the confounder, which brings spurious associations between the input images and target labels, making the model predictions less reliable. Inspired by the causal understanding, we propose the Causality-inspired Backdoor Defense (CBD), to learn deconfounded representations for reliable classification. Specifically, a backdoored model is intentionally trained to capture the confounding effects. The other clean model dedicates to capturing the desired causal effects by minimizing the mutual information with the confounding representations from the backdoored model and employing a sample-wise re-weighting scheme. Extensive experiments on multiple benchmark datasets against 6 state-of-the-art attacks verify that our proposed defense method is effective in reducing backdoor threats while maintaining high accuracy in predicting benign samples. Further analysis shows that CBD can also resist potential adaptive attacks.
5 |
6 | # Train CBD
7 | You can run CBD by
8 | ```
9 | python3 train.py
10 | ```
11 |
12 | The configurations can be adjusted by modifying config.py
13 |
14 | ## Cite
15 |
16 | If you find this repo to be useful, please cite our paper. Thank you!
17 |
18 | ```
19 | @inproceedings{
20 | anonymous2023backdoor,
21 | title={Backdoor Defense via Deconfounded Representation Learning},
22 | author={Zhang, Zaixi and Liu, Qi and Wang, Zhicai and Lu, Zepu and Hu, Qingyong},
23 | booktitle={Conference on Computer Vision and Pattern Recognition 2023},
24 | year={2023}
25 | }
26 | ```
27 |
--------------------------------------------------------------------------------
/models/selector.py:
--------------------------------------------------------------------------------
1 | from models.wresnet import *
2 | from models.resnet import *
3 | import os
4 |
5 | def select_model(dataset,
6 | model_name,
7 | pretrained=False,
8 | pretrained_models_path=None,
9 | n_classes=10):
10 |
11 | assert model_name in ['WRN-16-1', 'WRN-16-2', 'WRN-40-1', 'WRN-40-2', 'ResNet34', 'WRN-10-2', 'WRN-10-1']
12 | if model_name=='WRN-16-1':
13 | model = WideResNet(depth=16, num_classes=n_classes, widen_factor=1, dropRate=0)
14 | elif model_name=='WRN-16-2':
15 | model = WideResNet(depth=16, num_classes=n_classes, widen_factor=2, dropRate=0)
16 | elif model_name=='WRN-40-1':
17 | model = WideResNet(depth=40, num_classes=n_classes, widen_factor=1, dropRate=0)
18 | elif model_name=='WRN-40-2':
19 | model = WideResNet(depth=40, num_classes=n_classes, widen_factor=2, dropRate=0)
20 | elif model_name == 'WRN-10-2':
21 | model = WideResNet(depth=10, num_classes=n_classes, widen_factor=2, dropRate=0)
22 | elif model_name == 'WRN-10-1':
23 | model = WideResNet(depth=10, num_classes=n_classes, widen_factor=1, dropRate=0)
24 | elif model_name=='ResNet34':
25 | model = resnet(depth=32, num_classes=n_classes)
26 | else:
27 | raise NotImplementedError
28 |
29 | checkpoint_epoch = None
30 | if pretrained:
31 | model_path = os.path.join(pretrained_models_path)
32 | print('Loading Model from {}'.format(model_path))
33 | checkpoint = torch.load(model_path, map_location='cpu')
34 | print(checkpoint.keys())
35 | model.load_state_dict(checkpoint['state_dict'])
36 |
37 | checkpoint_epoch = checkpoint['epoch']
38 | print("=> loaded checkpoint '{}' (epoch {}) ".format(model_path, checkpoint['epoch']))
39 |
40 | return model, checkpoint_epoch
41 |
42 |
43 | if __name__ == '__main__':
44 |
45 | import torch
46 | from torchsummary import summary
47 | import random
48 | import time
49 |
50 | random.seed(1234) # torch transforms use this seed
51 | torch.manual_seed(1234)
52 | torch.cuda.manual_seed(1234)
53 |
54 | support_x_task = torch.autograd.Variable(torch.FloatTensor(64, 3, 32, 32).uniform_(0, 1))
55 |
56 | t0 = time.time()
57 | model = select_model('CIFAR10', model_name='WRN-16-2')
58 | output, act = model(support_x_task)
59 | print("Time taken for forward pass: {} s".format(time.time() - t0))
60 | print("\nOUTPUT SHAPE: ", output.shape)
61 | summary(model, (3, 32, 32))
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
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 | 1649061675061
36 |
37 |
38 | 1649061675061
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 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/mobilenetv2.py:
--------------------------------------------------------------------------------
1 | '''MobileNetV2 in PyTorch.
2 |
3 | See the paper "Inverted Residuals and Linear Bottlenecks:
4 | Mobile Networks for Classification, Detection and Segmentation" for more details.
5 | '''
6 | import torch
7 | import torch.nn as nn
8 | import torch.nn.functional as F
9 |
10 |
11 | class Block(nn.Module):
12 | '''expand + depthwise + pointwise'''
13 | def __init__(self, in_planes, out_planes, expansion, stride):
14 | super(Block, self).__init__()
15 | self.stride = stride
16 |
17 | planes = expansion * in_planes
18 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, stride=1, padding=0, bias=False)
19 | self.bn1 = nn.BatchNorm2d(planes)
20 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, groups=planes, bias=False)
21 | self.bn2 = nn.BatchNorm2d(planes)
22 | self.conv3 = nn.Conv2d(planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
23 | self.bn3 = nn.BatchNorm2d(out_planes)
24 |
25 | self.shortcut = nn.Sequential()
26 | if stride == 1 and in_planes != out_planes:
27 | self.shortcut = nn.Sequential(
28 | nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False),
29 | nn.BatchNorm2d(out_planes),
30 | )
31 |
32 | def forward(self, x):
33 | out = F.relu(self.bn1(self.conv1(x)))
34 | out = F.relu(self.bn2(self.conv2(out)))
35 | out = self.bn3(self.conv3(out))
36 | out = out + self.shortcut(x) if self.stride==1 else out
37 | return out
38 |
39 |
40 | class MobileNetV2(nn.Module):
41 | # (expansion, out_planes, num_blocks, stride)
42 | cfg = [(1, 16, 1, 1),
43 | (6, 24, 2, 1), # NOTE: change stride 2 -> 1 for CIFAR10
44 | (6, 32, 3, 2),
45 | (6, 64, 4, 2),
46 | (6, 96, 3, 1),
47 | (6, 160, 3, 2),
48 | (6, 320, 1, 1)]
49 |
50 | def __init__(self, num_classes=10):
51 | super(MobileNetV2, self).__init__()
52 | # NOTE: change conv1 stride 2 -> 1 for CIFAR10
53 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3, stride=1, padding=1, bias=False)
54 | self.bn1 = nn.BatchNorm2d(32)
55 | self.layers = self._make_layers(in_planes=32)
56 | self.conv2 = nn.Conv2d(320, 1280, kernel_size=1, stride=1, padding=0, bias=False)
57 | self.bn2 = nn.BatchNorm2d(1280)
58 | self.linear = nn.Linear(1280, num_classes)
59 |
60 | def _make_layers(self, in_planes):
61 | layers = []
62 | for expansion, out_planes, num_blocks, stride in self.cfg:
63 | strides = [stride] + [1]*(num_blocks-1)
64 | for stride in strides:
65 | layers.append(Block(in_planes, out_planes, expansion, stride))
66 | in_planes = out_planes
67 | return nn.Sequential(*layers)
68 |
69 | def forward(self, x):
70 | out = F.relu(self.bn1(self.conv1(x)))
71 | out = self.layers(out)
72 | out = F.relu(self.bn2(self.conv2(out)))
73 | # NOTE: change pooling kernel_size 7 -> 4 for CIFAR10
74 | out = F.avg_pool2d(out, 4)
75 | out = out.view(out.size(0), -1)
76 | out = self.linear(out)
77 | return out
78 |
79 |
80 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/googlenet.py:
--------------------------------------------------------------------------------
1 | '''GoogLeNet with PyTorch.'''
2 | import torch
3 | import torch.nn as nn
4 | import torch.nn.functional as F
5 |
6 |
7 | class Inception(nn.Module):
8 | def __init__(self, in_planes, n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes):
9 | super(Inception, self).__init__()
10 | # 1x1 conv branch
11 | self.b1 = nn.Sequential(
12 | nn.Conv2d(in_planes, n1x1, kernel_size=1),
13 | nn.BatchNorm2d(n1x1),
14 | nn.ReLU(True),
15 | )
16 |
17 | # 1x1 conv -> 3x3 conv branch
18 | self.b2 = nn.Sequential(
19 | nn.Conv2d(in_planes, n3x3red, kernel_size=1),
20 | nn.BatchNorm2d(n3x3red),
21 | nn.ReLU(True),
22 | nn.Conv2d(n3x3red, n3x3, kernel_size=3, padding=1),
23 | nn.BatchNorm2d(n3x3),
24 | nn.ReLU(True),
25 | )
26 |
27 | # 1x1 conv -> 5x5 conv branch
28 | self.b3 = nn.Sequential(
29 | nn.Conv2d(in_planes, n5x5red, kernel_size=1),
30 | nn.BatchNorm2d(n5x5red),
31 | nn.ReLU(True),
32 | nn.Conv2d(n5x5red, n5x5, kernel_size=3, padding=1),
33 | nn.BatchNorm2d(n5x5),
34 | nn.ReLU(True),
35 | nn.Conv2d(n5x5, n5x5, kernel_size=3, padding=1),
36 | nn.BatchNorm2d(n5x5),
37 | nn.ReLU(True),
38 | )
39 |
40 | # 3x3 pool -> 1x1 conv branch
41 | self.b4 = nn.Sequential(
42 | nn.MaxPool2d(3, stride=1, padding=1),
43 | nn.Conv2d(in_planes, pool_planes, kernel_size=1),
44 | nn.BatchNorm2d(pool_planes),
45 | nn.ReLU(True),
46 | )
47 |
48 | def forward(self, x):
49 | y1 = self.b1(x)
50 | y2 = self.b2(x)
51 | y3 = self.b3(x)
52 | y4 = self.b4(x)
53 | return torch.cat([y1,y2,y3,y4], 1)
54 |
55 |
56 | class GoogLeNet(nn.Module):
57 | def __init__(self):
58 | super(GoogLeNet, self).__init__()
59 | self.pre_layers = nn.Sequential(
60 | nn.Conv2d(3, 192, kernel_size=3, padding=1),
61 | nn.BatchNorm2d(192),
62 | nn.ReLU(True),
63 | )
64 |
65 | self.a3 = Inception(192, 64, 96, 128, 16, 32, 32)
66 | self.b3 = Inception(256, 128, 128, 192, 32, 96, 64)
67 |
68 | self.maxpool = nn.MaxPool2d(3, stride=2, padding=1)
69 |
70 | self.a4 = Inception(480, 192, 96, 208, 16, 48, 64)
71 | self.b4 = Inception(512, 160, 112, 224, 24, 64, 64)
72 | self.c4 = Inception(512, 128, 128, 256, 24, 64, 64)
73 | self.d4 = Inception(512, 112, 144, 288, 32, 64, 64)
74 | self.e4 = Inception(528, 256, 160, 320, 32, 128, 128)
75 |
76 | self.a5 = Inception(832, 256, 160, 320, 32, 128, 128)
77 | self.b5 = Inception(832, 384, 192, 384, 48, 128, 128)
78 |
79 | self.avgpool = nn.AvgPool2d(8, stride=1)
80 | self.linear = nn.Linear(1024, 10)
81 |
82 | def forward(self, x):
83 | out = self.pre_layers(x)
84 | out = self.a3(out)
85 | out = self.b3(out)
86 | out = self.maxpool(out)
87 | out = self.a4(out)
88 | out = self.b4(out)
89 | out = self.c4(out)
90 | out = self.d4(out)
91 | out = self.e4(out)
92 | out = self.maxpool(out)
93 | out = self.a5(out)
94 | out = self.b5(out)
95 | out = self.avgpool(out)
96 | out = out.view(out.size(0), -1)
97 | out = self.linear(out)
98 | return out
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/resnext.py:
--------------------------------------------------------------------------------
1 | '''ResNeXt in PyTorch.
2 |
3 | See the paper "Aggregated Residual Transformations for Deep Neural Networks" for more details.
4 | '''
5 | import torch
6 | import torch.nn as nn
7 | import torch.nn.functional as F
8 |
9 |
10 | class Block(nn.Module):
11 | '''Grouped convolution block.'''
12 | expansion = 2
13 |
14 | def __init__(self, in_planes, cardinality=32, bottleneck_width=4, stride=1):
15 | super(Block, self).__init__()
16 | group_width = cardinality * bottleneck_width
17 | self.conv1 = nn.Conv2d(in_planes, group_width, kernel_size=1, bias=False)
18 | self.bn1 = nn.BatchNorm2d(group_width)
19 | self.conv2 = nn.Conv2d(group_width, group_width, kernel_size=3, stride=stride, padding=1, groups=cardinality, bias=False)
20 | self.bn2 = nn.BatchNorm2d(group_width)
21 | self.conv3 = nn.Conv2d(group_width, self.expansion*group_width, kernel_size=1, bias=False)
22 | self.bn3 = nn.BatchNorm2d(self.expansion*group_width)
23 |
24 | self.shortcut = nn.Sequential()
25 | if stride != 1 or in_planes != self.expansion*group_width:
26 | self.shortcut = nn.Sequential(
27 | nn.Conv2d(in_planes, self.expansion*group_width, kernel_size=1, stride=stride, bias=False),
28 | nn.BatchNorm2d(self.expansion*group_width)
29 | )
30 |
31 | def forward(self, x):
32 | out = F.relu(self.bn1(self.conv1(x)))
33 | out = F.relu(self.bn2(self.conv2(out)))
34 | out = self.bn3(self.conv3(out))
35 | out += self.shortcut(x)
36 | out = F.relu(out)
37 | return out
38 |
39 |
40 | class ResNeXt(nn.Module):
41 | def __init__(self, num_blocks, cardinality, bottleneck_width, num_classes=10):
42 | super(ResNeXt, self).__init__()
43 | self.cardinality = cardinality
44 | self.bottleneck_width = bottleneck_width
45 | self.in_planes = 64
46 |
47 | self.conv1 = nn.Conv2d(3, 64, kernel_size=1, bias=False)
48 | self.bn1 = nn.BatchNorm2d(64)
49 | self.layer1 = self._make_layer(num_blocks[0], 1)
50 | self.layer2 = self._make_layer(num_blocks[1], 2)
51 | self.layer3 = self._make_layer(num_blocks[2], 2)
52 | # self.layer4 = self._make_layer(num_blocks[3], 2)
53 | self.linear = nn.Linear(cardinality*bottleneck_width*8, num_classes)
54 |
55 | def _make_layer(self, num_blocks, stride):
56 | strides = [stride] + [1]*(num_blocks-1)
57 | layers = []
58 | for stride in strides:
59 | layers.append(Block(self.in_planes, self.cardinality, self.bottleneck_width, stride))
60 | self.in_planes = Block.expansion * self.cardinality * self.bottleneck_width
61 | # Increase bottleneck_width by 2 after each stage.
62 | self.bottleneck_width *= 2
63 | return nn.Sequential(*layers)
64 |
65 | def forward(self, x):
66 | out = F.relu(self.bn1(self.conv1(x)))
67 | out = self.layer1(out)
68 | out = self.layer2(out)
69 | out = self.layer3(out)
70 | # out = self.layer4(out)
71 | out = F.avg_pool2d(out, 8)
72 | out = out.view(out.size(0), -1)
73 | out = self.linear(out)
74 | return out
75 |
76 |
77 | def ResNeXt29_2x64d():
78 | return ResNeXt(num_blocks=[3,3,3], cardinality=2, bottleneck_width=64)
79 |
80 | def ResNeXt29_4x64d():
81 | return ResNeXt(num_blocks=[3,3,3], cardinality=4, bottleneck_width=64)
82 |
83 | def ResNeXt29_8x64d():
84 | return ResNeXt(num_blocks=[3,3,3], cardinality=8, bottleneck_width=64)
85 |
86 | def ResNeXt29_32x4d():
87 | return ResNeXt(num_blocks=[3,3,3], cardinality=32, bottleneck_width=4)
88 |
89 | def test_resnext():
90 | net = ResNeXt29_2x64d()
91 | x = torch.randn(1,3,32,32)
92 | y = net(x)
93 | print(y.size())
94 |
95 | # test_resnext()
96 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/dpn.py:
--------------------------------------------------------------------------------
1 | '''Dual Path Networks in PyTorch.'''
2 | import torch
3 | import torch.nn as nn
4 | import torch.nn.functional as F
5 |
6 |
7 | class Bottleneck(nn.Module):
8 | def __init__(self, last_planes, in_planes, out_planes, dense_depth, stride, first_layer):
9 | super(Bottleneck, self).__init__()
10 | self.out_planes = out_planes
11 | self.dense_depth = dense_depth
12 |
13 | self.conv1 = nn.Conv2d(last_planes, in_planes, kernel_size=1, bias=False)
14 | self.bn1 = nn.BatchNorm2d(in_planes)
15 | self.conv2 = nn.Conv2d(in_planes, in_planes, kernel_size=3, stride=stride, padding=1, groups=32, bias=False)
16 | self.bn2 = nn.BatchNorm2d(in_planes)
17 | self.conv3 = nn.Conv2d(in_planes, out_planes+dense_depth, kernel_size=1, bias=False)
18 | self.bn3 = nn.BatchNorm2d(out_planes+dense_depth)
19 |
20 | self.shortcut = nn.Sequential()
21 | if first_layer:
22 | self.shortcut = nn.Sequential(
23 | nn.Conv2d(last_planes, out_planes+dense_depth, kernel_size=1, stride=stride, bias=False),
24 | nn.BatchNorm2d(out_planes+dense_depth)
25 | )
26 |
27 | def forward(self, x):
28 | out = F.relu(self.bn1(self.conv1(x)))
29 | out = F.relu(self.bn2(self.conv2(out)))
30 | out = self.bn3(self.conv3(out))
31 | x = self.shortcut(x)
32 | d = self.out_planes
33 | out = torch.cat([x[:,:d,:,:]+out[:,:d,:,:], x[:,d:,:,:], out[:,d:,:,:]], 1)
34 | out = F.relu(out)
35 | return out
36 |
37 |
38 | class DPN(nn.Module):
39 | def __init__(self, cfg):
40 | super(DPN, self).__init__()
41 | in_planes, out_planes = cfg['in_planes'], cfg['out_planes']
42 | num_blocks, dense_depth = cfg['num_blocks'], cfg['dense_depth']
43 |
44 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
45 | self.bn1 = nn.BatchNorm2d(64)
46 | self.last_planes = 64
47 | self.layer1 = self._make_layer(in_planes[0], out_planes[0], num_blocks[0], dense_depth[0], stride=1)
48 | self.layer2 = self._make_layer(in_planes[1], out_planes[1], num_blocks[1], dense_depth[1], stride=2)
49 | self.layer3 = self._make_layer(in_planes[2], out_planes[2], num_blocks[2], dense_depth[2], stride=2)
50 | self.layer4 = self._make_layer(in_planes[3], out_planes[3], num_blocks[3], dense_depth[3], stride=2)
51 | self.linear = nn.Linear(out_planes[3]+(num_blocks[3]+1)*dense_depth[3], 10)
52 |
53 | def _make_layer(self, in_planes, out_planes, num_blocks, dense_depth, stride):
54 | strides = [stride] + [1]*(num_blocks-1)
55 | layers = []
56 | for i,stride in enumerate(strides):
57 | layers.append(Bottleneck(self.last_planes, in_planes, out_planes, dense_depth, stride, i==0))
58 | self.last_planes = out_planes + (i+2) * dense_depth
59 | return nn.Sequential(*layers)
60 |
61 | def forward(self, x):
62 | out = F.relu(self.bn1(self.conv1(x)))
63 | out = self.layer1(out)
64 | out = self.layer2(out)
65 | out = self.layer3(out)
66 | out = self.layer4(out)
67 | out = F.avg_pool2d(out, 4)
68 | out = out.view(out.size(0), -1)
69 | out = self.linear(out)
70 | return out
71 |
72 |
73 | def DPN26():
74 | cfg = {
75 | 'in_planes': (96,192,384,768),
76 | 'out_planes': (256,512,1024,2048),
77 | 'num_blocks': (2,2,2,2),
78 | 'dense_depth': (16,32,24,128)
79 | }
80 | return DPN(cfg)
81 |
82 | def DPN92():
83 | cfg = {
84 | 'in_planes': (96,192,384,768),
85 | 'out_planes': (256,512,1024,2048),
86 | 'num_blocks': (3,4,20,3),
87 | 'dense_depth': (16,32,24,128)
88 | }
89 | return DPN(cfg)
90 |
91 |
92 | def test():
93 | net = DPN92()
94 | x = torch.randn(1,3,32,32)
95 | y = net(x)
96 | print(y)
97 |
98 | # test()
99 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/densenet.py:
--------------------------------------------------------------------------------
1 | '''DenseNet in PyTorch.'''
2 | import math
3 |
4 | import torch
5 | import torch.nn as nn
6 | import torch.nn.functional as F
7 |
8 |
9 | class Bottleneck(nn.Module):
10 | def __init__(self, in_planes, growth_rate):
11 | super(Bottleneck, self).__init__()
12 | self.bn1 = nn.BatchNorm2d(in_planes)
13 | self.conv1 = nn.Conv2d(in_planes, 4*growth_rate, kernel_size=1, bias=False)
14 | self.bn2 = nn.BatchNorm2d(4*growth_rate)
15 | self.conv2 = nn.Conv2d(4*growth_rate, growth_rate, kernel_size=3, padding=1, bias=False)
16 |
17 | def forward(self, x):
18 | out = self.conv1(F.relu(self.bn1(x)))
19 | out = self.conv2(F.relu(self.bn2(out)))
20 | out = torch.cat([out,x], 1)
21 | return out
22 |
23 |
24 | class Transition(nn.Module):
25 | def __init__(self, in_planes, out_planes):
26 | super(Transition, self).__init__()
27 | self.bn = nn.BatchNorm2d(in_planes)
28 | self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=1, bias=False)
29 |
30 | def forward(self, x):
31 | out = self.conv(F.relu(self.bn(x)))
32 | out = F.avg_pool2d(out, 2)
33 | return out
34 |
35 |
36 | class DenseNet(nn.Module):
37 | def __init__(self, block, nblocks, growth_rate=12, reduction=0.5, num_classes=10):
38 | super(DenseNet, self).__init__()
39 | self.growth_rate = growth_rate
40 |
41 | num_planes = 2*growth_rate
42 | self.conv1 = nn.Conv2d(3, num_planes, kernel_size=3, padding=1, bias=False)
43 |
44 | self.dense1 = self._make_dense_layers(block, num_planes, nblocks[0])
45 | num_planes += nblocks[0]*growth_rate
46 | out_planes = int(math.floor(num_planes*reduction))
47 | self.trans1 = Transition(num_planes, out_planes)
48 | num_planes = out_planes
49 |
50 | self.dense2 = self._make_dense_layers(block, num_planes, nblocks[1])
51 | num_planes += nblocks[1]*growth_rate
52 | out_planes = int(math.floor(num_planes*reduction))
53 | self.trans2 = Transition(num_planes, out_planes)
54 | num_planes = out_planes
55 |
56 | self.dense3 = self._make_dense_layers(block, num_planes, nblocks[2])
57 | num_planes += nblocks[2]*growth_rate
58 | out_planes = int(math.floor(num_planes*reduction))
59 | self.trans3 = Transition(num_planes, out_planes)
60 | num_planes = out_planes
61 |
62 | self.dense4 = self._make_dense_layers(block, num_planes, nblocks[3])
63 | num_planes += nblocks[3]*growth_rate
64 |
65 | self.bn = nn.BatchNorm2d(num_planes)
66 | self.linear = nn.Linear(num_planes, num_classes)
67 |
68 | def _make_dense_layers(self, block, in_planes, nblock):
69 | layers = []
70 | for i in range(nblock):
71 | layers.append(block(in_planes, self.growth_rate))
72 | in_planes += self.growth_rate
73 | return nn.Sequential(*layers)
74 |
75 | def forward(self, x):
76 | out = self.conv1(x)
77 | out = self.trans1(self.dense1(out))
78 | out = self.trans2(self.dense2(out))
79 | out = self.trans3(self.dense3(out))
80 | out = self.dense4(out)
81 | out = F.avg_pool2d(F.relu(self.bn(out)), 4)
82 | out = out.view(out.size(0), -1)
83 | out = self.linear(out)
84 | return out
85 |
86 | def DenseNet121():
87 | return DenseNet(Bottleneck, [6,12,24,16], growth_rate=32)
88 |
89 | def DenseNet169():
90 | return DenseNet(Bottleneck, [6,12,32,32], growth_rate=32)
91 |
92 | def DenseNet201():
93 | return DenseNet(Bottleneck, [6,12,48,32], growth_rate=32)
94 |
95 | def DenseNet161():
96 | return DenseNet(Bottleneck, [6,12,36,24], growth_rate=48)
97 |
98 | def densenet_cifar():
99 | return DenseNet(Bottleneck, [6,12,24,16], growth_rate=12)
100 |
101 | def test():
102 | net = densenet_cifar()
103 | x = torch.randn(1,3,32,32)
104 | y = net(x)
105 | print(y)
106 |
107 | # test()
108 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/shufflenet.py:
--------------------------------------------------------------------------------
1 | '''ShuffleNet in PyTorch.
2 |
3 | See the paper "ShuffleNet: An Extremely Efficient Convolutional Neural Network for Mobile Devices" for more details.
4 | '''
5 | import torch
6 | import torch.nn as nn
7 | import torch.nn.functional as F
8 |
9 |
10 | class ShuffleBlock(nn.Module):
11 | def __init__(self, groups):
12 | super(ShuffleBlock, self).__init__()
13 | self.groups = groups
14 |
15 | def forward(self, x):
16 | '''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]'''
17 | N,C,H,W = x.size()
18 | g = self.groups
19 | return x.view(N,g,C//g,H,W).permute(0,2,1,3,4).reshape(N,C,H,W)
20 |
21 |
22 | class Bottleneck(nn.Module):
23 | def __init__(self, in_planes, out_planes, stride, groups):
24 | super(Bottleneck, self).__init__()
25 | self.stride = stride
26 |
27 | mid_planes = out_planes/4
28 | g = 1 if in_planes==24 else groups
29 | self.conv1 = nn.Conv2d(in_planes, mid_planes, kernel_size=1, groups=g, bias=False)
30 | self.bn1 = nn.BatchNorm2d(mid_planes)
31 | self.shuffle1 = ShuffleBlock(groups=g)
32 | self.conv2 = nn.Conv2d(mid_planes, mid_planes, kernel_size=3, stride=stride, padding=1, groups=mid_planes, bias=False)
33 | self.bn2 = nn.BatchNorm2d(mid_planes)
34 | self.conv3 = nn.Conv2d(mid_planes, out_planes, kernel_size=1, groups=groups, bias=False)
35 | self.bn3 = nn.BatchNorm2d(out_planes)
36 |
37 | self.shortcut = nn.Sequential()
38 | if stride == 2:
39 | self.shortcut = nn.Sequential(nn.AvgPool2d(3, stride=2, padding=1))
40 |
41 | def forward(self, x):
42 | out = F.relu(self.bn1(self.conv1(x)))
43 | out = self.shuffle1(out)
44 | out = F.relu(self.bn2(self.conv2(out)))
45 | out = self.bn3(self.conv3(out))
46 | res = self.shortcut(x)
47 | out = F.relu(torch.cat([out,res], 1)) if self.stride==2 else F.relu(out+res)
48 | return out
49 |
50 |
51 | class ShuffleNet(nn.Module):
52 | def __init__(self, cfg):
53 | super(ShuffleNet, self).__init__()
54 | out_planes = cfg['out_planes']
55 | num_blocks = cfg['num_blocks']
56 | groups = cfg['groups']
57 |
58 | self.conv1 = nn.Conv2d(3, 24, kernel_size=1, bias=False)
59 | self.bn1 = nn.BatchNorm2d(24)
60 | self.in_planes = 24
61 | self.layer1 = self._make_layer(out_planes[0], num_blocks[0], groups)
62 | self.layer2 = self._make_layer(out_planes[1], num_blocks[1], groups)
63 | self.layer3 = self._make_layer(out_planes[2], num_blocks[2], groups)
64 | self.linear = nn.Linear(out_planes[2], 10)
65 |
66 | def _make_layer(self, out_planes, num_blocks, groups):
67 | layers = []
68 | for i in range(num_blocks):
69 | stride = 2 if i == 0 else 1
70 | cat_planes = self.in_planes if i == 0 else 0
71 | layers.append(Bottleneck(self.in_planes, out_planes-cat_planes, stride=stride, groups=groups))
72 | self.in_planes = out_planes
73 | return nn.Sequential(*layers)
74 |
75 | def forward(self, x):
76 | out = F.relu(self.bn1(self.conv1(x)))
77 | out = self.layer1(out)
78 | out = self.layer2(out)
79 | out = self.layer3(out)
80 | out = F.avg_pool2d(out, 4)
81 | out = out.view(out.size(0), -1)
82 | out = self.linear(out)
83 | return out
84 |
85 |
86 | def ShuffleNetG2():
87 | cfg = {
88 | 'out_planes': [200,400,800],
89 | 'num_blocks': [4,8,4],
90 | 'groups': 2
91 | }
92 | return ShuffleNet(cfg)
93 |
94 | def ShuffleNetG3():
95 | cfg = {
96 | 'out_planes': [240,480,960],
97 | 'num_blocks': [4,8,4],
98 | 'groups': 3
99 | }
100 | return ShuffleNet(cfg)
101 |
102 |
103 | def test():
104 | net = ShuffleNetG2()
105 | x = torch.randn(1,3,32,32)
106 | y = net(x)
107 | print(y)
108 |
109 | # test()
110 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/efficientnet.py:
--------------------------------------------------------------------------------
1 | '''EfficientNet in PyTorch.
2 |
3 | Paper: "EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks".
4 |
5 | Reference: https://github.com/keras-team/keras-applications/blob/master/keras_applications/efficientnet.py
6 | '''
7 | import torch
8 | import torch.nn as nn
9 | import torch.nn.functional as F
10 |
11 |
12 | def swish(x):
13 | return x * x.sigmoid()
14 |
15 |
16 | class Block(nn.Module):
17 | '''expansion + depthwise + pointwise + squeeze-excitation'''
18 |
19 | def __init__(self, in_planes, out_planes, kernel_size, stride, expand_ratio=1, se_ratio=0., drop_rate=0.):
20 | super(Block, self).__init__()
21 | self.stride = stride
22 | self.drop_rate = drop_rate
23 |
24 | # Expansion
25 | planes = expand_ratio * in_planes
26 | self.conv1 = nn.Conv2d(
27 | in_planes, planes, kernel_size=1, stride=1, padding=0, bias=False)
28 | self.bn1 = nn.BatchNorm2d(planes)
29 |
30 | # Depthwise conv
31 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=kernel_size,
32 | stride=stride, padding=(kernel_size-1)//2, groups=planes, bias=False)
33 | self.bn2 = nn.BatchNorm2d(planes)
34 |
35 | # SE layers
36 | se_planes = max(1, int(planes * se_ratio))
37 | self.se1 = nn.Conv2d(planes, se_planes, kernel_size=1)
38 | self.se2 = nn.Conv2d(se_planes, planes, kernel_size=1)
39 |
40 | # Output
41 | self.conv3 = nn.Conv2d(planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
42 | self.bn3 = nn.BatchNorm2d(out_planes)
43 |
44 | self.shortcut = nn.Sequential()
45 | if stride == 1 and in_planes != out_planes:
46 | self.shortcut = nn.Sequential(
47 | nn.Conv2d(in_planes, out_planes, kernel_size=1,
48 | stride=1, padding=0, bias=False),
49 | nn.BatchNorm2d(out_planes),
50 | )
51 |
52 |
53 | def forward(self, x):
54 | out = swish(self.bn1(self.conv1(x)))
55 | out = swish(self.bn2(self.conv2(out)))
56 | # Squeeze-Excitation
57 | w = F.avg_pool2d(out, out.size(2))
58 | w = swish(self.se1(w))
59 | w = self.se2(w).sigmoid()
60 | out = out * w
61 | # Output
62 | out = self.bn3(self.conv3(out))
63 | if self.drop_rate > 0:
64 | out = F.dropout2d(out, self.drop_rate)
65 | shortcut = self.shortcut(x) if self.stride == 1 else out
66 | out = out + shortcut
67 | return out
68 |
69 |
70 | class EfficientNet(nn.Module):
71 | def __init__(self, cfg, num_classes=10):
72 | super(EfficientNet, self).__init__()
73 | self.cfg = cfg
74 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3,
75 | stride=1, padding=1, bias=False)
76 | self.bn1 = nn.BatchNorm2d(32)
77 | self.layers = self._make_layers(in_planes=32)
78 | self.linear = nn.Linear(cfg[-1][1], num_classes)
79 |
80 | def _make_layers(self, in_planes):
81 | layers = []
82 | for expansion, out_planes, num_blocks, kernel_size, stride in self.cfg:
83 | strides = [stride] + [1]*(num_blocks-1)
84 | for stride in strides:
85 | layers.append(Block(in_planes, out_planes, kernel_size, stride, expansion, se_ratio=0.25, drop_rate=0.2))
86 | in_planes = out_planes
87 | return nn.Sequential(*layers)
88 |
89 | def forward(self, x):
90 | out = swish(self.bn1(self.conv1(x)))
91 | out = self.layers(out)
92 | out = F.adaptive_avg_pool2d(out, 1)
93 | out = out.view(out.size(0), -1)
94 | out = self.linear(out)
95 | return out
96 |
97 |
98 | def EfficientNetB0():
99 | # (expansion, out_planes, num_blocks, kernel_size, stride)
100 | cfg = [(1, 16, 1, 3, 1),
101 | (6, 24, 2, 3, 2),
102 | (6, 40, 2, 5, 2),
103 | (6, 80, 3, 3, 2),
104 | (6, 112, 3, 5, 1),
105 | (6, 192, 4, 5, 2),
106 | (6, 320, 1, 3, 1)]
107 | return EfficientNet(cfg)
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/create_dynamic_backdoor_data.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import os
3 | import torch.utils.data as data
4 | import torch
5 | import torchvision
6 | import torchvision.transforms as transforms
7 | import torch.nn as nn
8 | from networks.models import NetC_MNIST, Generator
9 | import random
10 | import torch.utils.data as Data
11 | from tqdm import tqdm
12 |
13 | cifar10_param = {
14 | 'target_class': 1,
15 | 'inject_portion': 1,
16 | 'save_root': './poisoned_data',
17 | 'dataset_name': '/cifar10-inject0.1-target1-dynamic.npy',
18 | 'model_state': 'generate_dynamic_model.tar',
19 | }
20 |
21 | def noramlization(data):
22 | minVals = data.min()
23 | maxVals = data.max()
24 | ranges = maxVals - minVals
25 | normData = np.zeros(np.shape(data))
26 | m = data.shape[0]
27 | normData = data.cpu() - np.tile(minVals.cpu(), (m, 1))
28 | normData = normData.cpu()/np.tile(ranges.cpu(), (m, 1))
29 | return normData, ranges, minVals, maxVals
30 |
31 | def create_targets_bd(targets, opt):
32 | if(opt.attack_mode == 'all2one'):
33 | bd_targets = torch.ones_like(targets) * opt.target_label
34 | elif(opt.attack_mode == 'all2all'):
35 | bd_targets = torch.tensor([(label + 1) % opt.num_classes for label in targets])
36 | else:
37 | raise Exception("{} attack mode is not implemented".format(opt.attack_mode))
38 | return bd_targets.to(opt.device)
39 |
40 | def create_bd(netG, netM, inputs, targets, opt):
41 | bd_targets = create_targets_bd(targets, opt)
42 | patterns = netG(inputs)
43 | patterns = netG.normalize_pattern(patterns)
44 | patterns = patterns.to("cuda")
45 | masks_output = netM.threshold(netM(inputs))
46 | bd_inputs = inputs + (patterns - inputs) * masks_output
47 | return bd_inputs, bd_targets
48 |
49 | def create_dynamic(netC, netG, netM, dataset, opt):
50 | n_output_batches = 3
51 | n_output_images = 3
52 | mat=[]
53 | chosen=random.sample(range(0, int(len(dataset))), int(len(dataset)*cifar10_param['inject_portion']))
54 | print("injection:"+str(len(chosen)))
55 | print("begin:")
56 | for idx in tqdm(range(len(dataset))):
57 | data = dataset[idx]
58 | targets = np.array(data[1])
59 | targets = torch.from_numpy(targets)
60 | inputs = data[0].unsqueeze(0).to(opt.device)
61 | if idx in chosen:
62 | inputs_bd, targets_bd = create_bd(netG, netM, inputs, targets, opt)
63 | inputs_bd = inputs_bd.cpu().numpy()
64 |
65 | targets = np.array(cifar10_param['target_class'])
66 | inputs_bd = inputs_bd.squeeze()
67 | mat.append((inputs_bd, targets))
68 |
69 | else:
70 | inputs = inputs.cpu().numpy()
71 | targets = np.array(targets)
72 | inputs = inputs.squeeze()
73 | mat.append((inputs, targets))
74 |
75 | print("mat:"+str(len(mat)))
76 | np.save(cifar10_param['save_root']+cifar10_param['dataset_name'], mat)
77 |
78 | def main():
79 | opt = get_arguments().parse_args()
80 | opt.dataset = 'cifar10'
81 | print(opt.dataset)
82 |
83 | opt.num_classes = 10
84 | opt.input_height = 32
85 | opt.input_width = 32
86 | opt.input_channel = 3
87 | netC = PreActResNet18().to(opt.device)
88 | state_dict = torch.load(cifar10_param['model_state'])
89 | print('load C')
90 | netC.load_state_dict(state_dict['netC'])
91 | netC.to(opt.device)
92 | netC.eval()
93 | netC.requires_grad_(False)
94 | print('load G')
95 | netG = Generator(opt)
96 | netG.load_state_dict(state_dict['netG'])
97 | netG.to(opt.device)
98 | netG.eval()
99 | netG.requires_grad_(False)
100 | print('load M')
101 | netM = Generator(opt, out_channels=1)
102 | netM.load_state_dict(state_dict['netM'])
103 | netM.to(opt.device)
104 | netM.eval()
105 | netM.requires_grad_(False)
106 |
107 | transform = transforms.Compose([
108 | transforms.ToTensor(),
109 | ])
110 | dataset = torchvision.datasets.CIFAR10("data", True, transform=transform, download=True)
111 |
112 | print(len(dataset))
113 | create_dynamic(netC, netG, netM, dataset, opt)
114 |
115 |
116 | if(__name__ == '__main__'):
117 | main()
118 |
119 |
120 |
121 |
122 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/resnet.py:
--------------------------------------------------------------------------------
1 | '''ResNet in PyTorch.
2 |
3 | For Pre-activation ResNet, see 'preact_resnet.py'.
4 |
5 | Reference:
6 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
7 | Deep Residual Learning for Image Recognition. arXiv:1512.03385
8 | '''
9 | import torch
10 | import torch.nn as nn
11 | import torch.nn.functional as F
12 |
13 |
14 | class BasicBlock(nn.Module):
15 | expansion = 1
16 |
17 | def __init__(self, in_planes, planes, stride=1):
18 | super(BasicBlock, self).__init__()
19 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
20 | self.bn1 = nn.BatchNorm2d(planes)
21 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
22 | self.bn2 = nn.BatchNorm2d(planes)
23 |
24 | self.shortcut = nn.Sequential()
25 | if stride != 1 or in_planes != self.expansion*planes:
26 | self.shortcut = nn.Sequential(
27 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False),
28 | nn.BatchNorm2d(self.expansion*planes)
29 | )
30 |
31 | def forward(self, x):
32 | out = F.relu(self.bn1(self.conv1(x)))
33 | out = self.bn2(self.conv2(out))
34 | out += self.shortcut(x)
35 | out = F.relu(out)
36 | return out
37 |
38 |
39 | class Bottleneck(nn.Module):
40 | expansion = 4
41 |
42 | def __init__(self, in_planes, planes, stride=1):
43 | super(Bottleneck, self).__init__()
44 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
45 | self.bn1 = nn.BatchNorm2d(planes)
46 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
47 | self.bn2 = nn.BatchNorm2d(planes)
48 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False)
49 | self.bn3 = nn.BatchNorm2d(self.expansion*planes)
50 |
51 | self.shortcut = nn.Sequential()
52 | if stride != 1 or in_planes != self.expansion*planes:
53 | self.shortcut = nn.Sequential(
54 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False),
55 | nn.BatchNorm2d(self.expansion*planes)
56 | )
57 |
58 | def forward(self, x):
59 | out = F.relu(self.bn1(self.conv1(x)))
60 | out = F.relu(self.bn2(self.conv2(out)))
61 | out = self.bn3(self.conv3(out))
62 | out += self.shortcut(x)
63 | out = F.relu(out)
64 | return out
65 |
66 |
67 | class ResNet(nn.Module):
68 | def __init__(self, block, num_blocks, num_classes=10):
69 | super(ResNet, self).__init__()
70 | self.in_planes = 64
71 |
72 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
73 | self.bn1 = nn.BatchNorm2d(64)
74 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
75 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
76 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
77 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
78 | self.linear = nn.Linear(512*block.expansion, num_classes)
79 |
80 | def _make_layer(self, block, planes, num_blocks, stride):
81 | strides = [stride] + [1]*(num_blocks-1)
82 | layers = []
83 | for stride in strides:
84 | layers.append(block(self.in_planes, planes, stride))
85 | self.in_planes = planes * block.expansion
86 | return nn.Sequential(*layers)
87 |
88 | def forward(self, x):
89 | out = F.relu(self.bn1(self.conv1(x)))
90 | out = self.layer1(out)
91 | out = self.layer2(out)
92 | out = self.layer3(out)
93 | out = self.layer4(out)
94 | out = F.avg_pool2d(out, 4)
95 | out = out.view(out.size(0), -1)
96 | out = self.linear(out)
97 | return out
98 |
99 |
100 | def ResNet18():
101 | return ResNet(BasicBlock, [2,2,2,2])
102 |
103 | def ResNet34():
104 | return ResNet(BasicBlock, [3,4,6,3])
105 |
106 | def ResNet50():
107 | return ResNet(Bottleneck, [3,4,6,3])
108 |
109 | def ResNet101():
110 | return ResNet(Bottleneck, [3,4,23,3])
111 |
112 | def ResNet152():
113 | return ResNet(Bottleneck, [3,8,36,3])
114 |
115 |
116 | def test():
117 | net = ResNet18()
118 | y = net(torch.randn(1,3,32,32))
119 | print(y.size())
120 |
121 | # test()
122 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/senet.py:
--------------------------------------------------------------------------------
1 | '''SENet in PyTorch.
2 |
3 | SENet is the winner of ImageNet-2017. The paper is not released yet.
4 | '''
5 | import torch
6 | import torch.nn as nn
7 | import torch.nn.functional as F
8 |
9 |
10 | class BasicBlock(nn.Module):
11 | def __init__(self, in_planes, planes, stride=1):
12 | super(BasicBlock, self).__init__()
13 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
14 | self.bn1 = nn.BatchNorm2d(planes)
15 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
16 | self.bn2 = nn.BatchNorm2d(planes)
17 |
18 | self.shortcut = nn.Sequential()
19 | if stride != 1 or in_planes != planes:
20 | self.shortcut = nn.Sequential(
21 | nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False),
22 | nn.BatchNorm2d(planes)
23 | )
24 |
25 | # SE layers
26 | self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1) # Use nn.Conv2d instead of nn.Linear
27 | self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1)
28 |
29 | def forward(self, x):
30 | out = F.relu(self.bn1(self.conv1(x)))
31 | out = self.bn2(self.conv2(out))
32 |
33 | # Squeeze
34 | w = F.avg_pool2d(out, out.size(2))
35 | w = F.relu(self.fc1(w))
36 | w = F.sigmoid(self.fc2(w))
37 | # Excitation
38 | out = out * w # New broadcasting feature from v0.2!
39 |
40 | out += self.shortcut(x)
41 | out = F.relu(out)
42 | return out
43 |
44 |
45 | class PreActBlock(nn.Module):
46 | def __init__(self, in_planes, planes, stride=1):
47 | super(PreActBlock, self).__init__()
48 | self.bn1 = nn.BatchNorm2d(in_planes)
49 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
50 | self.bn2 = nn.BatchNorm2d(planes)
51 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
52 |
53 | if stride != 1 or in_planes != planes:
54 | self.shortcut = nn.Sequential(
55 | nn.Conv2d(in_planes, planes, kernel_size=1, stride=stride, bias=False)
56 | )
57 |
58 | # SE layers
59 | self.fc1 = nn.Conv2d(planes, planes//16, kernel_size=1)
60 | self.fc2 = nn.Conv2d(planes//16, planes, kernel_size=1)
61 |
62 | def forward(self, x):
63 | out = F.relu(self.bn1(x))
64 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x
65 | out = self.conv1(out)
66 | out = self.conv2(F.relu(self.bn2(out)))
67 |
68 | # Squeeze
69 | w = F.avg_pool2d(out, out.size(2))
70 | w = F.relu(self.fc1(w))
71 | w = F.sigmoid(self.fc2(w))
72 | # Excitation
73 | out = out * w
74 |
75 | out += shortcut
76 | return out
77 |
78 |
79 | class SENet(nn.Module):
80 | def __init__(self, block, num_blocks, num_classes=10):
81 | super(SENet, self).__init__()
82 | self.in_planes = 64
83 |
84 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
85 | self.bn1 = nn.BatchNorm2d(64)
86 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
87 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
88 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
89 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
90 | self.linear = nn.Linear(512, num_classes)
91 |
92 | def _make_layer(self, block, planes, num_blocks, stride):
93 | strides = [stride] + [1]*(num_blocks-1)
94 | layers = []
95 | for stride in strides:
96 | layers.append(block(self.in_planes, planes, stride))
97 | self.in_planes = planes
98 | return nn.Sequential(*layers)
99 |
100 | def forward(self, x):
101 | out = F.relu(self.bn1(self.conv1(x)))
102 | out = self.layer1(out)
103 | out = self.layer2(out)
104 | out = self.layer3(out)
105 | out = self.layer4(out)
106 | out = F.avg_pool2d(out, 4)
107 | out = out.view(out.size(0), -1)
108 | out = self.linear(out)
109 | return out
110 |
111 |
112 | def SENet18():
113 | return SENet(PreActBlock, [2,2,2,2])
114 |
115 |
116 | def test():
117 | net = SENet18()
118 | y = net(torch.randn(1,3,32,32))
119 | print(y.size())
120 |
121 | # test()
122 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/pnasnet.py:
--------------------------------------------------------------------------------
1 | '''PNASNet in PyTorch.
2 |
3 | Paper: Progressive Neural Architecture Search
4 | '''
5 | import torch
6 | import torch.nn as nn
7 | import torch.nn.functional as F
8 |
9 |
10 | class SepConv(nn.Module):
11 | '''Separable Convolution.'''
12 | def __init__(self, in_planes, out_planes, kernel_size, stride):
13 | super(SepConv, self).__init__()
14 | self.conv1 = nn.Conv2d(in_planes, out_planes,
15 | kernel_size, stride,
16 | padding=(kernel_size-1)//2,
17 | bias=False, groups=in_planes)
18 | self.bn1 = nn.BatchNorm2d(out_planes)
19 |
20 | def forward(self, x):
21 | return self.bn1(self.conv1(x))
22 |
23 |
24 | class CellA(nn.Module):
25 | def __init__(self, in_planes, out_planes, stride=1):
26 | super(CellA, self).__init__()
27 | self.stride = stride
28 | self.sep_conv1 = SepConv(in_planes, out_planes, kernel_size=7, stride=stride)
29 | if stride==2:
30 | self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
31 | self.bn1 = nn.BatchNorm2d(out_planes)
32 |
33 | def forward(self, x):
34 | y1 = self.sep_conv1(x)
35 | y2 = F.max_pool2d(x, kernel_size=3, stride=self.stride, padding=1)
36 | if self.stride==2:
37 | y2 = self.bn1(self.conv1(y2))
38 | return F.relu(y1+y2)
39 |
40 | class CellB(nn.Module):
41 | def __init__(self, in_planes, out_planes, stride=1):
42 | super(CellB, self).__init__()
43 | self.stride = stride
44 | # Left branch
45 | self.sep_conv1 = SepConv(in_planes, out_planes, kernel_size=7, stride=stride)
46 | self.sep_conv2 = SepConv(in_planes, out_planes, kernel_size=3, stride=stride)
47 | # Right branch
48 | self.sep_conv3 = SepConv(in_planes, out_planes, kernel_size=5, stride=stride)
49 | if stride==2:
50 | self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
51 | self.bn1 = nn.BatchNorm2d(out_planes)
52 | # Reduce channels
53 | self.conv2 = nn.Conv2d(2*out_planes, out_planes, kernel_size=1, stride=1, padding=0, bias=False)
54 | self.bn2 = nn.BatchNorm2d(out_planes)
55 |
56 | def forward(self, x):
57 | # Left branch
58 | y1 = self.sep_conv1(x)
59 | y2 = self.sep_conv2(x)
60 | # Right branch
61 | y3 = F.max_pool2d(x, kernel_size=3, stride=self.stride, padding=1)
62 | if self.stride==2:
63 | y3 = self.bn1(self.conv1(y3))
64 | y4 = self.sep_conv3(x)
65 | # Concat & reduce channels
66 | b1 = F.relu(y1+y2)
67 | b2 = F.relu(y3+y4)
68 | y = torch.cat([b1,b2], 1)
69 | return F.relu(self.bn2(self.conv2(y)))
70 |
71 | class PNASNet(nn.Module):
72 | def __init__(self, cell_type, num_cells, num_planes):
73 | super(PNASNet, self).__init__()
74 | self.in_planes = num_planes
75 | self.cell_type = cell_type
76 |
77 | self.conv1 = nn.Conv2d(3, num_planes, kernel_size=3, stride=1, padding=1, bias=False)
78 | self.bn1 = nn.BatchNorm2d(num_planes)
79 |
80 | self.layer1 = self._make_layer(num_planes, num_cells=6)
81 | self.layer2 = self._downsample(num_planes*2)
82 | self.layer3 = self._make_layer(num_planes*2, num_cells=6)
83 | self.layer4 = self._downsample(num_planes*4)
84 | self.layer5 = self._make_layer(num_planes*4, num_cells=6)
85 |
86 | self.linear = nn.Linear(num_planes*4, 10)
87 |
88 | def _make_layer(self, planes, num_cells):
89 | layers = []
90 | for _ in range(num_cells):
91 | layers.append(self.cell_type(self.in_planes, planes, stride=1))
92 | self.in_planes = planes
93 | return nn.Sequential(*layers)
94 |
95 | def _downsample(self, planes):
96 | layer = self.cell_type(self.in_planes, planes, stride=2)
97 | self.in_planes = planes
98 | return layer
99 |
100 | def forward(self, x):
101 | out = F.relu(self.bn1(self.conv1(x)))
102 | out = self.layer1(out)
103 | out = self.layer2(out)
104 | out = self.layer3(out)
105 | out = self.layer4(out)
106 | out = self.layer5(out)
107 | out = F.avg_pool2d(out, 8)
108 | out = self.linear(out.view(out.size(0), -1))
109 | return out
110 |
111 |
112 | def PNASNetA():
113 | return PNASNet(CellA, num_cells=6, num_planes=44)
114 |
115 | def PNASNetB():
116 | return PNASNet(CellB, num_cells=6, num_planes=32)
117 |
118 |
119 | def test():
120 | net = PNASNetB()
121 | x = torch.randn(1,3,32,32)
122 | y = net(x)
123 | print(y)
124 |
125 | # test()
126 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/preact_resnet.py:
--------------------------------------------------------------------------------
1 | '''Pre-activation ResNet in PyTorch.
2 |
3 | Reference:
4 | [1] Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
5 | Identity Mappings in Deep Residual Networks. arXiv:1603.05027
6 | '''
7 | import torch
8 | import torch.nn as nn
9 | import torch.nn.functional as F
10 |
11 |
12 |
13 | class PreActBlock(nn.Module):
14 | '''Pre-activation version of the BasicBlock.'''
15 | expansion = 1
16 |
17 | def __init__(self, in_planes, planes, stride=1):
18 | super(PreActBlock, self).__init__()
19 | self.bn1 = nn.BatchNorm2d(in_planes)
20 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
21 | self.bn2 = nn.BatchNorm2d(planes)
22 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=1, padding=1, bias=False)
23 | self.ind = None
24 |
25 | if stride != 1 or in_planes != self.expansion*planes:
26 | self.shortcut = nn.Sequential(
27 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False)
28 | )
29 |
30 | def forward(self, x):
31 | out = F.relu(self.bn1(x))
32 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x
33 | out = self.conv1(out)
34 | out = self.conv2(F.relu(self.bn2(out)))
35 | if self.ind is not None:
36 | out += shortcut[:,self.ind,:,:]
37 | else:
38 | out += shortcut
39 | return out
40 |
41 |
42 | class PreActBottleneck(nn.Module):
43 | '''Pre-activation version of the original Bottleneck module.'''
44 | expansion = 4
45 |
46 | def __init__(self, in_planes, planes, stride=1):
47 | super(PreActBottleneck, self).__init__()
48 | self.bn1 = nn.BatchNorm2d(in_planes)
49 | self.conv1 = nn.Conv2d(in_planes, planes, kernel_size=1, bias=False)
50 | self.bn2 = nn.BatchNorm2d(planes)
51 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, padding=1, bias=False)
52 | self.bn3 = nn.BatchNorm2d(planes)
53 | self.conv3 = nn.Conv2d(planes, self.expansion*planes, kernel_size=1, bias=False)
54 |
55 | if stride != 1 or in_planes != self.expansion*planes:
56 | self.shortcut = nn.Sequential(
57 | nn.Conv2d(in_planes, self.expansion*planes, kernel_size=1, stride=stride, bias=False)
58 | )
59 |
60 | def forward(self, x):
61 | out = F.relu(self.bn1(x))
62 | shortcut = self.shortcut(out) if hasattr(self, 'shortcut') else x
63 | out = self.conv1(out)
64 | out = self.conv2(F.relu(self.bn2(out)))
65 | out = self.conv3(F.relu(self.bn3(out)))
66 | out += shortcut
67 | return out
68 |
69 |
70 | class PreActResNet(nn.Module):
71 | def __init__(self, block, num_blocks, num_classes=10):
72 | super(PreActResNet, self).__init__()
73 | self.in_planes = 64
74 |
75 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
76 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1)
77 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2)
78 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2)
79 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2)
80 | self.avgpool = nn.AvgPool2d(4)
81 | self.linear = nn.Linear(512*block.expansion, num_classes)
82 |
83 | def _make_layer(self, block, planes, num_blocks, stride):
84 | strides = [stride] + [1]*(num_blocks-1)
85 | layers = []
86 | for stride in strides:
87 | layers.append(block(self.in_planes, planes, stride))
88 | self.in_planes = planes * block.expansion
89 | return nn.Sequential(*layers)
90 |
91 | def forward(self, x):
92 | out = self.conv1(x)
93 | out = self.layer1(out)
94 | out = self.layer2(out)
95 | out = self.layer3(out)
96 | out = self.layer4(out)
97 | out = self.avgpool(out)
98 | out = out.view(out.size(0), -1)
99 | out = self.linear(out)
100 | return out
101 |
102 |
103 | def PreActResNet18(num_classes=10):
104 | return PreActResNet(PreActBlock, [2,2,2,2], num_classes=num_classes)
105 |
106 | def PreActResNet34():
107 | return PreActResNet(PreActBlock, [3,4,6,3])
108 |
109 | def PreActResNet50():
110 | return PreActResNet(PreActBottleneck, [3,4,6,3])
111 |
112 | def PreActResNet101():
113 | return PreActResNet(PreActBottleneck, [3,4,23,3])
114 |
115 | def PreActResNet152():
116 | return PreActResNet(PreActBottleneck, [3,8,36,3])
117 |
118 |
119 | def test():
120 | net = PreActResNet18()
121 | y = net((torch.randn(1,3,32,32)))
122 | print(y.size())
123 |
124 | # test()
125 |
--------------------------------------------------------------------------------
/models/wresnet.py:
--------------------------------------------------------------------------------
1 | """
2 | Code adapted from https://github.com/xternalz/WideResNet-pytorch
3 | Modifications = return activations for use in attention transfer,
4 | as done before e.g in https://github.com/BayesWatch/pytorch-moonshine
5 | """
6 |
7 | import math
8 | import torch
9 | import torch.nn as nn
10 | import torch.nn.functional as F
11 |
12 |
13 | class BasicBlock(nn.Module):
14 | def __init__(self, in_planes, out_planes, stride, dropRate=0.0):
15 | super(BasicBlock, self).__init__()
16 | self.bn1 = nn.BatchNorm2d(in_planes)
17 | self.relu1 = nn.ReLU(inplace=True)
18 | self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
19 | padding=1, bias=False)
20 | self.bn2 = nn.BatchNorm2d(out_planes)
21 | self.relu2 = nn.ReLU(inplace=True)
22 | self.conv2 = nn.Conv2d(out_planes, out_planes, kernel_size=3, stride=1,
23 | padding=1, bias=False)
24 | self.droprate = dropRate
25 | self.equalInOut = (in_planes == out_planes)
26 | self.convShortcut = (not self.equalInOut) and nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride,
27 | padding=0, bias=False) or None
28 | def forward(self, x):
29 | if not self.equalInOut:
30 | x = self.relu1(self.bn1(x))
31 | else:
32 | out = self.relu1(self.bn1(x))
33 | out = self.relu2(self.bn2(self.conv1(out if self.equalInOut else x)))
34 | if self.droprate > 0:
35 | out = F.dropout(out, p=self.droprate, training=self.training)
36 | out = self.conv2(out)
37 | return torch.add(x if self.equalInOut else self.convShortcut(x), out)
38 |
39 | class NetworkBlock(nn.Module):
40 | def __init__(self, nb_layers, in_planes, out_planes, block, stride, dropRate=0.0):
41 | super(NetworkBlock, self).__init__()
42 | self.layer = self._make_layer(block, in_planes, out_planes, nb_layers, stride, dropRate)
43 |
44 | def _make_layer(self, block, in_planes, out_planes, nb_layers, stride, dropRate):
45 | layers = []
46 | for i in range(int(nb_layers)):
47 | layers.append(block(i == 0 and in_planes or out_planes, out_planes, i == 0 and stride or 1, dropRate))
48 | return nn.Sequential(*layers)
49 |
50 | def forward(self, x):
51 | return self.layer(x)
52 |
53 | class WideResNet(nn.Module):
54 | def __init__(self, depth, num_classes, widen_factor=1, dropRate=0.0):
55 | super(WideResNet, self).__init__()
56 | nChannels = [16, 16*widen_factor, 32*widen_factor, 64*widen_factor]
57 | assert((depth - 4) % 6 == 0)
58 | n = (depth - 4) / 6
59 | block = BasicBlock
60 | # 1st conv before any network block
61 | self.conv1 = nn.Conv2d(3, nChannels[0], kernel_size=3, stride=1,
62 | padding=1, bias=False)
63 | # 1st block
64 | self.block1 = NetworkBlock(n, nChannels[0], nChannels[1], block, 1, dropRate)
65 | # 2nd block
66 | self.block2 = NetworkBlock(n, nChannels[1], nChannels[2], block, 2, dropRate)
67 | # 3rd block
68 | self.block3 = NetworkBlock(n, nChannels[2], nChannels[3], block, 2, dropRate)
69 | # global average pooling and classifier
70 | self.bn1 = nn.BatchNorm2d(nChannels[3])
71 | self.relu = nn.ReLU(inplace=True)
72 | self.fc = nn.Linear(nChannels[3], num_classes)
73 | self.nChannels = nChannels[3]
74 |
75 | for m in self.modules():
76 | if isinstance(m, nn.Conv2d):
77 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
78 | m.weight.data.normal_(0, math.sqrt(2. / n))
79 | elif isinstance(m, nn.BatchNorm2d):
80 | m.weight.data.fill_(1)
81 | m.bias.data.zero_()
82 | elif isinstance(m, nn.Linear):
83 | m.bias.data.zero_()
84 |
85 |
86 | def forward(self, x, output_embedding=False):
87 | out = self.conv1(x)
88 | out = self.block1(out)
89 | out = self.block2(out)
90 | out = self.block3(out)
91 | out = self.relu(self.bn1(out))
92 | out = F.avg_pool2d(out, 8)
93 | out = out.view(-1, self.nChannels)
94 | if output_embedding:
95 | return self.fc(out), out
96 | else:
97 | return self.fc(out)
98 |
99 |
100 | if __name__ == '__main__':
101 | import random
102 | import time
103 | # from torchsummary import summary
104 |
105 | random.seed(1234) # torch transforms use this seed
106 | torch.manual_seed(1234)
107 | torch.cuda.manual_seed(1234)
108 |
109 | x = torch.FloatTensor(64, 3, 32, 32).uniform_(0, 1)
110 |
111 | ### WideResNets
112 | # Notation: W-depth-wideningfactor
113 | model = WideResNet(depth=16, num_classes=10, widen_factor=1, dropRate=0.0)
114 | model = WideResNet(depth=16, num_classes=10, widen_factor=2, dropRate=0.0)
115 | #model = WideResNet(depth=16, num_classes=10, widen_factor=8, dropRate=0.0)
116 | #model = WideResNet(depth=16, num_classes=10, widen_factor=10, dropRate=0.0)
117 | #model = WideResNet(depth=22, num_classes=10, widen_factor=8, dropRate=0.0)
118 | #model = WideResNet(depth=34, num_classes=10, widen_factor=2, dropRate=0.0)
119 | #model = WideResNet(depth=40, num_classes=10, widen_factor=10, dropRate=0.0)
120 | model = WideResNet(depth=40, num_classes=10, widen_factor=1, dropRate=0.0)
121 | model = WideResNet(depth=40, num_classes=10, widen_factor=2, dropRate=0.0)
122 | ###model = WideResNet(depth=50, num_classes=10, widen_factor=2, dropRate=0.0)
123 |
124 |
125 | t0 = time.time()
126 | output, _, __, ___ = model(x)
127 | print("Time taken for forward pass: {} s".format(time.time() - t0))
128 | print("\nOUTPUT SHPAE: ", output.shape)
129 |
130 | # summary(model, input_size=(3, 32, 32))
--------------------------------------------------------------------------------
/networks/models.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn.functional as F
3 | import torchvision
4 | from torch import nn
5 | from torchvision import transforms
6 |
7 | from .blocks import *
8 |
9 |
10 | class Normalize:
11 | def __init__(self, opt, expected_values, variance):
12 | self.n_channels = opt.input_channel
13 | self.expected_values = expected_values
14 | self.variance = variance
15 | assert self.n_channels == len(self.expected_values)
16 |
17 | def __call__(self, x):
18 | x_clone = x.clone()
19 | for channel in range(self.n_channels):
20 | x_clone[:, channel] = (x[:, channel] - self.expected_values[channel]) / self.variance[channel]
21 | return x_clone
22 |
23 |
24 | class Denormalize:
25 | def __init__(self, opt, expected_values, variance):
26 | self.n_channels = opt.input_channel
27 | self.expected_values = expected_values
28 | self.variance = variance
29 | assert self.n_channels == len(self.expected_values)
30 |
31 | def __call__(self, x):
32 | x_clone = x.clone()
33 | for channel in range(self.n_channels):
34 | x_clone[:, channel] = x[:, channel] * self.variance[channel] + self.expected_values[channel]
35 | return x_clone
36 |
37 |
38 | # ---------------------------- Generators ----------------------------#
39 |
40 |
41 | class Generator(nn.Sequential):
42 | def __init__(self, opt, out_channels=None):
43 | super(Generator, self).__init__()
44 | if opt.dataset == "mnist":
45 | channel_init = 16
46 | steps = 2
47 | else:
48 | channel_init = 32
49 | steps = 3
50 |
51 | channel_current = opt.input_channel
52 | channel_next = channel_init
53 | for step in range(steps):
54 | self.add_module("convblock_down_{}".format(2 * step), Conv2dBlock(channel_current, channel_next))
55 | self.add_module("convblock_down_{}".format(2 * step + 1), Conv2dBlock(channel_next, channel_next))
56 | self.add_module("downsample_{}".format(step), DownSampleBlock())
57 | if step < steps - 1:
58 | channel_current = channel_next
59 | channel_next *= 2
60 |
61 | self.add_module("convblock_middle", Conv2dBlock(channel_next, channel_next))
62 |
63 | channel_current = channel_next
64 | channel_next = channel_current // 2
65 | for step in range(steps):
66 | self.add_module("upsample_{}".format(step), UpSampleBlock())
67 | self.add_module("convblock_up_{}".format(2 * step), Conv2dBlock(channel_current, channel_current))
68 | if step == steps - 1:
69 | self.add_module(
70 | "convblock_up_{}".format(2 * step + 1), Conv2dBlock(channel_current, channel_next, relu=False)
71 | )
72 | else:
73 | self.add_module("convblock_up_{}".format(2 * step + 1), Conv2dBlock(channel_current, channel_next))
74 | channel_current = channel_next
75 | channel_next = channel_next // 2
76 | if step == steps - 2:
77 | if out_channels is None:
78 | channel_next = opt.input_channel
79 | else:
80 | channel_next = out_channels
81 |
82 | self._EPSILON = 1e-7
83 | self._normalizer = self._get_normalize(opt)
84 | self._denormalizer = self._get_denormalize(opt)
85 |
86 | def _get_denormalize(self, opt):
87 | if opt.dataset == "CIFAR10":
88 | denormalizer = Denormalize(opt, [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261])
89 | elif opt.dataset == "mnist":
90 | denormalizer = Denormalize(opt, [0.5], [0.5])
91 | elif opt.dataset == "gtsrb":
92 | denormalizer = None
93 | else:
94 | raise Exception("Invalid dataset")
95 | return denormalizer
96 |
97 | def _get_normalize(self, opt):
98 | if opt.dataset == "CIFAR10":
99 | normalizer = Normalize(opt, [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261])
100 | elif opt.dataset == "mnist":
101 | normalizer = Normalize(opt, [0.5], [0.5])
102 | elif opt.dataset == "gtsrb":
103 | normalizer = None
104 | else:
105 | raise Exception("Invalid dataset")
106 | return normalizer
107 |
108 | def forward(self, x):
109 | for module in self.children():
110 | x = module(x)
111 | x = nn.Tanh()(x) / (2 + self._EPSILON) + 0.5
112 | return x
113 |
114 | def normalize_pattern(self, x):
115 | if self._normalizer:
116 | x = self._normalizer(x)
117 | return x
118 |
119 | def denormalize_pattern(self, x):
120 | if self._denormalizer:
121 | x = self._denormalizer(x)
122 | return x
123 |
124 | def threshold(self, x):
125 | return nn.Tanh()(x * 20 - 10) / (2 + self._EPSILON) + 0.5
126 |
127 |
128 | # ---------------------------- Classifiers ----------------------------#
129 |
130 |
131 | class NetC_MNIST(nn.Module):
132 | def __init__(self):
133 | super(NetC_MNIST, self).__init__()
134 | self.conv1 = nn.Conv2d(1, 32, (5, 5), 1, 0)
135 | self.relu2 = nn.ReLU(inplace=True)
136 | self.dropout3 = nn.Dropout(0.1)
137 |
138 | self.maxpool4 = nn.MaxPool2d((2, 2))
139 | self.conv5 = nn.Conv2d(32, 64, (5, 5), 1, 0)
140 | self.relu6 = nn.ReLU(inplace=True)
141 | self.dropout7 = nn.Dropout(0.1)
142 |
143 | self.maxpool5 = nn.MaxPool2d((2, 2))
144 | self.flatten = nn.Flatten()
145 | self.linear6 = nn.Linear(64 * 4 * 4, 512)
146 | self.relu7 = nn.ReLU(inplace=True)
147 | self.dropout8 = nn.Dropout(0.1)
148 | self.linear9 = nn.Linear(512, 10)
149 |
150 | def forward(self, x):
151 | for module in self.children():
152 | x = module(x)
153 | return x
154 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/models.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torchvision
3 | import torch.nn.functional as F
4 | from torch import nn
5 | from .blocks import *
6 | from torchvision import transforms
7 |
8 |
9 |
10 | class Normalize:
11 | def __init__(self, opt, expected_values, variance):
12 | self.n_channels = opt.input_channel
13 | self.expected_values = expected_values
14 | self.variance = variance
15 | assert self.n_channels == len(self.expected_values)
16 |
17 | def __call__(self, x):
18 | x_clone = x.clone()
19 | for channel in range(self.n_channels):
20 | x_clone[:, channel] = (x[:, channel] - self.expected_values[channel]) / self.variance[channel]
21 | return x_clone
22 |
23 |
24 | class Denormalize:
25 | def __init__(self, opt, expected_values, variance):
26 | self.n_channels = opt.input_channel
27 | self.expected_values = expected_values
28 | self.variance = variance
29 | assert self.n_channels == len(self.expected_values)
30 |
31 | def __call__(self, x):
32 | x_clone = x.clone()
33 | for channel in range(self.n_channels):
34 | x_clone[:, channel] = x[:, channel] * self.variance[channel] + self.expected_values[channel]
35 | return x_clone
36 |
37 |
38 | #---------------------------- Generators ----------------------------#
39 |
40 | class Generator(nn.Sequential):
41 | def __init__(self, opt, out_channels = None):
42 | super(Generator, self).__init__()
43 | if(opt.dataset == 'mnist'):
44 | channel_init = 16
45 | steps = 2
46 | else:
47 | channel_init = 32
48 | steps = 3
49 |
50 | channel_current = opt.input_channel
51 | channel_next = channel_init
52 | for step in range(steps):
53 | self.add_module('convblock_down_{}'.format(2 * step), Conv2dBlock(channel_current, channel_next))
54 | self.add_module('convblock_down_{}'.format(2 * step + 1), Conv2dBlock(channel_next, channel_next))
55 | self.add_module('downsample_{}'.format(step), DownSampleBlock())
56 | if(step < steps - 1):
57 | channel_current = channel_next
58 | channel_next *= 2
59 |
60 | self.add_module('convblock_middle', Conv2dBlock(channel_next, channel_next))
61 |
62 | channel_current = channel_next
63 | channel_next = channel_current // 2
64 | for step in range(steps):
65 | self.add_module('upsample_{}'.format(step), UpSampleBlock())
66 | self.add_module('convblock_up_{}'.format(2 * step), Conv2dBlock(channel_current, channel_current))
67 | if step == steps - 1:
68 | self.add_module('convblock_up_{}'.format(2 * step + 1), Conv2dBlock(channel_current, channel_next, relu=False))
69 | else:
70 | self.add_module('convblock_up_{}'.format(2 * step + 1), Conv2dBlock(channel_current, channel_next))
71 | channel_current = channel_next
72 | channel_next = channel_next // 2
73 | if(step == steps - 2):
74 | if out_channels is None:
75 | channel_next = opt.input_channel
76 | else:
77 | channel_next = out_channels
78 |
79 | self._EPSILON = 1e-7
80 | self._normalizer = self._get_normalize(opt)
81 | self._denormalizer = self._get_denormalize(opt)
82 |
83 | def _get_denormalize(self, opt):
84 | if(opt.dataset == 'cifar10'):
85 | denormalizer = Denormalize(opt, [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261])#反归一化
86 | elif(opt.dataset == 'mnist'):
87 | denormalizer = Denormalize(opt, [0.5], [0.5])
88 | elif(opt.dataset == 'gtsrb'):
89 | denormalizer = None
90 | else:
91 | raise Exception("Invalid dataset")
92 | return denormalizer
93 |
94 | def _get_normalize(self, opt):
95 | if(opt.dataset == 'cifar10'):
96 | normalizer = Normalize(opt, [0.4914, 0.4822, 0.4465], [0.247, 0.243, 0.261])#归一化
97 | elif(opt.dataset == 'mnist'):
98 | normalizer = Normalize(opt, [0.5], [0.5])
99 | elif(opt.dataset == 'gtsrb'):
100 | normalizer = None
101 | else:
102 | raise Exception("Invalid dataset")
103 | return normalizer
104 |
105 | def forward(self, x):
106 | for module in self.children():
107 | x = module(x)
108 | x = nn.Tanh()(x) / (2 + self._EPSILON) + 0.5
109 | return x
110 |
111 | def normalize_pattern(self, x):
112 | if(self._normalizer):
113 | x = self._normalizer(x)
114 | return x
115 |
116 | def denormalize_pattern(self, x):
117 | if(self._denormalizer):
118 | x = self._denormalizer(x)
119 | return x
120 |
121 | def threshold(self, x):
122 | return nn.Tanh()(x*20 - 10) / (2 + self._EPSILON) + 0.5
123 |
124 | #---------------------------- Classifiers ----------------------------#
125 |
126 | class NetC_MNIST(nn.Module):
127 | def __init__(self):
128 | super(NetC_MNIST, self).__init__()
129 | self.conv1 = nn.Conv2d(1, 32, (5, 5), 1, 0)
130 | self.relu2 = nn.ReLU(inplace=True)
131 | self.dropout3 = nn.Dropout(0.1)
132 |
133 | self.maxpool4 = nn.MaxPool2d((2, 2))
134 | self.conv5 = nn.Conv2d(32, 64, (5, 5), 1, 0)
135 | self.relu6 = nn.ReLU(inplace=True)
136 | self.dropout7 = nn.Dropout(0.1)
137 |
138 | self.maxpool5 = nn.MaxPool2d((2, 2))
139 | self.flatten = nn.Flatten()
140 | self.linear6 = nn.Linear(64 * 4 * 4, 512)
141 | self.relu7 = nn.ReLU(inplace=True)
142 | self.dropout8 = nn.Dropout(0.1)
143 | self.linear9 = nn.Linear(512, 10)
144 |
145 | def forward(self, x):
146 | for module in self.children():
147 | x = module(x)
148 | return x
149 |
150 |
151 |
--------------------------------------------------------------------------------
/models/resnet.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # @Data:2020/7/14 17:37
3 | # @Author:lyg
4 |
5 | from __future__ import absolute_import
6 |
7 | '''Resnet for cifar dataset.
8 | Ported form
9 | https://github.com/facebook/fb.resnet.torch
10 | and
11 | https://github.com/pytorch/vision/blob/master/torchvision/models/resnet.py
12 | (c) YANG, Wei
13 | '''
14 | import torch.nn as nn
15 | import math
16 |
17 | __all__ = ['resnet']
18 |
19 |
20 | def conv3x3(in_planes, out_planes, stride=1):
21 | "3x3 convolution with padding"
22 | return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride,
23 | padding=1, bias=False)
24 |
25 |
26 | class BasicBlock(nn.Module):
27 | expansion = 1
28 |
29 | def __init__(self, inplanes, planes, stride=1, downsample=None):
30 | super(BasicBlock, self).__init__()
31 | self.conv1 = conv3x3(inplanes, planes, stride)
32 | self.bn1 = nn.BatchNorm2d(planes)
33 | self.relu = nn.ReLU(inplace=True)
34 | self.conv2 = conv3x3(planes, planes)
35 | self.bn2 = nn.BatchNorm2d(planes)
36 | self.downsample = downsample
37 | self.stride = stride
38 |
39 | def forward(self, x):
40 | residual = x
41 |
42 | out = self.conv1(x)
43 | out = self.bn1(out)
44 | out = self.relu(out)
45 |
46 | out = self.conv2(out)
47 | out = self.bn2(out)
48 |
49 | if self.downsample is not None:
50 | residual = self.downsample(x)
51 |
52 | out += residual
53 | out = self.relu(out)
54 |
55 | return out
56 |
57 |
58 | class Bottleneck(nn.Module):
59 | expansion = 4
60 |
61 | def __init__(self, inplanes, planes, stride=1, downsample=None):
62 | super(Bottleneck, self).__init__()
63 | self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False)
64 | self.bn1 = nn.BatchNorm2d(planes)
65 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride,
66 | padding=1, bias=False)
67 | self.bn2 = nn.BatchNorm2d(planes)
68 | self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False)
69 | self.bn3 = nn.BatchNorm2d(planes * 4)
70 | self.relu = nn.ReLU(inplace=True)
71 | self.downsample = downsample
72 | self.stride = stride
73 |
74 | def forward(self, x):
75 | residual = x
76 |
77 | out = self.conv1(x)
78 | out = self.bn1(out)
79 | out = self.relu(out)
80 |
81 | out = self.conv2(out)
82 | out = self.bn2(out)
83 | out = self.relu(out)
84 |
85 | out = self.conv3(out)
86 | out = self.bn3(out)
87 |
88 | if self.downsample is not None:
89 | residual = self.downsample(x)
90 |
91 | out += residual
92 | out = self.relu(out)
93 |
94 | return out
95 |
96 |
97 | class ResNet(nn.Module):
98 |
99 | def __init__(self, depth, num_classes=1000, block_name='BasicBlock'):
100 | super(ResNet, self).__init__()
101 | # Model type specifies number of layers for CIFAR-10 model
102 | if block_name.lower() == 'basicblock':
103 | assert (depth - 2) % 6 == 0, 'When use basicblock, depth should be 6n+2, e.g. 20, 32, 44, 56, 110, 1202'
104 | n = (depth - 2) // 6
105 | block = BasicBlock
106 | elif block_name.lower() == 'bottleneck':
107 | assert (depth - 2) % 9 == 0, 'When use bottleneck, depth should be 9n+2, e.g. 20, 29, 47, 56, 110, 1199'
108 | n = (depth - 2) // 9
109 | block = Bottleneck
110 | else:
111 | raise ValueError('block_name shoule be Basicblock or Bottleneck')
112 |
113 | self.inplanes = 16
114 | self.conv1 = nn.Conv2d(3, 16, kernel_size=3, padding=1,
115 | bias=False)
116 | self.bn1 = nn.BatchNorm2d(16)
117 | self.relu = nn.ReLU(inplace=True)
118 | self.layer1 = self._make_layer(block, 16, n)
119 | self.layer2 = self._make_layer(block, 32, n, stride=2)
120 | self.layer3 = self._make_layer(block, 64, n, stride=2)
121 | self.avgpool = nn.AvgPool2d(8)
122 | self.fc = nn.Linear(64 * block.expansion, num_classes)
123 |
124 | for m in self.modules():
125 | if isinstance(m, nn.Conv2d):
126 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
127 | m.weight.data.normal_(0, math.sqrt(2. / n))
128 | elif isinstance(m, nn.BatchNorm2d):
129 | m.weight.data.fill_(1)
130 | m.bias.data.zero_()
131 |
132 | def _make_layer(self, block, planes, blocks, stride=1):
133 | downsample = None
134 | if stride != 1 or self.inplanes != planes * block.expansion:
135 | downsample = nn.Sequential(
136 | nn.Conv2d(self.inplanes, planes * block.expansion,
137 | kernel_size=1, stride=stride, bias=False),
138 | nn.BatchNorm2d(planes * block.expansion),
139 | )
140 |
141 | layers = []
142 | layers.append(block(self.inplanes, planes, stride, downsample))
143 | self.inplanes = planes * block.expansion
144 | for i in range(1, blocks):
145 | layers.append(block(self.inplanes, planes))
146 |
147 | return nn.Sequential(*layers)
148 |
149 | def forward(self, x):
150 | x = self.conv1(x)
151 | x = self.bn1(x)
152 | x = self.relu(x) # 32x32
153 |
154 | x = self.layer1(x) # 32x32
155 | activation1 = x
156 | x = self.layer2(x) # 16x16
157 | activation2 = x
158 | x = self.layer3(x) # 8x8
159 | activation3 = x
160 |
161 | x = self.avgpool(x)
162 | x = x.view(x.size(0), -1)
163 | x = self.fc(x)
164 |
165 | return activation1, activation2, activation3, x
166 |
167 |
168 | def resnet(**kwargs):
169 | """
170 | Constructs a ResNet model.
171 | """
172 | return ResNet(**kwargs)
--------------------------------------------------------------------------------
/models/lenet.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn as nn
3 | import torch.nn.functional as F
4 |
5 | class View(nn.Module):
6 | """
7 | For convenience so we can add in in nn.Sequential
8 | instead of doing it manually in forward()
9 | """
10 | def __init__(self, size):
11 | super(View, self).__init__()
12 | self.size = size
13 |
14 | def forward(self, tensor):
15 | return tensor.view(self.size)
16 |
17 | class LeNet5(nn.Module):
18 | """
19 | For SVHN/CIFAR experiments
20 | """
21 | def __init__(self, n_classes):
22 | super(LeNet5, self).__init__()
23 | self.n_classes = n_classes
24 | self.conv1 = nn.Conv2d(3, 32, kernel_size=3)
25 | self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
26 | # self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
27 | # self.conv3 = nn.Conv2d(32, 64, kernel_size=3)
28 | # self.conv4 = nn.Conv2d(64, 64, kernel_size=3)
29 | # self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
30 | # self.conv4_drop = nn.Dropout2d(0.5)
31 | self.fc1 = nn.Linear(64*6*6, 128)
32 | self.fc2 = nn.Linear(128, n_classes)
33 |
34 | def forward(self, x):
35 | out = F.relu(F.max_pool2d(self.conv1(x), 2))
36 | # print('out;', out.shape)
37 | out = F.relu(F.max_pool2d(self.conv2(out), 2))
38 | activation = out
39 | #print('out;', out.shape)
40 | out = out.view(-1, 64*6*6)
41 | out = F.relu(self.fc1(out))
42 | out = F.dropout(out, training=self.training)
43 | out = self.fc2(out)
44 | return activation, out
45 |
46 |
47 |
48 | class LeNet7_T(nn.Module):
49 | """
50 | For SVHN/MNIST experiments
51 | """
52 | def __init__(self, n_classes):
53 | super(LeNet7_T, self).__init__()
54 | self.n_classes = n_classes
55 | self.conv1 = nn.Conv2d(1, 32, kernel_size=3)
56 | self.conv2 = nn.Conv2d(32, 32, kernel_size=3)
57 | # self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
58 | self.conv3 = nn.Conv2d(32, 64, kernel_size=3)
59 | self.conv4 = nn.Conv2d(64, 64, kernel_size=3)
60 | # self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
61 | # self.conv4_drop = nn.Dropout2d(0.5)
62 | self.fc1 = nn.Linear(64*4*4, 200)
63 | self.fc2 = nn.Linear(200, n_classes)
64 |
65 | def forward(self, x):
66 | out = F.relu((self.conv1(x)))
67 | # print('out;', out.shape)
68 | out = F.relu(F.max_pool2d(self.conv2(out), 2))
69 | out = F.relu((self.conv3(out)))
70 | out = F.relu(F.max_pool2d(self.conv4(out), 2))
71 | activation = out
72 | # print('out;', out.shape)
73 | out = out.view(-1, 64*4*4)
74 | out = F.relu(self.fc1(out))
75 | out = F.dropout(out, training=self.training)
76 | out = self.fc2(out)
77 | return activation, out
78 |
79 |
80 | class LeNet7_S(nn.Module):
81 | """
82 | For SVHN/MNIST experiments
83 | """
84 | def __init__(self, n_classes):
85 | super(LeNet7_S, self).__init__()
86 |
87 | self.n_classes = n_classes
88 | self.conv1 = nn.Conv2d(1, 64, kernel_size=3)
89 | self.conv2 = nn.Conv2d(64, 64, kernel_size=3)
90 | # self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
91 | self.conv3 = nn.Conv2d(64, 128, kernel_size=3)
92 | self.conv4 = nn.Conv2d(128, 128, kernel_size=3)
93 | # self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
94 | # self.conv4_drop = nn.Dropout2d(0.5)
95 | self.fc1 = nn.Linear(128*4*4, 256)
96 | self.fc2 = nn.Linear(256, n_classes)
97 |
98 | def forward(self, x):
99 | out = F.relu((self.conv1(x)))
100 | out = F.relu(F.max_pool2d(self.conv2(out), 2))
101 | out = F.relu((self.conv3(out)))
102 | out = F.relu(F.max_pool2d(self.conv4(out), 2))
103 | activation = out
104 | # print('out;', out.shape)
105 | out = out.view(-1, 128*4*4)
106 | out = F.relu(self.fc1(out))
107 | out = F.dropout(out, training=self.training)
108 | out = self.fc2(out)
109 | return activation, out
110 |
111 | class trojan_model(nn.Module):
112 | """
113 | For train trojan model
114 | """
115 | def __init__(self, n_classes):
116 | super(trojan_model, self).__init__()
117 |
118 | self.n_classes = n_classes
119 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
120 | self.conv2 = nn.Conv2d(64, 64, kernel_size=3)
121 | # self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
122 | self.conv3 = nn.Conv2d(64, 128, kernel_size=3)
123 | self.conv4 = nn.Conv2d(128, 128, kernel_size=3)
124 | # self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
125 | # self.conv4_drop = nn.Dropout2d(0.5)
126 | self.fc1 = nn.Linear(128*5*5, 256)
127 | self.fc2 = nn.Linear(256, n_classes)
128 |
129 | def forward(self, x):
130 | out = F.relu((self.conv1(x)))
131 | out = F.relu(F.max_pool2d(self.conv2(out), 2))
132 | activation1 = out
133 | out = F.relu((self.conv3(out)))
134 | activation2 = out
135 | out = F.relu(F.max_pool2d(self.conv4(out), 2))
136 | activation3 = out
137 | # print('out;', out.shape)
138 | out = out.view(-1, 128*5*5)
139 | out = F.relu(self.fc1(out))
140 | out = F.dropout(out, training=self.training)
141 | out = self.fc2(out)
142 | return activation1, activation2, activation3, out
143 |
144 | #
145 | # if __name__ == '__main__':
146 | # import random
147 | # import sys
148 | # # from torchsummary import summary
149 | #
150 | # random.seed(1234) # torch transforms use this seed
151 | # torch.manual_seed(1234)
152 | # torch.cuda.manual_seed(1234)
153 | #
154 | # ### LENET5
155 | # x = torch.FloatTensor(64, 3, 32, 32).uniform_(0, 1)
156 | # true_labels = torch.tensor([[2.], [3], [1], [8], [4]], requires_grad=True)
157 | # model = LeNet5(n_classes=10)
158 | # output, act = model(x)
159 | # print("\nOUTPUT SHAPE: ", output.shape)
160 | #
161 | # # summary(model, input_size=(3,32,32))
162 |
163 |
--------------------------------------------------------------------------------
/create_backdoor_data/Dynamic/networks/shufflenetv2.py:
--------------------------------------------------------------------------------
1 | '''ShuffleNetV2 in PyTorch.
2 |
3 | See the paper "ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design" for more details.
4 | '''
5 | import torch
6 | import torch.nn as nn
7 | import torch.nn.functional as F
8 |
9 |
10 | class ShuffleBlock(nn.Module):
11 | def __init__(self, groups=2):
12 | super(ShuffleBlock, self).__init__()
13 | self.groups = groups
14 |
15 | def forward(self, x):
16 | '''Channel shuffle: [N,C,H,W] -> [N,g,C/g,H,W] -> [N,C/g,g,H,w] -> [N,C,H,W]'''
17 | N, C, H, W = x.size()
18 | g = self.groups
19 | return x.view(N, g, C//g, H, W).permute(0, 2, 1, 3, 4).reshape(N, C, H, W)
20 |
21 |
22 | class SplitBlock(nn.Module):
23 | def __init__(self, ratio):
24 | super(SplitBlock, self).__init__()
25 | self.ratio = ratio
26 |
27 | def forward(self, x):
28 | c = int(x.size(1) * self.ratio)
29 | return x[:, :c, :, :], x[:, c:, :, :]
30 |
31 |
32 | class BasicBlock(nn.Module):
33 | def __init__(self, in_channels, split_ratio=0.5):
34 | super(BasicBlock, self).__init__()
35 | self.split = SplitBlock(split_ratio)
36 | in_channels = int(in_channels * split_ratio)
37 | self.conv1 = nn.Conv2d(in_channels, in_channels,
38 | kernel_size=1, bias=False)
39 | self.bn1 = nn.BatchNorm2d(in_channels)
40 | self.conv2 = nn.Conv2d(in_channels, in_channels,
41 | kernel_size=3, stride=1, padding=1, groups=in_channels, bias=False)
42 | self.bn2 = nn.BatchNorm2d(in_channels)
43 | self.conv3 = nn.Conv2d(in_channels, in_channels,
44 | kernel_size=1, bias=False)
45 | self.bn3 = nn.BatchNorm2d(in_channels)
46 | self.shuffle = ShuffleBlock()
47 |
48 | def forward(self, x):
49 | x1, x2 = self.split(x)
50 | out = F.relu(self.bn1(self.conv1(x2)))
51 | out = self.bn2(self.conv2(out))
52 | out = F.relu(self.bn3(self.conv3(out)))
53 | out = torch.cat([x1, out], 1)
54 | out = self.shuffle(out)
55 | return out
56 |
57 |
58 | class DownBlock(nn.Module):
59 | def __init__(self, in_channels, out_channels):
60 | super(DownBlock, self).__init__()
61 | mid_channels = out_channels // 2
62 | # left
63 | self.conv1 = nn.Conv2d(in_channels, in_channels,
64 | kernel_size=3, stride=2, padding=1, groups=in_channels, bias=False)
65 | self.bn1 = nn.BatchNorm2d(in_channels)
66 | self.conv2 = nn.Conv2d(in_channels, mid_channels,
67 | kernel_size=1, bias=False)
68 | self.bn2 = nn.BatchNorm2d(mid_channels)
69 | # right
70 | self.conv3 = nn.Conv2d(in_channels, mid_channels,
71 | kernel_size=1, bias=False)
72 | self.bn3 = nn.BatchNorm2d(mid_channels)
73 | self.conv4 = nn.Conv2d(mid_channels, mid_channels,
74 | kernel_size=3, stride=2, padding=1, groups=mid_channels, bias=False)
75 | self.bn4 = nn.BatchNorm2d(mid_channels)
76 | self.conv5 = nn.Conv2d(mid_channels, mid_channels,
77 | kernel_size=1, bias=False)
78 | self.bn5 = nn.BatchNorm2d(mid_channels)
79 |
80 | self.shuffle = ShuffleBlock()
81 |
82 | def forward(self, x):
83 | # left
84 | out1 = self.bn1(self.conv1(x))
85 | out1 = F.relu(self.bn2(self.conv2(out1)))
86 | # right
87 | out2 = F.relu(self.bn3(self.conv3(x)))
88 | out2 = self.bn4(self.conv4(out2))
89 | out2 = F.relu(self.bn5(self.conv5(out2)))
90 | # concat
91 | out = torch.cat([out1, out2], 1)
92 | out = self.shuffle(out)
93 | return out
94 |
95 |
96 | class ShuffleNetV2(nn.Module):
97 | def __init__(self, net_size):
98 | super(ShuffleNetV2, self).__init__()
99 | out_channels = configs[net_size]['out_channels']
100 | num_blocks = configs[net_size]['num_blocks']
101 |
102 | self.conv1 = nn.Conv2d(3, 24, kernel_size=3,
103 | stride=1, padding=1, bias=False)
104 | self.bn1 = nn.BatchNorm2d(24)
105 | self.in_channels = 24
106 | self.layer1 = self._make_layer(out_channels[0], num_blocks[0])
107 | self.layer2 = self._make_layer(out_channels[1], num_blocks[1])
108 | self.layer3 = self._make_layer(out_channels[2], num_blocks[2])
109 | self.conv2 = nn.Conv2d(out_channels[2], out_channels[3],
110 | kernel_size=1, stride=1, padding=0, bias=False)
111 | self.bn2 = nn.BatchNorm2d(out_channels[3])
112 | self.linear = nn.Linear(out_channels[3], 10)
113 |
114 | def _make_layer(self, out_channels, num_blocks):
115 | layers = [DownBlock(self.in_channels, out_channels)]
116 | for i in range(num_blocks):
117 | layers.append(BasicBlock(out_channels))
118 | self.in_channels = out_channels
119 | return nn.Sequential(*layers)
120 |
121 | def forward(self, x):
122 | out = F.relu(self.bn1(self.conv1(x)))
123 | # out = F.max_pool2d(out, 3, stride=2, padding=1)
124 | out = self.layer1(out)
125 | out = self.layer2(out)
126 | out = self.layer3(out)
127 | out = F.relu(self.bn2(self.conv2(out)))
128 | out = F.avg_pool2d(out, 4)
129 | out = out.view(out.size(0), -1)
130 | out = self.linear(out)
131 | return out
132 |
133 |
134 | configs = {
135 | 0.5: {
136 | 'out_channels': (48, 96, 192, 1024),
137 | 'num_blocks': (3, 7, 3)
138 | },
139 |
140 | 1: {
141 | 'out_channels': (116, 232, 464, 1024),
142 | 'num_blocks': (3, 7, 3)
143 | },
144 | 1.5: {
145 | 'out_channels': (176, 352, 704, 1024),
146 | 'num_blocks': (3, 7, 3)
147 | },
148 | 2: {
149 | 'out_channels': (224, 488, 976, 2048),
150 | 'num_blocks': (3, 7, 3)
151 | }
152 | }
153 |
154 |
155 | def test():
156 | net = ShuffleNetV2(net_size=0.5)
157 | x = torch.randn(3, 3, 32, 32)
158 | y = net(x)
159 | print(y.shape)
160 |
161 |
162 | # test()
163 |
--------------------------------------------------------------------------------
/config.py:
--------------------------------------------------------------------------------
1 | import argparse
2 |
3 | def get_arguments():
4 | parser = argparse.ArgumentParser()
5 |
6 | # various path
7 | parser.add_argument('--weight_root', type=str, default='./weight', help='save model weights')
8 | parser.add_argument('--log_root', type=str, default='./logs', help='logs are saved here')
9 | parser.add_argument('--dataset', type=str, default='CIFAR10', help='name of image dataset')
10 | parser.add_argument('--model_name', type=str, default='WRN-16-1', help='name of model')
11 | parser.add_argument('--load_fixed_data', type=int, default=0, help='load the local poisoned dataest')
12 | parser.add_argument('--checkpoint_root', type=str, default='./weight/backdoored_model/', help='path of backdoored model')
13 | parser.add_argument('--data_root', type=str,default='./data/',help='path of data')
14 |
15 | # training hyper parameters
16 | parser.add_argument('--print_freq', type=int, default=200, help='frequency of showing training results on console')
17 | parser.add_argument('--tuning_epochs', type=int, default=100, help='number of tune epochs to run')
18 | parser.add_argument('--batch_size', type=int, default=64, help='The size of batch')
19 | parser.add_argument('--lr', type=float, default=0.1, help='initial learning rate')
20 | parser.add_argument('--momentum', type=float, default=0.9, help='momentum')
21 | parser.add_argument('--weight_decay', type=float, default=1e-4, help='weight decay')
22 | parser.add_argument('--num_class', type=int, default=10, help='number of classes')
23 |
24 | parser.add_argument('--cuda', type=int, default=1)
25 | parser.add_argument('--device', type=str, default='cuda:1')
26 | parser.add_argument('--save', type=int, default=1)
27 | parser.add_argument('--disentangle', type=int, default=0)
28 | parser.add_argument('--interval', type=int, default=5, help='frequency of save model')
29 |
30 | # others
31 | parser.add_argument('--seed', type=int, default=2, help='random seed')
32 | parser.add_argument('--note', type=str, default='try', help='note for this run')
33 |
34 | # backdoor attacks
35 | parser.add_argument('--inject_portion', type=float, default=0.1, help='ratio of backdoor samples')
36 | parser.add_argument('--target_label', type=int, default=0, help='class of target label')
37 | parser.add_argument('--trigger_type', type=str, default='gridTrigger', help='type of backdoor trigger')
38 | parser.add_argument('--target_type', type=str, default='all2one', help='type of backdoor label')
39 | parser.add_argument('--trig_w', type=int, default=3, help='width of trigger pattern')
40 | parser.add_argument('--trig_h', type=int, default=3, help='height of trigger pattern')
41 | parser.add_argument("--input_height", type=int, default=32)
42 | parser.add_argument("--input_width", type=int, default=32)
43 |
44 | # for dynamic
45 | '''
46 | parser.add_argument("--data_root", type=str, default="data/")
47 | parser.add_argument("--temps", type=str, default="./temps")
48 |
49 | parser.add_argument("--input_height", type=int, default=32)
50 | parser.add_argument("--input_width", type=int, default=32)
51 | parser.add_argument("--input_channel", type=int, default=3)
52 | parser.add_argument("--num_classes", type=int, default=10)
53 |
54 | parser.add_argument("--batchsize", type=int, default=128)
55 | parser.add_argument("--lr_G", type=float, default=1e-2)
56 | parser.add_argument("--lr_C", type=float, default=1e-2)
57 | parser.add_argument("--lr_M", type=float, default=1e-2)
58 | parser.add_argument("--schedulerG_milestones", type=list, default=[200, 300, 400, 500])
59 | parser.add_argument("--schedulerC_milestones", type=list, default=[100, 200, 300, 400])
60 | parser.add_argument("--schedulerM_milestones", type=list, default=[10, 20])
61 | parser.add_argument("--schedulerG_lambda", type=float, default=0.1)
62 | parser.add_argument("--schedulerC_lambda", type=float, default=0.1)
63 | parser.add_argument("--schedulerM_lambda", type=float, default=0.1)
64 | parser.add_argument("--n_iters", type=int, default=600)
65 | parser.add_argument("--lambda_div", type=float, default=1)
66 | parser.add_argument("--lambda_norm", type=float, default=100)
67 | parser.add_argument("--num_workers", type=float, default=4)
68 |
69 | parser.add_argument("--attack_mode", type=str, default="all2one", help="all2one or all2all")
70 | parser.add_argument("--p_attack", type=float, default=0.1)
71 | parser.add_argument("--p_cross", type=float, default=0.1)
72 | parser.add_argument("--mask_density", type=float, default=0.032)
73 | parser.add_argument("--EPSILON", type=float, default=1e-7)
74 |
75 | parser.add_argument("--random_rotation", type=int, default=10)
76 | parser.add_argument("--random_crop", type=int, default=5)
77 |
78 | #for wanet
79 | parser.add_argument("--checkpoints", type=str, default="./checkpoints")
80 | parser.add_argument("--temps", type=str, default="./temps")
81 | parser.add_argument("--continue_training", action="store_true")
82 |
83 | parser.add_argument("--attack_mode", type=str, default="all2one")
84 |
85 | parser.add_argument("--input_channel", type=int, default=3)
86 | parser.add_argument("--num_classes", type=int, default=43)
87 |
88 | parser.add_argument("--bs", type=int, default=128)
89 | parser.add_argument("--lr_C", type=float, default=1e-2)
90 | parser.add_argument("--schedulerC_milestones", type=list, default=[100, 200, 300, 400])
91 | parser.add_argument("--schedulerC_lambda", type=float, default=0.1)
92 | parser.add_argument("--n_iters", type=int, default=1000)
93 | parser.add_argument("--num_workers", type=float, default=6)
94 |
95 | parser.add_argument("--pc", type=float, default=0.1)
96 | parser.add_argument("--cross_ratio", type=float, default=2) # rho_a = pc, rho_n = pc * cross_ratio
97 |
98 | parser.add_argument("--random_rotation", type=int, default=10)
99 | parser.add_argument("--random_crop", type=int, default=5)
100 |
101 | parser.add_argument("--s", type=float, default=0.5)
102 | parser.add_argument("--k", type=int, default=4)
103 | parser.add_argument(
104 | "--grid-rescale", type=float, default=1
105 | )
106 | '''
107 | return parser
108 |
--------------------------------------------------------------------------------
/utils/util.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import os
3 | import pandas as pd
4 | #import matplotlib.pyplot as plt
5 | import numpy as np
6 | from torch import nn
7 | from torch.nn import functional as F
8 |
9 | class AverageMeter(object):
10 | def __init__(self):
11 | self.reset()
12 |
13 | def reset(self):
14 | self.val = 0
15 | self.avg = 0
16 | self.sum = 0
17 | self.count = 0
18 |
19 | def update(self, val, n=1):
20 | self.val = val
21 | self.sum += val * n
22 | self.count += n
23 | self.avg = self.sum / self.count
24 |
25 |
26 | def print_network(net):
27 | num_params = 0
28 | for param in net.parameters():
29 | num_params += param.numel()
30 | print(net)
31 | print('Total number of parameters: %d' % num_params)
32 |
33 |
34 | def load_pretrained_model(model, pretrained_dict, wfc=True):
35 | model_dict = model.state_dict()
36 | # 1. filter out unnecessary keys
37 | if wfc:
38 | pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
39 | else:
40 | pretrained_dict = {k: v for k, v in pretrained_dict.items() if ((k in model_dict) and ('fc' not in k))}
41 | # 2. overwrite entries in the existing state dict
42 | model_dict.update(pretrained_dict)
43 | # 3. load the new state dict
44 | model.load_state_dict(model_dict)
45 |
46 |
47 | def transform_time(s):
48 | m, s = divmod(s, 60)
49 | h, m = divmod(m, 60)
50 | return h, m, s
51 |
52 |
53 | def accuracy(output, target, topk=(1,)):
54 | """Computes the precision@k for the specified values of k"""
55 | maxk = max(topk)
56 | batch_size = target.size(0)
57 |
58 | _, pred = output.topk(maxk, 1, True, True)
59 | pred = pred.t()
60 | correct = pred.eq(target.view(1, -1).expand_as(pred))
61 |
62 | res = []
63 | for k in topk:
64 | correct_k = correct[:k].reshape(-1).float().sum(0)
65 | res.append(correct_k.mul_(100.0 / batch_size))
66 | return res
67 |
68 |
69 | def save_history(cls_orig_acc, clease_trig_acc, cls_trig_loss, at_trig_loss, at_epoch_list, logs_dir):
70 | dataframe = pd.DataFrame({'epoch': at_epoch_list, 'cls_orig_acc': cls_orig_acc, 'clease_trig_acc': clease_trig_acc,
71 | 'cls_trig_loss': cls_trig_loss, 'at_trig_loss': at_trig_loss})
72 | dataframe.to_csv(logs_dir, index=False, sep=',')
73 |
74 |
75 | def shuffle(real):
76 | """
77 | shuffle data in a batch
78 | [1, 2, 3, 4, 5] -> [2, 3, 4, 5, 1]
79 | P(X,Y) -> P(X)P(Y) by shuffle Y in a batch
80 | P(X,Y) = [(1,1'),(2,2'),(3,3')] -> P(X)P(Y) = [(1,2'),(2,3'),(3,1')]
81 | :param real: Tensor of (batch_size, ...), data, batch_size > 1
82 | :returns: Tensor of (batch_size, ...), shuffled data
83 | """
84 | # |0 1 2 3| => |1 2 3 0|
85 | device = real.device
86 | batch_size = real.size(0)
87 | shuffled_index = (torch.arange(batch_size) + 1) % batch_size
88 | shuffled_index = shuffled_index.to(device)
89 | shuffled = real.index_select(dim=0, index=shuffled_index)
90 | return shuffled
91 |
92 |
93 | def spectral_norm(W, n_iteration=5):
94 | """
95 | Spectral normalization for Lipschitz constrain in Disc of WGAN
96 | Following https://blog.csdn.net/qq_16568205/article/details/99586056
97 | |W|^2 = principal eigenvalue of W^TW through power iteration
98 | v = W^Tu/|W^Tu|
99 | u = Wv / |Wv|
100 | |W|^2 = u^TWv
101 |
102 | :param w: Tensor of (out_dim, in_dim) or (out_dim), weight matrix of NN
103 | :param n_iteration: int, number of iterations for iterative calculation of spectral normalization:
104 | :returns: Tensor of (), spectral normalization of weight matrix
105 | """
106 | device = W.device
107 | # (o, i)
108 | # bias: (O) -> (o, 1)
109 | if W.dim() == 1:
110 | W = W.unsqueeze(-1)
111 | out_dim, in_dim = W.size()
112 | # (i, o)
113 | Wt = W.transpose(0, 1)
114 | # (1, i)
115 | u = torch.ones(1, in_dim).to(device)
116 | for _ in range(n_iteration):
117 | # (1, i) * (i, o) -> (1, o)
118 | v = torch.mm(u, Wt)
119 | v = v / v.norm(p=2)
120 | # (1, o) * (o, i) -> (1, i)
121 | u = torch.mm(v, W)
122 | u = u / u.norm(p=2)
123 | # (1, i) * (i, o) * (o, 1) -> (1, 1)
124 | sn = torch.mm(torch.mm(u, Wt), v.transpose(0, 1)).sum() ** 0.5
125 | return sn
126 |
127 |
128 | class MLP(nn.Module):
129 | """
130 | Multi-Layer Perceptron
131 | :param in_dim: int, size of input feature
132 | :param n_classes: int, number of output classes
133 | :param hidden_dim: int, size of hidden vector
134 | :param dropout: float, dropout rate
135 | :param n_layers: int, number of layers, at least 2, default = 2
136 | :param act: function, activation function, default = leaky_relu
137 | """
138 |
139 | def __init__(self, in_dim, n_classes, hidden_dim, dropout, n_layers=2, act=F.leaky_relu):
140 | super(MLP, self).__init__()
141 | self.l_in = nn.Linear(in_dim, hidden_dim)
142 | self.l_hs = nn.ModuleList(nn.Linear(hidden_dim, hidden_dim) for _ in range(n_layers - 2))
143 | self.l_out = nn.Linear(hidden_dim, n_classes)
144 | self.dropout = nn.Dropout(p=dropout)
145 | self.act = act
146 | return
147 |
148 | def forward(self, input):
149 | """
150 | :param input: Tensor of (batch_size, in_dim), input feature
151 | :returns: Tensor of (batch_size, n_classes), output class
152 | """
153 | hidden = self.act(self.l_in(self.dropout(input)))
154 | for l_h in self.l_hs:
155 | hidden = self.act(l_h(self.dropout(hidden)))
156 | output = self.l_out(self.dropout(hidden))
157 | return output
158 |
159 |
160 | class Disc(nn.Module):
161 | """
162 | 2-layer discriminator for MI estimator
163 | :param x_dim: int, size of x vector
164 | :param y_dim: int, size of y vector
165 | :param dropout: float, dropout rate
166 | """
167 |
168 | def __init__(self, x_dim, y_dim, dropout):
169 | super(Disc, self).__init__()
170 | self.disc = MLP(x_dim + y_dim, 1, y_dim, dropout, n_layers=2)
171 | return
172 |
173 | def forward(self, x, y):
174 | """
175 | :param x: Tensor of (batch_size, hidden_dim), x
176 | :param y: Tensor of (batch_size, hidden_dim), y
177 | :returns: Tensor of (batch_size), score
178 | """
179 | input = torch.cat((x, y), dim=-1)
180 | # (b, 1) -> (b)
181 | score = self.disc(input).squeeze(-1)
182 | return score
183 |
184 |
185 | class DisenEstimator(nn.Module):
186 | """
187 | Disentangling estimator by WGAN-like adversarial training and spectral normalization for MI minimization
188 | MI(X,Y) = E_pxy[T(x,y)] - E_pxpy[T(x,y)]
189 | min_xy max_T MI(X,Y)
190 |
191 | :param hidden_dim: int, size of question embedding
192 | :param dropout: float, dropout rate
193 | """
194 |
195 | def __init__(self, dim1, dim2, dropout):
196 | super(DisenEstimator, self).__init__()
197 | self.disc = Disc(dim1, dim2, dropout)
198 | return
199 |
200 | def forward(self, x, y):
201 | """
202 | :param x: Tensor of (batch_size, hidden_dim), x
203 | :param y: Tensor of (batch_size, hidden_dim), y
204 | :returns: Tensor of (), loss for MI minimization
205 | """
206 | sy = shuffle(y)
207 | loss = self.disc(x, y).mean() - self.disc(x, sy).mean()
208 | return loss*0.01
209 |
210 | def spectral_norm(self):
211 | """
212 | spectral normalization to satisfy Lipschitz constrain for Disc of WGAN
213 | """
214 | # Lipschitz constrain for Disc of WGAN
215 | with torch.no_grad():
216 | for w in self.parameters():
217 | w.data /= spectral_norm(w.data)
218 | return
--------------------------------------------------------------------------------
/train.py:
--------------------------------------------------------------------------------
1 | from models.selector import *
2 | from utils.util import *
3 | from data_loader import *
4 | from config import get_arguments
5 | import torch
6 | import torch.nn as nn
7 | import torch.nn.functional as F
8 | from torch.optim.adam import Adam
9 | from torch.optim.lr_scheduler import StepLR
10 | import numpy as np
11 | import random
12 |
13 |
14 | def train_step_clean(opt, train_loader, model_clean, model_backdoor, disen_estimator, optimizer, adv_optimizer,
15 | criterion, epoch):
16 | criterion1 = nn.CrossEntropyLoss(reduction='none')
17 | losses = AverageMeter()
18 | disen_losses = AverageMeter()
19 | top1 = AverageMeter()
20 | top5 = AverageMeter()
21 | model_clean.train()
22 | model_backdoor.eval()
23 |
24 | if opt.disentangle:
25 | for idx, (img, target, indicator) in enumerate(train_loader, start=1):
26 | if opt.cuda:
27 | img = img.type(torch.FloatTensor)
28 | img = img.to(opt.device)
29 |
30 | output1, z_hidden = model_clean(img, True)
31 | with torch.no_grad():
32 | output2, r_hidden = model_backdoor(img, True)
33 |
34 | # Train discriminator
35 | # stop gradient propagation to encoder
36 | r_hidden, z_hidden = r_hidden.detach(), z_hidden.detach()
37 | # max dis_loss
38 | dis_loss = - disen_estimator(r_hidden, z_hidden)
39 | disen_losses.update(dis_loss.item(), img.size(0))
40 | adv_optimizer.zero_grad()
41 | dis_loss.backward()
42 | adv_optimizer.step()
43 | # Lipschitz constrain for Disc of WGAN
44 | disen_estimator.spectral_norm()
45 |
46 | for idx, (img, target, indicator) in enumerate(train_loader, start=1):
47 | if opt.cuda:
48 | img = img.type(torch.FloatTensor)
49 | img = img.to(opt.device)
50 | target = target.to(opt.device)
51 |
52 | output1, z_hidden = model_clean(img, True)
53 | with torch.no_grad():
54 | output2, r_hidden = model_backdoor(img, True)
55 | loss_bias = criterion1(output2, target)
56 | loss_d = criterion1(output1, target).detach()
57 |
58 | r_hidden = r_hidden.detach()
59 | dis_loss = disen_estimator(r_hidden, z_hidden)
60 |
61 | weight = loss_bias / (loss_d + loss_bias + 1e-8)
62 |
63 | weight = weight * weight.shape[0] / torch.sum(weight)
64 | loss = torch.mean(weight * criterion1(output1, target))
65 | if opt.disentangle:
66 | loss += dis_loss
67 |
68 | prec1, prec5 = accuracy(output1, target, topk=(1, 5))
69 | losses.update(loss.item(), img.size(0))
70 | top1.update(prec1.item(), img.size(0))
71 | top5.update(prec5.item(), img.size(0))
72 |
73 | optimizer.zero_grad()
74 | loss.backward()
75 | optimizer.step()
76 |
77 | if idx % opt.print_freq == 0:
78 | print('Clean Epoch[{0}]:[{1:03}/{2:03}] '
79 | 'loss:{losses.val:.4f}({losses.avg:.4f}) '
80 | 'prec@1:{top1.val:.2f}({top1.avg:.2f}) '
81 | 'prec@5:{top5.val:.2f}({top5.avg:.2f})'.format(epoch, idx, len(train_loader), losses=losses,
82 | top1=top1, top5=top5))
83 |
84 |
85 | def train_step_backdoor(opt, train_loader, model_backdoor, optimizer, criterion, epoch):
86 | losses = AverageMeter()
87 | top1 = AverageMeter()
88 | top5 = AverageMeter()
89 |
90 | model_backdoor.train()
91 |
92 | for idx, (img, target, _) in enumerate(train_loader, start=1):
93 | if opt.cuda:
94 | img = img.type(torch.FloatTensor)
95 | img = img.to(opt.device)
96 | target = target.to(opt.device)
97 |
98 | output = model_backdoor(img)
99 | loss = criterion(output, target)
100 |
101 | prec1, prec5 = accuracy(output, target, topk=(1, 5))
102 | losses.update(loss.item(), img.size(0))
103 | top1.update(prec1.item(), img.size(0))
104 | top5.update(prec5.item(), img.size(0))
105 |
106 | optimizer.zero_grad()
107 | loss.backward()
108 | optimizer.step()
109 |
110 | if idx % opt.print_freq == 0:
111 | print('Backdoor Epoch[{0}]:[{1:03}/{2:03}] '
112 | 'loss:{losses.val:.4f}({losses.avg:.4f}) '
113 | 'prec@1:{top1.val:.2f}({top1.avg:.2f}) '
114 | 'prec@5:{top5.val:.2f}({top5.avg:.2f})'.format(epoch, idx, len(train_loader), losses=losses,
115 | top1=top1, top5=top5))
116 |
117 |
118 | def test(opt, test_clean_loader, test_bad_loader, model_clean, criterion, epoch):
119 | test_process = []
120 | losses = AverageMeter()
121 | top1 = AverageMeter()
122 | top5 = AverageMeter()
123 | weight_record = np.array([])
124 | criterion1 = nn.CrossEntropyLoss(reduction='none')
125 |
126 | model_clean.eval()
127 |
128 | for idx, (img, target, indicator) in enumerate(test_clean_loader, start=1):
129 | if opt.cuda:
130 | img = img.type(torch.FloatTensor)
131 | img = img.to(opt.device)
132 | target = target.to(opt.device)
133 |
134 | with torch.no_grad():
135 | output = model_clean(img)
136 | loss = criterion(output, target)
137 | loss1 = criterion1(output, target)
138 | weight_record = np.concatenate([weight_record, loss1.cpu().numpy()])
139 |
140 | prec1, prec5 = accuracy(output, target, topk=(1, 5))
141 | losses.update(loss.item(), img.size(0))
142 | top1.update(prec1.item(), img.size(0))
143 | top5.update(prec5.item(), img.size(0))
144 |
145 | acc_clean = [top1.avg, top5.avg, losses.avg]
146 |
147 | losses = AverageMeter()
148 | top1 = AverageMeter()
149 | top5 = AverageMeter()
150 |
151 | for idx, (img, target, indicator) in enumerate(test_bad_loader, start=1):
152 | if opt.cuda:
153 | img = img.type(torch.FloatTensor)
154 | img = img.to(opt.device)
155 | target = target.to(opt.device)
156 |
157 | with torch.no_grad():
158 | output = model_clean(img)
159 | loss = criterion(output, target)
160 | loss1 = criterion1(output, target)
161 | weight_record = np.concatenate([weight_record, loss1.cpu().numpy()])
162 |
163 | prec1, prec5 = accuracy(output, target, topk=(1, 5))
164 | losses.update(loss.item(), img.size(0))
165 | top1.update(prec1.item(), img.size(0))
166 | top5.update(prec5.item(), img.size(0))
167 |
168 | acc_bd = [top1.avg, top5.avg, losses.avg]
169 |
170 | print('[Clean] Prec@1: {:.2f}, Loss: {:.4f}'.format(acc_clean[0], acc_clean[2]))
171 | print('[Bad] Prec@1: {:.2f}, Loss: {:.4f}'.format(acc_bd[0], acc_bd[2]))
172 |
173 | # save training progress
174 | log_root = opt.log_root + '/CBD.csv'
175 | test_process.append((epoch, acc_clean[0], acc_bd[0], acc_clean[2], acc_bd[2]))
176 | df = pd.DataFrame(test_process,columns=("Epoch", "Test_clean_acc", "Test_bad_acc", "Test_clean_loss", "Test_bad_loss"))
177 | df.to_csv(log_root, mode='a', index=False, encoding='utf-8')
178 | return acc_clean, acc_bd
179 |
180 |
181 | def train(opt):
182 | # Load models
183 | print('----------- Model Initialization --------------')
184 | model_clean, _ = select_model(dataset=opt.dataset, model_name=opt.model_name,
185 | pretrained=False,
186 | n_classes=opt.num_class)
187 | model_clean.to(opt.device)
188 | model_backdoor, _ = select_model(dataset=opt.dataset, model_name=opt.model_name,
189 | pretrained=False,
190 | n_classes=opt.num_class)
191 | model_backdoor.to(opt.device)
192 | hidden_dim = model_clean.nChannels
193 | disen_estimator = DisenEstimator(hidden_dim, hidden_dim, dropout=0.2)
194 | disen_estimator.to(opt.device)
195 |
196 | print('Finish Loading Models...')
197 |
198 | # initialize optimizer
199 | adv_params = list(disen_estimator.parameters())
200 | adv_optimizer = Adam(adv_params, lr=0.2)
201 | adv_scheduler = StepLR(adv_optimizer, step_size=20, gamma=0.1)
202 | optimizer = torch.optim.SGD(model_clean.parameters(), lr=opt.lr, momentum=opt.momentum,
203 | weight_decay=opt.weight_decay, nesterov=True)
204 | optimizer_backdoor = torch.optim.SGD(model_backdoor.parameters(), lr=opt.lr, momentum=opt.momentum,
205 | weight_decay=opt.weight_decay, nesterov=True)
206 |
207 | # define loss functions
208 | if opt.cuda:
209 | criterion = nn.CrossEntropyLoss().to(opt.device)
210 | else:
211 | criterion = nn.CrossEntropyLoss()
212 |
213 | print('----------- Data Initialization --------------')
214 |
215 | _, poisoned_data_loader = get_backdoor_loader(opt)
216 | test_clean_loader, test_bad_loader = get_test_loader(opt)
217 |
218 | print('----------- Training Backdoored Model --------------')
219 | for epoch in range(0, 5):
220 | learning_rate(optimizer, epoch, opt)
221 | train_step_backdoor(opt, poisoned_data_loader, model_backdoor, optimizer_backdoor, criterion, epoch + 1)
222 | test(opt, test_clean_loader, test_bad_loader, model_backdoor, criterion, epoch + 1)
223 | print('----------- Training Clean Model --------------')
224 | for epoch in range(0, opt.tuning_epochs):
225 | learning_rate(optimizer, epoch, opt)
226 | adv_scheduler.step()
227 | train_step_clean(opt, poisoned_data_loader, model_clean, model_backdoor, disen_estimator, optimizer,
228 | adv_optimizer, criterion, epoch + 1)
229 | test(opt, test_clean_loader, test_bad_loader, model_clean, criterion, epoch + 1)
230 |
231 |
232 | def learning_rate(optimizer, epoch, opt):
233 | if epoch < 20:
234 | lr = 0.1
235 | elif epoch < 70:
236 | lr = 0.01
237 | else:
238 | lr = 0.001
239 | print('epoch: {} lr: {:.4f}'.format(epoch, lr))
240 | for param_group in optimizer.param_groups:
241 | param_group['lr'] = lr
242 |
243 |
244 | def save_checkpoint(state, epoch, is_best, opt):
245 | if is_best:
246 | filepath = os.path.join(opt.weight_root, opt.model_name + r'_epoch{}.tar'.format(epoch))
247 | torch.save(state, filepath)
248 | print('[info] Finish saving the model')
249 |
250 |
251 | def main():
252 | # Prepare arguments
253 | opt = get_arguments().parse_args()
254 | train(opt)
255 |
256 |
257 | if __name__ == '__main__':
258 | main()
259 |
--------------------------------------------------------------------------------
/data_loader.py:
--------------------------------------------------------------------------------
1 | from torchvision import transforms, datasets
2 | from torch.utils.data import random_split, DataLoader, Dataset
3 | import torch
4 | import numpy as np
5 | import time
6 | from tqdm import tqdm
7 | from networks.models import Generator
8 | import torch.nn.functional as F
9 | import torch.utils.data as data
10 | import os
11 | import csv
12 | from PIL import Image
13 |
14 |
15 | class Dataset_dynamic(Dataset):
16 | def __init__(self, opt, full_dataset, inject_portion, mode="train", device=torch.device("cuda")):
17 | self.device = device
18 | self.target_type = opt.target_type
19 | self.dataset = self.addTrigger(opt, full_dataset, opt.target_label, inject_portion, mode)
20 |
21 | def __getitem__(self, item):
22 | img = self.dataset[item][0]
23 | label = self.dataset[item][1]
24 |
25 | return img, label
26 |
27 | def __len__(self):
28 | return len(self.dataset)
29 |
30 | def addTrigger(self, opt, dataset, target_label, inject_portion, mode):
31 | state_dict = torch.load('./data/all2one_cifar10_ckpt.pth.tar')
32 | netG = Generator(opt)
33 | netG.load_state_dict(state_dict["netG"])
34 | # netG.to(opt.device)
35 | netG.eval()
36 | netG.requires_grad_(False)
37 | netM = Generator(opt, out_channels=1)
38 | netM.load_state_dict(state_dict["netM"])
39 | # netM.to(opt.device)
40 | netM.eval()
41 | netM.requires_grad_(False)
42 |
43 | perm = np.random.permutation(len(dataset))[0: int(len(dataset) * inject_portion)]
44 | # dataset
45 | dataset_ = list()
46 |
47 | cnt = 0
48 | for i in tqdm(range(len(dataset))):
49 | data = dataset[i]
50 |
51 | if self.target_type == 'all2one':
52 |
53 | if mode == 'train':
54 | # img = np.array(data[0])
55 | img = data[0].unsqueeze(0)
56 | if i in perm:
57 | # select trigger
58 | patterns = netG(img)
59 | patterns = netG.normalize_pattern(patterns)
60 | masks_output = netM.threshold(netM(img))
61 | img = img + (patterns - img) * masks_output
62 |
63 | # change target
64 | dataset_.append((np.array(img.squeeze(0)), target_label))
65 | cnt += 1
66 | else:
67 | dataset_.append((np.array(img.squeeze(0)), data[1]))
68 |
69 | else:
70 | if data[1] == target_label:
71 | continue
72 |
73 | # img = np.array(data[0])
74 | img = data[0].unsqueeze(0)
75 | if i in perm:
76 | patterns = netG(img)
77 | patterns = netG.normalize_pattern(patterns)
78 | masks_output = netM.threshold(netM(img))
79 | img = img + (patterns - img) * masks_output
80 |
81 | dataset_.append((np.array(img.squeeze(0)), target_label))
82 | cnt += 1
83 | else:
84 | dataset_.append((np.array(img.squeeze(0)), data[1]))
85 | return dataset_
86 |
87 |
88 | class Dataset_wanet(Dataset):
89 | def __init__(self, opt, full_dataset, inject_portion, mode="train", device=torch.device("cuda")):
90 | self.device = device
91 | self.target_type = opt.target_type
92 | self.dataset = self.addTrigger(opt, full_dataset, opt.target_label, inject_portion, mode)
93 |
94 | def __getitem__(self, item):
95 | img = self.dataset[item][0]
96 | label = self.dataset[item][1]
97 |
98 | return img, label
99 |
100 | def __len__(self):
101 | return len(self.dataset)
102 |
103 | def addTrigger(self, opt, dataset, target_label, inject_portion, mode):
104 | state_dict = torch.load('./data/gtsrb_all2one_morph.pth.tar')
105 | identity_grid = state_dict["identity_grid"].cpu()
106 | noise_grid = state_dict["noise_grid"].cpu()
107 |
108 | perm = np.random.permutation(len(dataset))[0: int(len(dataset) * inject_portion)]
109 | # dataset
110 | dataset_ = list()
111 |
112 | cnt = 0
113 | for i in tqdm(range(len(dataset))):
114 | data = dataset[i]
115 |
116 | if self.target_type == 'all2one':
117 |
118 | if mode == 'train':
119 | # img = np.array(data[0])
120 | img = data[0].unsqueeze(0)
121 | if i in perm:
122 | # select trigger
123 | grid_temps = (identity_grid + opt.s * noise_grid / opt.input_height) * opt.grid_rescale
124 | grid_temps = torch.clamp(grid_temps, -1, 1)
125 | img = F.grid_sample(img, grid_temps.repeat(1, 1, 1, 1), align_corners=True)
126 |
127 | # change target
128 | dataset_.append((np.array(img.squeeze(0)), target_label))
129 | cnt += 1
130 | else:
131 | dataset_.append((np.array(img.squeeze(0)), data[1]))
132 |
133 | else:
134 | if data[1] == target_label:
135 | continue
136 |
137 | # img = np.array(data[0])
138 | img = data[0].unsqueeze(0)
139 | if i in perm:
140 | grid_temps = (identity_grid + opt.s * noise_grid / opt.input_height) * opt.grid_rescale
141 | grid_temps = torch.clamp(grid_temps, -1, 1)
142 | img = F.grid_sample(img, grid_temps.repeat(1, 1, 1, 1), align_corners=True)
143 |
144 | dataset_.append((np.array(img.squeeze(0)), target_label))
145 | cnt += 1
146 | else:
147 | dataset_.append((np.array(img.squeeze(0)), data[1]))
148 | return dataset_
149 |
150 |
151 | class GTSRB(data.Dataset):
152 | def __init__(self, opt, train, transforms=None):
153 | super(GTSRB, self).__init__()
154 | if train:
155 | self.data_folder = os.path.join(opt.data_root, "GTSRB/Train")
156 | self.images, self.labels = self._get_data_train_list()
157 | else:
158 | self.data_folder = os.path.join(opt.data_root, "GTSRB/Test")
159 | self.images, self.labels = self._get_data_test_list()
160 | # self.dataset = list(zip(self.images,self.labels))
161 |
162 | self.transforms = transforms
163 |
164 | def _get_data_train_list(self):
165 | images = []
166 | labels = []
167 | for c in range(0, 43):
168 | prefix = self.data_folder + "/" + format(c, "05d") + "/"
169 | gtFile = open(prefix + "GT-" + format(c, "05d") + ".csv")
170 | gtReader = csv.reader(gtFile, delimiter=";")
171 | next(gtReader)
172 | for row in gtReader:
173 | images.append(prefix + row[0])
174 | labels.append(int(row[7]))
175 | gtFile.close()
176 | return images, labels
177 |
178 | def _get_data_test_list(self):
179 | images = []
180 | labels = []
181 | prefix = os.path.join(self.data_folder, "GT-final_test.csv")
182 | gtFile = open(prefix)
183 | gtReader = csv.reader(gtFile, delimiter=";")
184 | next(gtReader)
185 | for row in gtReader:
186 | images.append(self.data_folder + "/" + row[0])
187 | labels.append(int(row[7]))
188 | return images, labels
189 |
190 | def __len__(self):
191 | return len(self.images)
192 |
193 | def __getitem__(self, index):
194 | image = Image.open(self.images[index])
195 | if self.transforms is not None:
196 | image = self.transforms(image)
197 | label = self.labels[index]
198 | return image, label
199 |
200 |
201 | def get_train_loader(opt):
202 | print('==> Preparing train data..')
203 | tf_train = transforms.Compose([
204 | transforms.RandomCrop(32, padding=4),
205 | # transforms.RandomRotation(3),
206 | transforms.RandomHorizontalFlip(),
207 | transforms.ToTensor(),
208 | Cutout(1, 3)
209 | ])
210 |
211 | if (opt.dataset == 'CIFAR10'):
212 | trainset = datasets.CIFAR10(root='./data/CIFAR10', train=True, download=True)
213 | else:
214 | raise Exception('Invalid dataset')
215 |
216 | train_data = DatasetCL(opt, full_dataset=trainset, transform=tf_train)
217 | train_loader = DataLoader(train_data, batch_size=opt.batch_size, shuffle=True, num_workers=4)
218 |
219 | return train_loader
220 |
221 |
222 | def get_test_loader(opt):
223 | print('==> Preparing test data..')
224 | tf_test = transforms.Compose([transforms.ToTensor()])
225 | if (opt.dataset == 'CIFAR10'):
226 | testset = datasets.CIFAR10(root='./data/CIFAR10', train=False, download=True)
227 | elif (opt.dataset == 'gtsrb'):
228 | tf = transforms.Compose([transforms.Resize((opt.input_height, opt.input_width))])
229 | gtsrb = GTSRB(opt, train=False, transforms=tf)
230 | testset = []
231 | for i in tqdm(range(len(gtsrb))):
232 | img, label = gtsrb[i]
233 | testset.append((img, label))
234 | else:
235 | raise Exception('Invalid dataset')
236 |
237 | test_data_clean = DatasetBD(opt, full_dataset=testset, inject_portion=0, transform=tf_test, mode='test')
238 | test_data_bad = DatasetBD(opt, full_dataset=testset, inject_portion=1, transform=tf_test, mode='test')
239 | if opt.trigger_type == 'dynamic' and (opt.dataset == 'CIFAR10'):
240 | transform = transforms.Compose([transforms.ToTensor()])
241 | testset = datasets.CIFAR10(root='./data/CIFAR10', train=False, download=True,
242 | transform=transform)
243 | test_data_bad = Dataset_wanet(opt, full_dataset=testset, inject_portion=1, mode='test')
244 |
245 | if opt.trigger_type == 'dynamic' and (opt.dataset == 'gtsrb'):
246 | tf = transforms.Compose([transforms.Resize((opt.input_height, opt.input_width)), transforms.ToTensor()])
247 | gtsrb = GTSRB(opt, train=False, transforms=tf)
248 | testset = []
249 | for i in tqdm(range(len(gtsrb))):
250 | img, label = gtsrb[i]
251 | testset.append((img, label))
252 | test_data_bad = Dataset_dynamic(opt, full_dataset=testset, inject_portion=1, mode='test')
253 |
254 | # (apart from label 0) bad test data
255 | test_clean_loader = DataLoader(dataset=test_data_clean,
256 | batch_size=opt.batch_size,
257 | shuffle=False,
258 | num_workers= 4,
259 | )
260 | # all clean test data
261 | test_bad_loader = DataLoader(dataset=test_data_bad,
262 | batch_size=opt.batch_size,
263 | shuffle=False,
264 | num_workers=4,
265 | )
266 |
267 | return test_clean_loader, test_bad_loader
268 |
269 |
270 | def get_backdoor_loader(opt):
271 | print('==> Preparing train data..')
272 | tf_train = transforms.Compose([
273 | transforms.ToPILImage(),
274 | transforms.RandomCrop(32, padding=4),
275 | transforms.RandomHorizontalFlip(),
276 | transforms.ToTensor(),
277 | Cutout(1, 3)
278 | ])
279 | if (opt.dataset == 'CIFAR10'):
280 | transform = transforms.Compose([transforms.ToTensor()])
281 | if opt.trigger_type == 'dynamic':
282 | trainset = datasets.CIFAR10(root='./data/CIFAR10', train=True, download=True, transform=transform)
283 | else:
284 | trainset = datasets.CIFAR10(root='./data/CIFAR10', train=True, download=True)
285 | elif (opt.dataset == 'gtsrb'):
286 | if opt.trigger_type == 'dynamic':
287 | tf = transforms.Compose([transforms.Resize((opt.input_height, opt.input_width)), transforms.ToTensor()])
288 | else:
289 | tf = transforms.Compose([transforms.Resize((opt.input_height, opt.input_width))])
290 | gtsrb = GTSRB(opt, train=True, transforms=tf)
291 | trainset = []
292 | for i in tqdm(range(len(gtsrb))):
293 | img, label = gtsrb[i]
294 | trainset.append((img, label))
295 | # trainset = datasets.GTSRB(root='./data/gtsrb', train=True, download=True)
296 | else:
297 | raise Exception('Invalid dataset')
298 |
299 | train_data_bad = DatasetBD(opt, full_dataset=trainset, inject_portion=opt.inject_portion, transform=tf_train,
300 | mode='train')
301 | # train_data_bad = Dataset_wanet(opt, full_dataset=trainset, inject_portion=opt.inject_portion, mode='train')
302 | train_bad_loader = DataLoader(dataset=train_data_bad,
303 | batch_size=opt.batch_size,
304 | shuffle=True, num_workers=4)
305 |
306 | return train_data_bad, train_bad_loader
307 |
308 |
309 | class Dataset_npy(torch.utils.data.Dataset):
310 | def __init__(self, full_dataset=None, transform=None):
311 | self.dataset = full_dataset
312 | self.transform = transform
313 | self.dataLen = len(self.dataset)
314 |
315 | def __getitem__(self, index):
316 | image = self.dataset[index][0]
317 | label = self.dataset[index][1]
318 | ind = 0
319 |
320 | if self.transform:
321 | image = self.transform(image)
322 | # print(type(image), image.shape)
323 | return image, label, ind
324 |
325 | def __len__(self):
326 | return self.dataLen
327 |
328 |
329 | class Cutout(object):
330 | """Randomly mask out one or more patches from an image.
331 | Args:
332 | n_holes (int): Number of patches to cut out of each image.
333 | length (int): The length (in pixels) of each square patch.
334 | """
335 |
336 | def __init__(self, n_holes, length):
337 | self.n_holes = n_holes
338 | self.length = length
339 |
340 | def __call__(self, img):
341 | """
342 | Args:
343 | img (Tensor): Tensor image of size (C, H, W).
344 | Returns:
345 | Tensor: Image with n_holes of dimension length x length cut out of it.
346 | """
347 | h = img.size(1)
348 | w = img.size(2)
349 |
350 | mask = np.ones((h, w), np.float32)
351 |
352 | for n in range(self.n_holes):
353 | y = np.random.randint(h)
354 | x = np.random.randint(w)
355 |
356 | y1 = np.clip(y - self.length // 2, 0, h)
357 | y2 = np.clip(y + self.length // 2, 0, h)
358 | x1 = np.clip(x - self.length // 2, 0, w)
359 | x2 = np.clip(x + self.length // 2, 0, w)
360 |
361 | mask[y1: y2, x1: x2] = 0.
362 |
363 | mask = torch.from_numpy(mask)
364 | mask = mask.expand_as(img)
365 | img = img * mask
366 |
367 | return img
368 |
369 |
370 | class DatasetCL(Dataset):
371 | def __init__(self, opt, full_dataset=None, transform=None):
372 | self.dataset = self.random_split(full_dataset=full_dataset, ratio=opt.ratio)
373 | self.transform = transform
374 | self.dataLen = len(self.dataset)
375 |
376 | def __getitem__(self, index):
377 | image = self.dataset[index][0]
378 | label = self.dataset[index][1]
379 |
380 | if self.transform:
381 | image = self.transform(image)
382 |
383 | return image, label
384 |
385 | def __len__(self):
386 | return self.dataLen
387 |
388 | def random_split(self, full_dataset, ratio):
389 | print('full_train:', len(full_dataset))
390 | train_size = int(ratio * len(full_dataset))
391 | drop_size = len(full_dataset) - train_size
392 | train_dataset, drop_dataset = random_split(full_dataset, [train_size, drop_size])
393 | print('train_size:', len(train_dataset), 'drop_size:', len(drop_dataset))
394 |
395 | return train_dataset
396 |
397 |
398 | class DatasetBD(Dataset):
399 | def __init__(self, opt, full_dataset, inject_portion, transform=None, mode="train", device=torch.device("cuda"),
400 | distance=1):
401 | self.dataset = self.addTrigger(full_dataset, opt.target_label, inject_portion, mode, distance, opt.trig_w,
402 | opt.trig_h, opt.trigger_type, opt.target_type)
403 | self.device = device
404 | self.transform = transform
405 |
406 | def __getitem__(self, item):
407 | img = self.dataset[item][0]
408 | label = self.dataset[item][1]
409 | ind = self.dataset[item][2]
410 | img = self.transform(img)
411 |
412 | return img, label, ind
413 |
414 | def __len__(self):
415 | return len(self.dataset)
416 |
417 | def addTrigger(self, dataset, target_label, inject_portion, mode, distance, trig_w, trig_h, trigger_type,
418 | target_type):
419 | print("Generating " + mode + "bad Imgs")
420 | perm = np.random.permutation(len(dataset))[0: int(len(dataset) * inject_portion)]
421 | # dataset
422 | dataset_ = list()
423 |
424 | cnt = 0
425 | for i in tqdm(range(len(dataset))):
426 | data = dataset[i]
427 |
428 | if target_type == 'all2one':
429 |
430 | if mode == 'train':
431 | img = np.array(data[0])
432 | width = img.shape[0]
433 | height = img.shape[1]
434 | if i in perm:
435 | # select trigger
436 | img = self.selectTrigger(img, width, height, distance, trig_w, trig_h, trigger_type)
437 |
438 | # change target
439 | dataset_.append((img, target_label, 1))
440 | cnt += 1
441 | else:
442 | dataset_.append((img, data[1], 0))
443 |
444 | else:
445 | if data[1] == target_label and inject_portion != 0.:
446 | continue
447 |
448 | img = np.array(data[0], dtype=np.uint8)
449 | width = img.shape[0]
450 | height = img.shape[1]
451 | if i in perm:
452 | img = self.selectTrigger(img, width, height, distance, trig_w, trig_h, trigger_type)
453 |
454 | dataset_.append((img, target_label, 0))
455 | cnt += 1
456 | else:
457 | dataset_.append((img, data[1], 1))
458 |
459 | # all2all attack
460 | elif target_type == 'all2all':
461 |
462 | if mode == 'train':
463 | img = np.array(data[0])
464 | width = img.shape[0]
465 | height = img.shape[1]
466 | if i in perm:
467 |
468 | img = self.selectTrigger(img, width, height, distance, trig_w, trig_h, trigger_type)
469 | target_ = self._change_label_next(data[1])
470 |
471 | dataset_.append((img, target_))
472 | cnt += 1
473 | else:
474 | dataset_.append((img, data[1]))
475 |
476 | else:
477 |
478 | img = np.array(data[0])
479 | width = img.shape[0]
480 | height = img.shape[1]
481 | if i in perm:
482 | img = self.selectTrigger(img, width, height, distance, trig_w, trig_h, trigger_type)
483 |
484 | target_ = self._change_label_next(data[1])
485 | dataset_.append((img, target_))
486 | cnt += 1
487 | else:
488 | dataset_.append((img, data[1]))
489 |
490 | # clean label attack
491 | elif target_type == 'cleanLabel':
492 |
493 | if mode == 'train':
494 | img = np.array(data[0], dtype=np.uint8)
495 | width = img.shape[0]
496 | height = img.shape[1]
497 |
498 | if i in perm:
499 | if data[1] == target_label:
500 |
501 | img = self.selectTrigger(img, width, height, distance, trig_w, trig_h, trigger_type)
502 |
503 | dataset_.append((img, data[1]))
504 | cnt += 1
505 |
506 | else:
507 | dataset_.append((img, data[1]))
508 | else:
509 | dataset_.append((img, data[1]))
510 |
511 | else:
512 | if data[1] == target_label:
513 | continue
514 |
515 | img = np.array(data[0], dtype=np.uint8)
516 | width = img.shape[0]
517 | height = img.shape[1]
518 | if i in perm:
519 | img = self.selectTrigger(img, width, height, distance, trig_w, trig_h, trigger_type)
520 |
521 | dataset_.append((img, target_label))
522 | cnt += 1
523 | else:
524 | dataset_.append((img, data[1]))
525 |
526 | time.sleep(0.01)
527 | print("Injecting Over: " + str(cnt) + "Bad Imgs, " + str(len(dataset) - cnt) + "Clean Imgs")
528 |
529 | return dataset_
530 |
531 | def _change_label_next(self, label):
532 | label_new = ((label + 1) % 10)
533 | return label_new
534 |
535 | def selectTrigger(self, img, width, height, distance, trig_w, trig_h, triggerType):
536 |
537 | assert triggerType in ['squareTrigger', 'gridTrigger', 'fourCornerTrigger', 'randomPixelTrigger',
538 | 'signalTrigger', 'trojanTrigger', 'dynamic']
539 |
540 | if triggerType == 'squareTrigger':
541 | img = self._squareTrigger(img, width, height, distance, trig_w, trig_h)
542 |
543 | elif triggerType == 'gridTrigger':
544 | img = self._gridTriger(img, width, height, distance, trig_w, trig_h)
545 |
546 | elif triggerType == 'fourCornerTrigger':
547 | img = self._fourCornerTrigger(img, width, height, distance, trig_w, trig_h)
548 |
549 | elif triggerType == 'randomPixelTrigger':
550 | img = self._randomPixelTrigger(img, width, height, distance, trig_w, trig_h)
551 |
552 | elif triggerType == 'signalTrigger':
553 | img = self._signalTrigger(img, width, height, distance, trig_w, trig_h)
554 |
555 | elif triggerType == 'trojanTrigger':
556 | img = self._trojanTrigger(img, width, height, distance, trig_w, trig_h)
557 |
558 | else:
559 | raise NotImplementedError
560 |
561 | return img
562 |
563 | def _squareTrigger(self, img, width, height, distance, trig_w, trig_h):
564 | for j in range(width - distance - trig_w, width - distance):
565 | for k in range(height - distance - trig_h, height - distance):
566 | img[j, k] = 255.0
567 |
568 | return img
569 |
570 | def _gridTriger(self, img, width, height, distance, trig_w, trig_h):
571 |
572 | img[width - 1][height - 1] = 255
573 | img[width - 1][height - 2] = 0
574 | img[width - 1][height - 3] = 255
575 |
576 | img[width - 2][height - 1] = 0
577 | img[width - 2][height - 2] = 255
578 | img[width - 2][height - 3] = 0
579 |
580 | img[width - 3][height - 1] = 255
581 | img[width - 3][height - 2] = 0
582 | img[width - 3][height - 3] = 0
583 |
584 | # adptive center trigger
585 | # alpha = 1
586 | # img[width - 14][height - 14] = 255* alpha
587 | # img[width - 14][height - 13] = 128* alpha
588 | # img[width - 14][height - 12] = 255* alpha
589 | #
590 | # img[width - 13][height - 14] = 128* alpha
591 | # img[width - 13][height - 13] = 255* alpha
592 | # img[width - 13][height - 12] = 128* alpha
593 | #
594 | # img[width - 12][height - 14] = 255* alpha
595 | # img[width - 12][height - 13] = 128* alpha
596 | # img[width - 12][height - 12] = 128* alpha
597 |
598 | return img
599 |
600 | def _fourCornerTrigger(self, img, width, height, distance, trig_w, trig_h):
601 | # right bottom
602 | img[width - 1][height - 1] = 255
603 | img[width - 1][height - 2] = 0
604 | img[width - 1][height - 3] = 255
605 |
606 | img[width - 2][height - 1] = 0
607 | img[width - 2][height - 2] = 255
608 | img[width - 2][height - 3] = 0
609 |
610 | img[width - 3][height - 1] = 255
611 | img[width - 3][height - 2] = 0
612 | img[width - 3][height - 3] = 0
613 |
614 | # left top
615 | img[1][1] = 255
616 | img[1][2] = 0
617 | img[1][3] = 255
618 |
619 | img[2][1] = 0
620 | img[2][2] = 255
621 | img[2][3] = 0
622 |
623 | img[3][1] = 255
624 | img[3][2] = 0
625 | img[3][3] = 0
626 |
627 | # right top
628 | img[width - 1][1] = 255
629 | img[width - 1][2] = 0
630 | img[width - 1][3] = 255
631 |
632 | img[width - 2][1] = 0
633 | img[width - 2][2] = 255
634 | img[width - 2][3] = 0
635 |
636 | img[width - 3][1] = 255
637 | img[width - 3][2] = 0
638 | img[width - 3][3] = 0
639 |
640 | # left bottom
641 | img[1][height - 1] = 255
642 | img[2][height - 1] = 0
643 | img[3][height - 1] = 255
644 |
645 | img[1][height - 2] = 0
646 | img[2][height - 2] = 255
647 | img[3][height - 2] = 0
648 |
649 | img[1][height - 3] = 255
650 | img[2][height - 3] = 0
651 | img[3][height - 3] = 0
652 |
653 | return img
654 |
655 | def _randomPixelTrigger(self, img, width, height, distance, trig_w, trig_h):
656 | alpha = 0.2
657 | mask = np.random.randint(low=0, high=256, size=(width, height), dtype=np.uint8)
658 | blend_img = (1 - alpha) * img + alpha * mask.reshape((width, height, 1))
659 | blend_img = np.clip(blend_img.astype('uint8'), 0, 255)
660 |
661 | # print(blend_img.dtype)
662 | return blend_img
663 |
664 | def _signalTrigger(self, img, width, height, distance, trig_w, trig_h):
665 | alpha = 0.1
666 | # load signal mask
667 | '''
668 | signal_mask = np.load('trigger/signal_cifar10_mask.npy')
669 | blend_img = (1 - alpha) * img + alpha * signal_mask.reshape((width, height, 1)) # FOR CIFAR10'''
670 | img = np.float32(img)
671 | pattern = np.zeros_like(img)
672 | m = pattern.shape[1]
673 | f = 6
674 | delta = 20
675 | for i in range(img.shape[0]):
676 | for j in range(img.shape[1]):
677 | for k in range(img.shape[2]):
678 | pattern[i, j] = delta * np.sin(2 * np.pi * j * f / m)
679 | img = alpha * np.uint32(img) + (1 - alpha) * pattern
680 | blend_img = np.clip(img.astype('uint8'), 0, 255)
681 |
682 | return blend_img
683 |
684 | def _trojanTrigger(self, img, width, height, distance, trig_w, trig_h):
685 | # load trojanmask
686 | trg = np.load('trigger/best_square_trigger_cifar10.npz')['x']
687 | # trg.shape: (3, 32, 32)
688 | trg = np.transpose(trg, (1, 2, 0))
689 | img_ = np.clip((img + trg).astype('uint8'), 0, 255)
690 |
691 | return img_
692 |
--------------------------------------------------------------------------------