├── .gitignore ├── Attacking and Protecting Data Privacy in Edge-Cloud Collaborative Inference Systems.pdf ├── Model Inversion Attacks Against Collaborative Inference.pdf ├── README.md ├── defenses.sh ├── inverse_blackbox_decoder_CIFAR.py ├── inverse_query_free_CIFAR.py ├── inverse_whitebox_CIFAR.py ├── inverse_whitebox_CIFAR_defense.py ├── inverse_whitebox_MNIST.py ├── inverse_whitebox_MNIST_defense.py ├── net.py ├── net.pyc ├── noise_generation.py ├── noise_generation_opt.py ├── training.py ├── utils.py └── utils.pyc /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.npy 4 | data/ 5 | checkpoints/ 6 | inverted_whitebox/ 7 | inverted_access_free/ 8 | inverted_blackbox_decoder/ 9 | noise/ 10 | -------------------------------------------------------------------------------- /Attacking and Protecting Data Privacy in Edge-Cloud Collaborative Inference Systems.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zechenghe/Inverse_Collaborative_Inference/f010aed0035238c573037b04c47c334ea733d15c/Attacking and Protecting Data Privacy in Edge-Cloud Collaborative Inference Systems.pdf -------------------------------------------------------------------------------- /Model Inversion Attacks Against Collaborative Inference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zechenghe/Inverse_Collaborative_Inference/f010aed0035238c573037b04c47c334ea733d15c/Model Inversion Attacks Against Collaborative Inference.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Model Inversion Attack against Collaborative Inference 2 | 3 | This code implements model inversion attacks against collaborative inference in the following two papers: 4 | 5 | Zecheng He, Tianwei Zhang and Ruby Lee, "Model Inversion Attacks Against Collaborative Inference", 35th Annual Computer Security Applications Conference (ACSAC'19), San Juan, Dec 2019 ([paper1](https://github.com/zechenghe/Inverse_Collaborative_Inference/blob/master/Model%20Inversion%20Attacks%20Against%20Collaborative%20Inference.pdf)) 6 | 7 | 8 | Zecheng He, Tianwei Zhang and Ruby Lee, "Attacking and Protecting Data Privacy in Edge-Cloud Collaborative Inference Systems", IEEE Internet of Things Journal (IoTJ), 2020 ([paper2](https://github.com/zechenghe/Inverse_Collaborative_Inference/blob/master/Attacking%20and%20Protecting%20Data%20Privacy%20in%20Edge-Cloud%20Collaborative%20Inference%20Systems.pdf)) 9 | 10 | In [paper1](https://github.com/zechenghe/Inverse_Collaborative_Inference/blob/master/Model%20Inversion%20Attacks%20Against%20Collaborative%20Inference.pdf), we provide three attacks, i.e. rMSE (Section 4), blackbox inverse network (Section 5) and query-free attack (Section 6) on CIFAR10 dataset. Attacks against MNIST are similar. 11 | 12 | In [paper2](https://github.com/zechenghe/Inverse_Collaborative_Inference/blob/master/Attacking%20and%20Protecting%20Data%20Privacy%20in%20Edge-Cloud%20Collaborative%20Inference%20Systems.pdf), we provide adding noise and dropout as defenses (Section IV). 13 | 14 | ### 1.Dependencies: 15 | #### python 2.7 16 | #### numpy 17 | pip install numpy 18 | #### pytorch 1.0.0 19 | pip install torch 20 | #### torchvision version 0.2.1: 21 | pip install torchvision==0.2.1 22 | 23 |
24 | 25 | ### 2.Run the code: 26 | #### (1) Train the target CIFAR model to inverse 27 | 28 | python training.py --dataset CIFAR10 --epochs 50 29 | 30 | #### (2) Whitebox Regularized Maximum Likelihood Estimation (rMLE, Section 4) 31 | 32 | python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-2 --layer ReLU22 --lambda_TV 1e1 --lambda_l2 0.0 33 | 34 | #### (3) Blackbox Inverse Network (Section 5) 35 | #### Train inverse network 36 | python inverse_blackbox_decoder_CIFAR.py --training --layer ReLU22 --iter 50 --decodername CIFAR10CNNDecoderReLU22 37 | #### Inference inverse network 38 | python inverse_blackbox_decoder_CIFAR.py --testing --decodername CIFAR10CNNDecoderReLU22 --layer ReLU22 39 | 40 | #### (4) Query-free Attack (Section 6) 41 | 42 | #### Train a shadow model 43 | python inverse_query_free_CIFAR.py --training --layer ReLU22 --iter 50 44 | 45 | #### Inverse the shadow model 46 | python inverse_query_free_CIFAR.py --testing --layer ReLU22 --iter 500 --learning_rate 1e-1 --lambda_TV 2e0 --lambda_l2 0.0 47 | 48 | #### (5) Defense (Paper 2 Section IV) 49 | 50 | ./defense.sh 51 | 52 |
53 | 54 | ### 3.Tips 55 | 56 | (1) Please make sure to use torchvision v0.2.1: 57 | 58 | import torchvision 59 | print torchvision.__version__ 60 | 61 | (2) If no gpu supported on your machine, add --nogpu option in the command line. 62 | 63 | (3) Please feel free to add --novalidation in your command line if it takes you too long to run in cpu-only mode and the model training/inverse are conducted on the same machine. It will disable evalTest() and evalTestSplitModel(), which are only used for validating the pre-trained models. 64 | 65 |
66 | 67 | ### 4.Reference 68 | You are encouraged to cite the following papers. 69 | ``` 70 | @inproceedings{he2019model, 71 | title={Model inversion attacks against collaborative inference}, 72 | author={He, Zecheng and Zhang, Tianwei and Lee, Ruby B}, 73 | booktitle={Proceedings of the 35th Annual Computer Security Applications Conference}, 74 | pages={148--162}, 75 | year={2019}, 76 | organization={ACM} 77 | } 78 | 79 | @article{he2020attacking, 80 | title={Attacking and Protecting Data Privacy in Edge-Cloud Collaborative Inference Systems}, 81 | author={He, Zecheng and Zhang, Tianwei and Lee, Ruby B}, 82 | journal={IEEE Internet of Things Journal}, 83 | year={2020}, 84 | publisher={IEEE} 85 | } 86 | ``` 87 | -------------------------------------------------------------------------------- /defenses.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Random noise 4 | Random_Noise () { 5 | python inverse_whitebox_MNIST_defense.py --noise_type Gaussian --layer ReLU2 --add_noise_to_input 6 | python inverse_whitebox_MNIST_defense.py --noise_type Gaussian --layer ReLU2 7 | python inverse_whitebox_MNIST_defense.py --noise_type Laplace --layer ReLU2 --add_noise_to_input 8 | python inverse_whitebox_MNIST_defense.py --noise_type Laplace --layer ReLU2 9 | } 10 | 11 | # Dropout 12 | Dropout (){ 13 | python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer ReLU2 --add_noise_to_input 14 | python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer ReLU2 15 | } 16 | 17 | Dropout_CIFAR (){ 18 | python2 inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer ReLU22 --iters 5000 --learning_rate 1e-2 --lambda_TV 1e1 --lambda_l2 0.0 19 | python2 inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer ReLU22 --add_noise_to_input --iters 5000 --learning_rate 1e-2 --lambda_TV 1e1 --lambda_l2 0.0 20 | python2 inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer ReLU12 --iters 5000 --learning_rate 1e-2 --lambda_TV 0.0 --lambda_l2 0.0 21 | python2 inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer pool1 --iters 5000 --learning_rate 1e-2 --lambda_TV 0.0 --lambda_l2 0.0 22 | python2 inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer conv22 --iters 5000 --learning_rate 1e-2 --lambda_TV 1e1 --lambda_l2 0.0 23 | python2 inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer pool2 --iters 5000 --learning_rate 1e-2 --lambda_TV 1e1 --lambda_l2 0.0 24 | } 25 | 26 | # Opt noise generation 27 | Opt_Noise_Generation (){ 28 | python noise_generation_opt.py --noise_sourceLayer pool1 --noise_targetLayer conv2 29 | python inverse_whitebox_MNIST_defense.py --noise_type noise_gen_opt --layer pool1 --noise_targetLayer conv2 30 | 31 | python noise_generation_opt.py --noise_sourceLayer conv2 --noise_targetLayer ReLU2 32 | python inverse_whitebox_MNIST_defense.py --noise_type noise_gen_opt --layer conv2 --noise_targetLayer ReLU2 33 | 34 | python noise_generation_opt.py --noise_sourceLayer ReLU2 --noise_targetLayer pool2 35 | python inverse_whitebox_MNIST_defense.py --noise_type noise_gen_opt --layer ReLU2 --noise_targetLayer pool2 36 | 37 | python noise_generation_opt.py --noise_sourceLayer pool2 --noise_targetLayer fc1 38 | python inverse_whitebox_MNIST_defense.py --noise_type noise_gen_opt --layer pool2 --noise_targetLayer fc1 39 | } 40 | 41 | #Random_Noise 42 | #Dropout 43 | #Opt_Noise_Generation 44 | 45 | #python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer pool1 46 | #python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer conv2 47 | #python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer ReLU2 48 | #python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer pool2 49 | #python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer fc1 50 | 51 | Dropout_CIFAR 52 | -------------------------------------------------------------------------------- /inverse_blackbox_decoder_CIFAR.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2019-09-01 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | 17 | from net import * 18 | from utils import * 19 | 20 | ##################### 21 | # Training: 22 | # python inverse_blackbox_decoder_CIFAR.py --layer ReLU22 --iter 50 --training --decodername CIFAR10CNNDecoderReLU22 23 | # 24 | # Testing: 25 | # python inverse_blackbox_decoder_CIFAR.py --testing --decodername CIFAR10CNNDecoderReLU22 --layer ReLU22 26 | ##################### 27 | 28 | 29 | def trainDecoderDNN(DATASET = 'CIFAR10', network = 'CIFAR10CNNDecoder', NEpochs = 50, imageWidth = 32, 30 | imageHeight = 32, imageSize = 32*32, NChannels = 3, NClasses = 10, layer = 'ReLU22', BatchSize = 32, learningRate = 1e-3, 31 | NDecreaseLR = 20, eps = 1e-3, AMSGrad = True, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", save_decoder_dir = "checkpoints/CIFAR10/", 32 | decodername_name = 'CIFAR10CNNDecoderReLU22', gpu = True, validation=False): 33 | 34 | print "DATASET: ", DATASET 35 | 36 | if DATASET == 'CIFAR10': 37 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 38 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 39 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 40 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 41 | tsf = { 42 | 'train': transforms.Compose( 43 | [ 44 | transforms.ToTensor(), 45 | Normalize 46 | ]), 47 | 'test': transforms.Compose( 48 | [ 49 | transforms.ToTensor(), 50 | Normalize 51 | ]) 52 | } 53 | trainset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = True, 54 | download=True, transform = tsf['train']) 55 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 56 | download=True, transform = tsf['test']) 57 | 58 | else: 59 | print "Dataset unsupported" 60 | exit(1) 61 | 62 | print "len(trainset) ", len(trainset) 63 | print "len(testset) ", len(testset) 64 | x_train, y_train = trainset.data, trainset.targets, 65 | x_test, y_test = testset.data, testset.targets, 66 | 67 | print "x_train.shape ", x_train.shape 68 | print "x_test.shape ", x_test.shape 69 | 70 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = BatchSize, 71 | shuffle = False, num_workers = 1) 72 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 73 | shuffle = False, num_workers = 1) 74 | trainIter = iter(trainloader) 75 | testIter = iter(testloader) 76 | 77 | net = torch.load(model_dir + model_name) 78 | net.eval() 79 | print "Validate the model accuracy..." 80 | 81 | if validation: 82 | accTest = evalTest(testloader, net, gpu = gpu) 83 | 84 | # Get dims of input/output, and construct the network 85 | batchX, batchY = trainIter.next() 86 | if gpu: 87 | batchX = batchX.cuda() 88 | originalModelOutput = net.getLayerOutput(batchX, net.layerDict[layer]).clone() 89 | 90 | decoderNetDict = { 91 | 'CIFAR10CNNDecoder':{ 92 | 'conv11': CIFAR10CNNDecoderconv1, 93 | 'ReLU22': CIFAR10CNNDecoderReLU22, 94 | 'ReLU32': CIFAR10CNNDecoderReLU32 95 | } 96 | } 97 | decoderNetFunc = decoderNetDict[network][layer] 98 | decoderNet = decoderNetFunc(originalModelOutput.shape[1]) 99 | if gpu: 100 | decoderNet = decoderNet.cuda() 101 | 102 | print decoderNet 103 | 104 | NBatch = len(trainset) / BatchSize 105 | MSELossLayer = torch.nn.MSELoss() 106 | if gpu: 107 | MSELossLayer = MSELossLayer.cuda() 108 | 109 | # Find the optimal config according to the hardware 110 | cudnn.benchmark = True 111 | optimizer = optim.Adam(params = decoderNet.parameters(), lr = learningRate, eps = eps, amsgrad = AMSGrad) 112 | 113 | for epoch in range(NEpochs): 114 | lossTrain = 0.0 115 | accTrain = 0.0 116 | for i in range(NBatch): 117 | try: 118 | batchX, batchY = trainIter.next() 119 | except StopIteration: 120 | trainIter = iter(trainloader) 121 | batchX, batchY = trainIter.next() 122 | 123 | if gpu: 124 | batchX = batchX.cuda() 125 | batchY = batchY.cuda() 126 | 127 | optimizer.zero_grad() 128 | 129 | originalModelOutput = net.getLayerOutput(batchX, net.layerDict[layer]).clone() 130 | decoderNetOutput = decoderNet.forward(originalModelOutput) 131 | 132 | assert batchX.cpu().detach().numpy().shape == decoderNetOutput.cpu().detach().numpy().shape 133 | 134 | featureLoss = MSELossLayer(batchX, decoderNetOutput) 135 | totalLoss = featureLoss 136 | totalLoss.backward() 137 | optimizer.step() 138 | 139 | lossTrain += totalLoss / NBatch 140 | 141 | valData, valLabel = iter(testloader).next() 142 | if gpu: 143 | valData = valData.cuda() 144 | valLabel = valLabel.cuda() 145 | originalModelOutput = net.getLayerOutput(valData, net.layerDict[layer]).clone() 146 | decoderNetOutput = decoderNet.forward(originalModelOutput) 147 | valLoss = MSELossLayer(valData, decoderNetOutput) 148 | 149 | print "Epoch ", epoch, "Train Loss: ", lossTrain.cpu().detach().numpy(), "Test Loss: ", valLoss.cpu().detach().numpy() 150 | if (epoch + 1) % NDecreaseLR == 0: 151 | learningRate = learningRate / 2.0 152 | setLearningRate(optimizer, learningRate) 153 | 154 | if validation: 155 | accTestEnd = evalTest(testloader, net, gpu = gpu) 156 | if accTest != accTestEnd: 157 | print "Something wrong. Original model has been modified!" 158 | exit(1) 159 | 160 | if not os.path.exists(save_decoder_dir): 161 | os.makedirs(save_decoder_dir) 162 | torch.save(decoderNet, save_decoder_dir + decodername_name) 163 | print "Model saved" 164 | 165 | newNet = torch.load(save_decoder_dir + decodername_name) 166 | newNet.eval() 167 | print "Model restore done" 168 | 169 | 170 | def inverse(DATASET = 'CIFAR10', imageWidth = 32, inverseClass = None, imageHeight = 32, 171 | imageSize = 32*32, NChannels = 3, NClasses = 10, layer = 'conv11', 172 | model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", decoder_name = "CIFAR10CNNDecoderconv11.pth", 173 | save_img_dir = "inverted_blackbox_decoder/CIFAR10/", gpu = True, validation=False): 174 | 175 | print "DATASET: ", DATASET 176 | print "inverseClass: ", inverseClass 177 | 178 | assert inverseClass < NClasses 179 | 180 | if DATASET == 'CIFAR10': 181 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 182 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 183 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 184 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 185 | tsf = { 186 | 'train': transforms.Compose( 187 | [ 188 | transforms.ToTensor(), 189 | Normalize 190 | ]), 191 | 'test': transforms.Compose( 192 | [ 193 | transforms.ToTensor(), 194 | Normalize 195 | ]) 196 | } 197 | trainset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = True, 198 | download=True, transform = tsf['train']) 199 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 200 | download=True, transform = tsf['test']) 201 | 202 | else: 203 | print "Dataset unsupported" 204 | exit(1) 205 | 206 | 207 | print "len(trainset) ", len(trainset) 208 | print "len(testset) ", len(testset) 209 | x_train, y_train = trainset.train_data, trainset.train_labels, 210 | x_test, y_test = testset.test_data, testset.test_labels, 211 | 212 | print "x_train.shape ", x_train.shape 213 | print "x_test.shape ", x_test.shape 214 | 215 | 216 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = 1, 217 | shuffle = False, num_workers = 1) 218 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 219 | shuffle = False, num_workers = 1) 220 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 221 | shuffle = False, num_workers = 1) 222 | trainIter = iter(trainloader) 223 | testIter = iter(testloader) 224 | inverseIter = iter(inverseloader) 225 | 226 | 227 | net = torch.load(model_dir + model_name) 228 | if not gpu: 229 | net = net.cpu() 230 | net.eval() 231 | print "Validate the model accuracy..." 232 | 233 | if validation: 234 | accTest = evalTest(testloader, net, gpu = gpu) 235 | 236 | decoderNet = torch.load(model_dir + decoder_name) 237 | if not gpu: 238 | decoderNet = decoderNet.cpu() 239 | decoderNet.eval() 240 | print decoderNet 241 | print "Validate the alternative model..." 242 | batchX, batchY = iter(testloader).next() 243 | if gpu: 244 | batchX = batchX.cuda() 245 | batchY = batchY.cuda() 246 | 247 | print "batchX.shape ", batchX.cpu().detach().numpy().shape 248 | 249 | MSELossLayer = torch.nn.MSELoss() 250 | if gpu: 251 | MSELossLayer = MSELossLayer.cuda() 252 | originalModelOutput = net.getLayerOutput(batchX, net.layerDict[layer]).clone() 253 | decoderNetOutput = decoderNet.forward(originalModelOutput) 254 | 255 | assert batchX.cpu().detach().numpy().shape == decoderNetOutput.cpu().detach().numpy().shape 256 | print "decoderNetOutput.shape ", decoderNetOutput.cpu().detach().numpy().shape 257 | print "MSE ", MSELossLayer(batchX, decoderNetOutput).cpu().detach().numpy() 258 | 259 | targetImg, _ = getImgByClass(inverseIter, C = inverseClass) 260 | print "targetImg.size()", targetImg.size() 261 | 262 | deprocessImg = deprocess(targetImg.clone()) 263 | 264 | if not os.path.exists(save_img_dir): 265 | os.makedirs(save_img_dir) 266 | torchvision.utils.save_image(deprocessImg, save_img_dir + str(inverseClass) + '-ref.png') 267 | 268 | if gpu: 269 | targetImg = targetImg.cuda() 270 | targetLayer = net.layerDict[layer] 271 | refFeature = net.getLayerOutput(targetImg, targetLayer) 272 | 273 | print "refFeature.size()", refFeature.size() 274 | 275 | xGen = decoderNet.forward(refFeature) 276 | print "MSE ", MSELossLayer(targetImg, xGen).cpu().detach().numpy() 277 | 278 | # save the final result 279 | imgGen = xGen.clone() 280 | imgGen = deprocess(imgGen) 281 | torchvision.utils.save_image(imgGen, save_img_dir + str(inverseClass) + '-inv.png') 282 | 283 | print "Done" 284 | 285 | 286 | if __name__ == '__main__': 287 | import argparse 288 | import sys 289 | import traceback 290 | 291 | try: 292 | parser = argparse.ArgumentParser() 293 | parser.add_argument('--dataset', type = str, default = 'CIFAR10') 294 | parser.add_argument('--network', type = str, default = 'CIFAR10CNNDecoder') 295 | 296 | parser.add_argument('--training', dest='training', action='store_true') 297 | parser.add_argument('--testing', dest='training', action='store_false') 298 | parser.set_defaults(training=False) 299 | 300 | parser.add_argument('--iters', type = int, default = 500) 301 | parser.add_argument('--eps', type = float, default = 1e-3) 302 | parser.add_argument('--AMSGrad', type = bool, default = True) 303 | parser.add_argument('--batch_size', type = int, default = 32) 304 | parser.add_argument('--learning_rate', type = float, default = 1e-3) 305 | parser.add_argument('--decrease_LR', type = int, default = 10) 306 | parser.add_argument('--layer', type = str, default = 'ReLU22') 307 | parser.add_argument('--save_iter', type = int, default = 10) 308 | parser.add_argument('--inverseClass', type = int, default = 0) 309 | parser.add_argument('--decodername', type = str, default = "CIFAR10CNNDecoderReLU22") 310 | 311 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 312 | parser.set_defaults(gpu=True) 313 | 314 | parser.add_argument('--novalidation', dest='validation', action='store_false') 315 | parser.set_defaults(validation=True) 316 | args = parser.parse_args() 317 | 318 | model_dir = "checkpoints/" + args.dataset + '/' 319 | model_name = "ckpt.pth" 320 | decoder_name = args.decodername + '.pth' 321 | 322 | save_img_dir = "inverted_blackbox_decoder/" + args.dataset + '/' + args.layer + '/' 323 | 324 | if args.dataset == 'CIFAR10': 325 | 326 | imageWidth = 32 327 | imageHeight = 32 328 | imageSize = imageWidth * imageHeight 329 | NChannels = 3 330 | NClasses = 10 331 | 332 | else: 333 | print "No Dataset Found" 334 | exit() 335 | 336 | if args.training: 337 | trainDecoderDNN(DATASET = args.dataset, network = 'CIFAR10CNNDecoder', NEpochs = args.iters, imageWidth = imageWidth, 338 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, BatchSize = args.batch_size, learningRate = args.learning_rate, 339 | NDecreaseLR = args.decrease_LR, eps = args.eps, AMSGrad = True, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", save_decoder_dir = "checkpoints/CIFAR10/", 340 | decodername_name = decoder_name, gpu = args.gpu, validation=args.validation) 341 | 342 | else: 343 | for c in range(NClasses): 344 | inverse(DATASET = args.dataset, imageHeight = imageHeight, imageWidth = imageWidth, inverseClass = c, 345 | imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, 346 | model_dir = model_dir, model_name = model_name, decoder_name = decoder_name, 347 | save_img_dir = save_img_dir, gpu = args.gpu, validation=args.validation) 348 | 349 | except: 350 | traceback.print_exc(file=sys.stdout) 351 | sys.exit(1) 352 | -------------------------------------------------------------------------------- /inverse_query_free_CIFAR.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2019-08-31 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | 17 | from net import * 18 | from utils import * 19 | 20 | ##################### 21 | # Training: 22 | # python inverse_access_free_CIFAR.py --layer ReLU22 --iter 50 --training 23 | # 24 | # Testing: 25 | # python inverse_access_free_CIFAR.py --testing --layer ReLU22 --iter 500 --learning_rate 1e-1 --lambda_TV 2e0 --lambda_l2 0.0 26 | ##################### 27 | 28 | 29 | def trainAlternativeDNN(DATASET = 'CIFAR10', network = 'CIFAR10CNNAlternative', NEpochs = 200, imageWidth = 32, 30 | imageHeight = 32, imageSize = 32*32, NChannels = 3, NClasses = 10, layer = 'conv', BatchSize = 32, learningRate = 1e-3, 31 | NDecreaseLR = 5, eps = 1e-3, AMSGrad = True, model_dir = "checkpoints/MNIST/", model_name = "ckpt.pth", save_alternative_model_dir = "checkpoints/MNIST/", 32 | alternative_model_name = "LeNetAccessFree.pth", gpu = True, validation=False): 33 | 34 | print "DATASET: ", DATASET 35 | 36 | if DATASET == 'CIFAR10': 37 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 38 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 39 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 40 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 41 | tsf = { 42 | 'train': transforms.Compose( 43 | [ 44 | transforms.ToTensor(), 45 | Normalize 46 | ]), 47 | 'test': transforms.Compose( 48 | [ 49 | transforms.ToTensor(), 50 | Normalize 51 | ]) 52 | } 53 | trainset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = True, 54 | download=True, transform = tsf['train']) 55 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 56 | download=True, transform = tsf['test']) 57 | 58 | else: 59 | print "Dataset unsupported" 60 | exit(1) 61 | 62 | print "len(trainset) ", len(trainset) 63 | print "len(testset) ", len(testset) 64 | x_train, y_train = trainset.data, trainset.targets, 65 | x_test, y_test = testset.data, testset.targets, 66 | 67 | print "x_train.shape ", x_train.shape 68 | print "x_test.shape ", x_test.shape 69 | 70 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = BatchSize, 71 | shuffle = False, num_workers = 1) 72 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 73 | shuffle = False, num_workers = 1) 74 | trainIter = iter(trainloader) 75 | testIter = iter(testloader) 76 | 77 | # Load the trained model 78 | net = torch.load(model_dir + model_name) 79 | if not gpu: 80 | net = net.cpu() 81 | 82 | net.eval() 83 | print "Validate the model accuracy..." 84 | 85 | if validation: 86 | accTest = evalTest(testloader, net, gpu = gpu) 87 | 88 | altnetDict = { 89 | 'CIFAR10CNNAlternative':{ 90 | 'conv11': CIFAR10CNNAlternativeconv11, 91 | 'ReLU22': CIFAR10CNNAlternativeReLU22, 92 | 'ReLU32': CIFAR10CNNAlternativeReLU32 93 | } 94 | } 95 | alternativeNetFunc = altnetDict[network][layer] 96 | 97 | if gpu: 98 | alternativeNet = alternativeNetFunc(NChannels).cuda() 99 | else: 100 | alternativeNet = alternativeNetFunc(NChannels) 101 | 102 | print alternativeNet 103 | 104 | # Get dims of input/output, and construct the network 105 | batchX, batchY = trainIter.next() 106 | if gpu: 107 | batchX = batchX.cuda() 108 | 109 | edgeOutput = alternativeNet.forward(batchX) 110 | 111 | if gpu: 112 | cloudOuput = net.forward_from(edgeOutput, layer).clone() 113 | else: 114 | cloudOuput = net.forward_from(edgeOutput, layer) 115 | 116 | print "edgeOutput.size", edgeOutput.size() 117 | print "cloudOuput.size", cloudOuput.size() 118 | 119 | NBatch = len(trainset) / BatchSize 120 | if gpu: 121 | CrossEntropyLossLayer = nn.CrossEntropyLoss().cuda() 122 | else: 123 | CrossEntropyLossLayer = nn.CrossEntropyLoss() 124 | 125 | # Find the optimal config according to the hardware 126 | cudnn.benchmark = True 127 | optimizer = optim.Adam(params = alternativeNet.parameters(), lr = learningRate, eps = eps, amsgrad = AMSGrad) 128 | 129 | # Sanity check 130 | valData, valLabel = iter(testloader).next() 131 | if gpu: 132 | valData = valData.cuda() 133 | valLabel = valLabel.cuda() 134 | 135 | edgeOutput = alternativeNet.forward(valData) 136 | cloudOuput = net.forward_from(edgeOutput, layer).clone() 137 | valLoss = CrossEntropyLossLayer(cloudOuput, valLabel) 138 | 139 | print "Test Loss without training: ", valLoss.cpu().detach().numpy() 140 | 141 | for epoch in range(NEpochs): 142 | lossTrain = 0.0 143 | accTrain = 0.0 144 | for i in range(NBatch): 145 | try: 146 | batchX, batchY = trainIter.next() 147 | except StopIteration: 148 | trainIter = iter(trainloader) 149 | batchX, batchY = trainIter.next() 150 | 151 | if gpu: 152 | batchX = batchX.cuda() 153 | batchY = batchY.cuda() 154 | 155 | optimizer.zero_grad() 156 | 157 | edgeOutput = alternativeNet.forward(batchX).clone() 158 | cloudOuput = net.forward_from(edgeOutput, layer) 159 | 160 | featureLoss = CrossEntropyLossLayer(cloudOuput, batchY) 161 | 162 | totalLoss = featureLoss 163 | totalLoss.backward() 164 | optimizer.step() 165 | 166 | lossTrain += totalLoss.cpu().detach().numpy() / NBatch 167 | 168 | valData, valLabel = iter(testloader).next() 169 | if gpu: 170 | valData = valData.cuda() 171 | valLabel = valLabel.cuda() 172 | edgeOutput = alternativeNet.forward(valData) 173 | cloudOuput = net.forward_from(edgeOutput, layer).clone() 174 | valLoss = CrossEntropyLossLayer(cloudOuput, valLabel) 175 | 176 | if validation: 177 | accTestSplitModel = evalTestSplitModel(testloader, alternativeNet, net, layer, gpu = gpu) 178 | print "Epoch ", epoch, "Train Loss: ", lossTrain, "Test Loss: ", valLoss.cpu().detach().numpy(), "Test Accuracy", accTestSplitModel 179 | 180 | if (epoch + 1) % NDecreaseLR == 0: 181 | learningRate = learningRate / 2.0 182 | setLearningRate(optimizer, learningRate) 183 | 184 | if validation: 185 | accTestEnd = evalTest(testloader, net, gpu = gpu) 186 | if accTest != accTestEnd: 187 | print "Something wrong. Original model has been modified!" 188 | exit(1) 189 | 190 | if not os.path.exists(save_alternative_model_dir): 191 | os.makedirs(save_alternative_model_dir) 192 | torch.save(alternativeNet, save_alternative_model_dir + alternative_model_name) 193 | print "Model saved" 194 | 195 | newNet = torch.load(save_alternative_model_dir + alternative_model_name) 196 | newNet.eval() 197 | print "Model restore done" 198 | 199 | 200 | def inverse(DATASET = 'CIFAR10', NIters = 500, imageWidth = 32, inverseClass = None, 201 | imageHeight = 32, imageSize = 32*32, NChannels = 3, NClasses = 10, layer = 'ReLU2', 202 | learningRate = 1e-3, NDecreaseLR = 20, eps = 1e-3, lambda_TV = 1e3, lambda_l2 = 1.0, 203 | AMSGrad = True, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", 204 | alternative_model_name = "CIFAR10CNNAccessFree.pth", save_img_dir = "inverted_access_free/CIFAR10/MSE_TV/", 205 | saveIter = 10, gpu = True, validation=False): 206 | 207 | print "DATASET: ", DATASET 208 | print "inverseClass: ", inverseClass 209 | 210 | assert inverseClass < NClasses 211 | 212 | if DATASET == 'CIFAR10': 213 | 214 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 215 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 216 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 217 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 218 | tsf = { 219 | 'train': transforms.Compose( 220 | [ 221 | transforms.ToTensor(), 222 | Normalize 223 | ]), 224 | 'test': transforms.Compose( 225 | [ 226 | transforms.ToTensor(), 227 | Normalize 228 | ]) 229 | } 230 | trainset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = True, 231 | download=True, transform = tsf['train']) 232 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 233 | download=True, transform = tsf['test']) 234 | 235 | else: 236 | print "Dataset unsupported" 237 | exit(1) 238 | 239 | 240 | print "len(trainset) ", len(trainset) 241 | print "len(testset) ", len(testset) 242 | x_train, y_train = trainset.train_data, trainset.train_labels, 243 | x_test, y_test = testset.test_data, testset.test_labels, 244 | 245 | print "x_train.shape ", x_train.shape 246 | print "x_test.shape ", x_test.shape 247 | 248 | 249 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = 1, 250 | shuffle = False, num_workers = 1) 251 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 252 | shuffle = False, num_workers = 1) 253 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 254 | shuffle = False, num_workers = 1) 255 | trainIter = iter(trainloader) 256 | testIter = iter(testloader) 257 | inverseIter = iter(inverseloader) 258 | 259 | # Load the trained model 260 | net = torch.load(model_dir + model_name) 261 | if not gpu: 262 | net = net.cpu() 263 | net.eval() 264 | print "Validate the model accuracy..." 265 | 266 | if validation: 267 | accTest = evalTest(testloader, net, gpu = gpu) 268 | 269 | alternativeNet = torch.load(model_dir + alternative_model_name) 270 | if not gpu: 271 | alternativeNet = alternativeNet.cpu() 272 | alternativeNet.eval() 273 | print alternativeNet 274 | #print "Validate the alternative model..." 275 | batchX, batchY = iter(testloader).next() 276 | if gpu: 277 | batchX = batchX.cuda() 278 | batchY = batchY.cuda() 279 | 280 | if gpu: 281 | MSELossLayer = torch.nn.MSELoss().cuda() 282 | else: 283 | MSELossLayer = torch.nn.MSELoss() 284 | 285 | originalModelOutput = net.getLayerOutput(batchX, net.layerDict[layer]).clone() 286 | alternativeModelOutput = alternativeNet.forward(batchX) 287 | 288 | print "originalModelOutput.shape: ", originalModelOutput.shape, "alternativeModelOutput.shape: ", alternativeModelOutput.shape 289 | print "MSE difference on layer " + layer, MSELossLayer(originalModelOutput, alternativeModelOutput) 290 | 291 | 292 | targetImg, _ = getImgByClass(inverseIter, C = inverseClass) 293 | print "targetImg.size()", targetImg.size() 294 | 295 | deprocessImg = deprocess(targetImg.clone()) 296 | 297 | if not os.path.exists(save_img_dir): 298 | os.makedirs(save_img_dir) 299 | torchvision.utils.save_image(deprocessImg, save_img_dir + str(inverseClass) + '-ref.png') 300 | 301 | if gpu: 302 | targetImg = targetImg.cuda() 303 | targetLayer = net.layerDict[layer] 304 | refFeature = net.getLayerOutput(targetImg, targetLayer) 305 | 306 | print "refFeature.size()", refFeature.size() 307 | 308 | if gpu: 309 | xGen = torch.zeros(targetImg.size(), requires_grad = True, device="cuda") 310 | else: 311 | xGen = torch.zeros(targetImg.size(), requires_grad = True) 312 | 313 | optimizer = optim.Adam(params = [xGen], lr = learningRate, eps = eps, amsgrad = AMSGrad) 314 | 315 | for i in range(NIters): 316 | 317 | optimizer.zero_grad() 318 | 319 | xFeature = alternativeNet.forward(xGen) 320 | featureLoss = ((xFeature - refFeature)**2).mean() 321 | 322 | TVLoss = TV(xGen) 323 | normLoss = l2loss(xGen) 324 | 325 | totalLoss = featureLoss + lambda_TV * TVLoss + lambda_l2 * normLoss 326 | 327 | totalLoss.backward(retain_graph=True) 328 | optimizer.step() 329 | 330 | print "Iter ", i, "Feature loss: ", featureLoss.cpu().detach().numpy(), "TVLoss: ", TVLoss.cpu().detach().numpy(), "l2Loss: ", normLoss.cpu().detach().numpy() 331 | 332 | # save the final result 333 | imgGen = xGen.clone() 334 | imgGen = deprocess(imgGen) 335 | torchvision.utils.save_image(imgGen, save_img_dir + str(inverseClass) + '-inv.png') 336 | 337 | print "Done" 338 | 339 | 340 | if __name__ == '__main__': 341 | import argparse 342 | import sys 343 | import traceback 344 | 345 | try: 346 | parser = argparse.ArgumentParser() 347 | parser.add_argument('--dataset', type = str, default = 'CIFAR10') 348 | parser.add_argument('--network', type = str, default = 'CIFAR10CNNAlternative') 349 | 350 | parser.add_argument('--training', dest='training', action='store_true') 351 | parser.add_argument('--testing', dest='training', action='store_false') 352 | parser.set_defaults(training=False) 353 | parser.add_argument('--iters', type = int, default = 50) 354 | parser.add_argument('--eps', type = float, default = 1e-3) 355 | parser.add_argument('--lambda_TV', type = float, default = 1.0) 356 | parser.add_argument('--lambda_l2', type = float, default = 1.0) 357 | parser.add_argument('--AMSGrad', type = bool, default = True) 358 | parser.add_argument('--batch_size', type = int, default = 32) 359 | parser.add_argument('--learning_rate', type = float, default = 1e-3) 360 | parser.add_argument('--decrease_LR', type = int, default = 10) 361 | parser.add_argument('--layer', type = str, default = 'conv11') 362 | parser.add_argument('--method', type = str, default = "MSE_TV") 363 | parser.add_argument('--save_iter', type = int, default = 10) 364 | parser.add_argument('--inverseClass', type = int, default = 0) 365 | parser.add_argument('--altmodelname', type = str, default = "CIFAR10CNNAccessFree") 366 | 367 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 368 | parser.set_defaults(gpu=True) 369 | 370 | parser.add_argument('--novalidation', dest='validation', action='store_false') 371 | parser.set_defaults(validation=True) 372 | args = parser.parse_args() 373 | 374 | model_dir = "checkpoints/" + args.dataset + '/' 375 | model_name = "ckpt.pth" 376 | alternative_model_name = args.altmodelname + args.layer + '.pth' 377 | 378 | save_img_dir = "inverted_access_free/" + args.dataset + '/' + args.layer + '/' 379 | 380 | if args.dataset == 'CIFAR10': 381 | 382 | imageWidth = 32 383 | imageHeight = 32 384 | imageSize = imageWidth * imageHeight 385 | NChannels = 3 386 | NClasses = 10 387 | 388 | else: 389 | print "No Dataset Found" 390 | exit() 391 | 392 | if args.training: 393 | trainAlternativeDNN(DATASET = args.dataset, network = 'CIFAR10CNNAlternative', NEpochs = args.iters, imageWidth = imageWidth, 394 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, BatchSize = args.batch_size, learningRate = args.learning_rate, 395 | NDecreaseLR = args.decrease_LR, eps = args.eps, AMSGrad = True, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", save_alternative_model_dir = "checkpoints/CIFAR10/", 396 | alternative_model_name = alternative_model_name, gpu = args.gpu, validation=args.validation) 397 | 398 | else: 399 | for c in range(NClasses): 400 | inverse(DATASET = args.dataset, NIters = args.iters, imageWidth = imageWidth, inverseClass = c, 401 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, 402 | learningRate = args.learning_rate, NDecreaseLR = args.decrease_LR, eps = args.eps, lambda_TV = args.lambda_TV, lambda_l2 = args.lambda_l2, 403 | AMSGrad = args.AMSGrad, model_dir = model_dir, model_name = model_name, alternative_model_name = alternative_model_name, 404 | save_img_dir = save_img_dir, saveIter = args.save_iter, gpu = args.gpu, validation=args.validation) 405 | 406 | except: 407 | traceback.print_exc(file=sys.stdout) 408 | sys.exit(1) 409 | -------------------------------------------------------------------------------- /inverse_whitebox_CIFAR.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2019-08-31 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | from net import * 17 | from utils import * 18 | 19 | ##################### 20 | # Useful Hyperparameters: 21 | 22 | # CIFAR conv11 23 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-2 --layer conv11 --lambda_TV 0.0 --lambda_l2 0.0 24 | 25 | # CIFAR ReLU22 26 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-2 --layer ReLU22 --lambda_TV 1e1 --lambda_l2 0.0 27 | 28 | # CIFAR ReLU32 29 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-2 --layer ReLU32 --lambda_TV 1e3 --lambda_l2 0.0 30 | 31 | # CIFAR fc1 32 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-3 --layer fc1 --lambda_TV 1e4 --lambda_l2 0.0 33 | # python inverse_whitebox_CIFAR.py --iters 1000 --learning_rate 5e-2 --layer fc1 --lambda_TV 1e5 --lambda_l2 0.0 34 | 35 | # CIFAR fc2 36 | # python inverse_whitebox_CIFAR.py --iters 500 --learning_rate 1e-1 --layer fc2 --lambda_TV 5e2 --lambda_l2 1e2 37 | 38 | # CIFAR label 39 | # python inverse_whitebox_CIFAR.py --iters 500 --learning_rate 5e-2 --layer label --lambda_TV 5e-1 --lambda_l2 0.0 40 | ##################### 41 | 42 | def inverse(DATASET = 'CIFAR10', network = 'CIFAR10CNN', NIters = 500, imageWidth = 32, inverseClass = None, 43 | imageHeight = 32, imageSize = 32*32, NChannels = 3, NClasses = 10, layer = 'conv22', 44 | BatchSize = 32, learningRate = 1e-3, NDecreaseLR = 20, eps = 1e-3, lambda_TV = 1e3, lambda_l2 = 1.0, 45 | AMSGrad = True, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", 46 | save_img_dir = "inverted/CIFAR10/MSE_TV/", saveIter = 10, gpu = True, validation=False): 47 | 48 | print "DATASET: ", DATASET 49 | print "inverseClass: ", inverseClass 50 | 51 | assert inverseClass < NClasses 52 | 53 | if DATASET == 'CIFAR10': 54 | 55 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 56 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 57 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 58 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 59 | 60 | tsf = { 61 | 'train': transforms.Compose( 62 | [ 63 | transforms.ToTensor(), 64 | Normalize 65 | ]), 66 | 'test': transforms.Compose( 67 | [ 68 | transforms.ToTensor(), 69 | Normalize 70 | ]) 71 | } 72 | 73 | trainset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = True, 74 | download=True, transform = tsf['train']) 75 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 76 | download=True, transform = tsf['test']) 77 | 78 | 79 | print "len(trainset) ", len(trainset) 80 | print "len(testset) ", len(testset) 81 | x_train, y_train = trainset.data, trainset.targets, 82 | x_test, y_test = testset.data, testset.targets, 83 | 84 | print "x_train.shape ", x_train.shape 85 | print "x_test.shape ", x_test.shape 86 | 87 | 88 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = 1, 89 | shuffle = False, num_workers = 1) 90 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 91 | shuffle = False, num_workers = 1) 92 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 93 | shuffle = False, num_workers = 1) 94 | trainIter = iter(trainloader) 95 | testIter = iter(testloader) 96 | inverseIter = iter(inverseloader) 97 | 98 | net = torch.load(model_dir + model_name) 99 | if not gpu: 100 | net = net.cpu() 101 | 102 | net.eval() 103 | print "Validate the model accuracy..." 104 | if validation: 105 | accTest = evalTest(testloader, net, gpu = gpu) 106 | 107 | targetImg, _ = getImgByClass(inverseIter, C = inverseClass) 108 | print "targetImg.size()", targetImg.size() 109 | 110 | deprocessImg = deprocess(targetImg.clone()) 111 | 112 | if not os.path.exists(save_img_dir): 113 | os.makedirs(save_img_dir) 114 | torchvision.utils.save_image(deprocessImg, save_img_dir + str(inverseClass) + '-ref.png') 115 | 116 | if gpu: 117 | targetImg = targetImg.cuda() 118 | softmaxLayer = nn.Softmax().cuda() 119 | 120 | if layer == 'prob': 121 | reflogits = net.forward(targetImg) 122 | refFeature = softmaxLayer(reflogits) 123 | elif layer == 'label': 124 | refFeature = torch.zeros(1,NClasses) 125 | refFeature[0, inverseClass] = 1 126 | else: 127 | targetLayer = net.layerDict[layer] 128 | refFeature = net.getLayerOutput(targetImg, targetLayer) 129 | 130 | print "refFeature.size()", refFeature.size() 131 | 132 | if gpu: 133 | xGen = torch.zeros(targetImg.size(), requires_grad = True, device="cuda") 134 | else: 135 | xGen = torch.zeros(targetImg.size(), requires_grad = True) 136 | 137 | optimizer = optim.Adam(params = [xGen], lr = learningRate, eps = eps, amsgrad = AMSGrad) 138 | 139 | for i in range(NIters): 140 | 141 | optimizer.zero_grad() 142 | if layer == 'prob': 143 | xlogits = net.forward(xGen) 144 | xFeature = softmaxLayer(xlogits) 145 | featureLoss = ((xFeature - refFeature)**2).mean() 146 | elif layer == 'label': 147 | xlogits = net.forward(xGen) 148 | xFeature = softmaxLayer(xlogits) 149 | featureLoss = - torch.log(xFeature[0, inverseClass]) 150 | else: 151 | xFeature = net.getLayerOutput(xGen, targetLayer) 152 | featureLoss = ((xFeature - refFeature)**2).mean() 153 | 154 | TVLoss = TV(xGen) 155 | normLoss = l2loss(xGen) 156 | 157 | totalLoss = featureLoss + lambda_TV * TVLoss + lambda_l2 * normLoss #- 1.0 * conv1Loss 158 | 159 | totalLoss.backward(retain_graph=True) 160 | optimizer.step() 161 | 162 | print "Iter ", i, "Feature loss: ", featureLoss.cpu().detach().numpy(), "TVLoss: ", TVLoss.cpu().detach().numpy(), "l2Loss: ", normLoss.cpu().detach().numpy() 163 | 164 | # save the final result 165 | imgGen = xGen.clone() 166 | imgGen = deprocess(imgGen) 167 | torchvision.utils.save_image(imgGen, save_img_dir + str(inverseClass) + '-inv.png') 168 | 169 | print "targetImg l1 Stat:" 170 | getL1Stat(net, targetImg) 171 | print "xGen l1 Stat:" 172 | getL1Stat(net, xGen) 173 | print "Done" 174 | 175 | 176 | if __name__ == '__main__': 177 | import argparse 178 | import sys 179 | import traceback 180 | 181 | try: 182 | parser = argparse.ArgumentParser() 183 | parser.add_argument('--dataset', type = str, default = 'CIFAR10') 184 | parser.add_argument('--network', type = str, default = 'CIFAR10CNN') 185 | parser.add_argument('--iters', type = int, default = 500) 186 | parser.add_argument('--eps', type = float, default = 1e-3) 187 | parser.add_argument('--lambda_TV', type = float, default = 1.0) 188 | parser.add_argument('--lambda_l2', type = float, default = 1.0) 189 | parser.add_argument('--AMSGrad', type = bool, default = True) 190 | parser.add_argument('--batch_size', type = int, default = 32) 191 | parser.add_argument('--learning_rate', type = float, default = 1e-3) 192 | parser.add_argument('--decrease_LR', type = int, default = 20) 193 | parser.add_argument('--layer', type = str, default = 'conv22') 194 | parser.add_argument('--save_iter', type = int, default = 10) 195 | parser.add_argument('--inverseClass', type = int, default = None) 196 | 197 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 198 | parser.set_defaults(gpu=True) 199 | 200 | parser.add_argument('--novalidation', dest='validation', action='store_false') 201 | parser.set_defaults(validation=True) 202 | args = parser.parse_args() 203 | 204 | model_dir = "checkpoints/" + args.dataset + '/' 205 | model_name = "ckpt.pth" 206 | 207 | save_img_dir = "inverted_whitebox/" + args.dataset + '/' + args.layer + '/' 208 | 209 | if args.dataset == 'MNIST': 210 | 211 | imageWidth = 28 212 | imageHeight = 28 213 | imageSize = imageWidth * imageHeight 214 | NChannels = 1 215 | NClasses = 10 216 | 217 | elif args.dataset == 'CIFAR10': 218 | 219 | imageWidth = 32 220 | imageHeight = 32 221 | imageSize = imageWidth * imageHeight 222 | NChannels = 3 223 | NClasses = 10 224 | 225 | else: 226 | print "No Dataset Found" 227 | exit() 228 | 229 | for c in range(NClasses): 230 | inverse(DATASET = args.dataset, network = args.network, NIters = args.iters, imageWidth = imageWidth, inverseClass = c, 231 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, 232 | BatchSize = args.batch_size, learningRate = args.learning_rate, NDecreaseLR = args.decrease_LR, eps = args.eps, lambda_TV = args.lambda_TV, lambda_l2 = args.lambda_l2, 233 | AMSGrad = args.AMSGrad, model_dir = model_dir, model_name = model_name, save_img_dir = save_img_dir, saveIter = args.save_iter, 234 | gpu = args.gpu, validation=args.validation) 235 | 236 | except: 237 | traceback.print_exc(file=sys.stdout) 238 | sys.exit(1) 239 | -------------------------------------------------------------------------------- /inverse_whitebox_CIFAR_defense.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2020-04-20 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | from net import * 17 | from utils import * 18 | 19 | from skimage.measure import compare_ssim 20 | 21 | ##################### 22 | # Useful Hyperparameters: 23 | 24 | # CIFAR conv11 25 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-2 --layer conv11 --lambda_TV 0.0 --lambda_l2 0.0 26 | 27 | # CIFAR ReLU22 28 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-2 --layer ReLU22 --lambda_TV 1e1 --lambda_l2 0.0 29 | 30 | # CIFAR ReLU32 31 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-2 --layer ReLU32 --lambda_TV 1e3 --lambda_l2 0.0 32 | 33 | # CIFAR fc1 34 | # python inverse_whitebox_CIFAR.py --iters 5000 --learning_rate 1e-3 --layer fc1 --lambda_TV 1e4 --lambda_l2 0.0 35 | # python inverse_whitebox_CIFAR.py --iters 1000 --learning_rate 5e-2 --layer fc1 --lambda_TV 1e5 --lambda_l2 0.0 36 | 37 | # CIFAR fc2 38 | # python inverse_whitebox_CIFAR.py --iters 500 --learning_rate 1e-1 --layer fc2 --lambda_TV 5e2 --lambda_l2 1e2 39 | 40 | # CIFAR label 41 | # python inverse_whitebox_CIFAR.py --iters 500 --learning_rate 5e-2 --layer label --lambda_TV 5e-1 --lambda_l2 0.0 42 | 43 | # Gaussian and laplace noise 44 | # python inverse_whitebox_CIFAR_defense.py --noise_type Laplace --layer ReLU22 45 | # python inverse_whitebox_CIFAR_defense.py --noise_type Laplace --layer ReLU22 --add_noise_to_input 46 | 47 | # Dropout 48 | # python inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer ReLU22 49 | # python inverse_whitebox_CIFAR_defense.py --noise_type dropout --layer ReLU22 --add_noise_to_input 50 | 51 | ##################### 52 | 53 | def eval_DP_defense(args, noise_type, noise_level, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth"): 54 | if args.dataset == 'CIFAR10': 55 | 56 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 57 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 58 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 59 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 60 | 61 | tsf = { 62 | 'train': transforms.Compose( 63 | [ 64 | transforms.ToTensor(), 65 | Normalize 66 | ]), 67 | 'test': transforms.Compose( 68 | [ 69 | transforms.ToTensor(), 70 | Normalize 71 | ]) 72 | } 73 | 74 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 75 | download=False, transform = tsf['test']) 76 | 77 | #print "len(testset) ", len(testset) 78 | x_test, y_test = testset.data, testset.targets, 79 | 80 | #print "x_test.shape ", x_test.shape 81 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 82 | shuffle = False, num_workers = 1) 83 | testIter = iter(testloader) 84 | 85 | net = torch.load(model_dir + model_name) 86 | if not args.gpu: 87 | net = net.cpu() 88 | 89 | net.eval() 90 | #print "Validate the model accuracy..." 91 | 92 | acc = evalTestSplitModel(testloader, net, net, layer=args.layer, gpu = args.gpu, 93 | noise_type = noise_type, 94 | noise_level = noise_level, 95 | args = args 96 | ) 97 | return acc 98 | 99 | def inverse(DATASET = 'CIFAR10', network = 'CIFAR10CNN', NIters = 500, imageWidth = 32, inverseClass = None, 100 | imageHeight = 32, imageSize = 32*32, NChannels = 3, NClasses = 10, layer = 'conv22', 101 | BatchSize = 32, learningRate = 1e-3, NDecreaseLR = 20, eps = 1e-3, lambda_TV = 1e3, lambda_l2 = 1.0, 102 | AMSGrad = True, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", 103 | save_img_dir = "inverted/CIFAR10/MSE_TV/", saveIter = 10, gpu = True, validation=False, 104 | noise_type = None, noise_level = 0.0, args=None): 105 | 106 | assert inverseClass < NClasses 107 | 108 | if DATASET == 'CIFAR10': 109 | 110 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 111 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 112 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 113 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 114 | 115 | tsf = { 116 | 'train': transforms.Compose( 117 | [ 118 | transforms.ToTensor(), 119 | Normalize 120 | ]), 121 | 'test': transforms.Compose( 122 | [ 123 | transforms.ToTensor(), 124 | Normalize 125 | ]) 126 | } 127 | 128 | trainset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = True, 129 | download=False, transform = tsf['train']) 130 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 131 | download=False, transform = tsf['test']) 132 | 133 | x_train, y_train = trainset.data, trainset.targets, 134 | x_test, y_test = testset.data, testset.targets, 135 | 136 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = 1, 137 | shuffle = False, num_workers = 1) 138 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 139 | shuffle = False, num_workers = 1) 140 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 141 | shuffle = False, num_workers = 1) 142 | trainIter = iter(trainloader) 143 | testIter = iter(testloader) 144 | inverseIter = iter(inverseloader) 145 | 146 | net = torch.load(model_dir + model_name) 147 | if not gpu: 148 | net = net.cpu() 149 | 150 | net.eval() 151 | 152 | targetImg, _ = getImgByClass(inverseIter, C = inverseClass) 153 | deprocessImg = deprocess(targetImg.clone()) 154 | 155 | if not os.path.exists(save_img_dir): 156 | os.makedirs(save_img_dir) 157 | torchvision.utils.save_image(deprocessImg, save_img_dir + str(inverseClass) + '-ref.png') 158 | 159 | if gpu: 160 | targetImg = targetImg.cuda() 161 | softmaxLayer = nn.Softmax().cuda() 162 | 163 | #if hasattr(args, 'add_noise_to_input') and args.add_noise_to_input: 164 | # targetImg = apply_noise(targetImg, noise_type, noise_level, gpu=args.gpu, args=args) 165 | 166 | if layer == 'prob': 167 | if hasattr(args, 'add_noise_to_input') and args.add_noise_to_input: 168 | targetImg_noised = apply_noise(targetImg, noise_type, noise_level, gpu=args.gpu, args=args) 169 | reflogits = net.forward(targetImg_noised) 170 | else: 171 | reflogits = net.forward(targetImg) 172 | refFeature = softmaxLayer(reflogits) 173 | elif layer == 'label': 174 | refFeature = torch.zeros(1,NClasses) 175 | refFeature[0, inverseClass] = 1 176 | else: 177 | targetLayer = net.layerDict[layer] 178 | if hasattr(args, 'add_noise_to_input') and args.add_noise_to_input: 179 | #print "Noise added to input" 180 | targetImg_noised = apply_noise(targetImg, noise_type, noise_level, gpu=args.gpu, args=args) 181 | refFeature = net.getLayerOutput(targetImg_noised, targetLayer) 182 | else: 183 | refFeature = net.getLayerOutput(targetImg, targetLayer) 184 | 185 | # Apply noise 186 | if noise_type != None and not (hasattr(args, 'add_noise_to_input') and args.add_noise_to_input): 187 | refFeature = apply_noise(refFeature, noise_type, noise_level, gpu=args.gpu, args=args) 188 | 189 | if gpu: 190 | xGen = torch.zeros(targetImg.size(), requires_grad = True, device="cuda") 191 | else: 192 | xGen = torch.zeros(targetImg.size(), requires_grad = True) 193 | 194 | optimizer = optim.Adam(params = [xGen], lr = learningRate, eps = eps, amsgrad = AMSGrad) 195 | 196 | for i in range(NIters): 197 | 198 | optimizer.zero_grad() 199 | if layer == 'prob': 200 | xlogits = net.forward(xGen) 201 | xFeature = softmaxLayer(xlogits) 202 | featureLoss = ((xFeature - refFeature)**2).mean() 203 | elif layer == 'label': 204 | xlogits = net.forward(xGen) 205 | xFeature = softmaxLayer(xlogits) 206 | featureLoss = - torch.log(xFeature[0, inverseClass]) 207 | else: 208 | xFeature = net.getLayerOutput(xGen, targetLayer) 209 | featureLoss = ((xFeature - refFeature)**2).mean() 210 | 211 | TVLoss = TV(xGen) 212 | normLoss = l2loss(xGen) 213 | 214 | totalLoss = featureLoss + lambda_TV * TVLoss + lambda_l2 * normLoss #- 1.0 * conv1Loss 215 | 216 | totalLoss.backward(retain_graph=True) 217 | optimizer.step() 218 | 219 | #print "Iter ", i, "Feature loss: ", featureLoss.cpu().detach().numpy(), "TVLoss: ", TVLoss.cpu().detach().numpy(), "l2Loss: ", normLoss.cpu().detach().numpy() 220 | 221 | # save the final result 222 | imgGen = xGen.clone() 223 | imgGen = deprocess(imgGen) 224 | torchvision.utils.save_image(imgGen, save_img_dir + str(inverseClass) + '-inv.png') 225 | 226 | ref_img = deprocessImg.detach().cpu().numpy().squeeze() 227 | inv_img = imgGen.detach().cpu().numpy().squeeze() 228 | 229 | #print "ref_img.shape", ref_img.shape, "inv_img.shape", inv_img.shape 230 | #print "ref_img ", ref_img.min(), ref_img.max() 231 | #print "inv_img ", inv_img.min(), inv_img.max() 232 | 233 | psnr = get_PSNR(ref_img, inv_img, peak=1.0) 234 | 235 | #print("ref_img.shape", ref_img.shape) 236 | #print("inv_img.shape", inv_img.shape) 237 | ssim = compare_ssim( 238 | X=np.moveaxis(ref_img, 0, -1), 239 | Y=np.moveaxis(inv_img, 0, -1), 240 | data_range = inv_img.max() - inv_img.min(), 241 | multichannel=True) 242 | 243 | #print "targetImg l1 Stat:" 244 | #getL1Stat(net, targetImg) 245 | #print "xGen l1 Stat:" 246 | #getL1Stat(net, xGen) 247 | #print "Done" 248 | 249 | return psnr, ssim 250 | 251 | 252 | if __name__ == '__main__': 253 | import argparse 254 | import sys 255 | import traceback 256 | 257 | try: 258 | parser = argparse.ArgumentParser() 259 | parser.add_argument('--dataset', type = str, default = 'CIFAR10') 260 | parser.add_argument('--network', type = str, default = 'CIFAR10CNN') 261 | parser.add_argument('--iters', type = int, default = 500) 262 | parser.add_argument('--eps', type = float, default = 1e-3) 263 | parser.add_argument('--lambda_TV', type = float, default = 1.0) 264 | parser.add_argument('--lambda_l2', type = float, default = 1.0) 265 | parser.add_argument('--AMSGrad', type = bool, default = True) 266 | parser.add_argument('--batch_size', type = int, default = 32) 267 | parser.add_argument('--learning_rate', type = float, default = 1e-3) 268 | parser.add_argument('--decrease_LR', type = int, default = 20) 269 | parser.add_argument('--layer', type = str, default = 'conv22') 270 | parser.add_argument('--save_iter', type = int, default = 10) 271 | parser.add_argument('--inverseClass', type = int, default = None) 272 | 273 | parser.add_argument('--noise_type', type = str, default = None) 274 | parser.add_argument('--noise_level', type = float, default = None) 275 | 276 | parser.add_argument('--add_noise_to_input', dest='add_noise_to_input', action='store_true') 277 | 278 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 279 | parser.set_defaults(gpu=True) 280 | 281 | parser.add_argument('--novalidation', dest='validation', action='store_false') 282 | parser.set_defaults(validation=True) 283 | 284 | parser.add_argument('--noise_iters', type = int, default = 500) 285 | parser.add_argument('--noise_eps', type = float, default = 1e-3) 286 | parser.add_argument('--noise_AMSGrad', type = bool, default = True) 287 | parser.add_argument('--noise_learning_rate', type = float, default = 1e-1) 288 | parser.add_argument('--noise_lambda_sourcelayer', type = float, default = 1e-1) 289 | parser.add_argument('--noise_decrease_LR', type = int, default = 20) 290 | parser.add_argument('--noise_targetLayer', type = str, default = 'fc3') 291 | 292 | args = parser.parse_args() 293 | 294 | 295 | args.noise_sourceLayer = args.layer 296 | args.model_dir = "checkpoints/" + args.dataset + '/' 297 | args.model_name = "ckpt.pth" 298 | 299 | if args.dataset == 'CIFAR10': 300 | 301 | imageWidth = 32 302 | imageHeight = 32 303 | imageSize = imageWidth * imageHeight 304 | NChannels = 3 305 | NClasses = 10 306 | 307 | else: 308 | print "No Dataset Found" 309 | exit() 310 | 311 | noise_type = args.noise_type 312 | noise_hist = [] 313 | acc_hist = [] 314 | psnr_hist = [] 315 | ssim_hist = [] 316 | 317 | if 'noise_gen' in args.noise_type: 318 | default_nl = np.concatenate((np.arange(0, 110, 10), np.arange(100, 1100, 100)), axis=0) 319 | elif 'dropout' in args.noise_type: 320 | default_nl = np.arange(0, 1, 0.1) 321 | else: 322 | default_nl = np.concatenate((np.arange(0, 1, 0.1), np.arange(1.0, 5.5, 0.5)), axis=0) 323 | 324 | noise_range = [args.noise_level] if args.noise_level != None else default_nl 325 | 326 | for noise_level in noise_range: 327 | noise_hist.append(noise_level) 328 | 329 | if args.add_noise_to_input: 330 | save_img_dir = "inverted_whitebox/" + args.dataset + '/' + args.layer + '/' + 'noised_add_to_input/' + noise_type + '/' + str(round(noise_level,1)) + '/' 331 | else: 332 | save_img_dir = "inverted_whitebox/" + args.dataset + '/' + args.layer + '/' + 'noised/' + noise_type + '/' + str(round(noise_level,1)) + '/' 333 | 334 | if not os.path.exists(save_img_dir): 335 | os.makedirs(save_img_dir) 336 | 337 | acc = eval_DP_defense(args, noise_type, noise_level) 338 | acc_hist.append(acc) 339 | 340 | psnr_sum = 0.0 341 | ssim_sum = 0.0 342 | for c in range(NClasses): 343 | psnr, ssim = inverse(DATASET = args.dataset, network = args.network, NIters = args.iters, imageWidth = imageWidth, inverseClass = c, 344 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, 345 | BatchSize = args.batch_size, learningRate = args.learning_rate, NDecreaseLR = args.decrease_LR, eps = args.eps, lambda_TV = args.lambda_TV, lambda_l2 = args.lambda_l2, 346 | AMSGrad = args.AMSGrad, model_dir = args.model_dir, model_name = args.model_name, save_img_dir = save_img_dir, saveIter = args.save_iter, 347 | gpu = args.gpu, validation=args.validation, noise_type = noise_type, noise_level = noise_level, args = args) 348 | 349 | psnr_sum += psnr / NClasses 350 | ssim_sum += ssim / NClasses 351 | 352 | psnr_hist.append(psnr_sum) 353 | ssim_hist.append(ssim_sum) 354 | print "Noise_type:", noise_type, " Add to input:", args.add_noise_to_input, " Noise_level:", round(noise_level,2), " Acc:", round(acc,4), " PSNR:", round(psnr_sum,4), " SSIM:", round(ssim_sum,4) 355 | 356 | except: 357 | traceback.print_exc(file=sys.stdout) 358 | sys.exit(1) 359 | -------------------------------------------------------------------------------- /inverse_whitebox_MNIST.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2020-04-20 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | from net import * 17 | from utils import * 18 | 19 | ##################### 20 | # Useful Hyperparameters: 21 | 22 | # A good parameter set to invert MNIST ReLU2 layer 23 | # python inverse.py --dataset MNIST --iters 5000 --learning_rate 1e-2 --layer ReLU2 --lambda_TV 1e0 --lambda_l2 0.0 24 | 25 | # A good parameter set to invert MNIST fc3 layer 26 | # python inverse.py --dataset MNIST --iters 5000 --learning_rate 1e-2 --layer fc3 --lambda_TV 1e3 --lambda_l2 0.0 27 | # 28 | # A good parameter set to invert MNIST label only 29 | # python inverse.py --dataset MNIST --iters 5000 --learning_rate 1e-2 --layer prob --lambda_TV 1e-1 --lambda_l2 0.0 30 | 31 | ##################### 32 | 33 | def inverse(DATASET = 'MNIST', network = 'LeNet', NIters = 500, imageWidth = 28, inverseClass = None, 34 | imageHeight = 28, imageSize = 28*28, NChannels = 1, NClasses = 10, layer = 'conv2', 35 | BatchSize = 32, learningRate = 1e-3, NDecreaseLR = 20, eps = 1e-3, lambda_TV = 1e3, lambda_l2 = 1.0, 36 | AMSGrad = True, model_dir = "checkpoints/MNIST/", model_name = "ckpt.pth", 37 | save_img_dir = "inverted/MNIST/MSE_TV/", saveIter = 10, gpu = True, validation=False): 38 | 39 | print "DATASET: ", DATASET 40 | print "inverseClass: ", inverseClass 41 | 42 | assert inverseClass < NClasses 43 | 44 | if DATASET == 'MNIST': 45 | 46 | mu = torch.tensor([0.5], dtype=torch.float32) 47 | sigma = torch.tensor([0.5], dtype=torch.float32) 48 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 49 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 50 | 51 | tsf = { 52 | 'train': transforms.Compose( 53 | [ 54 | transforms.ToTensor(), 55 | Normalize 56 | ]), 57 | 58 | 'test': transforms.Compose( 59 | [ 60 | transforms.ToTensor(), 61 | Normalize 62 | ]) 63 | } 64 | 65 | trainset = torchvision.datasets.MNIST(root='./data/MNIST', train=True, 66 | download=True, transform = tsf['train']) 67 | 68 | testset = torchvision.datasets.MNIST(root='./data/MNIST', train=False, 69 | download=True, transform = tsf['test']) 70 | 71 | print "len(trainset) ", len(trainset) 72 | print "len(testset) ", len(testset) 73 | x_train, y_train = trainset.data, trainset.targets, 74 | x_test, y_test = testset.data, testset.targets, 75 | 76 | print "x_train.shape ", x_train.shape 77 | print "x_test.shape ", x_test.shape 78 | 79 | 80 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = 1, 81 | shuffle = False, num_workers = 1) 82 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 83 | shuffle = False, num_workers = 1) 84 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 85 | shuffle = False, num_workers = 1) 86 | trainIter = iter(trainloader) 87 | testIter = iter(testloader) 88 | inverseIter = iter(inverseloader) 89 | 90 | net = torch.load(model_dir + model_name) 91 | if not gpu: 92 | net = net.cpu() 93 | 94 | net.eval() 95 | print "Validate the model accuracy..." 96 | if validation: 97 | accTest = evalTest(testloader, net, gpu = gpu) 98 | 99 | targetImg, _ = getImgByClass(inverseIter, C = inverseClass) 100 | print "targetImg.size()", targetImg.size() 101 | 102 | deprocessImg = deprocess(targetImg.clone()) 103 | 104 | if not os.path.exists(save_img_dir): 105 | os.makedirs(save_img_dir) 106 | torchvision.utils.save_image(deprocessImg, save_img_dir + str(inverseClass) + '-ref.png') 107 | 108 | if gpu: 109 | targetImg = targetImg.cuda() 110 | softmaxLayer = nn.Softmax().cuda() 111 | 112 | if layer == 'prob': 113 | reflogits = net.forward(targetImg) 114 | refFeature = softmaxLayer(reflogits) 115 | elif layer == 'label': 116 | refFeature = torch.zeros(1,NClasses) 117 | refFeature[0, inverseClass] = 1 118 | else: 119 | targetLayer = net.layerDict[layer] 120 | refFeature = net.getLayerOutput(targetImg, targetLayer) 121 | 122 | print "refFeature.size()", refFeature.size() 123 | 124 | if gpu: 125 | xGen = torch.zeros(targetImg.size(), requires_grad = True, device="cuda") 126 | else: 127 | xGen = torch.zeros(targetImg.size(), requires_grad = True) 128 | 129 | optimizer = optim.Adam(params = [xGen], lr = learningRate, eps = eps, amsgrad = AMSGrad) 130 | 131 | for i in range(NIters): 132 | 133 | optimizer.zero_grad() 134 | if layer == 'prob': 135 | xlogits = net.forward(xGen) 136 | xFeature = softmaxLayer(xlogits) 137 | featureLoss = ((xFeature - refFeature)**2).mean() 138 | elif layer == 'label': 139 | xlogits = net.forward(xGen) 140 | xFeature = softmaxLayer(xlogits) 141 | featureLoss = - torch.log(xFeature[0, inverseClass]) 142 | else: 143 | xFeature = net.getLayerOutput(xGen, targetLayer) 144 | featureLoss = ((xFeature - refFeature)**2).mean() 145 | 146 | TVLoss = TV(xGen) 147 | normLoss = l2loss(xGen) 148 | 149 | totalLoss = featureLoss + lambda_TV * TVLoss + lambda_l2 * normLoss #- 1.0 * conv1Loss 150 | 151 | totalLoss.backward(retain_graph=True) 152 | optimizer.step() 153 | 154 | print "Iter ", i, "Feature loss: ", featureLoss.cpu().detach().numpy(), "TVLoss: ", TVLoss.cpu().detach().numpy(), "l2Loss: ", normLoss.cpu().detach().numpy() 155 | 156 | # save the final result 157 | imgGen = xGen.clone() 158 | imgGen = deprocess(imgGen) 159 | torchvision.utils.save_image(imgGen, save_img_dir + str(inverseClass) + '-inv.png') 160 | 161 | print "targetImg l1 Stat:" 162 | getL1Stat(net, targetImg) 163 | print "xGen l1 Stat:" 164 | getL1Stat(net, xGen) 165 | print "Done" 166 | 167 | 168 | if __name__ == '__main__': 169 | import argparse 170 | import sys 171 | import traceback 172 | 173 | try: 174 | parser = argparse.ArgumentParser() 175 | parser.add_argument('--dataset', type = str, default = 'MNIST') 176 | parser.add_argument('--network', type = str, default = 'LeNet') 177 | parser.add_argument('--iters', type = int, default = 500) 178 | parser.add_argument('--eps', type = float, default = 1e-3) 179 | parser.add_argument('--lambda_TV', type = float, default = 1.0) 180 | parser.add_argument('--lambda_l2', type = float, default = 0.0) 181 | parser.add_argument('--AMSGrad', type = bool, default = True) 182 | parser.add_argument('--batch_size', type = int, default = 32) 183 | parser.add_argument('--learning_rate', type = float, default = 1e-2) 184 | parser.add_argument('--decrease_LR', type = int, default = 20) 185 | parser.add_argument('--layer', type = str, default = 'ReLU2') 186 | parser.add_argument('--save_iter', type = int, default = 10) 187 | parser.add_argument('--inverseClass', type = int, default = None) 188 | 189 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 190 | parser.set_defaults(gpu=True) 191 | 192 | parser.add_argument('--novalidation', dest='validation', action='store_false') 193 | parser.set_defaults(validation=True) 194 | args = parser.parse_args() 195 | 196 | model_dir = "checkpoints/" + args.dataset + '/' 197 | model_name = "ckpt.pth" 198 | 199 | save_img_dir = "inverted_whitebox/" + args.dataset + '/' + args.layer + '/' 200 | 201 | if args.dataset == 'MNIST': 202 | 203 | imageWidth = 28 204 | imageHeight = 28 205 | imageSize = imageWidth * imageHeight 206 | NChannels = 1 207 | NClasses = 10 208 | 209 | else: 210 | print "No Dataset Found" 211 | exit() 212 | 213 | for c in range(NClasses): 214 | inverse(DATASET = args.dataset, network = args.network, NIters = args.iters, imageWidth = imageWidth, inverseClass = c, 215 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, 216 | BatchSize = args.batch_size, learningRate = args.learning_rate, NDecreaseLR = args.decrease_LR, eps = args.eps, lambda_TV = args.lambda_TV, lambda_l2 = args.lambda_l2, 217 | AMSGrad = args.AMSGrad, model_dir = model_dir, model_name = model_name, save_img_dir = save_img_dir, saveIter = args.save_iter, 218 | gpu = args.gpu, validation=args.validation) 219 | 220 | except: 221 | traceback.print_exc(file=sys.stdout) 222 | sys.exit(1) 223 | -------------------------------------------------------------------------------- /inverse_whitebox_MNIST_defense.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2020-04-20 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | from net import * 17 | from utils import * 18 | 19 | from skimage.measure import compare_ssim 20 | 21 | ##################### 22 | # Useful Hyperparameters: 23 | 24 | # A good parameter set to invert MNIST ReLU2 layer 25 | # python inverse.py --dataset MNIST --iters 5000 --learning_rate 1e-2 --layer ReLU2 --lambda_TV 1e0 --lambda_l2 0.0 26 | 27 | # A good parameter set to invert MNIST fc3 layer 28 | # python inverse.py --dataset MNIST --iters 5000 --learning_rate 1e-2 --layer fc3 --lambda_TV 1e3 --lambda_l2 0.0 29 | # 30 | # A good parameter set to invert MNIST label only 31 | # python inverse.py --dataset MNIST --iters 5000 --learning_rate 1e-2 --layer prob --lambda_TV 1e-1 --lambda_l2 0.0 32 | 33 | # Gaussian and laplace noise 34 | # python inverse_whitebox_MNIST_defense.py --noise_type Laplace --layer ReLU2 35 | # python inverse_whitebox_MNIST_defense.py --noise_type Laplace --layer ReLU2 --add_noise_to_input 36 | 37 | # Dropout 38 | # python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer ReLU2 39 | # python inverse_whitebox_MNIST_defense.py --noise_type dropout --layer ReLU2 --add_noise_to_input 40 | 41 | # Noise opt 42 | # Generate a noise applied to noise_targetLayer that minimize the difference in noise_targetLayer 43 | # python noise_generation_opt.py --noise_sourceLayer ReLU2 --noise_targetLayer fc1 44 | # python inverse_whitebox_MNIST_defense.py --noise_type noise_gen --noise_targetLayer fc1 45 | # python noise_generation_opt.py --noise_sourceLayer conv2 --noise_targetLayer ReLU2 --noise_lambda_sourcelayer 1e-3 --noise_level 200 46 | 47 | ##################### 48 | 49 | def eval_DP_defense(args, noise_type, noise_level, model_dir = "checkpoints/MNIST/", model_name = "ckpt.pth"): 50 | if args.dataset == 'MNIST': 51 | 52 | mu = torch.tensor([0.5], dtype=torch.float32) 53 | sigma = torch.tensor([0.5], dtype=torch.float32) 54 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 55 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 56 | 57 | tsf = { 58 | 'test': transforms.Compose( 59 | [ 60 | transforms.ToTensor(), 61 | Normalize 62 | ]) 63 | } 64 | 65 | testset = torchvision.datasets.MNIST(root='./data/MNIST', train=False, 66 | download=True, transform = tsf['test']) 67 | 68 | #print "len(testset) ", len(testset) 69 | x_test, y_test = testset.data, testset.targets, 70 | 71 | #print "x_test.shape ", x_test.shape 72 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 73 | shuffle = False, num_workers = 1) 74 | testIter = iter(testloader) 75 | 76 | net = torch.load(model_dir + model_name) 77 | if not args.gpu: 78 | net = net.cpu() 79 | 80 | net.eval() 81 | #print "Validate the model accuracy..." 82 | 83 | acc = evalTestSplitModel(testloader, net, net, layer=args.layer, gpu = args.gpu, 84 | noise_type = noise_type, 85 | noise_level = noise_level, 86 | args = args 87 | ) 88 | return acc 89 | 90 | def inverse(DATASET = 'MNIST', network = 'LeNet', NIters = 500, imageWidth = 28, inverseClass = None, 91 | imageHeight = 28, imageSize = 28*28, NChannels = 1, NClasses = 10, layer = 'conv2', 92 | BatchSize = 32, learningRate = 1e-3, NDecreaseLR = 20, eps = 1e-3, lambda_TV = 1e3, lambda_l2 = 1.0, 93 | AMSGrad = True, model_dir = "checkpoints/MNIST/", model_name = "ckpt.pth", 94 | save_img_dir = "inverted/MNIST/MSE_TV/", saveIter = 10, gpu = True, validation=False, 95 | noise_type = None, noise_level = 0.0, args=None): 96 | 97 | assert inverseClass < NClasses 98 | 99 | if DATASET == 'MNIST': 100 | 101 | mu = torch.tensor([0.5], dtype=torch.float32) 102 | sigma = torch.tensor([0.5], dtype=torch.float32) 103 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 104 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 105 | 106 | tsf = { 107 | 'train': transforms.Compose( 108 | [ 109 | transforms.ToTensor(), 110 | Normalize 111 | ]), 112 | 113 | 'test': transforms.Compose( 114 | [ 115 | transforms.ToTensor(), 116 | Normalize 117 | ]) 118 | } 119 | 120 | trainset = torchvision.datasets.MNIST(root='./data/MNIST', train=True, 121 | download=True, transform = tsf['train']) 122 | 123 | testset = torchvision.datasets.MNIST(root='./data/MNIST', train=False, 124 | download=True, transform = tsf['test']) 125 | 126 | x_train, y_train = trainset.data, trainset.targets, 127 | x_test, y_test = testset.data, testset.targets, 128 | 129 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = 1, 130 | shuffle = False, num_workers = 1) 131 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 132 | shuffle = False, num_workers = 1) 133 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 134 | shuffle = False, num_workers = 1) 135 | trainIter = iter(trainloader) 136 | testIter = iter(testloader) 137 | inverseIter = iter(inverseloader) 138 | 139 | net = torch.load(model_dir + model_name) 140 | if not gpu: 141 | net = net.cpu() 142 | 143 | net.eval() 144 | 145 | targetImg, _ = getImgByClass(inverseIter, C = inverseClass) 146 | deprocessImg = deprocess(targetImg.clone()) 147 | 148 | if not os.path.exists(save_img_dir): 149 | os.makedirs(save_img_dir) 150 | torchvision.utils.save_image(deprocessImg, save_img_dir + str(inverseClass) + '-ref.png') 151 | 152 | if gpu: 153 | targetImg = targetImg.cuda() 154 | softmaxLayer = nn.Softmax().cuda() 155 | 156 | #if hasattr(args, 'add_noise_to_input') and args.add_noise_to_input: 157 | # targetImg = apply_noise(targetImg, noise_type, noise_level, gpu=args.gpu, args=args) 158 | 159 | if layer == 'prob': 160 | if hasattr(args, 'add_noise_to_input') and args.add_noise_to_input: 161 | targetImg_noised = apply_noise(targetImg, noise_type, noise_level, gpu=args.gpu, args=args) 162 | reflogits = net.forward(targetImg_noised) 163 | else: 164 | reflogits = net.forward(targetImg) 165 | refFeature = softmaxLayer(reflogits) 166 | elif layer == 'label': 167 | refFeature = torch.zeros(1,NClasses) 168 | refFeature[0, inverseClass] = 1 169 | else: 170 | targetLayer = net.layerDict[layer] 171 | if hasattr(args, 'add_noise_to_input') and args.add_noise_to_input: 172 | #print "Noise added to input" 173 | targetImg_noised = apply_noise(targetImg, noise_type, noise_level, gpu=args.gpu, args=args) 174 | refFeature = net.getLayerOutput(targetImg_noised, targetLayer) 175 | else: 176 | refFeature = net.getLayerOutput(targetImg, targetLayer) 177 | 178 | # Apply noise 179 | if noise_type != None and not (hasattr(args, 'add_noise_to_input') and args.add_noise_to_input): 180 | refFeature = apply_noise(refFeature, noise_type, noise_level, gpu=args.gpu, args=args) 181 | 182 | if gpu: 183 | xGen = torch.zeros(targetImg.size(), requires_grad = True, device="cuda") 184 | else: 185 | xGen = torch.zeros(targetImg.size(), requires_grad = True) 186 | 187 | optimizer = optim.Adam(params = [xGen], lr = learningRate, eps = eps, amsgrad = AMSGrad) 188 | 189 | for i in range(NIters): 190 | 191 | optimizer.zero_grad() 192 | if layer == 'prob': 193 | xlogits = net.forward(xGen) 194 | xFeature = softmaxLayer(xlogits) 195 | featureLoss = ((xFeature - refFeature)**2).mean() 196 | elif layer == 'label': 197 | xlogits = net.forward(xGen) 198 | xFeature = softmaxLayer(xlogits) 199 | featureLoss = - torch.log(xFeature[0, inverseClass]) 200 | else: 201 | xFeature = net.getLayerOutput(xGen, targetLayer) 202 | featureLoss = ((xFeature - refFeature)**2).mean() 203 | 204 | TVLoss = TV(xGen) 205 | normLoss = l2loss(xGen) 206 | 207 | totalLoss = featureLoss + lambda_TV * TVLoss + lambda_l2 * normLoss #- 1.0 * conv1Loss 208 | 209 | totalLoss.backward(retain_graph=True) 210 | optimizer.step() 211 | 212 | #print "Iter ", i, "Feature loss: ", featureLoss.cpu().detach().numpy(), "TVLoss: ", TVLoss.cpu().detach().numpy(), "l2Loss: ", normLoss.cpu().detach().numpy() 213 | 214 | # save the final result 215 | imgGen = xGen.clone() 216 | imgGen = deprocess(imgGen) 217 | torchvision.utils.save_image(imgGen, save_img_dir + str(inverseClass) + '-inv.png') 218 | 219 | ref_img = deprocessImg.detach().cpu().numpy().squeeze() 220 | inv_img = imgGen.detach().cpu().numpy().squeeze() 221 | 222 | #print "ref_img.shape", ref_img.shape, "inv_img.shape", inv_img.shape 223 | #print "ref_img ", ref_img.min(), ref_img.max() 224 | #print "inv_img ", inv_img.min(), inv_img.max() 225 | 226 | psnr = get_PSNR(ref_img, inv_img, peak=1.0) 227 | ssim = compare_ssim(ref_img, inv_img, data_range = inv_img.max() - inv_img.min(), multichannel=False) 228 | 229 | #print "targetImg l1 Stat:" 230 | #getL1Stat(net, targetImg) 231 | #print "xGen l1 Stat:" 232 | #getL1Stat(net, xGen) 233 | #print "Done" 234 | 235 | return psnr, ssim 236 | 237 | 238 | if __name__ == '__main__': 239 | import argparse 240 | import sys 241 | import traceback 242 | 243 | try: 244 | parser = argparse.ArgumentParser() 245 | parser.add_argument('--dataset', type = str, default = 'MNIST') 246 | parser.add_argument('--network', type = str, default = 'LeNet') 247 | parser.add_argument('--iters', type = int, default = 500) 248 | parser.add_argument('--eps', type = float, default = 1e-3) 249 | parser.add_argument('--lambda_TV', type = float, default = 1.0) 250 | parser.add_argument('--lambda_l2', type = float, default = 0.0) 251 | parser.add_argument('--AMSGrad', type = bool, default = True) 252 | parser.add_argument('--batch_size', type = int, default = 32) 253 | parser.add_argument('--learning_rate', type = float, default = 1e-2) 254 | parser.add_argument('--decrease_LR', type = int, default = 20) 255 | parser.add_argument('--layer', type = str, default = 'ReLU2') 256 | parser.add_argument('--save_iter', type = int, default = 10) 257 | parser.add_argument('--inverseClass', type = int, default = None) 258 | parser.add_argument('--noise_type', type = str, default = None) 259 | parser.add_argument('--noise_level', type = float, default = None) 260 | 261 | parser.add_argument('--add_noise_to_input', dest='add_noise_to_input', action='store_true') 262 | 263 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 264 | parser.set_defaults(gpu=True) 265 | 266 | parser.add_argument('--novalidation', dest='validation', action='store_false') 267 | parser.set_defaults(validation=True) 268 | 269 | parser.add_argument('--noise_iters', type = int, default = 500) 270 | parser.add_argument('--noise_eps', type = float, default = 1e-3) 271 | parser.add_argument('--noise_AMSGrad', type = bool, default = True) 272 | parser.add_argument('--noise_learning_rate', type = float, default = 1e-1) 273 | parser.add_argument('--noise_lambda_sourcelayer', type = float, default = 1e-1) 274 | parser.add_argument('--noise_decrease_LR', type = int, default = 20) 275 | parser.add_argument('--noise_targetLayer', type = str, default = 'fc3') 276 | 277 | args = parser.parse_args() 278 | 279 | 280 | args.noise_sourceLayer = args.layer 281 | args.model_dir = "checkpoints/" + args.dataset + '/' 282 | args.model_name = "ckpt.pth" 283 | 284 | if args.dataset == 'MNIST': 285 | 286 | imageWidth = 28 287 | imageHeight = 28 288 | imageSize = imageWidth * imageHeight 289 | NChannels = 1 290 | NClasses = 10 291 | 292 | else: 293 | print "No Dataset Found" 294 | exit() 295 | 296 | noise_type = args.noise_type 297 | noise_hist = [] 298 | acc_hist = [] 299 | psnr_hist = [] 300 | ssim_hist = [] 301 | 302 | if 'noise_gen' in args.noise_type: 303 | default_nl = np.concatenate((np.arange(0, 110, 10), np.arange(100, 1100, 100)), axis=0) 304 | elif 'dropout' in args.noise_type: 305 | default_nl = np.arange(0, 1, 0.1) 306 | else: 307 | default_nl = np.concatenate((np.arange(0, 1, 0.1), np.arange(1.0, 5.5, 0.5)), axis=0) 308 | 309 | noise_range = [args.noise_level] if args.noise_level != None else default_nl 310 | 311 | for noise_level in noise_range: 312 | noise_hist.append(noise_level) 313 | 314 | if args.add_noise_to_input: 315 | save_img_dir = "inverted_whitebox/" + args.dataset + '/' + args.layer + '/' + 'noised_add_to_input/' + noise_type + '/' + str(round(noise_level,1)) + '/' 316 | else: 317 | save_img_dir = "inverted_whitebox/" + args.dataset + '/' + args.layer + '/' + 'noised/' + noise_type + '/' + str(round(noise_level,1)) + '/' 318 | 319 | if not os.path.exists(save_img_dir): 320 | os.makedirs(save_img_dir) 321 | 322 | acc = eval_DP_defense(args, noise_type, noise_level) 323 | acc_hist.append(acc) 324 | 325 | psnr_sum = 0.0 326 | ssim_sum = 0.0 327 | for c in range(NClasses): 328 | psnr, ssim = inverse(DATASET = args.dataset, network = args.network, NIters = args.iters, imageWidth = imageWidth, inverseClass = c, 329 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, layer = args.layer, 330 | BatchSize = args.batch_size, learningRate = args.learning_rate, NDecreaseLR = args.decrease_LR, eps = args.eps, lambda_TV = args.lambda_TV, lambda_l2 = args.lambda_l2, 331 | AMSGrad = args.AMSGrad, model_dir = args.model_dir, model_name = args.model_name, save_img_dir = save_img_dir, saveIter = args.save_iter, 332 | gpu = args.gpu, validation=args.validation, noise_type = noise_type, noise_level = noise_level, args = args) 333 | 334 | psnr_sum += psnr / NClasses 335 | ssim_sum += ssim / NClasses 336 | 337 | psnr_hist.append(psnr_sum) 338 | ssim_hist.append(ssim_sum) 339 | print "Noise_type:", noise_type, " Add to input:", args.add_noise_to_input, " Noise_level:", round(noise_level,2), " Acc:", round(acc,4), " PSNR:", round(psnr_sum,4), " SSIM:", round(ssim_sum,4) 340 | 341 | except: 342 | traceback.print_exc(file=sys.stdout) 343 | sys.exit(1) 344 | -------------------------------------------------------------------------------- /net.py: -------------------------------------------------------------------------------- 1 | # @Author: zechenghe 2 | # @Date: 2019-01-21T12:17:31-05:00 3 | # @Last modified by: zechenghe 4 | # @Last modified time: 2019-02-01T14:01:15-05:00 5 | 6 | import time 7 | import math 8 | import os 9 | import sys 10 | import numpy as np 11 | 12 | import torch 13 | import torchvision 14 | import torch.nn as nn 15 | import torch.nn.functional as F 16 | 17 | import collections 18 | 19 | class LeNet(nn.Module): 20 | def __init__(self, NChannels): 21 | super(LeNet, self).__init__() 22 | self.features = [] 23 | self.classifier = [] 24 | self.layerDict = collections.OrderedDict() 25 | 26 | self.conv1 = nn.Conv2d( 27 | in_channels = NChannels, 28 | out_channels = 8, 29 | kernel_size = 5 30 | ) 31 | self.features.append(self.conv1) 32 | self.layerDict['conv1'] = self.conv1 33 | 34 | self.ReLU1 = nn.ReLU(True) 35 | self.features.append(self.ReLU1) 36 | self.layerDict['ReLU1'] = self.ReLU1 37 | 38 | self.pool1 = nn.MaxPool2d(2,2) 39 | self.features.append(self.pool1) 40 | self.layerDict['pool1'] = self.pool1 41 | 42 | self.conv2 = nn.Conv2d( 43 | in_channels = 8, 44 | out_channels = 16, 45 | kernel_size = 5 46 | ) 47 | self.features.append(self.conv2) 48 | self.layerDict['conv2'] = self.conv2 49 | 50 | self.ReLU2 = nn.ReLU(True) 51 | self.features.append(self.ReLU2) 52 | self.layerDict['ReLU2'] = self.ReLU2 53 | 54 | self.pool2 = nn.MaxPool2d(2,2) 55 | self.features.append(self.pool2) 56 | self.layerDict['pool2'] = self.pool2 57 | 58 | self.feature_dims = 16 * 4 * 4 59 | self.fc1 = nn.Linear(self.feature_dims, 120) 60 | self.classifier.append(self.fc1) 61 | self.layerDict['fc1'] = self.fc1 62 | 63 | self.fc1act = nn.ReLU(True) 64 | self.classifier.append(self.fc1act) 65 | self.layerDict['fc1act'] = self.fc1act 66 | 67 | 68 | self.fc2 = nn.Linear(120, 84) 69 | self.classifier.append(self.fc2) 70 | self.layerDict['fc2'] = self.fc2 71 | 72 | self.fc2act = nn.ReLU(True) 73 | self.classifier.append(self.fc2act) 74 | self.layerDict['fc2act'] = self.fc2act 75 | 76 | self.fc3 = nn.Linear(84, 10) 77 | self.classifier.append(self.fc3) 78 | self.layerDict['fc3'] = self.fc3 79 | 80 | 81 | def forward(self, x): 82 | for layer in self.features: 83 | x = layer(x) 84 | 85 | #print 'x.size', x.size() 86 | x = x.view(-1, self.feature_dims) 87 | 88 | for layer in self.classifier: 89 | x = layer(x) 90 | return x 91 | 92 | def forward_from(self, x, layer): 93 | 94 | if layer == 'input': 95 | return x 96 | 97 | if layer in self.layerDict: 98 | targetLayer = self.layerDict[layer] 99 | 100 | if targetLayer in self.features: 101 | layeridx = self.features.index(targetLayer) 102 | for func in self.features[layeridx+1:]: 103 | x = func(x) 104 | # print "x.size() ", x.size() 105 | 106 | # print "Pass Features " 107 | x = x.view(-1, self.feature_dims) 108 | for func in self.classifier: 109 | x = func(x) 110 | return x 111 | 112 | else: 113 | layeridx = self.classifier.index(targetLayer) 114 | for func in self.classifier[layeridx+1:]: 115 | x = func(x) 116 | return x 117 | else: 118 | print "layer not exists" 119 | exit(1) 120 | 121 | 122 | def getLayerOutput(self, x, targetLayer): 123 | if targetLayer == 'input': 124 | return x 125 | 126 | for layer in self.features: 127 | x = layer(x) 128 | if layer == targetLayer: 129 | return x 130 | 131 | x = x.view(-1, self.feature_dims) 132 | for layer in self.classifier: 133 | x = layer(x) 134 | if layer == targetLayer: 135 | return x 136 | 137 | # Should not go here 138 | raise Exception("Target layer not found") 139 | 140 | def getLayerOutputFrom(self, x, sourceLayer, targetLayer): 141 | 142 | if targetLayer == 'input': 143 | return x 144 | 145 | if sourceLayer == 'input': 146 | return getLayerOutput(self, x, self.layerDict[targetLayer]) 147 | 148 | if sourceLayer in self.layerDict and targetLayer in self.layerDict: 149 | sourceLayer = self.layerDict[sourceLayer] 150 | targetLayer = self.layerDict[targetLayer] 151 | 152 | if sourceLayer in self.features and targetLayer in self.features: 153 | sourceLayeridx = self.features.index(sourceLayer) 154 | targetLayeridx = self.features.index(targetLayer) 155 | 156 | for func in self.features[sourceLayeridx+1:targetLayeridx+1]: 157 | x = func(x) 158 | return x 159 | 160 | elif sourceLayer in self.classifier and targetLayer in self.classifier: 161 | sourceLayeridx = self.classifier.index(sourceLayer) 162 | targetLayeridx = self.classifier.index(targetLayer) 163 | 164 | for func in self.classifier[sourceLayeridx+1:targetLayeridx+1]: 165 | x = func(x) 166 | return x 167 | 168 | elif sourceLayer in self.features and targetLayer in self.classifier: 169 | sourceLayeridx = self.features.index(sourceLayer) 170 | for func in self.features[sourceLayeridx+1:]: 171 | x = func(x) 172 | 173 | x = x.view(-1, self.feature_dims) 174 | targetLayeridx = self.classifier.index(targetLayer) 175 | for func in self.classifier[:targetLayeridx+1]: 176 | x = func(x) 177 | return x 178 | 179 | else: 180 | print "Target layer cannot before source layer" 181 | exit(1) 182 | else: 183 | print "layer not exists" 184 | exit(1) 185 | 186 | 187 | class CIFAR10CNN(nn.Module): 188 | def __init__(self, NChannels): 189 | super(CIFAR10CNN, self).__init__() 190 | self.features = [] 191 | self.layerDict = collections.OrderedDict() 192 | 193 | self.conv11 = nn.Conv2d( 194 | in_channels = NChannels, 195 | out_channels = 64, 196 | kernel_size = 3, 197 | padding = 1 198 | ) 199 | self.features.append(self.conv11) 200 | self.layerDict['conv11'] = self.conv11 201 | 202 | self.ReLU11 = nn.ReLU() 203 | self.features.append(self.ReLU11) 204 | self.layerDict['ReLU11'] = self.ReLU11 205 | 206 | self.conv12 = nn.Conv2d( 207 | in_channels = 64, 208 | out_channels = 64, 209 | kernel_size = 3, 210 | padding = 1 211 | ) 212 | self.features.append(self.conv12) 213 | self.layerDict['conv12'] = self.conv12 214 | 215 | self.ReLU12 = nn.ReLU() 216 | self.features.append(self.ReLU12) 217 | self.layerDict['ReLU12'] = self.ReLU12 218 | 219 | self.pool1 = nn.MaxPool2d(2,2) 220 | self.features.append(self.pool1) 221 | self.layerDict['pool1'] = self.pool1 222 | 223 | 224 | self.conv21 = nn.Conv2d( 225 | in_channels = 64, 226 | out_channels = 128, 227 | kernel_size = 3, 228 | padding = 1 229 | ) 230 | self.features.append(self.conv21) 231 | self.layerDict['conv21'] = self.conv21 232 | 233 | self.ReLU21 = nn.ReLU() 234 | self.features.append(self.ReLU21) 235 | self.layerDict['ReLU21'] = self.ReLU21 236 | 237 | self.conv22 = nn.Conv2d( 238 | in_channels = 128, 239 | out_channels = 128, 240 | kernel_size = 3, 241 | padding = 1 242 | ) 243 | self.features.append(self.conv22) 244 | self.layerDict['conv22'] = self.conv22 245 | 246 | self.ReLU22 = nn.ReLU() 247 | self.features.append(self.ReLU22) 248 | self.layerDict['ReLU22'] = self.ReLU22 249 | 250 | self.pool2 = nn.MaxPool2d(2,2) 251 | self.features.append(self.pool2) 252 | self.layerDict['pool2'] = self.pool2 253 | 254 | self.conv31 = nn.Conv2d( 255 | in_channels = 128, 256 | out_channels = 128, 257 | kernel_size = 3, 258 | padding = 1 259 | ) 260 | self.features.append(self.conv31) 261 | self.layerDict['conv31'] = self.conv31 262 | 263 | self.ReLU31 = nn.ReLU() 264 | self.features.append(self.ReLU31) 265 | self.layerDict['ReLU31'] = self.ReLU31 266 | 267 | self.conv32 = nn.Conv2d( 268 | in_channels = 128, 269 | out_channels = 128, 270 | kernel_size = 3, 271 | padding = 1 272 | ) 273 | self.features.append(self.conv32) 274 | self.layerDict['conv32'] = self.conv32 275 | 276 | 277 | self.ReLU32 = nn.ReLU() 278 | self.features.append(self.ReLU32) 279 | self.layerDict['ReLU32'] = self.ReLU32 280 | 281 | self.pool3 = nn.MaxPool2d(2,2) 282 | self.features.append(self.pool3) 283 | self.layerDict['pool3'] = self.pool3 284 | 285 | self.classifier = [] 286 | 287 | self.feature_dims = 4 * 4 * 128 288 | self.fc1 = nn.Linear(self.feature_dims, 512) 289 | self.classifier.append(self.fc1) 290 | self.layerDict['fc1'] = self.fc1 291 | 292 | self.fc1act = nn.Sigmoid() 293 | self.classifier.append(self.fc1act) 294 | self.layerDict['fc1act'] = self.fc1act 295 | 296 | self.fc2 = nn.Linear(512, 10) 297 | self.classifier.append(self.fc2) 298 | self.layerDict['fc2'] = self.fc2 299 | 300 | def forward(self, x): 301 | for layer in self.features: 302 | x = layer(x) 303 | 304 | x = x.view(-1, self.feature_dims) 305 | 306 | for layer in self.classifier: 307 | x = layer(x) 308 | return x 309 | 310 | 311 | def forward_from(self, x, layer): 312 | 313 | if layer in self.layerDict: 314 | targetLayer = self.layerDict[layer] 315 | 316 | if targetLayer in self.features: 317 | layeridx = self.features.index(targetLayer) 318 | for func in self.features[layeridx+1:]: 319 | x = func(x) 320 | 321 | x = x.view(-1, self.feature_dims) 322 | for func in self.classifier: 323 | x = func(x) 324 | return x 325 | 326 | else: 327 | layeridx = self.classifier.index(targetLayer) 328 | for func in self.classifier[layeridx:]: 329 | x = func(x) 330 | return x 331 | else: 332 | print "layer not exists" 333 | exit(1) 334 | 335 | 336 | def getLayerOutput(self, x, targetLayer): 337 | for layer in self.features: 338 | x = layer(x) 339 | if layer == targetLayer: 340 | return x 341 | 342 | x = x.view(-1, self.feature_dims) 343 | for layer in self.classifier: 344 | x = layer(x) 345 | if layer == targetLayer: 346 | return x 347 | 348 | # Should not go here 349 | print "Target layer not found" 350 | exit(1) 351 | 352 | 353 | class LeNetAlternativeconv1(nn.Module): 354 | def __init__(self, NChannels): 355 | super(LeNetAlternativeconv1, self).__init__() 356 | self.features = [] 357 | self.classifier = [] 358 | self.layerDict = collections.OrderedDict() 359 | 360 | self.conv0 = nn.Conv2d( 361 | in_channels = NChannels, 362 | out_channels = 8, 363 | kernel_size = 3 364 | ) 365 | self.features.append(self.conv0) 366 | self.layerDict['conv0'] = self.conv0 367 | 368 | self.conv1 = nn.Conv2d( 369 | in_channels = 8, 370 | out_channels = 8, 371 | kernel_size = 3 372 | ) 373 | self.features.append(self.conv1) 374 | self.layerDict['conv1'] = self.conv1 375 | 376 | def forward(self, x): 377 | for layer in self.features: 378 | x = layer(x) 379 | return x 380 | 381 | 382 | class LeNetAlternativeconv1Archi2(nn.Module): 383 | def __init__(self, NChannels): 384 | super(LeNetAlternativeconv1Archi2, self).__init__() 385 | self.features = [] 386 | self.classifier = [] 387 | self.layerDict = collections.OrderedDict() 388 | 389 | self.conv0 = nn.Conv2d( 390 | in_channels = NChannels, 391 | out_channels = 8, 392 | kernel_size = 3 393 | ) 394 | self.features.append(self.conv0) 395 | self.layerDict['conv0'] = self.conv0 396 | 397 | self.conv1 = nn.Conv2d( 398 | in_channels = 8, 399 | out_channels = 8, 400 | kernel_size = 3 401 | ) 402 | self.features.append(self.conv1) 403 | self.layerDict['conv1'] = self.conv1 404 | 405 | def forward(self, x): 406 | for layer in self.features: 407 | x = layer(x) 408 | return x 409 | 410 | 411 | class LeNetAlternativeReLU1(nn.Module): 412 | def __init__(self, NChannels): 413 | super(LeNetAlternativeReLU1, self).__init__() 414 | self.features = [] 415 | self.classifier = [] 416 | self.layerDict = collections.OrderedDict() 417 | 418 | self.conv1 = nn.Conv2d( 419 | in_channels = NChannels, 420 | out_channels = 8, 421 | kernel_size = 5 422 | ) 423 | self.features.append(self.conv1) 424 | self.layerDict['conv1'] = self.conv1 425 | 426 | self.ReLU1 = nn.ReLU(True) 427 | self.features.append(self.ReLU1) 428 | self.layerDict['ReLU1'] = self.ReLU1 429 | 430 | def forward(self, x): 431 | for layer in self.features: 432 | x = layer(x) 433 | return x 434 | 435 | 436 | class LeNetAlternativepool1(nn.Module): 437 | def __init__(self, NChannels): 438 | super(LeNetAlternativepool1, self).__init__() 439 | self.features = [] 440 | self.classifier = [] 441 | self.layerDict = collections.OrderedDict() 442 | 443 | self.conv1 = nn.Conv2d( 444 | in_channels = NChannels, 445 | out_channels = 8, 446 | kernel_size = 5 447 | ) 448 | self.features.append(self.conv1) 449 | self.layerDict['conv1'] = self.conv1 450 | 451 | self.ReLU1 = nn.ReLU(True) 452 | self.features.append(self.ReLU1) 453 | self.layerDict['ReLU1'] = self.ReLU1 454 | 455 | self.pool1 = nn.MaxPool2d(2,2) 456 | self.features.append(self.pool1) 457 | self.layerDict['pool1'] = self.pool1 458 | 459 | def forward(self, x): 460 | for layer in self.features: 461 | x = layer(x) 462 | return x 463 | 464 | class LeNetAlternativeconv2(nn.Module): 465 | def __init__(self, NChannels): 466 | super(LeNetAlternativeconv2, self).__init__() 467 | self.features = [] 468 | self.classifier = [] 469 | self.layerDict = collections.OrderedDict() 470 | 471 | self.conv1 = nn.Conv2d( 472 | in_channels = NChannels, 473 | out_channels = 8, 474 | kernel_size = 5 475 | ) 476 | self.features.append(self.conv1) 477 | self.layerDict['conv1'] = self.conv1 478 | 479 | self.ReLU1 = nn.ReLU(True) 480 | self.features.append(self.ReLU1) 481 | self.layerDict['ReLU1'] = self.ReLU1 482 | 483 | self.pool1 = nn.MaxPool2d(2,2) 484 | self.features.append(self.pool1) 485 | self.layerDict['pool1'] = self.pool1 486 | 487 | self.conv2 = nn.Conv2d( 488 | in_channels = 8, 489 | out_channels = 16, 490 | kernel_size = 5 491 | ) 492 | self.features.append(self.conv2) 493 | self.layerDict['conv2'] = self.conv2 494 | 495 | def forward(self, x): 496 | for layer in self.features: 497 | x = layer(x) 498 | return x 499 | 500 | 501 | class LeNetAlternativeReLU2(nn.Module): 502 | def __init__(self, NChannels): 503 | super(LeNetAlternativeReLU2, self).__init__() 504 | self.features = [] 505 | self.classifier = [] 506 | self.layerDict = collections.OrderedDict() 507 | 508 | self.conv1 = nn.Conv2d( 509 | in_channels = NChannels, 510 | out_channels = 8, 511 | kernel_size = 5 512 | ) 513 | self.features.append(self.conv1) 514 | self.layerDict['conv1'] = self.conv1 515 | 516 | self.ReLU1 = nn.ReLU(True) 517 | self.features.append(self.ReLU1) 518 | self.layerDict['ReLU1'] = self.ReLU1 519 | 520 | self.pool1 = nn.MaxPool2d(2,2) 521 | self.features.append(self.pool1) 522 | self.layerDict['pool1'] = self.pool1 523 | 524 | self.conv2 = nn.Conv2d( 525 | in_channels = 8, 526 | out_channels = 16, 527 | kernel_size = 5 528 | ) 529 | self.features.append(self.conv2) 530 | self.layerDict['conv2'] = self.conv2 531 | 532 | self.ReLU2 = nn.ReLU(True) 533 | self.features.append(self.ReLU2) 534 | self.layerDict['ReLU2'] = self.ReLU2 535 | 536 | def forward(self, x): 537 | for layer in self.features: 538 | x = layer(x) 539 | return x 540 | 541 | 542 | class LeNetAlternativepool2(nn.Module): 543 | def __init__(self, NChannels): 544 | super(LeNetAlternativepool2, self).__init__() 545 | self.features = [] 546 | self.classifier = [] 547 | self.layerDict = collections.OrderedDict() 548 | 549 | self.conv1 = nn.Conv2d( 550 | in_channels = NChannels, 551 | out_channels = 8, 552 | kernel_size = 5 553 | ) 554 | self.features.append(self.conv1) 555 | self.layerDict['conv1'] = self.conv1 556 | 557 | self.ReLU1 = nn.ReLU(True) 558 | self.features.append(self.ReLU1) 559 | self.layerDict['ReLU1'] = self.ReLU1 560 | 561 | self.pool1 = nn.MaxPool2d(2,2) 562 | self.features.append(self.pool1) 563 | self.layerDict['pool1'] = self.pool1 564 | 565 | self.conv2 = nn.Conv2d( 566 | in_channels = 8, 567 | out_channels = 16, 568 | kernel_size = 5 569 | ) 570 | self.features.append(self.conv2) 571 | self.layerDict['conv2'] = self.conv2 572 | 573 | self.ReLU2 = nn.ReLU(True) 574 | self.features.append(self.ReLU2) 575 | self.layerDict['ReLU2'] = self.ReLU2 576 | 577 | self.pool2 = nn.MaxPool2d(2,2) 578 | self.features.append(self.pool2) 579 | self.layerDict['pool2'] = self.pool2 580 | 581 | def forward(self, x): 582 | for layer in self.features: 583 | x = layer(x) 584 | return x 585 | 586 | 587 | class LeNetAlternativefc1(nn.Module): 588 | def __init__(self, NChannels): 589 | super(LeNetAlternativefc1, self).__init__() 590 | self.features = [] 591 | self.classifier = [] 592 | self.layerDict = collections.OrderedDict() 593 | 594 | self.conv1 = nn.Conv2d( 595 | in_channels = NChannels, 596 | out_channels = 8, 597 | kernel_size = 5 598 | ) 599 | self.features.append(self.conv1) 600 | self.layerDict['conv1'] = self.conv1 601 | 602 | self.ReLU1 = nn.ReLU(True) 603 | self.features.append(self.ReLU1) 604 | self.layerDict['ReLU1'] = self.ReLU1 605 | 606 | self.pool1 = nn.MaxPool2d(2,2) 607 | self.features.append(self.pool1) 608 | self.layerDict['pool1'] = self.pool1 609 | 610 | self.conv2 = nn.Conv2d( 611 | in_channels = 8, 612 | out_channels = 16, 613 | kernel_size = 5 614 | ) 615 | self.features.append(self.conv2) 616 | self.layerDict['conv2'] = self.conv2 617 | 618 | self.ReLU2 = nn.ReLU(True) 619 | self.features.append(self.ReLU2) 620 | self.layerDict['ReLU2'] = self.ReLU2 621 | 622 | self.pool2 = nn.MaxPool2d(2,2) 623 | self.features.append(self.pool2) 624 | self.layerDict['pool2'] = self.pool2 625 | 626 | self.feature_dims = 16 * 4 * 4 627 | self.fc1 = nn.Linear(self.feature_dims, 120) 628 | self.classifier.append(self.fc1) 629 | self.layerDict['fc1'] = self.fc1 630 | 631 | 632 | def forward(self, x): 633 | for layer in self.features: 634 | x = layer(x) 635 | 636 | #print 'x.size', x.size() 637 | x = x.view(-1, self.feature_dims) 638 | 639 | for layer in self.classifier: 640 | x = layer(x) 641 | return x 642 | 643 | class LeNetAlternativefc1act(nn.Module): 644 | def __init__(self, NChannels): 645 | super(LeNetAlternativefc1act, self).__init__() 646 | self.features = [] 647 | self.classifier = [] 648 | self.layerDict = collections.OrderedDict() 649 | 650 | self.conv1 = nn.Conv2d( 651 | in_channels = NChannels, 652 | out_channels = 8, 653 | kernel_size = 5 654 | ) 655 | self.features.append(self.conv1) 656 | self.layerDict['conv1'] = self.conv1 657 | 658 | self.ReLU1 = nn.ReLU(True) 659 | self.features.append(self.ReLU1) 660 | self.layerDict['ReLU1'] = self.ReLU1 661 | 662 | self.pool1 = nn.MaxPool2d(2,2) 663 | self.features.append(self.pool1) 664 | self.layerDict['pool1'] = self.pool1 665 | 666 | self.conv2 = nn.Conv2d( 667 | in_channels = 8, 668 | out_channels = 16, 669 | kernel_size = 5 670 | ) 671 | self.features.append(self.conv2) 672 | self.layerDict['conv2'] = self.conv2 673 | 674 | self.ReLU2 = nn.ReLU(True) 675 | self.features.append(self.ReLU2) 676 | self.layerDict['ReLU2'] = self.ReLU2 677 | 678 | self.pool2 = nn.MaxPool2d(2,2) 679 | self.features.append(self.pool2) 680 | self.layerDict['pool2'] = self.pool2 681 | 682 | self.feature_dims = 16 * 4 * 4 683 | self.fc1 = nn.Linear(self.feature_dims, 120) 684 | self.classifier.append(self.fc1) 685 | self.layerDict['fc1'] = self.fc1 686 | 687 | self.fc1act = nn.ReLU(True) 688 | self.classifier.append(self.fc1act) 689 | self.layerDict['fc1act'] = self.fc1act 690 | 691 | 692 | def forward(self, x): 693 | for layer in self.features: 694 | x = layer(x) 695 | 696 | #print 'x.size', x.size() 697 | x = x.view(-1, self.feature_dims) 698 | 699 | for layer in self.classifier: 700 | x = layer(x) 701 | return x 702 | 703 | 704 | class LeNetAlternativefc2(nn.Module): 705 | def __init__(self, NChannels): 706 | super(LeNetAlternativefc2, self).__init__() 707 | self.features = [] 708 | self.classifier = [] 709 | self.layerDict = collections.OrderedDict() 710 | 711 | self.conv1 = nn.Conv2d( 712 | in_channels = NChannels, 713 | out_channels = 8, 714 | kernel_size = 5 715 | ) 716 | self.features.append(self.conv1) 717 | self.layerDict['conv1'] = self.conv1 718 | 719 | self.ReLU1 = nn.ReLU(True) 720 | self.features.append(self.ReLU1) 721 | self.layerDict['ReLU1'] = self.ReLU1 722 | 723 | self.pool1 = nn.MaxPool2d(2,2) 724 | self.features.append(self.pool1) 725 | self.layerDict['pool1'] = self.pool1 726 | 727 | self.conv2 = nn.Conv2d( 728 | in_channels = 8, 729 | out_channels = 16, 730 | kernel_size = 5 731 | ) 732 | self.features.append(self.conv2) 733 | self.layerDict['conv2'] = self.conv2 734 | 735 | self.ReLU2 = nn.ReLU(True) 736 | self.features.append(self.ReLU2) 737 | self.layerDict['ReLU2'] = self.ReLU2 738 | 739 | self.pool2 = nn.MaxPool2d(2,2) 740 | self.features.append(self.pool2) 741 | self.layerDict['pool2'] = self.pool2 742 | 743 | self.feature_dims = 16 * 4 * 4 744 | self.fc1 = nn.Linear(self.feature_dims, 120) 745 | self.classifier.append(self.fc1) 746 | self.layerDict['fc1'] = self.fc1 747 | 748 | self.fc1act = nn.ReLU(True) 749 | self.classifier.append(self.fc1act) 750 | self.layerDict['fc1act'] = self.fc1act 751 | 752 | 753 | self.fc2 = nn.Linear(120, 84) 754 | self.classifier.append(self.fc2) 755 | self.layerDict['fc2'] = self.fc2 756 | 757 | def forward(self, x): 758 | for layer in self.features: 759 | x = layer(x) 760 | 761 | #print 'x.size', x.size() 762 | x = x.view(-1, self.feature_dims) 763 | 764 | for layer in self.classifier: 765 | x = layer(x) 766 | return x 767 | 768 | class LeNetAlternativefc2act(nn.Module): 769 | def __init__(self, NChannels): 770 | super(LeNetAlternativefc2act, self).__init__() 771 | self.features = [] 772 | self.classifier = [] 773 | self.layerDict = collections.OrderedDict() 774 | 775 | self.conv1 = nn.Conv2d( 776 | in_channels = NChannels, 777 | out_channels = 8, 778 | kernel_size = 5 779 | ) 780 | self.features.append(self.conv1) 781 | self.layerDict['conv1'] = self.conv1 782 | 783 | self.ReLU1 = nn.ReLU(True) 784 | self.features.append(self.ReLU1) 785 | self.layerDict['ReLU1'] = self.ReLU1 786 | 787 | self.pool1 = nn.MaxPool2d(2,2) 788 | self.features.append(self.pool1) 789 | self.layerDict['pool1'] = self.pool1 790 | 791 | self.conv2 = nn.Conv2d( 792 | in_channels = 8, 793 | out_channels = 16, 794 | kernel_size = 5 795 | ) 796 | self.features.append(self.conv2) 797 | self.layerDict['conv2'] = self.conv2 798 | 799 | self.ReLU2 = nn.ReLU(True) 800 | self.features.append(self.ReLU2) 801 | self.layerDict['ReLU2'] = self.ReLU2 802 | 803 | self.pool2 = nn.MaxPool2d(2,2) 804 | self.features.append(self.pool2) 805 | self.layerDict['pool2'] = self.pool2 806 | 807 | self.feature_dims = 16 * 4 * 4 808 | self.fc1 = nn.Linear(self.feature_dims, 120) 809 | self.classifier.append(self.fc1) 810 | self.layerDict['fc1'] = self.fc1 811 | 812 | self.fc1act = nn.ReLU(True) 813 | self.classifier.append(self.fc1act) 814 | self.layerDict['fc1act'] = self.fc1act 815 | 816 | 817 | self.fc2 = nn.Linear(120, 84) 818 | self.classifier.append(self.fc2) 819 | self.layerDict['fc2'] = self.fc2 820 | 821 | self.fc2act = nn.ReLU(True) 822 | self.classifier.append(self.fc2act) 823 | self.layerDict['fc2act'] = self.fc2act 824 | 825 | def forward(self, x): 826 | for layer in self.features: 827 | x = layer(x) 828 | 829 | #print 'x.size', x.size() 830 | x = x.view(-1, self.feature_dims) 831 | 832 | for layer in self.classifier: 833 | x = layer(x) 834 | return x 835 | 836 | class LeNetAlternativefc3(nn.Module): 837 | def __init__(self, NChannels): 838 | super(LeNetAlternativefc3, self).__init__() 839 | self.features = [] 840 | self.classifier = [] 841 | self.layerDict = collections.OrderedDict() 842 | 843 | self.conv1 = nn.Conv2d( 844 | in_channels = NChannels, 845 | out_channels = 8, 846 | kernel_size = 5 847 | ) 848 | self.features.append(self.conv1) 849 | self.layerDict['conv1'] = self.conv1 850 | 851 | self.ReLU1 = nn.ReLU(True) 852 | self.features.append(self.ReLU1) 853 | self.layerDict['ReLU1'] = self.ReLU1 854 | 855 | self.pool1 = nn.MaxPool2d(2,2) 856 | self.features.append(self.pool1) 857 | self.layerDict['pool1'] = self.pool1 858 | 859 | self.conv2 = nn.Conv2d( 860 | in_channels = 8, 861 | out_channels = 16, 862 | kernel_size = 5 863 | ) 864 | self.features.append(self.conv2) 865 | self.layerDict['conv2'] = self.conv2 866 | 867 | self.ReLU2 = nn.ReLU(True) 868 | self.features.append(self.ReLU2) 869 | self.layerDict['ReLU2'] = self.ReLU2 870 | 871 | self.pool2 = nn.MaxPool2d(2,2) 872 | self.features.append(self.pool2) 873 | self.layerDict['pool2'] = self.pool2 874 | 875 | self.feature_dims = 16 * 4 * 4 876 | self.fc1 = nn.Linear(self.feature_dims, 120) 877 | self.classifier.append(self.fc1) 878 | self.layerDict['fc1'] = self.fc1 879 | 880 | self.fc1act = nn.ReLU(True) 881 | self.classifier.append(self.fc1act) 882 | self.layerDict['fc1act'] = self.fc1act 883 | 884 | 885 | self.fc2 = nn.Linear(120, 84) 886 | self.classifier.append(self.fc2) 887 | self.layerDict['fc2'] = self.fc2 888 | 889 | self.fc2act = nn.ReLU(True) 890 | self.classifier.append(self.fc2act) 891 | self.layerDict['fc2act'] = self.fc2act 892 | 893 | self.fc3 = nn.Linear(84, 10) 894 | self.classifier.append(self.fc3) 895 | self.layerDict['fc3'] = self.fc3 896 | 897 | 898 | def forward(self, x): 899 | for layer in self.features: 900 | x = layer(x) 901 | 902 | #print 'x.size', x.size() 903 | x = x.view(-1, self.feature_dims) 904 | 905 | for layer in self.classifier: 906 | x = layer(x) 907 | return x 908 | 909 | 910 | 911 | class LeNetAlternativeReLU2Archi2(nn.Module): 912 | def __init__(self, NChannels): 913 | super(LeNetAlternativeReLU2Archi2, self).__init__() 914 | self.features = [] 915 | self.classifier = [] 916 | self.layerDict = collections.OrderedDict() 917 | 918 | self.conv11 = nn.Conv2d( 919 | in_channels = NChannels, 920 | out_channels = 8, 921 | kernel_size = 3 922 | ) 923 | self.features.append(self.conv11) 924 | self.layerDict['conv11'] = self.conv11 925 | 926 | self.conv12 = nn.Conv2d( 927 | in_channels = 8, 928 | out_channels = 16, 929 | kernel_size = 3 930 | ) 931 | self.features.append(self.conv12) 932 | self.layerDict['conv12'] = self.conv12 933 | 934 | self.pool1 = nn.MaxPool2d(2,2) 935 | self.features.append(self.pool1) 936 | self.layerDict['pool1'] = self.pool1 937 | 938 | self.conv21 = nn.Conv2d( 939 | in_channels = 16, 940 | out_channels = 16, 941 | kernel_size = 3 942 | ) 943 | self.features.append(self.conv21) 944 | self.layerDict['conv21'] = self.conv21 945 | 946 | self.conv2 = nn.Conv2d( 947 | in_channels = 16, 948 | out_channels = 16, 949 | kernel_size = 3 950 | ) 951 | self.features.append(self.conv2) 952 | self.layerDict['conv2'] = self.conv2 953 | 954 | self.ReLU2 = nn.ReLU(True) 955 | self.features.append(self.ReLU2) 956 | self.layerDict['ReLU2'] = self.ReLU2 957 | 958 | def forward(self, x): 959 | for layer in self.features: 960 | x = layer(x) 961 | return x 962 | 963 | 964 | 965 | class CIFAR10CNNAlternativeconv11(nn.Module): 966 | def __init__(self, NChannels): 967 | super(CIFAR10CNNAlternativeconv11, self).__init__() 968 | self.features = [] 969 | self.layerDict = collections.OrderedDict() 970 | 971 | self.conv11 = nn.Conv2d( 972 | in_channels = NChannels, 973 | out_channels = 64, 974 | kernel_size = 3, 975 | padding = 1 976 | ) 977 | self.features.append(self.conv11) 978 | self.layerDict['conv11'] = self.conv11 979 | 980 | def forward(self, x): 981 | for layer in self.features: 982 | x = layer(x) 983 | return x 984 | 985 | def getLayerOutput(self, x, targetLayer): 986 | for layer in self.features: 987 | x = layer(x) 988 | if layer == targetLayer: 989 | return x 990 | 991 | # Should not go here 992 | print "Target layer not found" 993 | exit(1) 994 | 995 | 996 | class CIFAR10CNNAlternativeconv11Archi2(nn.Module): 997 | def __init__(self, NChannels): 998 | super(CIFAR10CNNAlternativeconv11Archi2, self).__init__() 999 | self.features = [] 1000 | self.layerDict = collections.OrderedDict() 1001 | 1002 | self.conv10 = nn.Conv2d( 1003 | in_channels = NChannels, 1004 | out_channels = 16, 1005 | kernel_size = 3, 1006 | padding = 1 1007 | ) 1008 | self.features.append(self.conv10) 1009 | self.layerDict['conv10'] = self.conv10 1010 | 1011 | self.conv11 = nn.Conv2d( 1012 | in_channels = 16, 1013 | out_channels = 64, 1014 | kernel_size = 3, 1015 | padding = 1 1016 | ) 1017 | self.features.append(self.conv11) 1018 | self.layerDict['conv11'] = self.conv11 1019 | 1020 | def forward(self, x): 1021 | for layer in self.features: 1022 | x = layer(x) 1023 | return x 1024 | 1025 | def getLayerOutput(self, x, targetLayer): 1026 | for layer in self.features: 1027 | x = layer(x) 1028 | if layer == targetLayer: 1029 | return x 1030 | 1031 | # Should not go here 1032 | print "Target layer not found" 1033 | exit(1) 1034 | 1035 | 1036 | class CIFAR10CNNAlternativeReLU22(nn.Module): 1037 | def __init__(self, NChannels): 1038 | super(CIFAR10CNNAlternativeReLU22, self).__init__() 1039 | self.features = [] 1040 | self.layerDict = collections.OrderedDict() 1041 | 1042 | self.conv11 = nn.Conv2d( 1043 | in_channels = NChannels, 1044 | out_channels = 64, 1045 | kernel_size = 3, 1046 | padding = 1 1047 | ) 1048 | self.features.append(self.conv11) 1049 | self.layerDict['conv11'] = self.conv11 1050 | 1051 | self.ReLU11 = nn.ReLU() 1052 | self.features.append(self.ReLU11) 1053 | self.layerDict['ReLU11'] = self.ReLU11 1054 | 1055 | self.conv12 = nn.Conv2d( 1056 | in_channels = 64, 1057 | out_channels = 64, 1058 | kernel_size = 3, 1059 | padding = 1 1060 | ) 1061 | self.features.append(self.conv12) 1062 | self.layerDict['conv12'] = self.conv12 1063 | 1064 | self.ReLU12 = nn.ReLU() 1065 | self.features.append(self.ReLU12) 1066 | self.layerDict['ReLU12'] = self.ReLU12 1067 | 1068 | self.pool1 = nn.MaxPool2d(2,2) 1069 | self.features.append(self.pool1) 1070 | self.layerDict['pool1'] = self.pool1 1071 | 1072 | 1073 | self.conv21 = nn.Conv2d( 1074 | in_channels = 64, 1075 | out_channels = 128, 1076 | kernel_size = 3, 1077 | padding = 1 1078 | ) 1079 | self.features.append(self.conv21) 1080 | self.layerDict['conv21'] = self.conv21 1081 | 1082 | self.ReLU21 = nn.ReLU() 1083 | self.features.append(self.ReLU21) 1084 | self.layerDict['ReLU21'] = self.ReLU21 1085 | 1086 | self.conv22 = nn.Conv2d( 1087 | in_channels = 128, 1088 | out_channels = 128, 1089 | kernel_size = 3, 1090 | padding = 1 1091 | ) 1092 | self.features.append(self.conv22) 1093 | self.layerDict['conv22'] = self.conv22 1094 | 1095 | self.ReLU22 = nn.ReLU() 1096 | self.features.append(self.ReLU22) 1097 | self.layerDict['ReLU22'] = self.ReLU22 1098 | 1099 | def forward(self, x): 1100 | for layer in self.features: 1101 | x = layer(x) 1102 | return x 1103 | 1104 | def getLayerOutput(self, x, targetLayer): 1105 | for layer in self.features: 1106 | x = layer(x) 1107 | if layer == targetLayer: 1108 | return x 1109 | 1110 | # Should not go here 1111 | raise Exception("Target layer not found") 1112 | 1113 | 1114 | 1115 | class CIFAR10CNNAlternativeReLU22Archi2(nn.Module): 1116 | def __init__(self, NChannels): 1117 | super(CIFAR10CNNAlternativeReLU22Archi2, self).__init__() 1118 | self.features = [] 1119 | self.layerDict = collections.OrderedDict() 1120 | 1121 | self.conv11 = nn.Conv2d( 1122 | in_channels = NChannels, 1123 | out_channels = 64, 1124 | kernel_size = 5, 1125 | padding = 2 1126 | ) 1127 | self.features.append(self.conv11) 1128 | self.layerDict['conv11'] = self.conv11 1129 | 1130 | self.ReLU11 = nn.ReLU() 1131 | self.features.append(self.ReLU11) 1132 | self.layerDict['ReLU11'] = self.ReLU11 1133 | 1134 | self.pool1 = nn.MaxPool2d(2,2) 1135 | self.features.append(self.pool1) 1136 | self.layerDict['pool1'] = self.pool1 1137 | 1138 | self.conv22 = nn.Conv2d( 1139 | in_channels = 64, 1140 | out_channels = 128, 1141 | kernel_size = 5, 1142 | padding = 2 1143 | ) 1144 | self.features.append(self.conv22) 1145 | self.layerDict['conv22'] = self.conv22 1146 | 1147 | self.ReLU22 = nn.ReLU() 1148 | self.features.append(self.ReLU22) 1149 | self.layerDict['ReLU22'] = self.ReLU22 1150 | 1151 | def forward(self, x): 1152 | for layer in self.features: 1153 | x = layer(x) 1154 | return x 1155 | 1156 | def getLayerOutput(self, x, targetLayer): 1157 | for layer in self.features: 1158 | x = layer(x) 1159 | if layer == targetLayer: 1160 | return x 1161 | 1162 | # Should not go here 1163 | raise Exception("Target layer not found") 1164 | 1165 | 1166 | class CIFAR10CNNAlternativeReLU32(nn.Module): 1167 | def __init__(self, NChannels): 1168 | super(CIFAR10CNNAlternativeReLU32, self).__init__() 1169 | self.features = [] 1170 | self.layerDict = collections.OrderedDict() 1171 | 1172 | self.conv11 = nn.Conv2d( 1173 | in_channels = NChannels, 1174 | out_channels = 64, 1175 | kernel_size = 3, 1176 | padding = 1 1177 | ) 1178 | self.features.append(self.conv11) 1179 | self.layerDict['conv11'] = self.conv11 1180 | 1181 | self.ReLU11 = nn.ReLU() 1182 | self.features.append(self.ReLU11) 1183 | self.layerDict['ReLU11'] = self.ReLU11 1184 | 1185 | self.conv12 = nn.Conv2d( 1186 | in_channels = 64, 1187 | out_channels = 64, 1188 | kernel_size = 3, 1189 | padding = 1 1190 | ) 1191 | self.features.append(self.conv12) 1192 | self.layerDict['conv12'] = self.conv12 1193 | 1194 | self.ReLU12 = nn.ReLU() 1195 | self.features.append(self.ReLU12) 1196 | self.layerDict['ReLU12'] = self.ReLU12 1197 | 1198 | self.pool1 = nn.MaxPool2d(2,2) 1199 | self.features.append(self.pool1) 1200 | self.layerDict['pool1'] = self.pool1 1201 | 1202 | 1203 | self.conv21 = nn.Conv2d( 1204 | in_channels = 64, 1205 | out_channels = 128, 1206 | kernel_size = 3, 1207 | padding = 1 1208 | ) 1209 | self.features.append(self.conv21) 1210 | self.layerDict['conv21'] = self.conv21 1211 | 1212 | self.ReLU21 = nn.ReLU() 1213 | self.features.append(self.ReLU21) 1214 | self.layerDict['ReLU21'] = self.ReLU21 1215 | 1216 | self.conv22 = nn.Conv2d( 1217 | in_channels = 128, 1218 | out_channels = 128, 1219 | kernel_size = 3, 1220 | padding = 1 1221 | ) 1222 | self.features.append(self.conv22) 1223 | self.layerDict['conv22'] = self.conv22 1224 | 1225 | self.ReLU22 = nn.ReLU() 1226 | self.features.append(self.ReLU22) 1227 | self.layerDict['ReLU22'] = self.ReLU22 1228 | 1229 | self.pool2 = nn.MaxPool2d(2,2) 1230 | self.features.append(self.pool2) 1231 | self.layerDict['pool2'] = self.pool2 1232 | 1233 | self.conv31 = nn.Conv2d( 1234 | in_channels = 128, 1235 | out_channels = 128, 1236 | kernel_size = 3, 1237 | padding = 1 1238 | ) 1239 | self.features.append(self.conv31) 1240 | self.layerDict['conv31'] = self.conv31 1241 | 1242 | self.ReLU31 = nn.ReLU() 1243 | self.features.append(self.ReLU31) 1244 | self.layerDict['ReLU31'] = self.ReLU31 1245 | 1246 | self.conv32 = nn.Conv2d( 1247 | in_channels = 128, 1248 | out_channels = 128, 1249 | kernel_size = 3, 1250 | padding = 1 1251 | ) 1252 | self.features.append(self.conv32) 1253 | self.layerDict['conv32'] = self.conv32 1254 | 1255 | 1256 | self.ReLU32 = nn.ReLU() 1257 | self.features.append(self.ReLU32) 1258 | self.layerDict['ReLU32'] = self.ReLU32 1259 | 1260 | def forward(self, x): 1261 | for layer in self.features: 1262 | x = layer(x) 1263 | return x 1264 | 1265 | def getLayerOutput(self, x, targetLayer): 1266 | for layer in self.features: 1267 | x = layer(x) 1268 | if layer == targetLayer: 1269 | return x 1270 | 1271 | # Should not go here 1272 | raise Exception("Target layer not found") 1273 | 1274 | 1275 | class CIFAR10CNNAlternativeReLU32Archi2(nn.Module): 1276 | def __init__(self, NChannels): 1277 | super(CIFAR10CNNAlternativeReLU32Archi2, self).__init__() 1278 | self.features = [] 1279 | self.layerDict = collections.OrderedDict() 1280 | 1281 | self.conv11 = nn.Conv2d( 1282 | in_channels = NChannels, 1283 | out_channels = 64, 1284 | kernel_size = 5, 1285 | padding = 2 1286 | ) 1287 | self.features.append(self.conv11) 1288 | self.layerDict['conv11'] = self.conv11 1289 | 1290 | self.ReLU11 = nn.ReLU() 1291 | self.features.append(self.ReLU11) 1292 | self.layerDict['ReLU11'] = self.ReLU11 1293 | 1294 | self.pool1 = nn.MaxPool2d(2,2) 1295 | self.features.append(self.pool1) 1296 | self.layerDict['pool1'] = self.pool1 1297 | 1298 | self.conv22 = nn.Conv2d( 1299 | in_channels = 64, 1300 | out_channels = 128, 1301 | kernel_size = 5, 1302 | padding = 2 1303 | ) 1304 | self.features.append(self.conv22) 1305 | self.layerDict['conv22'] = self.conv22 1306 | 1307 | self.ReLU22 = nn.ReLU() 1308 | self.features.append(self.ReLU22) 1309 | self.layerDict['ReLU22'] = self.ReLU22 1310 | 1311 | self.pool2 = nn.MaxPool2d(2,2) 1312 | self.features.append(self.pool2) 1313 | self.layerDict['pool2'] = self.pool2 1314 | 1315 | self.conv32 = nn.Conv2d( 1316 | in_channels = 128, 1317 | out_channels = 128, 1318 | kernel_size = 5, 1319 | padding = 2 1320 | ) 1321 | self.features.append(self.conv32) 1322 | self.layerDict['conv32'] = self.conv32 1323 | 1324 | self.ReLU32 = nn.ReLU() 1325 | self.features.append(self.ReLU32) 1326 | self.layerDict['ReLU32'] = self.ReLU32 1327 | 1328 | def forward(self, x): 1329 | for layer in self.features: 1330 | x = layer(x) 1331 | return x 1332 | 1333 | def getLayerOutput(self, x, targetLayer): 1334 | for layer in self.features: 1335 | x = layer(x) 1336 | if layer == targetLayer: 1337 | return x 1338 | 1339 | # Should not go here 1340 | raise Exception("Target layer not found") 1341 | 1342 | 1343 | 1344 | class MLPAlternative(nn.Module): 1345 | def __init__(self, inputSize, outputSize): 1346 | super(MLPAlternative, self).__init__() 1347 | self.features = [] 1348 | self.classifier = [] 1349 | self.layerDict = collections.OrderedDict() 1350 | 1351 | assert len(inputSize) == 3 1352 | assert len(outputSize) == 3 1353 | 1354 | self.inputSize = inputSize 1355 | self.outputSize = outputSize 1356 | 1357 | self.input_dims = 1 1358 | for d in inputSize: 1359 | self.input_dims *= d 1360 | 1361 | self.output_dims = 1 1362 | for d in outputSize: 1363 | self.output_dims *= d 1364 | 1365 | self.fc1_N = int(0.7*self.input_dims) 1366 | self.fc2_N = int(0.1*self.input_dims) 1367 | self.fc3_N = self.output_dims 1368 | 1369 | print "fc1_N: ", self.fc1_N 1370 | print "fc2_N: ", self.fc2_N 1371 | print "fc3_N: ", self.fc3_N 1372 | 1373 | self.fc1 = nn.Linear(self.input_dims, self.fc1_N) 1374 | self.classifier.append(self.fc1) 1375 | self.layerDict['fc1'] = self.fc1 1376 | self.fc1act = nn.ReLU() 1377 | self.classifier.append(self.fc1act) 1378 | self.layerDict['fc1act'] = self.fc1act 1379 | 1380 | self.fc2 = nn.Linear(self.fc1_N, self.fc2_N) 1381 | self.classifier.append(self.fc2) 1382 | self.layerDict['fc2'] = self.fc2 1383 | self.fc2act = nn.ReLU() 1384 | self.classifier.append(self.fc2act) 1385 | self.layerDict['fc2act'] = self.fc2act 1386 | 1387 | 1388 | self.fc3 = nn.Linear(self.fc2_N, self.fc3_N) 1389 | self.classifier.append(self.fc3) 1390 | self.layerDict['fc3'] = self.fc3 1391 | self.fc3act = nn.ReLU() 1392 | self.classifier.append(self.fc3act) 1393 | self.layerDict['fc3act'] = self.fc3act 1394 | 1395 | 1396 | def forward(self, x): 1397 | x = x.view(-1, self.input_dims) 1398 | for layer in self.classifier: 1399 | x = layer(x) 1400 | x = x.view(-1, self.outputSize[0], self.outputSize[1], self.outputSize[2]) 1401 | return x 1402 | 1403 | def getLayerOutput(self, x, targetLayer): 1404 | x = x.view(-1, self.input_dims) 1405 | for layer in self.classifier: 1406 | x = layer(x) 1407 | if layer == targetLayer: 1408 | return x 1409 | 1410 | # Should not go here 1411 | raise Exception("Target layer not found") 1412 | 1413 | 1414 | class LeNetDecoderconv1(nn.Module): 1415 | def __init__(self, NChannels): 1416 | super(LeNetDecoderconv1, self).__init__() 1417 | self.decoder = [] 1418 | self.layerDict = collections.OrderedDict() 1419 | 1420 | self.conv1 = nn.Conv2d( 1421 | in_channels = NChannels, 1422 | out_channels = 1, 1423 | kernel_size = 5, 1424 | padding = (4,4) 1425 | ) 1426 | self.layerDict['conv1'] = self.conv1 1427 | 1428 | def forward(self, x): 1429 | for layer in self.layerDict: 1430 | x = self.layerDict[layer](x) 1431 | return x 1432 | 1433 | 1434 | 1435 | class LeNetDecoderReLU2(nn.Module): 1436 | def __init__(self, NChannels): 1437 | super(LeNetDecoderReLU2, self).__init__() 1438 | self.decoder = [] 1439 | self.layerDict = collections.OrderedDict() 1440 | 1441 | 1442 | self.deconv1 = nn.ConvTranspose2d( 1443 | in_channels = 16, 1444 | out_channels = 8, 1445 | kernel_size = 5, 1446 | ) 1447 | 1448 | self.layerDict['deconv1'] = self.deconv1 1449 | 1450 | self.ReLU1 = nn.ReLU() 1451 | self.layerDict['ReLU1'] = self.ReLU1 1452 | 1453 | self.deconv2 = nn.ConvTranspose2d( 1454 | in_channels = 8, 1455 | out_channels = 1, 1456 | kernel_size = 5, 1457 | stride = 2, 1458 | output_padding = (1,1) 1459 | ) 1460 | self.layerDict['deconv2'] = self.deconv2 1461 | 1462 | 1463 | def forward(self, x): 1464 | for layer in self.layerDict: 1465 | x = self.layerDict[layer](x) 1466 | return x 1467 | 1468 | 1469 | 1470 | class CIFAR10CNNDecoderconv1(nn.Module): 1471 | def __init__(self, NChannels): 1472 | super(CIFAR10CNNDecoderconv1, self).__init__() 1473 | self.decoder = [] 1474 | self.layerDict = collections.OrderedDict() 1475 | self.deconv1 = nn.ConvTranspose2d( 1476 | in_channels = 16, 1477 | out_channels = 8, 1478 | kernel_size = 5, 1479 | ) 1480 | 1481 | self.layerDict['deconv1'] = self.deconv1 1482 | self.ReLU1 = nn.ReLU() 1483 | self.layerDict['ReLU1'] = self.ReLU1 1484 | self.deconv2 = nn.ConvTranspose2d( 1485 | in_channels = 8, 1486 | out_channels = 1, 1487 | kernel_size = 5, 1488 | stride = 2, 1489 | output_padding = (1,1) 1490 | ) 1491 | self.layerDict['deconv2'] = self.deconv2 1492 | def forward(self, x): 1493 | for layer in self.layerDict: 1494 | x = self.layerDict[layer](x) 1495 | return x 1496 | 1497 | 1498 | 1499 | class CIFAR10CNNDecoderconv1(nn.Module): 1500 | def __init__(self, NChannels): 1501 | super(CIFAR10CNNDecoderconv1, self).__init__() 1502 | self.decoder = [] 1503 | self.layerDict = collections.OrderedDict() 1504 | 1505 | self.deconv11 = nn.ConvTranspose2d( 1506 | in_channels = 64, 1507 | out_channels = 3, 1508 | kernel_size = 3, 1509 | padding = 1 1510 | ) 1511 | 1512 | self.layerDict['deconv11'] = self.deconv11 1513 | 1514 | 1515 | def forward(self, x): 1516 | for layer in self.layerDict: 1517 | x = self.layerDict[layer](x) 1518 | return x 1519 | 1520 | 1521 | class CIFAR10CNNDecoderReLU22(nn.Module): 1522 | def __init__(self, NChannels): 1523 | super(CIFAR10CNNDecoderReLU22, self).__init__() 1524 | 1525 | self.layerDict = collections.OrderedDict() 1526 | 1527 | self.deconv11 = nn.ConvTranspose2d( 1528 | in_channels = 128, 1529 | out_channels = 64, 1530 | kernel_size = 3, 1531 | stride = 2, 1532 | padding = 1, 1533 | output_padding = 1 1534 | ) 1535 | self.layerDict['deconv11'] = self.deconv11 1536 | 1537 | self.ReLU11 = nn.ReLU() 1538 | self.layerDict['ReLU11'] = self.ReLU11 1539 | 1540 | self.deconv21 = nn.ConvTranspose2d( 1541 | in_channels = 64, 1542 | out_channels = 3, 1543 | kernel_size = 3, 1544 | padding = 1 1545 | ) 1546 | 1547 | self.layerDict['deconv21'] = self.deconv21 1548 | 1549 | def forward(self, x): 1550 | for layer in self.layerDict: 1551 | x = self.layerDict[layer](x) 1552 | return x 1553 | 1554 | 1555 | class CIFAR10CNNDecoderReLU32(nn.Module): 1556 | def __init__(self, NChannels): 1557 | super(CIFAR10CNNDecoderReLU32, self).__init__() 1558 | 1559 | self.layerDict = collections.OrderedDict() 1560 | 1561 | self.deconv11 = nn.ConvTranspose2d( 1562 | in_channels = 128, 1563 | out_channels = 128, 1564 | kernel_size = 3, 1565 | stride = 2, 1566 | padding = 1, 1567 | output_padding = 1 1568 | ) 1569 | self.layerDict['deconv11'] = self.deconv11 1570 | 1571 | self.ReLU11 = nn.ReLU() 1572 | self.layerDict['ReLU11'] = self.ReLU11 1573 | 1574 | self.deconv21 = nn.ConvTranspose2d( 1575 | in_channels = 128, 1576 | out_channels = 64, 1577 | kernel_size = 3, 1578 | stride = 2, 1579 | padding = 1, 1580 | output_padding = 1 1581 | ) 1582 | self.layerDict['deconv21'] = self.deconv21 1583 | 1584 | self.ReLU21 = nn.ReLU() 1585 | self.layerDict['ReLU21'] = self.ReLU21 1586 | 1587 | self.deconv31 = nn.ConvTranspose2d( 1588 | in_channels = 64, 1589 | out_channels = 3, 1590 | kernel_size = 3, 1591 | padding = 1 1592 | ) 1593 | 1594 | self.layerDict['deconv31'] = self.deconv31 1595 | 1596 | def forward(self, x): 1597 | for layer in self.layerDict: 1598 | x = self.layerDict[layer](x) 1599 | return x 1600 | -------------------------------------------------------------------------------- /net.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zechenghe/Inverse_Collaborative_Inference/f010aed0035238c573037b04c47c334ea733d15c/net.pyc -------------------------------------------------------------------------------- /noise_generation.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2020-04-20 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | from net import * 17 | from utils import * 18 | 19 | from skimage.measure import compare_ssim 20 | 21 | ##################### 22 | 23 | # This function is used to generate noise that does not affect model output 24 | 25 | ##################### 26 | 27 | def noise_gen(args, model_dir = "checkpoints/MNIST/", model_name = "ckpt.pth"): 28 | 29 | sourceLayer = args.noise_sourceLayer 30 | targetLayer = args.noise_targetLayer 31 | gpu = args.gpu 32 | 33 | if args.dataset == 'MNIST': 34 | 35 | mu = torch.tensor([0.5], dtype=torch.float32) 36 | sigma = torch.tensor([0.5], dtype=torch.float32) 37 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 38 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 39 | 40 | tsf = { 41 | 'train': transforms.Compose( 42 | [ 43 | transforms.ToTensor(), 44 | Normalize 45 | ]), 46 | 47 | 'test': transforms.Compose( 48 | [ 49 | transforms.ToTensor(), 50 | Normalize 51 | ]) 52 | } 53 | 54 | trainset = torchvision.datasets.MNIST(root='./data/MNIST', train=True, 55 | download=True, transform = tsf['train']) 56 | 57 | testset = torchvision.datasets.MNIST(root='./data/MNIST', train=False, 58 | download=True, transform = tsf['test']) 59 | 60 | x_train, y_train = trainset.data, trainset.targets, 61 | x_test, y_test = testset.data, testset.targets, 62 | 63 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = 1, 64 | shuffle = False, num_workers = 1) 65 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 66 | shuffle = False, num_workers = 1) 67 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 68 | shuffle = False, num_workers = 1) 69 | trainIter = iter(trainloader) 70 | testIter = iter(testloader) 71 | inverseIter = iter(inverseloader) 72 | 73 | net = torch.load(model_dir + model_name) 74 | if not gpu: 75 | net = net.cpu() 76 | 77 | net.eval() 78 | 79 | # Only to get the feature size 80 | targetImg, _ = getImgByClass(inverseIter, C = 0) 81 | deprocessImg = deprocess(targetImg.clone()) 82 | 83 | softmaxLayer = nn.Softmax().cuda() if gpu else nn.Softmax() 84 | ReLULayer = nn.ReLU(False).cuda() if gpu else nn.ReLU(False) 85 | if gpu: 86 | targetImg = targetImg.cuda() 87 | 88 | layer = net.layerDict[sourceLayer] 89 | sourceLayerOutput = net.getLayerOutput(targetImg, layer) 90 | xGen = torch.ones(sourceLayerOutput.size(), requires_grad = True, device="cuda" if args.gpu else 'cpu') 91 | 92 | refSource = torch.randn(size=xGen.size(), requires_grad = True) * args.noise_level 93 | 94 | # If noise for relu layer, make all entries non-negtive 95 | if 'ReLU' in args.noise_sourceLayer: 96 | refSource = ReLULayer(refSource) 97 | 98 | 99 | layer = net.layerDict[targetLayer] 100 | targetLayerOutput = net.getLayerOutput(targetImg, layer) 101 | refTarget = torch.zeros(targetLayerOutput.size(), requires_grad = True) 102 | 103 | if args.gpu: 104 | refTarget = refTarget.cuda() 105 | refSource = refSource.cuda() 106 | 107 | #print "xGen.size", xGen.size() 108 | #print "refSource.size", refSource.size() 109 | #print "refTarget.size", refTarget.size() 110 | 111 | #targetLayerOutput = net.getLayerOutputFrom( 112 | # x = xGen, 113 | # sourceLayer = sourceLayer, 114 | # targetLayer = targetLayer 115 | #) 116 | 117 | #print "targetLayerOutput.size", targetLayerOutput.size() 118 | 119 | optimizer = optim.Adam( 120 | params = [xGen], 121 | lr = args.noise_learning_rate, 122 | eps = args.noise_eps, 123 | amsgrad = args.noise_AMSGrad 124 | ) 125 | 126 | for i in range(args.noise_iters): 127 | 128 | optimizer.zero_grad() 129 | 130 | targetLayerOutput = net.getLayerOutputFrom( 131 | x = ReLULayer(xGen) if 'ReLU' in args.noise_sourceLayer else xGen, 132 | sourceLayer = sourceLayer, 133 | targetLayer = targetLayer 134 | ) 135 | 136 | sourceLayerLoss = (((ReLULayer(xGen) if 'ReLU' in args.noise_sourceLayer else xGen) - refSource)**2).mean() 137 | #sourceLayerLoss = -((ReLULayer(xGen) if 'ReLU' in args.noise_sourceLayer else xGen)**2).mean() 138 | #sourceLayerLoss = -torch.abs(ReLULayer(xGen) if 'ReLU' in args.noise_sourceLayer else xGen).mean() 139 | 140 | 141 | targetLayerLoss = ((targetLayerOutput - refTarget)**2).mean() 142 | 143 | totalLoss = targetLayerLoss + sourceLayerLoss * args.noise_lambda_sourcelayer 144 | 145 | totalLoss.backward(retain_graph=True) 146 | optimizer.step() 147 | 148 | #print "Iter ", i, "loss: ", totalLoss.cpu().detach().numpy(), \ 149 | #"sourceLayerLoss: ", sourceLayerLoss.cpu().detach().numpy(), \ 150 | #"targetLayerLoss: ", targetLayerLoss.cpu().detach().numpy() 151 | 152 | noise_gen = (ReLULayer(xGen) if 'ReLU' in args.noise_sourceLayer else xGen).detach().cpu().numpy() 153 | noise_dir = 'noise/' + args.dataset + '/' 154 | noise_file_name = args.noise_sourceLayer + '-' + args.noise_targetLayer + '-' + str(round(args.noise_level, 2)) 155 | 156 | #print noise_gen 157 | #print sum(noise_gen) 158 | 159 | if not os.path.exists(noise_dir): 160 | os.makedirs(noise_dir) 161 | np.save(noise_dir + noise_file_name, noise_gen) 162 | 163 | acc = evalTestSplitModel( 164 | testloader, net, net, 165 | layer=args.noise_sourceLayer, 166 | gpu = args.gpu, 167 | noise_type = 'noise_gen', 168 | noise_level = args.noise_level, 169 | args = args 170 | ) 171 | print "noise level", args.noise_level, "acc", acc 172 | 173 | return noise_gen 174 | 175 | 176 | if __name__ == '__main__': 177 | import argparse 178 | import sys 179 | import traceback 180 | 181 | try: 182 | parser = argparse.ArgumentParser() 183 | parser.add_argument('--dataset', type = str, default = 'MNIST') 184 | parser.add_argument('--network', type = str, default = 'LeNet') 185 | parser.add_argument('--inverseClass', type = int, default = 0) 186 | 187 | parser.add_argument('--noise_iters', type = int, default = 500) 188 | parser.add_argument('--noise_eps', type = float, default = 1e-3) 189 | parser.add_argument('--noise_AMSGrad', type = bool, default = True) 190 | parser.add_argument('--noise_learning_rate', type = float, default = 1e-1) 191 | parser.add_argument('--noise_lambda_sourcelayer', type = float, default = 1e-1) 192 | parser.add_argument('--noise_decrease_LR', type = int, default = 20) 193 | parser.add_argument('--noise_sourceLayer', type = str, default = 'ReLU2') 194 | parser.add_argument('--noise_targetLayer', type = str, default = 'fc3') 195 | parser.add_argument('--noise_level', type = float, default = None) 196 | 197 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 198 | parser.set_defaults(gpu=True) 199 | 200 | parser.add_argument('--novalidation', dest='validation', action='store_false') 201 | parser.set_defaults(validation=True) 202 | args = parser.parse_args() 203 | 204 | args.model_dir = "checkpoints/" + args.dataset + '/' 205 | args.model_name = "ckpt.pth" 206 | 207 | if args.noise_level == None: 208 | for nl in np.arange(0, 5, 0.5): 209 | args.noise_level = nl 210 | noise_gen( 211 | args = args, 212 | model_dir = args.model_dir, 213 | model_name = args.model_name 214 | ) 215 | else: 216 | noise_gen( 217 | args = args, 218 | model_dir = args.model_dir, 219 | model_name = args.model_name 220 | ) 221 | 222 | except: 223 | traceback.print_exc(file=sys.stdout) 224 | sys.exit(1) 225 | -------------------------------------------------------------------------------- /noise_generation_opt.py: -------------------------------------------------------------------------------- 1 | # @Author: Zecheng He 2 | # @Date: 2020-04-20 3 | 4 | import time 5 | import math 6 | import os 7 | import numpy as np 8 | 9 | import torch 10 | import torchvision 11 | import torchvision.transforms as transforms 12 | import torch.nn as nn 13 | import torch.nn.functional as F 14 | import torch.optim as optim 15 | import torch.backends.cudnn as cudnn 16 | from net import * 17 | from utils import * 18 | 19 | from skimage.measure import compare_ssim 20 | 21 | ##################### 22 | 23 | # This function is used to generate noise that does not affect model output 24 | 25 | ##################### 26 | 27 | def noise_gen(args, model_dir = "checkpoints/MNIST/", model_name = "ckpt.pth"): 28 | 29 | sourceLayer = args.noise_sourceLayer 30 | targetLayer = args.noise_targetLayer 31 | gpu = args.gpu 32 | 33 | if args.dataset == 'MNIST': 34 | 35 | mu = torch.tensor([0.5], dtype=torch.float32) 36 | sigma = torch.tensor([0.5], dtype=torch.float32) 37 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 38 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 39 | 40 | tsf = { 41 | 'train': transforms.Compose( 42 | [ 43 | transforms.ToTensor(), 44 | Normalize 45 | ]), 46 | 47 | 'test': transforms.Compose( 48 | [ 49 | transforms.ToTensor(), 50 | Normalize 51 | ]) 52 | } 53 | 54 | trainset = torchvision.datasets.MNIST(root='./data/MNIST', train=True, 55 | download=True, transform = tsf['train']) 56 | 57 | testset = torchvision.datasets.MNIST(root='./data/MNIST', train=False, 58 | download=True, transform = tsf['test']) 59 | 60 | x_train, y_train = trainset.data, trainset.targets, 61 | x_test, y_test = testset.data, testset.targets, 62 | 63 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = args.noise_batch_size, 64 | shuffle = False, num_workers = 1) 65 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 66 | shuffle = False, num_workers = 1) 67 | inverseloader = torch.utils.data.DataLoader(testset, batch_size = 1, 68 | shuffle = False, num_workers = 1) 69 | trainIter = iter(trainloader) 70 | testIter = iter(testloader) 71 | inverseIter = iter(inverseloader) 72 | 73 | net = torch.load(model_dir + model_name) 74 | if not gpu: 75 | net = net.cpu() 76 | 77 | net.eval() 78 | 79 | # Only to get the feature size 80 | targetImg, _ = getImgByClass(inverseIter, C = 0) 81 | deprocessImg = deprocess(targetImg.clone()) 82 | 83 | softmaxLayer = nn.Softmax().cuda() if gpu else nn.Softmax() 84 | ReLULayer = nn.ReLU(False).cuda() if gpu else nn.ReLU(False) 85 | if gpu: 86 | targetImg = targetImg.cuda() 87 | 88 | layer = net.layerDict[sourceLayer] 89 | sourceLayerOutput = net.getLayerOutput(targetImg, layer) 90 | xGen = torch.ones(sourceLayerOutput.size(), requires_grad = True, device="cuda" if args.gpu else 'cpu') 91 | 92 | refSource = torch.randn(size=xGen.size(), requires_grad = True) * args.noise_level 93 | 94 | # If noise for relu layer, make all entries non-negtive 95 | #if 'ReLU' in args.noise_sourceLayer: 96 | # refSource = ReLULayer(refSource) 97 | 98 | 99 | layer = net.layerDict[targetLayer] 100 | targetLayerOutput = net.getLayerOutput(targetImg, layer) 101 | 102 | if args.gpu: 103 | refSource = refSource.cuda() 104 | 105 | optimizer = optim.Adam( 106 | params = [xGen], 107 | lr = args.noise_learning_rate, 108 | eps = args.noise_eps, 109 | amsgrad = args.noise_AMSGrad 110 | ) 111 | 112 | 113 | NBatch = len(trainset) / args.noise_batch_size 114 | cudnn.benchmark = True 115 | 116 | 117 | for epoch in range(args.noise_epochs): 118 | lossTrain = 0.0 119 | accTrain = 0.0 120 | for i in range(NBatch): 121 | try: 122 | batchX, batchY = trainIter.next() 123 | except StopIteration: 124 | trainIter = iter(trainloader) 125 | batchX, batchY = trainIter.next() 126 | 127 | if gpu: 128 | batchX = batchX.cuda() 129 | batchY = batchY.cuda() 130 | 131 | optimizer.zero_grad() 132 | 133 | sourceLayerOutput = net.getLayerOutput( 134 | x = batchX, 135 | targetLayer = net.layerDict[sourceLayer] 136 | ) 137 | 138 | #print "sourceLayerOutput.size", sourceLayerOutput.size() 139 | #print "xGen.size", xGen.size() 140 | 141 | targetLayerOutput = net.getLayerOutputFrom( 142 | x = sourceLayerOutput + torch.cat(args.noise_batch_size * [xGen]), 143 | sourceLayer = sourceLayer, 144 | targetLayer = targetLayer 145 | ) 146 | 147 | refTarget = net.getLayerOutput( 148 | x = batchX, 149 | targetLayer = net.layerDict[targetLayer] 150 | ) 151 | 152 | sourceLayerLoss = ((xGen - refSource)**2).mean() 153 | #sourceLayerLoss = -((ReLULayer(xGen) if 'ReLU' in args.noise_sourceLayer else xGen)**2).mean() 154 | #sourceLayerLoss = -torch.abs(ReLULayer(xGen) if 'ReLU' in args.noise_sourceLayer else xGen).mean() 155 | 156 | targetLayerLoss = ((targetLayerOutput - refTarget)**2).mean() 157 | 158 | totalLoss = targetLayerLoss + sourceLayerLoss * args.noise_lambda_sourcelayer 159 | 160 | totalLoss.backward(retain_graph=True) 161 | optimizer.step() 162 | 163 | print "Epoch", epoch, "loss: ", totalLoss.cpu().detach().numpy(), \ 164 | "sourceLayerLoss: ", sourceLayerLoss.cpu().detach().numpy(), \ 165 | "targetLayerLoss: ", targetLayerLoss.cpu().detach().numpy() 166 | 167 | noise_gen = xGen.detach().cpu().numpy() 168 | noise_dir = 'noise_opt/' + args.dataset + '/' 169 | noise_file_name = args.noise_sourceLayer + '-' + args.noise_targetLayer + '-' + str(round(args.noise_level, 2)) 170 | 171 | #print noise_gen 172 | #print sum(noise_gen) 173 | 174 | if not os.path.exists(noise_dir): 175 | os.makedirs(noise_dir) 176 | np.save(noise_dir + noise_file_name, noise_gen) 177 | 178 | acc = evalTestSplitModel( 179 | testloader, net, net, 180 | layer=args.noise_sourceLayer, 181 | gpu = args.gpu, 182 | noise_type = 'noise_gen_opt', 183 | noise_level = args.noise_level, 184 | args = args 185 | ) 186 | print "noise level", args.noise_level, "acc", acc 187 | 188 | return noise_gen 189 | 190 | 191 | if __name__ == '__main__': 192 | import argparse 193 | import sys 194 | import traceback 195 | 196 | try: 197 | parser = argparse.ArgumentParser() 198 | parser.add_argument('--dataset', type = str, default = 'MNIST') 199 | parser.add_argument('--network', type = str, default = 'LeNet') 200 | parser.add_argument('--inverseClass', type = int, default = 0) 201 | 202 | parser.add_argument('--noise_iters', type = int, default = 500) 203 | parser.add_argument('--noise_eps', type = float, default = 1e-3) 204 | parser.add_argument('--noise_AMSGrad', type = bool, default = True) 205 | parser.add_argument('--noise_learning_rate', type = float, default = 1e-1) 206 | parser.add_argument('--noise_lambda_sourcelayer', type = float, default = 1e-3) 207 | parser.add_argument('--noise_decrease_LR', type = int, default = 20) 208 | parser.add_argument('--noise_sourceLayer', type = str, default = 'ReLU2') 209 | parser.add_argument('--noise_targetLayer', type = str, default = 'fc3') 210 | parser.add_argument('--noise_level', type = float, default = None) 211 | parser.add_argument('--noise_epochs', type = int, default = 1) 212 | parser.add_argument('--noise_batch_size', type = int, default = 32) 213 | 214 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 215 | parser.set_defaults(gpu=True) 216 | 217 | parser.add_argument('--novalidation', dest='validation', action='store_false') 218 | parser.set_defaults(validation=True) 219 | args = parser.parse_args() 220 | 221 | args.model_dir = "checkpoints/" + args.dataset + '/' 222 | args.model_name = "ckpt.pth" 223 | 224 | if args.noise_level == None: 225 | for nl in np.concatenate((np.arange(0, 110, 10), np.arange(100, 1100, 100)), axis=0): 226 | args.noise_level = nl 227 | noise_gen( 228 | args = args, 229 | model_dir = args.model_dir, 230 | model_name = args.model_name 231 | ) 232 | else: 233 | noise_gen( 234 | args = args, 235 | model_dir = args.model_dir, 236 | model_name = args.model_name 237 | ) 238 | 239 | except: 240 | traceback.print_exc(file=sys.stdout) 241 | sys.exit(1) 242 | -------------------------------------------------------------------------------- /training.py: -------------------------------------------------------------------------------- 1 | # @Author: zechenghe 2 | # @Date: 2019-01-20T16:46:24-05:00 3 | # @Last modified by: zechenghe 4 | # @Last modified time: 2019-02-01T14:01:19-05:00 5 | 6 | import time 7 | import math 8 | import os 9 | import numpy as np 10 | 11 | import torch 12 | import torchvision 13 | import torchvision.transforms as transforms 14 | import torch.nn as nn 15 | import torch.nn.functional as F 16 | import torch.optim as optim 17 | import torch.backends.cudnn as cudnn 18 | 19 | from net import * 20 | from utils import * 21 | 22 | def train(DATASET = 'CIFAR10', network = 'CIFAR10CNN', NEpochs = 200, imageWidth = 32, 23 | imageHeight = 32, imageSize = 32*32, NChannels = 3, NClasses = 10, 24 | BatchSize = 32, learningRate = 1e-3, NDecreaseLR = 20, eps = 1e-3, 25 | AMSGrad = True, model_dir = "checkpoints/CIFAR10/", model_name = "ckpt.pth", gpu = True): 26 | 27 | print "DATASET: ", DATASET 28 | 29 | if DATASET == 'MNIST': 30 | 31 | mu = torch.tensor([0.5], dtype=torch.float32) 32 | sigma = torch.tensor([0.5], dtype=torch.float32) 33 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 34 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 35 | 36 | tsf = { 37 | 'train': transforms.Compose( 38 | [ 39 | transforms.ToTensor(), 40 | Normalize 41 | ]), 42 | 43 | 'test': transforms.Compose( 44 | [ 45 | transforms.ToTensor(), 46 | Normalize 47 | ]) 48 | } 49 | 50 | trainset = torchvision.datasets.MNIST(root='./data/MNIST', train=True, 51 | download=True, transform = tsf['train']) 52 | 53 | testset = torchvision.datasets.MNIST(root='./data/MNIST', train=False, 54 | download=True, transform = tsf['test']) 55 | 56 | elif DATASET == 'CIFAR10': 57 | 58 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 59 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 60 | Normalize = transforms.Normalize(mu.tolist(), sigma.tolist()) 61 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 62 | tsf = { 63 | 'train': transforms.Compose( 64 | [ 65 | transforms.RandomHorizontalFlip(), 66 | transforms.RandomAffine(degrees = 10, translate = [0.1, 0.1], scale = [0.9, 1.1]), 67 | transforms.ToTensor(), 68 | Normalize 69 | ]), 70 | 'test': transforms.Compose( 71 | [ 72 | transforms.ToTensor(), 73 | Normalize 74 | ]) 75 | } 76 | trainset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = True, 77 | download=True, transform = tsf['train']) 78 | testset = torchvision.datasets.CIFAR10(root='./data/CIFAR10', train = False, 79 | download=True, transform = tsf['test']) 80 | 81 | netDict = { 82 | 'LeNet': LeNet, 83 | 'CIFAR10CNN': CIFAR10CNN 84 | } 85 | 86 | if network in netDict: 87 | net = netDict[network](NChannels) 88 | else: 89 | print "Network not found" 90 | exit(1) 91 | 92 | print net 93 | print "len(trainset) ", len(trainset) 94 | print "len(testset) ", len(testset) 95 | x_train, y_train = trainset.data, trainset.targets, 96 | x_test, y_test = testset.data, testset.targets, 97 | 98 | print "x_train.shape ", x_train.shape 99 | print "x_test.shape ", x_test.shape 100 | 101 | trainloader = torch.utils.data.DataLoader(trainset, batch_size = BatchSize, 102 | shuffle = True, num_workers = 1) 103 | testloader = torch.utils.data.DataLoader(testset, batch_size = 1000, 104 | shuffle = False, num_workers = 1) 105 | trainIter = iter(trainloader) 106 | testIter = iter(testloader) 107 | 108 | criterion = nn.CrossEntropyLoss() 109 | softmax = nn.Softmax(dim=1) 110 | 111 | if gpu: 112 | net.cuda() 113 | criterion.cuda() 114 | softmax.cuda() 115 | 116 | optimizer = optim.Adam(params = net.parameters(), lr = learningRate, eps = eps, amsgrad = AMSGrad) 117 | 118 | NBatch = len(trainset) / BatchSize 119 | cudnn.benchmark = True 120 | for epoch in range(NEpochs): 121 | lossTrain = 0.0 122 | accTrain = 0.0 123 | for i in range(NBatch): 124 | try: 125 | batchX, batchY = trainIter.next() 126 | except StopIteration: 127 | trainIter = iter(trainloader) 128 | batchX, batchY = trainIter.next() 129 | 130 | if gpu: 131 | batchX = batchX.cuda() 132 | batchY = batchY.cuda() 133 | 134 | optimizer.zero_grad() 135 | logits = net.forward(batchX) 136 | prob = softmax(logits) 137 | 138 | loss = criterion(logits, batchY) 139 | loss.backward() 140 | optimizer.step() 141 | 142 | lossTrain += loss.cpu().detach().numpy() / NBatch 143 | if gpu: 144 | pred = np.argmax(prob.cpu().detach().numpy(), axis = 1) 145 | groundTruth = batchY.cpu().detach().numpy() 146 | else: 147 | pred = np.argmax(prob.detach().numpy(), axis = 1) 148 | groundTruth = batchY.detach().numpy() 149 | 150 | acc = np.mean(pred == groundTruth) 151 | accTrain += acc / NBatch 152 | 153 | if (epoch + 1) % NDecreaseLR == 0: 154 | learningRate = learningRate / 2.0 155 | setLearningRate(optimizer, learningRate) 156 | 157 | print "Epoch: ", epoch, "Loss: ", lossTrain, "Train accuracy: ", accTrain 158 | 159 | accTest = evalTest(testloader, net, gpu = gpu) 160 | 161 | if not os.path.exists(model_dir): 162 | os.makedirs(model_dir) 163 | torch.save(net, model_dir + model_name) 164 | print "Model saved" 165 | 166 | newNet = torch.load(model_dir + model_name) 167 | newNet.eval() 168 | accTest = evalTest(testloader, net, gpu = gpu) 169 | print "Model restore done" 170 | 171 | 172 | if __name__ == '__main__': 173 | import argparse 174 | import sys 175 | import traceback 176 | 177 | try: 178 | parser = argparse.ArgumentParser() 179 | parser.add_argument('--dataset', type = str, default = 'CIFAR10') 180 | parser.add_argument('--network', type = str, default = 'CIFAR10CNN') 181 | parser.add_argument('--epochs', type = int, default = 200) 182 | parser.add_argument('--eps', type = float, default = 1e-3) 183 | parser.add_argument('--AMSGrad', type = bool, default = True) 184 | parser.add_argument('--batch_size', type = int, default = 32) 185 | parser.add_argument('--learning_rate', type = float, default = 1e-3) 186 | parser.add_argument('--decrease_LR', type = int, default = 20) 187 | 188 | parser.add_argument('--nogpu', dest='gpu', action='store_false') 189 | parser.set_defaults(gpu=True) 190 | args = parser.parse_args() 191 | 192 | model_dir = "checkpoints/" + args.dataset + '/' 193 | model_name = "ckpt.pth" 194 | 195 | if args.dataset == 'MNIST': 196 | 197 | imageWidth = 28 198 | imageHeight = 28 199 | imageSize = imageWidth * imageHeight 200 | NChannels = 1 201 | NClasses = 10 202 | network = 'LeNet' 203 | 204 | elif args.dataset == 'CIFAR10': 205 | 206 | imageWidth = 32 207 | imageHeight = 32 208 | imageSize = imageWidth * imageHeight 209 | NChannels = 3 210 | NClasses = 10 211 | network = 'CIFAR10CNN' 212 | 213 | else: 214 | print "No Dataset Found" 215 | exit(0) 216 | 217 | train(DATASET = args.dataset, network = network, NEpochs = args.epochs, imageWidth = imageWidth, 218 | imageHeight = imageHeight, imageSize = imageSize, NChannels = NChannels, NClasses = NClasses, 219 | BatchSize = args.batch_size, learningRate = args.learning_rate, NDecreaseLR = args.decrease_LR, eps = args.eps, 220 | AMSGrad = args.AMSGrad, model_dir = model_dir, model_name = model_name, gpu = args.gpu) 221 | 222 | except: 223 | traceback.print_exc(file=sys.stdout) 224 | sys.exit(1) 225 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | # @Author: zechenghe 2 | # @Date: 2019-01-21T12:01:09-05:00 3 | # @Last modified by: zechenghe 4 | # @Last modified time: 2019-02-01T14:50:41-05:00 5 | 6 | import time 7 | import math 8 | import os 9 | import numpy as np 10 | 11 | import torch 12 | import torchvision 13 | import torchvision.transforms as transforms 14 | import torch.nn as nn 15 | import torch.nn.functional as F 16 | import torch.optim as optim 17 | import torch.backends.cudnn as cudnn 18 | 19 | 20 | def accuracy(predictions, labels): 21 | 22 | if not (predictions.shape == labels.shape): 23 | print "predictions.shape ", predictions.shape, "labels.shape ", labels.shape 24 | raise AssertionError 25 | 26 | correctly_predicted = np.sum(np.argmax(predictions, 1) == np.argmax(labels, 1)) 27 | accu = (100.0 * correctly_predicted) / predictions.shape[0] 28 | return accu 29 | 30 | def pseudoInverse(W): 31 | return np.linalg.pinv(W) 32 | 33 | 34 | def getImgByClass(Itr, C = None): 35 | 36 | if C == None: 37 | return Itr.next() 38 | 39 | while (True): 40 | img, label = Itr.next() 41 | if label == C: 42 | break 43 | return img, label 44 | 45 | 46 | def clip(data): 47 | data[data > 1.0] = 1.0 48 | data[data < 0.0] = 0.0 49 | return data 50 | 51 | def preprocess(data): 52 | 53 | size = data.shape 54 | NChannels = size[-1] 55 | assert NChannels == 1 or NChannels == 3 56 | if NChannels == 1: 57 | mu = 0.5 58 | sigma = 0.5 59 | elif NChannels == 3: 60 | mu = [0.485, 0.456, 0.406] 61 | sigma = [0.229, 0.224, 0.225] 62 | data = (data - mu) / sigma 63 | 64 | assert data.shape == size 65 | return data 66 | 67 | 68 | def deprocess(data): 69 | 70 | assert len(data.size()) == 4 71 | 72 | BatchSize = data.size()[0] 73 | assert BatchSize == 1 74 | 75 | NChannels = data.size()[1] 76 | if NChannels == 1: 77 | mu = torch.tensor([0.5], dtype=torch.float32) 78 | sigma = torch.tensor([0.5], dtype=torch.float32) 79 | elif NChannels == 3: 80 | mu = torch.tensor([0.485, 0.456, 0.406], dtype=torch.float32) 81 | sigma = torch.tensor([0.229, 0.224, 0.225], dtype=torch.float32) 82 | else: 83 | print "Unsupported image in deprocess()" 84 | exit(1) 85 | 86 | Unnormalize = transforms.Normalize((-mu / sigma).tolist(), (1.0 / sigma).tolist()) 87 | return clip(Unnormalize(data[0,:,:,:]).unsqueeze(0)) 88 | 89 | 90 | def evalTest(testloader, net, gpu = True): 91 | testIter = iter(testloader) 92 | acc = 0.0 93 | NBatch = 0 94 | for i, data in enumerate(testIter, 0): 95 | NBatch += 1 96 | batchX, batchY = data 97 | if gpu: 98 | batchX = batchX.cuda() 99 | batchY = batchY.cuda() 100 | logits = net.forward(batchX) 101 | 102 | if gpu: 103 | pred = np.argmax(logits.cpu().detach().numpy(), axis = 1) 104 | groundTruth = batchY.cpu().detach().numpy() 105 | else: 106 | pred = np.argmax(logits.detach().numpy(), axis = 1) 107 | groundTruth = batchY.detach().numpy() 108 | acc += np.mean(pred == groundTruth) 109 | accTest = acc / NBatch 110 | print "Test accuracy: ", accTest #, "NBatch: ", NBatch, "pred == groundTruth.shape", (pred == groundTruth).shape 111 | return accTest 112 | 113 | 114 | 115 | def weight_init(m): 116 | ''' 117 | Usage: 118 | model = Model() 119 | model.apply(weight_init) 120 | ''' 121 | if isinstance(m, nn.Conv1d): 122 | init.normal_(m.weight.data) 123 | if m.bias is not None: 124 | init.normal_(m.bias.data) 125 | elif isinstance(m, nn.Conv2d): 126 | init.xavier_normal_(m.weight.data) 127 | if m.bias is not None: 128 | init.normal_(m.bias.data) 129 | elif isinstance(m, nn.Conv3d): 130 | init.xavier_normal_(m.weight.data) 131 | if m.bias is not None: 132 | init.normal_(m.bias.data) 133 | elif isinstance(m, nn.ConvTranspose1d): 134 | init.normal_(m.weight.data) 135 | if m.bias is not None: 136 | init.normal_(m.bias.data) 137 | elif isinstance(m, nn.ConvTranspose2d): 138 | init.xavier_normal_(m.weight.data) 139 | if m.bias is not None: 140 | init.normal_(m.bias.data) 141 | elif isinstance(m, nn.ConvTranspose3d): 142 | init.xavier_normal_(m.weight.data) 143 | if m.bias is not None: 144 | init.normal_(m.bias.data) 145 | elif isinstance(m, nn.BatchNorm1d): 146 | init.normal_(m.weight.data, mean=1, std=0.02) 147 | init.constant_(m.bias.data, 0) 148 | elif isinstance(m, nn.BatchNorm2d): 149 | init.normal_(m.weight.data, mean=1, std=0.02) 150 | init.constant_(m.bias.data, 0) 151 | elif isinstance(m, nn.BatchNorm3d): 152 | init.normal_(m.weight.data, mean=1, std=0.02) 153 | init.constant_(m.bias.data, 0) 154 | elif isinstance(m, nn.Linear): 155 | init.xavier_normal_(m.weight.data) 156 | init.normal_(m.bias.data) 157 | elif isinstance(m, nn.LSTM): 158 | for param in m.parameters(): 159 | if len(param.shape) >= 2: 160 | init.orthogonal_(param.data) 161 | else: 162 | init.normal_(param.data) 163 | elif isinstance(m, nn.LSTMCell): 164 | for param in m.parameters(): 165 | if len(param.shape) >= 2: 166 | init.orthogonal_(param.data) 167 | else: 168 | init.normal_(param.data) 169 | elif isinstance(m, nn.GRU): 170 | for param in m.parameters(): 171 | if len(param.shape) >= 2: 172 | init.orthogonal_(param.data) 173 | else: 174 | init.normal_(param.data) 175 | elif isinstance(m, nn.GRUCell): 176 | for param in m.parameters(): 177 | if len(param.shape) >= 2: 178 | init.orthogonal_(param.data) 179 | else: 180 | init.normal_(param.data) 181 | 182 | def setLearningRate(optimizer, lr): 183 | """Sets the learning rate to the initial LR decayed by 10 every 30 epochs""" 184 | for param_group in optimizer.param_groups: 185 | param_group['lr'] = lr 186 | 187 | 188 | def TV(x): 189 | batch_size = x.size()[0] 190 | h_x = x.size()[2] 191 | w_x = x.size()[3] 192 | count_h = _tensor_size(x[:,:,1:,:]) 193 | count_w = _tensor_size(x[:,:,:,1:]) 194 | h_tv = torch.pow(x[:,:,1:,:]-x[:,:,:h_x-1,:], 2).sum() 195 | w_tv = torch.pow(x[:,:,:,1:]-x[:,:,:,:w_x-1], 2).sum() 196 | return (h_tv / count_h + w_tv / count_w) / batch_size 197 | 198 | def _tensor_size(t): 199 | return t.size()[1]*t.size()[2]*t.size()[3] 200 | 201 | 202 | def l2loss(x): 203 | return (x**2).mean() 204 | 205 | def l1loss(x): 206 | return (torch.abs(x)).mean() 207 | 208 | def getL1Stat(net, x): 209 | for layer in net.layerDict: 210 | targetLayer = net.layerDict[layer] 211 | layerOutput = net.getLayerOutput(x, targetLayer) 212 | print "Layer " + layer + ' l1 loss:', l1loss(layerOutput).cpu().detach().numpy() 213 | 214 | 215 | def getModule(net, blob): 216 | modules = blob.split('.') 217 | # print "Target layer: ", modules 218 | # if len(modules) == 1: 219 | # return net._modules.get(blob) 220 | # else: 221 | 222 | curr_module = net 223 | print curr_module 224 | for m in modules: 225 | curr_module = curr_module._modules.get(m) 226 | return curr_module 227 | 228 | def getLayerOutputHook(module, input, output): 229 | if not hasattr(module, 'activations'): 230 | module.activations = [] 231 | module.activations.append(output) 232 | 233 | def getHookActs(model, module, input): 234 | if hasattr(module, 'activations'): 235 | del module.activations[:] 236 | _ = model.forward(input) 237 | assert(len(module.activations) == 1) 238 | return module.activations[0] 239 | 240 | def saveImage(img, filepath): 241 | torchvision.utils.save_image(img, filepath) 242 | 243 | 244 | def apply_noise(input, noise_type, noise_level, mean=0.0, gpu=True, args=None): 245 | 246 | if noise_type == 'Gaussian': 247 | noise = torch.randn(input.size()) * noise_level + mean 248 | noise = noise.cuda() if gpu else noise 249 | output = input + noise 250 | 251 | elif noise_type == 'Laplace': 252 | noise = np.random.laplace( 253 | loc= mean, 254 | scale = noise_level, 255 | size = input.size() 256 | ) 257 | noise = torch.tensor(noise, dtype = torch.float) 258 | noise = noise.cuda() if gpu else noise 259 | output = input + noise 260 | 261 | elif noise_type == 'dropout': 262 | mask = np.random.choice([0.0, 1.0], size=input.size(), replace=True, p=[noise_level, 1-noise_level]) 263 | mask = torch.tensor(mask, dtype = torch.float) 264 | mask = mask.cuda() if gpu else mask 265 | output = input * mask 266 | 267 | elif noise_type == 'dropout-non-zero': 268 | input_list = input.detach().cpu().numpy().reshape([-1]) 269 | output = input_list.copy() 270 | 271 | for i in range(len(input_list)): 272 | if input_list[i] > 0: 273 | if np.random.rand() < noise_level: 274 | output[i] = -1.0 275 | else: 276 | output[i] = -np.random.rand() * 10.0 277 | output = torch.tensor(np.array(output).reshape(input.size()), dtype = torch.float) 278 | output = output.cuda() if gpu else output 279 | 280 | elif noise_type == 'redistribute': 281 | input_list = input.detach().cpu().numpy().reshape([-1]) 282 | idx = np.argsort(input_list) 283 | map = np.linspace(start=0.0, stop=1.0, num=len(input_list)) 284 | 285 | output = [0]*len(input_list) 286 | for i in range(len(idx)): 287 | if input_list[idx[i]] != 0 and np.random.rand() > noise_level: 288 | output[idx[i]] = 1.0 289 | output = torch.tensor(np.array(output).reshape(input.size()), dtype = torch.float) 290 | output = output.cuda() if gpu else output 291 | 292 | #print "input", input 293 | #print "output", output 294 | 295 | elif noise_type == 'impulse': 296 | noise = np.random.choice([0.0, 1.0], size=input.size(), replace=True, p=[1-noise_level, noise_level]) 297 | noise = torch.tensor(noise, dtype = torch.float) 298 | noise = noise.cuda() if gpu else noise 299 | output = input + noise 300 | 301 | elif noise_type == 'noise_gen' or 'noise_gen_opt': 302 | noise_dir = 'noise' + ('_opt' if noise_type == 'noise_gen_opt' else "") + '/' + args.dataset + '/' 303 | noise_file_name = args.noise_sourceLayer + '-' + args.noise_targetLayer + '-' + str(round(noise_level, 2)) 304 | 305 | noise = np.load(noise_dir + noise_file_name + '.npy') 306 | noise = torch.tensor(noise, dtype = torch.float) 307 | 308 | batch_size = input.size()[0] 309 | noise = torch.cat(batch_size * [noise]) 310 | noise = noise.cuda() if gpu else noise 311 | output = input + noise 312 | 313 | else: 314 | print "Unsupported Noise Type: ", noise_type 315 | exit(1) 316 | 317 | return output 318 | 319 | def evalTestSplitModel(testloader, netEdge, netCloud, layer, gpu, noise_type = None, noise_level = 0.0, args=None): 320 | testIter = iter(testloader) 321 | acc = 0.0 322 | NBatch = 0 323 | for i, data in enumerate(testIter, 0): 324 | batchX, batchY = data 325 | if gpu: 326 | batchX = batchX.cuda() 327 | batchY = batchY.cuda() 328 | 329 | if hasattr(args, 'add_noise_to_input') and args.add_noise_to_input: 330 | batchX = apply_noise(batchX, noise_type, noise_level, gpu=gpu, args=args) 331 | 332 | try: 333 | edgeOutput = netEdge.getLayerOutput(batchX, netEdge.layerDict[layer]).clone() 334 | except Exception, e: 335 | #print "Except in evalTestSplitModel getLayerOutput, this is a Edge-only model" 336 | #print str(e) 337 | edgeOutput = netEdge.forward(batchX).clone() 338 | 339 | if noise_type != None and not (hasattr(args, 'add_noise_to_input') and args.add_noise_to_input): 340 | edgeOutput = apply_noise(edgeOutput, noise_type, noise_level, gpu=gpu, args=args) 341 | 342 | #cloudOuput = net.forward(batchX) 343 | logits = netCloud.forward_from(edgeOutput, layer) 344 | 345 | #softmax = nn.Softmax().cuda() 346 | #prob = softmax(logits) 347 | #print prob[:100,:].max(dim=1) 348 | 349 | if gpu: 350 | pred = np.argmax(logits.cpu().detach().numpy(), axis = 1) 351 | groundTruth = batchY.cpu().detach().numpy() 352 | else: 353 | pred = np.argmax(logits.detach().numpy(), axis = 1) 354 | groundTruth = batchY.detach().numpy() 355 | acc += np.mean(pred == groundTruth) 356 | NBatch += 1 357 | 358 | accTest = acc / NBatch 359 | #print "Test accuracy: ", accTest #, "NBatch: ", NBatch, "pred == groundTruth.shape", (pred == groundTruth).shape 360 | return accTest 361 | 362 | def get_PSNR(refimg, invimg, peak = 1.0): 363 | psnr = 10*np.log10(peak**2 / np.mean((refimg - invimg)**2)) 364 | return psnr 365 | -------------------------------------------------------------------------------- /utils.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zechenghe/Inverse_Collaborative_Inference/f010aed0035238c573037b04c47c334ea733d15c/utils.pyc --------------------------------------------------------------------------------