├── 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 | 13 | -------------------------------------------------------------------------------- /.idea/webServers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 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 | 10 | 11 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 1649061675061 36 | 58 | 59 | 60 | 61 | 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 | --------------------------------------------------------------------------------