From 0bacc09d791156803ef2bb7ada04bb82b20922d2 Mon Sep 17 00:00:00 2001 From: john-m24 Date: Thu, 26 Aug 2021 14:50:40 +0000 Subject: [PATCH 01/10] integrated complex_nn --- src/algos/complex_nn.py | 168 +++++++++++ src/algos/simba_algo.py | 5 +- src/configs/complex_nn.json | 19 ++ src/interface.py | 3 + src/models/complex_models.py | 526 +++++++++++++++++++++++++++++++++++ src/models/model_zoo.py | 80 ++++-- src/scheduler.py | 7 +- src/utils/config_utils.py | 2 +- 8 files changed, 781 insertions(+), 29 deletions(-) create mode 100644 src/configs/complex_nn.json create mode 100644 src/models/complex_models.py diff --git a/src/algos/complex_nn.py b/src/algos/complex_nn.py index e69de29..931fb3b 100644 --- a/src/algos/complex_nn.py +++ b/src/algos/complex_nn.py @@ -0,0 +1,168 @@ +from algos.simba_algo import SimbaDefence +import torch.nn.functional as F +import torch +import torch.nn as nn +import numpy as np +from models.complex_models import Discriminator, RealToComplex, ComplexToReal, ResNetEncoderComplex, ResNetDecoderComplex + +def get_encoder_output_size(encoder, dims): + x = torch.randn((1,)+dims) + with torch.no_grad(): + out = encoder(x) + if type(out) == tuple: + out = out[0] + return list(out.size())[1:] + +class ComplexNN(SimbaDefence): + def __init__(self, config, utils) -> None: + super(ComplexNN, self).__init__(utils) + self.initialize(config) + + def initialize(self, config): + self.encoder_model,self.decoder_model = self.init_client_model(config) + size = get_encoder_output_size(self.encoder_model, (3,32,32)) + self.discriminator = Discriminator(size=size) + models = [self.encoder_model, self.decoder_model, self.discriminator] + self.put_on_gpus(models) + self.optimizer_idx = 0 + + self.utils.register_model("encoder_model", self.encoder_model) + self.utils.register_model("discriminator_model", self.discriminator) + self.utils.register_model("decoder_model", self.decoder_model) + self.optim, self.optim_d = self.init_optim(config, [self.encoder_model, self.decoder_model], self.discriminator) + + self.real_to_complex = RealToComplex() + self.complex_to_real = ComplexToReal() + self.loss_fn = F.cross_entropy + self.alpha = config["alpha"] + self.k = config["k"] + + self.g_loss_adv_tag = "g_adv_loss" + self.g_loss_ce_tag = "g_ce_loss" + self.d_loss_adv_tag = "d_loss" + self.loss_tag = "decoder_loss" + self.acc_tag = "decoder_acc" + tags = [self.g_loss_adv_tag, self.g_loss_ce_tag, self.d_loss_adv_tag, self.loss_tag, self.acc_tag] + for tag in tags: + self.utils.logger.register_tag("train/" + tag) + self.utils.logger.register_tag("val/" + tag) + + def put_on_gpus(self,models): + for model in models: + model = self.utils.model_on_gpus(model) + + def init_client_model(self, config): + if config["model_name"] == "resnet20complex": + encoder_model = ResNetEncoderComplex(3) + decoder_model = ResNetDecoderComplex(3, config["logits"], "alpha") + else: + print("can't find complex client model") + exit() + + return encoder_model,decoder_model + + def init_optim(self, config, models, discriminator): + parameters = set() + for net in models: + parameters |= set(net.parameters()) + + if config["optimizer"] == "adam": + optimizer = torch.optim.Adam(parameters, + lr=config["lr"], + ) + + optimizer_d = torch.optim.Adam( + discriminator.parameters(), + lr=config["lr"], + ) + + elif config["optimizer"] == "sgd": + optimizer = torch.optim.SGD( + parameters, + lr=config["lr"], + momentum = config["momentum"], + weight_decay = config["weight_decay"] + ) + + optimizer_d = torch.optim.SGD( + discriminator.parameters(), + lr=config["lr"], + momentum = config["momentum"], + weight_decay = config["weight_decay"] + ) + + else: + print("Unknown optimizer {}".format(config["optimizer"])) + return optimizer, optimizer_d + + def train(self): + self.mode = "train" + self.encoder_model.train() + self.decoder_model.train() + + def eval(self): + self.mode = "val" + self.encoder_model.eval() + self.decoder_model.eval() + + def forward(self, items): + inp = items["x"] + # Pass through encoder + a = self.encoder_model(inp) + self.a = a + # Shuffle batch elements of a to create b + with torch.no_grad(): + indices = np.random.permutation(a.size(0)) + b = a[indices] + + z, self.theta = self.real_to_complex(a,b) + + # Get discriminator score expectation over k rotations + self.score_fake = 0 + for k in self.k: + # Shuffle batch to get b + indices = np.random.permutation(a.size(0)) + b = a[indices] + + # Rotate a + x, _ = self.real_to_complex(a,b) + a_rotated = x[:,0] + # Get discriminator score + self.score_fake += self.discriminator(a_rotated) + + self.score_fake /= self.k # Average score + z = z.detach() + z.requires_grad = True + return z + + def infer(self, h, labels): + y = self.complex_to_real(h,self.theta) + self.preds = self.decoder_model(y) + self.acc = (self.preds.argmax(dim=1) == labels).sum().item() / self.preds.shape[0] + self.loss = self.loss_fn(self.preds,labels) + self.utils.logger.add_entry(self.mode + "/" + self.acc_tag, self.acc) + self.utils.logger.add_entry(self.mode + "/" + self.loss_tag, self.loss.item()) + loss = self.loss.detach() + loss.requires_grad = True + return loss + + def backward(self, items): + if (self.optimizer_idx % 2) == 0: + self.g_loss_adv = -torch.mean(self.score_fake) + self.g_loss_ce = self.loss_fn(self.preds,items["pred_lbls"]) + self.utils.logger.add_entry(self.mode + "/" + self.g_loss_adv_tag, self.g_loss_adv.item()) + self.utils.logger.add_entry(self.mode + "/" + self.g_loss_ce_tag, self.g_loss_ce.item()) + g_tot = self.g_loss_adv + self.g_loss_ce + self.optim.zero_grad() + g_tot.backward() + self.optim.step() + else: + for p in self.discriminator.parameters(): + p.data.clamp_(-0.01, 0.01) + self.d_loss_adv = -torch.mean(self.discriminator(self.a)) + torch.mean(self.score_fake) + self.utils.logger.add_entry(self.mode + "/" + self.d_loss_adv_tag, self.d_loss_adv.item()) + self.optim_d.zero_grad() + self.d_loss_adv.backward() + self.optim_d.step() + + self.optimizer_idx += 1 diff --git a/src/algos/simba_algo.py b/src/algos/simba_algo.py index 9d5a974..bcce86f 100644 --- a/src/algos/simba_algo.py +++ b/src/algos/simba_algo.py @@ -50,6 +50,9 @@ def init_optim(self, config, model): def put_on_gpus(self): self.client_model = self.utils.model_on_gpus(self.client_model) + def infer(self,data,labels): + pass + class SimbaAttack(nn.Module): def __init__(self, utils): @@ -86,4 +89,4 @@ def train(self): def eval(self): self.mode = "val" - self.model.eval() \ No newline at end of file + self.model.eval() diff --git a/src/configs/complex_nn.json b/src/configs/complex_nn.json new file mode 100644 index 0000000..53ccc80 --- /dev/null +++ b/src/configs/complex_nn.json @@ -0,0 +1,19 @@ +{ + "method": "complex_nn", + "client": {"model_name": "resnet20complex", "split_layer": 6, + "pretrained": false,"logits": 2, "optimizer": "adam", "lr": 3e-4, + "alpha": 0.9,"k":5, "momentum": 0.9, "weight_decay": 0.0001}, + "server": {"model_name": "resnet20complex", "split_layer":6, "logits": 2, "pretrained": false, + "lr": 3e-4, "optimizer": "adam", "momentum": 0.9, "weight_decay": 0.0001}, + "learning_rate": 0.1, + "total_epochs": 95, + "training_batch_size": 128, + "dataset": "cifar10", + "protected_attribute": "class", + "prediction_attribute": "animated", + "img_size": 32, + "split": false, + "test_batch_size": 128, + "exp_id": "1", + "exp_keys": ["client.alpha","client.optimizer"] +} diff --git a/src/interface.py b/src/interface.py index 70c3260..6618ed7 100644 --- a/src/interface.py +++ b/src/interface.py @@ -5,6 +5,7 @@ from algos.pca_embedding import PCAEmbedding from algos.deepobfuscator import DeepObfuscator from algos.pan import PAN +from algos.complex_nn import ComplexNN from algos.supervised_decoder import SupervisedDecoder from data.loaders import DataLoader from models.model_zoo import Model @@ -38,6 +39,8 @@ def load_algo(config, utils, dataloader=None): algo = UniformNoise(config["client"], utils) elif method == "siamese_embedding": algo = SiameseEmbedding(config["client"], utils) + elif method == "complex_nn": + algo = ComplexNN(config["client"], utils) elif method == "pca_embedding": algo = PCAEmbedding(config["client"], utils) elif method == "deep_obfuscator": diff --git a/src/models/complex_models.py b/src/models/complex_models.py new file mode 100644 index 0000000..d5be8a7 --- /dev/null +++ b/src/models/complex_models.py @@ -0,0 +1,526 @@ +import torch +import torch.nn as nn +import numpy as np +import torch.nn.functional as F + +def get_real_imag_parts(x): + ''' + Extracts the real and imaginary component tensors from a complex number tensor + + Input: + x: Complex number tensor of size [b,2,c,h,w] + Output: + real component tensor of size [b,c,h,w] + imaginary component tensor of size [b,c,h,w] + ''' + assert(x.size(1) == 2) # Complex tensor has real and imaginary components in 2nd dim + return x[:,0], x[:,1] + +def complex_norm(x): + ''' + Calculates the complex norm for each complex element in a tensor + + Input: + x: Complex number tensor of size [b,2,c,h,w] + Output: + tensor of norm values of size [b,c,h,w] + ''' + assert(x.size(1) == 2) # Complex tensor has real and imaginary components in 2nd dim + x_real, x_imag = get_real_imag_parts(x) + x_real = x_real.clone() + x_imag = x_imag.clone() + return torch.sqrt(torch.pow(x_real, 2) + torch.pow(x_imag, 2) + 1e-5) + +class RealToComplex(nn.Module): + ''' + Converts a real value tensor a into a complex value tensor x (Eq. 2). + Adds a fooling counterpart b and rotates the tensor by a random angle theta. + Returns theta for later decoding. + + Shape: + Input: + a: [b,c,h,w] + b: [b,c,h,w] + Output: + x: [b,2,c,h,w] + theta: [1] + ''' + def __init__(self): + super(RealToComplex, self).__init__() + + def forward(self, a, b): + # Randomly choose theta + theta = a.new(a.size(0)).uniform_(0, 2*np.pi) + + # Convert to complex and rotate by theta + real = a*torch.cos(theta)[:, None, None, None] - \ + b*torch.sin(theta)[:, None, None, None] + imag = b*torch.cos(theta)[:, None, None, None] + \ + a*torch.sin(theta)[:, None, None, None] + x = torch.stack((real, imag), dim=1) + + return x, theta + +class ComplexToReal(nn.Module): + ''' + Decodes a complex value tensor h into a real value tensor y by rotating + by -theta (Eq. 3). + + Shape: + Input: + h: [b,2,c,h,w] + theta: [b] + Output: [b,c,h,w] + ''' + def __init__(self): + super(ComplexToReal, self).__init__() + + def forward(self, h, theta): + # Apply opposite rotation to decode + a, b = get_real_imag_parts(h) + if a.dim() == 4: + y = a*torch.cos(-theta)[:, None, None, None] - \ + b*torch.sin(-theta)[:, None, None, None] # Only need real component + else: + y = a*torch.cos(-theta)[:, None] - \ + b*torch.sin(-theta)[:, None] # Only need real component + return y + +class ActivationComplex(nn.Module): + ''' + Complex activation function from Eq. 6. + + Args: + c: Positive constant (>0) from Eq. 6. Default: 1 + Shape: + Input: [b,2,c,h,w] + Output: [b,2,c,h,w] + ''' + def __init__(self, c=1): + super(ActivationComplex, self).__init__() + assert(c>0) + self.c = torch.Tensor([c]) + + def forward(self, x): + x_norm = complex_norm(x).unsqueeze(1) + c = self.c.to(x.device) + scale = x_norm/torch.max(x_norm, c) + return x*scale + +def activation_complex(x, c): + ''' + Complex activation function from Eq. 6. This is a functional api to + use in networks that don't have a static c value (AlexNet, LeNet, etc.). + + Input: + x: Complex number tensor of size [b,2,c,h,w] + c: Positive constant (>0) from Eq. 6. + Output: + output tensor of size [b,2,c,h,w] + ''' + assert(c>0) + x_norm = complex_norm(x).unsqueeze(1) + c = torch.Tensor([c]).to(x.device) + scale = x_norm/torch.max(x_norm, c) + return x*scale + +def activation_complex_dynamic(x): + ''' + Complex activation function from Eq. 6. This is a functional api to + use in networks that don't have a static c value (AlexNet, LeNet, etc.). + + Input: + x: Complex number tensor of size [b,2,c,h,w] or [b,2,f] + Output: + output tensor of size [b,2,c,h,w] or [b,2,f] + ''' + x_norm = complex_norm(x) + if x.dim() == 5: + # for [b,2,c,h,w] inputs + scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + x_norm.mean((2, 3))[:, :, None, None].unsqueeze(1)) + else: + # for [b,2,f] inputs + scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + x_norm.mean(1)[:, None, None]) + + return x*scale + +def activation_complex_dynamic(x): + ''' + Complex activation function from Eq. 6. This is a functional api to + use in networks that don't have a static c value (AlexNet, LeNet, etc.). + + Input: + x: Complex number tensor of size [b,2,c,h,w] or [b,2,f] + Output: + output tensor of size [b,2,c,h,w] or [b,2,f] + ''' + x_norm = complex_norm(x) + if x.dim() == 5: + # for [b,2,c,h,w] inputs + scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + x_norm.mean((2, 3))[:, :, None, None].unsqueeze(1)) + else: + # for [b,2,f] inputs + scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + x_norm.mean(1)[:, None, None]) + + return x*scale + +class MaxPool2dComplex(nn.Module): + ''' + Complex max pooling operation. Keeps the complex number feature with the maximum norm within + the window, keeping both the corresponding real and imaginary components. + + Args: + kernel_size: size of the window + stride: stride of the window. Default: kernel_size + padding: amount of zero padding. Default: 0 + dilation: element-wise stride in the window. Default: 1 + ceil_mode: use ceil instead of floor to compute the output shape. Default: False + Shape: + Input: [b,2,c,h_in,w_in] + Output: [b,2,c,h_out,w_out] + ''' + def __init__( + self, + kernel_size, + stride=None, + padding=0, + dilation=1, + ceil_mode=False + ): + super(MaxPool2dComplex, self).__init__() + self.pool = nn.MaxPool2d( + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + ceil_mode=ceil_mode, + return_indices=True + ) + + def get_indice_elements(self, x, indices): + ''' From: https://discuss.pytorch.org/t/pooling-using-idices-from-another-max-pooling/37209/4 ''' + x_flat = x.flatten(start_dim=2) + output = x_flat.gather(dim=2, index=indices.flatten(start_dim=2)).view_as(indices) + return output + + def forward(self, x): + x_real, x_imag = get_real_imag_parts(x) + x_norm = complex_norm(x) + + # Max pool complex feature norms and get indices + _, indices = self.pool(x_norm) + + # Extract the matching real and imaginary components of the max pooling indices + x_real = self.get_indice_elements(x_real, indices) + x_imag = self.get_indice_elements(x_imag, indices) + + return torch.stack((x_real, x_imag), dim=1) + +class DropoutComplex(nn.Module): + ''' + Complex dropout operation. Randomly zero out both the real and imaginary + components of a complex number feature. + + Args: + p: probability of an element being zeroed + Shape: + Input: [b,2,c,h,w] + Output: [b,2,c,h,w] + ''' + def __init__(self, p): + super(DropoutComplex, self).__init__() + self.p = p + self.dropout = nn.Dropout(p) + + def forward(self, x): + x_real, x_imag = get_real_imag_parts(x) + + # Apply dropout to real part + x_real = self.dropout(x_real) + + # Drop the same indices in the imaginary part + # and scale the rest by 1/1-p + if self.training: + mask = (x_real != 0).float()*(1/(1-self.p)) + x_imag *= mask + + return torch.stack((x_real, x_imag), dim=1) + +class LinearComplex(nn.Module): + ''' + Complex linear layer. The bias term is removed in order to leave the phase invariant. + + Args: + in_features: number of features of the input + out_features: number of channels of the produced output + Shape: + Input: [b,2,in_features] + Output: [b,2,out_features] + ''' + def __init__(self, in_features, out_features): + super(LinearComplex, self).__init__() + + self.linear_real = nn.Linear(in_features, out_features, bias=False) + self.linear_imag = nn.Linear(in_features, out_features, bias=False) + + def forward(self, x): + x_real, x_imag = get_real_imag_parts(x) + out_real = self.linear_real(x_real) - self.linear_imag(x_imag) + out_imag = self.linear_real(x_imag) + self.linear_imag(x_real) + return torch.stack((out_real, out_imag), dim=1) + +class Conv2dComplex(nn.Module): + ''' + Complex 2d convolution operation. Implementation the complex convolution from + https://arxiv.org/abs/1705.09792 (Section 3.2) and removes the bias term + to preserve phase. + + Args: + in_channels: number of channels in the input + out_channels: number of channels produced in the output + kernel_size: size of convolution window + stride: stride of convolution. Default: 1 + padding: amount of zero padding. Default: 0 + padding_mode: 'zeros', 'reflect', 'replicate' or 'circular'. Default: 'zeros' + groups: number of blocked connections from input to output channels. Default: 1 + Shape: + Input: [b,2,c,h_in,w_in] + Output: [b,2,c,h_out,w_out] + ''' + def __init__( + self, + in_channels, + out_channels, + kernel_size, + stride=1, + padding=0, + padding_mode='zeros', + groups=1, + ): + super(Conv2dComplex, self).__init__() + + self.in_channels = in_channels + + self.conv_real = nn.Conv2d( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + padding=padding, + padding_mode=padding_mode, + groups=groups, + bias=False # Bias always false + ) + self.conv_imag = nn.Conv2d( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + padding=padding, + padding_mode=padding_mode, + groups=groups, + bias=False # Bias always false + ) + + def forward(self, x): + x_real, x_imag = get_real_imag_parts(x) + out_real = self.conv_real(x_real) - self.conv_imag(x_imag) + out_imag = self.conv_real(x_imag) + self.conv_imag(x_real) + return torch.stack((out_real, out_imag), dim=1) + +class BatchNormComplex(nn.Module): + ''' + Complex batch normalization from Eq. 7. Code adapted from + https://github.com/ptrblck/pytorch_misc/blob/master/batch_norm_manual.py#L39 + + Args: + size: size of a single sample [c,h,w]. + momentum: exponential averaging momentum term for running mean. + Set to None for simple average. Default: 0.1 + track_running_stats: track the running mean for evaluation mode. Default: True + Shape: + Input: [b,2,c,h,w] + Output: [b,2,c,h,w] + ''' + def __init__( + self, + momentum=0.1, + track_running_stats=False + ): + super(BatchNormComplex, self).__init__() + + self.track_running_stats = track_running_stats + self.num_batches_tracked = 0 + self.momentum = momentum + self.running_mean = 0 + + def forward(self, x): + if self.track_running_stats == False: + # Calculate mean of complex norm + x_norm = torch.pow(complex_norm(x), 2) + mean = x_norm.mean([0]) + else: + # Setup exponential factor + ema_factor = 0.0 + if self.training and self.track_running_stats: + if self.num_batches_tracked is not None: + self.num_batches_tracked += 1 + if self.momentum is None: + ema_factor = 1.0/float(self.num_batches_tracked) # Cumulative moving average + else: + ema_factor = self.momentum + + # Calculate mean of complex norm + if self.training : + x_norm = torch.pow(complex_norm(x), 2) + mean = x_norm.mean([0]) + with torch.no_grad(): + self.running_mean = ema_factor * mean + (1-ema_factor) * self.running_mean + else: + if type(self.running_mean) == int: + mean = x.new(x.size(2), x.size(3), x.size(4))*0 + else: + mean = self.running_mean + + # Normalize + x /= torch.sqrt(mean[None, None, :, :, :] + 1e-5) + return x + +class ResidualBlock(nn.Module): + def __init__(self, channels, downsample): + super(ResidualBlock, self).__init__() + + self.downsample = downsample + self.channels = channels + + self.network = nn.Sequential( + nn.Conv2d(channels // 2 if downsample else channels, channels, kernel_size=3, padding=1, + stride=2 if downsample else 1, bias=False), + nn.BatchNorm2d(channels), + nn.ReLU(), + nn.Conv2d(channels, channels, kernel_size=3, padding=1, stride=1, bias=False), + nn.BatchNorm2d(channels) + ) + + def forward(self, x): + if self.downsample: + out = self.network(x) + F.pad(x[..., ::2, ::2], (0, 0, 0, 0, self.channels // 4, self.channels // 4)) + else: + out = self.network(x) + x + + return F.relu(out) + + +class ResidualBlockComplex(nn.Module): + def __init__(self, channels, downsample): + super(ResidualBlockComplex, self).__init__() + + self.downsample = downsample + self.channels = channels + self.network = nn.Sequential( + Conv2dComplex(channels // 2 if downsample else channels, channels, kernel_size=3, padding=1, + stride=2 if downsample else 1), + BatchNormComplex(), + ActivationComplex(), + Conv2dComplex(channels, channels, kernel_size=3, padding=1, stride=1), + BatchNormComplex() + ) + + def forward(self, x): + if self.downsample: + out = self.network(x) + F.pad(x[..., ::2, ::2], (0, 0, 0, 0, self.channels // 4, self.channels // 4)) + else: + out = self.network(x) + x + + return activation_complex(out, 1) + +class ResNetDecoderComplex(nn.Module): + def __init__(self, n, num_classes, variant="alpha"): + super(ResNetDecoderComplex, self).__init__() + + conv_layers = [ResidualBlock(64, False)] + if variant == "alpha": + for i in range(n - 2): + conv_layers.append(ResidualBlock(64, False)) + + self.conv_layers = nn.Sequential(*conv_layers) + self.linear = nn.Linear(64, num_classes) + + def forward(self, x): + out = self.conv_layers(x) + out = out.mean([2, 3]) # global average pooling + return self.linear(torch.flatten(out, 1)) + + +class ResNetEncoderComplex(nn.Module): + def __init__(self, n, additional_layers=True): + super(ResNetEncoderComplex, self).__init__() + + network = [ + nn.Conv2d(3, 16, kernel_size=3, padding=1, stride=1, bias=False), + nn.BatchNorm2d(16), + nn.ReLU() + ] + + for i in range(n): + network.append(ResidualBlock(16, False)) + + if additional_layers: + network += [ + nn.Conv2d(16, 16, kernel_size=3, padding=1, stride=1), + nn.ReLU(True) + ] + + self.network = nn.Sequential(*network) + + def forward(self, x): + return self.network(x) + +class ResNetProcessorComplex(nn.Module): + def __init__(self, n, variant="alpha"): + super(ResNetProcessorComplex, self).__init__() + + network = [ResidualBlockComplex(32, True)] + for i in range(n - 1): + network.append(ResidualBlockComplex(32, False)) + network.append(ResidualBlockComplex(64, True)) + + if variant == "beta": + for i in range(n - 2): + network.append(ResidualBlockComplex(64, False)) + + self.network = nn.Sequential(*network) + + def forward(self, x): + return self.network(x) + +class Discriminator(nn.Module): + ''' + Adversarial discriminator network. + Args: + size: List of input shape [c,h,w] + Shape: + Input: [b,c,h,w] + Output: [b,1] + ''' + def __init__(self, size): + super(Discriminator, self).__init__() + in_channels = size[0] + + self.net = nn.Sequential( + nn.Conv2d(in_channels, in_channels*2, kernel_size=4, stride=2, padding=1), + nn.BatchNorm2d(in_channels*2), + nn.ReLU(True), + nn.Flatten(), + nn.Linear(2*size[0]*size[1]//2*size[2]//2, 1) + ) + + def forward(self, x): + x = self.net(x) + return x + + diff --git a/src/models/model_zoo.py b/src/models/model_zoo.py index 6cfe46f..e35d07e 100644 --- a/src/models/model_zoo.py +++ b/src/models/model_zoo.py @@ -1,20 +1,22 @@ import torch import torchvision.models as models import torch.nn as nn - +import torch.nn.functional as F +from models.complex_models import ResNetProcessorComplex class Model(nn.Module): def __init__(self, config, utils): super(Model, self).__init__() self.loss_fn = nn.CrossEntropyLoss() self.utils = utils - self.loss_tag = "server_loss" - self.acc_tag = "server_acc" - self.utils.logger.register_tag("train/" + self.loss_tag) - self.utils.logger.register_tag("val/" + self.loss_tag) - self.utils.logger.register_tag("train/" + self.acc_tag) - self.utils.logger.register_tag("val/" + self.acc_tag) - + if config["model_name"] != "resnet20complex": + self.loss_tag = "server_loss" + self.acc_tag = "server_acc" + self.utils.logger.register_tag("train/" + self.loss_tag) + self.utils.logger.register_tag("val/" + self.loss_tag) + self.utils.logger.register_tag("train/" + self.acc_tag) + self.utils.logger.register_tag("val/" + self.acc_tag) + self.config = config self.assign_model(config) self.assign_optim(config) @@ -45,34 +47,62 @@ def assign_model(self, config): nn.Linear(num_ftrs, logits)) model = nn.ModuleList(list(model.children())[self.split_layer:]) self.model = nn.Sequential(*model) - + elif config["model_name"] == "resnet20complex": + self.model = ResNetProcessorComplex(3,'alpha') self.model = self.utils.model_on_gpus(self.model) self.utils.register_model("server_model", self.model) def assign_optim(self, config): lr = config["lr"] - if config["optimizer"] == "adam": - self.optim = torch.optim.Adam(self.model.parameters(), lr) + if config["model_name"] == "resnet20complex": + + if config["optimizer"] == "adam": + self.optim = torch.optim.Adam( + self.model.parameters(), + lr, + ) + + elif config["optimizer"] == "sgd": + self.optim = torch.optim.SGD( + self.model.parameters(), + lr, + momentum = config["momentum"], + weight_decay = config["weight_decay"] + ) + else: + if config["optimizer"] == "adam": + self.optim = torch.optim.Adam(self.model.parameters(), lr) - def forward(self, x): - x = self.model(x) - return nn.functional.softmax(x, dim=1) + def forward(self, z): + self.z = z + self.z.retain_grad() + if self.config["model_name"] == "resnet20complex": + h = self.model(self.z) + assert(h.size(1) == 2) + self.preds = None + h = h.detach() + h.requires_grad = True + return h + else: + x = self.model(self.z) + self.preds = nn.functional.softmax(x, dim=1) + return None def compute_loss(self, preds, y): - self.loss = self.loss_fn(preds, y) - self.utils.logger.add_entry(self.mode + "/" + self.loss_tag, - self.loss.item()) - self.utils.logger.add_entry(self.mode + "/" + self.acc_tag, - (preds, y), "acc") - + if self.config["model_name"] != "resnet20complex": + self.loss = self.loss_fn(preds, y) + self.utils.logger.add_entry(self.mode + "/" + self.loss_tag, + self.loss.item()) + self.utils.logger.add_entry(self.mode + "/" + self.acc_tag, + (preds, y), "acc") def optimize(self): self.optim.zero_grad() self.loss.backward() self.optim.step() - def processing(self, z, y): - z.retain_grad() - preds = self.forward(z) - self.compute_loss(preds, y) + def backward(self,y,decoder_loss): + self.loss = decoder_loss + self.compute_loss(self.preds, y) self.optimize() - return z.grad + return self.z.grad + diff --git a/src/scheduler.py b/src/scheduler.py index cb1a219..7f5cbb5 100644 --- a/src/scheduler.py +++ b/src/scheduler.py @@ -57,7 +57,9 @@ def defense_train(self) -> None: for _, sample in enumerate(self.dataloader.train): items = self.utils.get_data(sample) z = self.algo.forward(items) - items["server_grads"] = self.model.processing(z, items["pred_lbls"]) + data = self.model.forward(z) + decoder_loss = self.algo.infer(data,items["pred_lbls"]) + items["server_grads"] = self.model.backward(items["pred_lbls"],decoder_loss) self.algo.backward(items) def defense_test(self) -> None: @@ -66,7 +68,8 @@ def defense_test(self) -> None: for _, sample in enumerate(self.dataloader.test): items = self.utils.get_data(sample) z = self.algo.forward(items) - self.model.processing(z, items["pred_lbls"]) + data = self.model.forward(z) + self.algo.infer(data,items["pred_lbls"]) def attack_train(self) -> None: self.algo.train() diff --git a/src/utils/config_utils.py b/src/utils/config_utils.py index d08666e..0e96e5b 100644 --- a/src/utils/config_utils.py +++ b/src/utils/config_utils.py @@ -27,7 +27,7 @@ def config_loader(filepath): json_dict = research_dict json_dict['num_gpus'] = len(json_dict.get('gpu_devices')) - json_dict['train_batch_size'] = json_dict.get('train_batch_size', 64) * json_dict['num_gpus'] + json_dict['train_batch_size'] = json_dict.get('training_batch_size', 64) * json_dict['num_gpus'] json_dict['experiment_type'] = json_dict.get('experiment_type') or "defense" if 'manual_expt_name' in json_dict.keys(): From 212340e013f3ea8ed91e1312626f4f584af35932 Mon Sep 17 00:00:00 2001 From: john-m24 Date: Thu, 26 Aug 2021 15:05:37 +0000 Subject: [PATCH 02/10] configure dims in config --- src/algos/complex_nn.py | 3 ++- src/configs/complex_nn.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/algos/complex_nn.py b/src/algos/complex_nn.py index 931fb3b..70c62e5 100644 --- a/src/algos/complex_nn.py +++ b/src/algos/complex_nn.py @@ -20,7 +20,8 @@ def __init__(self, config, utils) -> None: def initialize(self, config): self.encoder_model,self.decoder_model = self.init_client_model(config) - size = get_encoder_output_size(self.encoder_model, (3,32,32)) + img_size = config["img_size"] + size = get_encoder_output_size(self.encoder_model, (3,img_size,img_size)) self.discriminator = Discriminator(size=size) models = [self.encoder_model, self.decoder_model, self.discriminator] self.put_on_gpus(models) diff --git a/src/configs/complex_nn.json b/src/configs/complex_nn.json index 53ccc80..680cf12 100644 --- a/src/configs/complex_nn.json +++ b/src/configs/complex_nn.json @@ -2,7 +2,7 @@ "method": "complex_nn", "client": {"model_name": "resnet20complex", "split_layer": 6, "pretrained": false,"logits": 2, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.9,"k":5, "momentum": 0.9, "weight_decay": 0.0001}, + "alpha": 0.9, "k":5, "momentum": 0.9, "weight_decay": 0.0001, "img_size":32 }, "server": {"model_name": "resnet20complex", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam", "momentum": 0.9, "weight_decay": 0.0001}, "learning_rate": 0.1, From 3b14bdde61ba9e051ac4f68cf240e818b4a556fd Mon Sep 17 00:00:00 2001 From: john-m24 Date: Fri, 5 Nov 2021 15:38:31 +0000 Subject: [PATCH 03/10] complex_nn implemented --- src/algos/complex_nn.py | 106 ++++++++++++----------------- src/configs/complex_nn.json | 15 ++-- src/configs/deep_obfuscator.json | 4 +- src/configs/nopeek.json | 4 +- src/configs/pan.json | 5 +- src/configs/siamese_embedding.json | 6 +- src/configs/system_config.json | 6 +- src/configs/uniform_noise.json | 4 +- src/data/loaders.py | 6 +- src/main.py | 4 +- src/models/complex_models.py | 12 ++-- src/models/model_zoo.py | 52 ++++++-------- src/scheduler.py | 5 +- 13 files changed, 103 insertions(+), 126 deletions(-) diff --git a/src/algos/complex_nn.py b/src/algos/complex_nn.py index 70c62e5..71c0143 100644 --- a/src/algos/complex_nn.py +++ b/src/algos/complex_nn.py @@ -19,18 +19,18 @@ def __init__(self, config, utils) -> None: self.initialize(config) def initialize(self, config): + self.optimizer_idx = 0 self.encoder_model,self.decoder_model = self.init_client_model(config) img_size = config["img_size"] size = get_encoder_output_size(self.encoder_model, (3,img_size,img_size)) self.discriminator = Discriminator(size=size) models = [self.encoder_model, self.decoder_model, self.discriminator] self.put_on_gpus(models) - self.optimizer_idx = 0 self.utils.register_model("encoder_model", self.encoder_model) self.utils.register_model("discriminator_model", self.discriminator) self.utils.register_model("decoder_model", self.decoder_model) - self.optim, self.optim_d = self.init_optim(config, [self.encoder_model, self.decoder_model], self.discriminator) + self.optim_encoder , self.optim_decoder , self.optim_discriminator = self.init_optim(config, self.encoder_model, self.decoder_model, self.discriminator) self.real_to_complex = RealToComplex() self.complex_to_real = ComplexToReal() @@ -38,12 +38,9 @@ def initialize(self, config): self.alpha = config["alpha"] self.k = config["k"] - self.g_loss_adv_tag = "g_adv_loss" - self.g_loss_ce_tag = "g_ce_loss" - self.d_loss_adv_tag = "d_loss" self.loss_tag = "decoder_loss" self.acc_tag = "decoder_acc" - tags = [self.g_loss_adv_tag, self.g_loss_ce_tag, self.d_loss_adv_tag, self.loss_tag, self.acc_tag] + tags = [self.loss_tag, self.acc_tag] for tag in tags: self.utils.logger.register_tag("train/" + tag) self.utils.logger.register_tag("val/" + tag) @@ -62,39 +59,24 @@ def init_client_model(self, config): return encoder_model,decoder_model - def init_optim(self, config, models, discriminator): - parameters = set() - for net in models: - parameters |= set(net.parameters()) + def init_optim(self, config, encoder, decoder, discriminator): + encoder_parameters = encoder.parameters() + decoder_parameters = decoder.parameters() if config["optimizer"] == "adam": - optimizer = torch.optim.Adam(parameters, - lr=config["lr"], - ) - - optimizer_d = torch.optim.Adam( - discriminator.parameters(), + optimizer_e = torch.optim.Adam(encoder_parameters, lr=config["lr"], ) - - elif config["optimizer"] == "sgd": - optimizer = torch.optim.SGD( - parameters, - lr=config["lr"], - momentum = config["momentum"], - weight_decay = config["weight_decay"] - ) - - optimizer_d = torch.optim.SGD( - discriminator.parameters(), - lr=config["lr"], - momentum = config["momentum"], - weight_decay = config["weight_decay"] - ) - + + optimizer_decoder = torch.optim.Adam(decoder_parameters) + + optimizer_discriminator = torch.optim.Adam( + discriminator.parameters(), + lr=config["lr"], + ) else: print("Unknown optimizer {}".format(config["optimizer"])) - return optimizer, optimizer_d + return optimizer_e,optimizer_decoder,optimizer_discriminator def train(self): self.mode = "train" @@ -116,11 +98,11 @@ def forward(self, items): indices = np.random.permutation(a.size(0)) b = a[indices] - z, self.theta = self.real_to_complex(a,b) + self.z, self.theta = self.real_to_complex(a,b) # Get discriminator score expectation over k rotations self.score_fake = 0 - for k in self.k: + for k in range(self.k): # Shuffle batch to get b indices = np.random.permutation(a.size(0)) b = a[indices] @@ -132,38 +114,40 @@ def forward(self, items): self.score_fake += self.discriminator(a_rotated) self.score_fake /= self.k # Average score - z = z.detach() + z = self.z.detach() z.requires_grad = True return z def infer(self, h, labels): - y = self.complex_to_real(h,self.theta) - self.preds = self.decoder_model(y) - self.acc = (self.preds.argmax(dim=1) == labels).sum().item() / self.preds.shape[0] - self.loss = self.loss_fn(self.preds,labels) - self.utils.logger.add_entry(self.mode + "/" + self.acc_tag, self.acc) - self.utils.logger.add_entry(self.mode + "/" + self.loss_tag, self.loss.item()) - loss = self.loss.detach() - loss.requires_grad = True - return loss - - def backward(self, items): - if (self.optimizer_idx % 2) == 0: - self.g_loss_adv = -torch.mean(self.score_fake) - self.g_loss_ce = self.loss_fn(self.preds,items["pred_lbls"]) - self.utils.logger.add_entry(self.mode + "/" + self.g_loss_adv_tag, self.g_loss_adv.item()) - self.utils.logger.add_entry(self.mode + "/" + self.g_loss_ce_tag, self.g_loss_ce.item()) - g_tot = self.g_loss_adv + self.g_loss_ce - self.optim.zero_grad() - g_tot.backward() - self.optim.step() - else: + h.retain_grad() + y = self.complex_to_real(h,self.theta) + y.retain_grad() + self.preds = self.decoder_model(y) + self.acc = (self.preds.argmax(dim=1) == labels).sum().item() / self.preds.shape[0] + self.utils.logger.add_entry(self.mode + "/" + self.acc_tag, self.acc) + if self.optimizer_idx%2 == 0: + g_loss_adv = -torch.mean(self.score_fake) + g_loss_ce = self.loss_fn(self.preds,labels) + loss = g_loss_adv + g_loss_ce + self.optim_decoder.zero_grad() + loss.backward(retain_graph=True) + self.optim_decoder.step() + self.utils.logger.add_entry(self.mode + "/" + self.loss_tag, loss.item()) + return h.grad + else: for p in self.discriminator.parameters(): p.data.clamp_(-0.01, 0.01) self.d_loss_adv = -torch.mean(self.discriminator(self.a)) + torch.mean(self.score_fake) - self.utils.logger.add_entry(self.mode + "/" + self.d_loss_adv_tag, self.d_loss_adv.item()) - self.optim_d.zero_grad() + self.optim_discriminator.zero_grad() self.d_loss_adv.backward() - self.optim_d.step() - + self.optim_discriminator.step() + return None + + def backward(self, items): + if self.optimizer_idx%2 == 0: + self.optim_encoder.zero_grad() + self.z.backward(items["server_grads"]) + self.optim_encoder.step() self.optimizer_idx += 1 + + diff --git a/src/configs/complex_nn.json b/src/configs/complex_nn.json index 680cf12..6a41c1d 100644 --- a/src/configs/complex_nn.json +++ b/src/configs/complex_nn.json @@ -1,19 +1,20 @@ { + "experiment_type": "challenge", "method": "complex_nn", "client": {"model_name": "resnet20complex", "split_layer": 6, "pretrained": false,"logits": 2, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.9, "k":5, "momentum": 0.9, "weight_decay": 0.0001, "img_size":32 }, + "alpha": 0.99, "k":5, "img_size":32}, "server": {"model_name": "resnet20complex", "split_layer":6, "logits": 2, "pretrained": false, - "lr": 3e-4, "optimizer": "adam", "momentum": 0.9, "weight_decay": 0.0001}, + "lr": 3e-4, "optimizer": "adam", "momentum": 0.99}, "learning_rate": 0.1, - "total_epochs": 95, + "total_epochs": 150, "training_batch_size": 128, - "dataset": "cifar10", - "protected_attribute": "class", - "prediction_attribute": "animated", + "dataset": "fairface", + "protected_attribute": "data", + "prediction_attribute": "gender", "img_size": 32, "split": false, - "test_batch_size": 128, + "test_batch_size": 32, "exp_id": "1", "exp_keys": ["client.alpha","client.optimizer"] } diff --git a/src/configs/deep_obfuscator.json b/src/configs/deep_obfuscator.json index 465967b..e739015 100644 --- a/src/configs/deep_obfuscator.json +++ b/src/configs/deep_obfuscator.json @@ -2,7 +2,7 @@ "method": "deep_obfuscator", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.9, + "alpha": 0.5, "proxy_adversary" : {"img_size": 128}}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, @@ -17,4 +17,4 @@ "test_batch_size": 64, "exp_id": "1", "exp_keys": ["client.alpha"] -} \ No newline at end of file +} diff --git a/src/configs/nopeek.json b/src/configs/nopeek.json index 72ac56d..aa34eb5 100644 --- a/src/configs/nopeek.json +++ b/src/configs/nopeek.json @@ -2,7 +2,7 @@ "method": "nopeek", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.9}, + "alpha": 0.92}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, "learning_rate": 0.01, @@ -16,4 +16,4 @@ "test_batch_size": 64, "exp_id": "1", "exp_keys": ["client.alpha"] -} \ No newline at end of file +} diff --git a/src/configs/pan.json b/src/configs/pan.json index 28c402d..f37a7dc 100644 --- a/src/configs/pan.json +++ b/src/configs/pan.json @@ -1,9 +1,8 @@ { - "experiment_type": "challenge", "method": "pan", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.9, + "alpha": 0.92, "proxy_adversary" : {"img_size": 128}}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, @@ -18,4 +17,4 @@ "test_batch_size": 64, "exp_id": "1", "exp_keys": ["client.alpha"] -} \ No newline at end of file +} diff --git a/src/configs/siamese_embedding.json b/src/configs/siamese_embedding.json index 60ee109..70105d5 100644 --- a/src/configs/siamese_embedding.json +++ b/src/configs/siamese_embedding.json @@ -2,7 +2,7 @@ "method": "siamese_embedding", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.9, "margin": 2}, + "alpha": 0.005, "margin": 2}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, "learning_rate": 0.01, @@ -11,9 +11,9 @@ "dataset": "fairface", "protected_attribute": "data", "prediction_attribute": "gender", - "img_size": 128, + "img_size": 32, "split": false, "test_batch_size": 64, "exp_id": "1", "exp_keys": ["client.alpha", "client.margin"] -} \ No newline at end of file +} diff --git a/src/configs/system_config.json b/src/configs/system_config.json index f077de0..f8e785c 100644 --- a/src/configs/system_config.json +++ b/src/configs/system_config.json @@ -1,5 +1,5 @@ { - "dataset_path": "/u/abhi24/Datasets/Faces/fairface/", - "experiments_folder": "/u/abhi24/Workspace/simba/experiments/", - "gpu_devices": [2,3] + "dataset_path": "/u/mosej24/CyberUROP/proj/datasets/fairface/", + "experiments_folder": "/u/mosej24/CyberUROP/Simba/experiments/", + "gpu_devices":[2,3] } diff --git a/src/configs/uniform_noise.json b/src/configs/uniform_noise.json index c445293..64ad80a 100644 --- a/src/configs/uniform_noise.json +++ b/src/configs/uniform_noise.json @@ -2,7 +2,7 @@ "method": "uniform_noise", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "distribution": "gaussian", "mean": 0, "sigma": 30}, + "distribution": "gaussian", "mean": 0, "sigma": 20000}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, "learning_rate": 0.01, @@ -16,4 +16,4 @@ "test_batch_size": 64, "exp_id": "1", "exp_keys": ["client.distribution", "client.mean", "client.sigma"] -} \ No newline at end of file +} diff --git a/src/data/loaders.py b/src/data/loaders.py index fee2c2b..f508f3d 100644 --- a/src/data/loaders.py +++ b/src/data/loaders.py @@ -1,7 +1,7 @@ import numpy as np import torch from torchvision import transforms -from data.dataset_utils import FairFace, CelebA, Cifar10_2, LFW#, UTKFace +from data.dataset_utils import FairFace,Cifar10, CelebA, Cifar10_2, LFW#, UTKFace from data.dataset_utils import Challenge class DataLoader(): @@ -62,8 +62,8 @@ def setup_data_pipeline(self): elif self.config["dataset"] == "cifar10": train_config["format"] = "jpg" test_config["format"] = "jpg" - train_dataset = Cifar10_2(train_config) - test_dataset = Cifar10_2(test_config) + train_dataset = Cifar10(train_config) + test_dataset = Cifar10(test_config) elif self.config["dataset"] == "lfw": train_config["format"] = "jpg" test_config["format"] = "jpg" diff --git a/src/main.py b/src/main.py index c87b259..6d68725 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,7 @@ import argparse from scheduler import Scheduler -b_default = "./configs/split_inference.json" +b_default = "./configs/complex_nn.json" s_default = "./configs/system_config.json" parser = argparse.ArgumentParser(description='Run SIMBA benchmark') @@ -13,4 +13,4 @@ args = parser.parse_args() scheduler = Scheduler(args) -scheduler.run_job() \ No newline at end of file +scheduler.run_job() diff --git a/src/models/complex_models.py b/src/models/complex_models.py index d5be8a7..ff22833 100644 --- a/src/models/complex_models.py +++ b/src/models/complex_models.py @@ -104,7 +104,7 @@ def __init__(self, c=1): def forward(self, x): x_norm = complex_norm(x).unsqueeze(1) c = self.c.to(x.device) - scale = x_norm/torch.max(x_norm, c) + scale = x_norm/torch.maximum(x_norm, c) return x*scale def activation_complex(x, c): @@ -121,7 +121,7 @@ def activation_complex(x, c): assert(c>0) x_norm = complex_norm(x).unsqueeze(1) c = torch.Tensor([c]).to(x.device) - scale = x_norm/torch.max(x_norm, c) + scale = x_norm/torch.maximum(x_norm, c) return x*scale def activation_complex_dynamic(x): @@ -137,11 +137,11 @@ def activation_complex_dynamic(x): x_norm = complex_norm(x) if x.dim() == 5: # for [b,2,c,h,w] inputs - scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + scale = x_norm.unsqueeze(1)/torch.maximum(x_norm.unsqueeze(1), x_norm.mean((2, 3))[:, :, None, None].unsqueeze(1)) else: # for [b,2,f] inputs - scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + scale = x_norm.unsqueeze(1)/torch.maximum(x_norm.unsqueeze(1), x_norm.mean(1)[:, None, None]) return x*scale @@ -159,11 +159,11 @@ def activation_complex_dynamic(x): x_norm = complex_norm(x) if x.dim() == 5: # for [b,2,c,h,w] inputs - scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + scale = x_norm.unsqueeze(1)/torch.maximum(x_norm.unsqueeze(1), x_norm.mean((2, 3))[:, :, None, None].unsqueeze(1)) else: # for [b,2,f] inputs - scale = x_norm.unsqueeze(1)/torch.max(x_norm.unsqueeze(1), + scale = x_norm.unsqueeze(1)/torch.maximum(x_norm.unsqueeze(1), x_norm.mean(1)[:, None, None]) return x*scale diff --git a/src/models/model_zoo.py b/src/models/model_zoo.py index e35d07e..02fcb67 100644 --- a/src/models/model_zoo.py +++ b/src/models/model_zoo.py @@ -54,39 +54,21 @@ def assign_model(self, config): def assign_optim(self, config): lr = config["lr"] - if config["model_name"] == "resnet20complex": - - if config["optimizer"] == "adam": - self.optim = torch.optim.Adam( - self.model.parameters(), - lr, - ) - - elif config["optimizer"] == "sgd": - self.optim = torch.optim.SGD( - self.model.parameters(), - lr, - momentum = config["momentum"], - weight_decay = config["weight_decay"] - ) - else: - if config["optimizer"] == "adam": - self.optim = torch.optim.Adam(self.model.parameters(), lr) + if config["optimizer"] == "adam": + self.optim = torch.optim.Adam(self.model.parameters(), lr) def forward(self, z): self.z = z self.z.retain_grad() if self.config["model_name"] == "resnet20complex": - h = self.model(self.z) - assert(h.size(1) == 2) - self.preds = None - h = h.detach() + self.h = self.model(self.z) + h = self.h.detach() h.requires_grad = True return h else: x = self.model(self.z) self.preds = nn.functional.softmax(x, dim=1) - return None + return self.preds def compute_loss(self, preds, y): if self.config["model_name"] != "resnet20complex": @@ -95,14 +77,24 @@ def compute_loss(self, preds, y): self.loss.item()) self.utils.logger.add_entry(self.mode + "/" + self.acc_tag, (preds, y), "acc") + def optimize(self): - self.optim.zero_grad() - self.loss.backward() - self.optim.step() + if self.config["model_name"] != "resnet20complex": + self.optim.zero_grad() + self.loss.backward() + self.optim.step() + else: + self.optim.zero_grad() + self.h.backward(self.decoder_grads) + self.optim.step() - def backward(self,y,decoder_loss): - self.loss = decoder_loss - self.compute_loss(self.preds, y) - self.optimize() + def backward(self,y,decoder_grads=None): + if decoder_grads != None: + self.decoder_grads = decoder_grads + self.optimize() + if self.config["model_name"] != "resnet20complex": + self.compute_loss(self.preds, y) + self.optimize() return self.z.grad + diff --git a/src/scheduler.py b/src/scheduler.py index 7f5cbb5..e184b4b 100644 --- a/src/scheduler.py +++ b/src/scheduler.py @@ -58,8 +58,8 @@ def defense_train(self) -> None: items = self.utils.get_data(sample) z = self.algo.forward(items) data = self.model.forward(z) - decoder_loss = self.algo.infer(data,items["pred_lbls"]) - items["server_grads"] = self.model.backward(items["pred_lbls"],decoder_loss) + items["decoder_grads"] = self.algo.infer(data,items["pred_lbls"]) + items["server_grads"] = self.model.backward(items["pred_lbls"],items["decoder_grads"]) self.algo.backward(items) def defense_test(self) -> None: @@ -70,6 +70,7 @@ def defense_test(self) -> None: z = self.algo.forward(items) data = self.model.forward(z) self.algo.infer(data,items["pred_lbls"]) + self.model.compute_loss(data,items["pred_lbls"]) def attack_train(self) -> None: self.algo.train() From 1c8406bfeda27d4005ffff8eaeb3a05a5d4ff7e4 Mon Sep 17 00:00:00 2001 From: john-m24 Date: Mon, 27 Dec 2021 00:00:12 +0000 Subject: [PATCH 04/10] in progress --- src/algos/supervised_decoder.py | 2 +- src/configs/decoder_attack.json | 4 ++-- src/configs/nopeek.json | 2 +- src/main.py | 2 +- src/scheduler.py | 5 +++-- src/utils/utils.py | 17 +++++++++++++---- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/algos/supervised_decoder.py b/src/algos/supervised_decoder.py index 8336070..6865ab6 100644 --- a/src/algos/supervised_decoder.py +++ b/src/algos/supervised_decoder.py @@ -36,7 +36,7 @@ def forward(self, items): self.loss = self.loss_fn(self.x, x) self.utils.logger.add_entry(self.mode + "/" + self.loss_tag, self.loss.item()) - + return self.x def backward(self, items): self.optim.zero_grad() (self.sign * self.loss).backward() diff --git a/src/configs/decoder_attack.json b/src/configs/decoder_attack.json index adc63a2..2328faf 100644 --- a/src/configs/decoder_attack.json +++ b/src/configs/decoder_attack.json @@ -5,7 +5,7 @@ "optimizer": "adam", "lr": 0.01, "attribute": "data"}, "total_epochs": 150, "training_batch_size": 128, - "challenge_experiment": "pan_fairface_data_resnet18_split6_1_alpha_0.9", + "challenge_experiment": "uniform_noise_fairface_data_resnet18_split6_1_distribution_gaussian_mean_0_sigma_0", "protected_attribute": "data", "dataset": "fairface", "exp_id": "1", @@ -14,4 +14,4 @@ "train_split": 0.9, "test_batch_size": 64, "exp_keys": ["train_split", "adversary.loss_fn"] -} \ No newline at end of file +} diff --git a/src/configs/nopeek.json b/src/configs/nopeek.json index aa34eb5..ce47e24 100644 --- a/src/configs/nopeek.json +++ b/src/configs/nopeek.json @@ -2,7 +2,7 @@ "method": "nopeek", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.92}, + "alpha": 0.8}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, "learning_rate": 0.01, diff --git a/src/main.py b/src/main.py index 6d68725..ecd41a7 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,7 @@ import argparse from scheduler import Scheduler -b_default = "./configs/complex_nn.json" +b_default = "./configs/decoder_attack.json" s_default = "./configs/system_config.json" parser = argparse.ArgumentParser(description='Run SIMBA benchmark') diff --git a/src/scheduler.py b/src/scheduler.py index e184b4b..548d64a 100644 --- a/src/scheduler.py +++ b/src/scheduler.py @@ -74,16 +74,17 @@ def defense_test(self) -> None: def attack_train(self) -> None: self.algo.train() - for _, sample in enumerate(self.dataloader.train): + for _, sample in enumerate(self.dataloader.test): items = self.utils.get_data(sample) z = self.algo.forward(items) self.algo.backward(items) def attack_test(self): self.algo.eval() - for _, sample in enumerate(self.dataloader.train): + for _, sample in enumerate(self.dataloader.test): items = self.utils.get_data(sample) z = self.algo.forward(items) + self.utils.save_images(z,items["filename"]) def epoch_summary(self): self.utils.logger.flush_epoch() diff --git a/src/utils/utils.py b/src/utils/utils.py index d9b9e0f..7b8503a 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -6,7 +6,7 @@ from shutil import copytree, copy2 from glob import glob import shutil - +from torchvision.utils import save_image class Utils(): def __init__(self, config) -> None: @@ -43,7 +43,7 @@ def get_data(self, sample): items["x"] = Variable(sample["img"]).to(self.device) items["pred_lbls"] = Variable(sample["prediction_label"]).to(self.device) items["prvt_lbls"] = Variable(sample["private_label"]).to(self.device) - items["filename"] = sample["filename"] + items["filename"] = sample["filename"] return items def copy_source_code(self, path): @@ -90,13 +90,22 @@ def save_data(self, z, filename, challenge_dir): for ele in range(int(z.shape[0])): z_path = challenge_dir + filename[ele] + '.pt' torch.save(z[ele].detach().cpu(), z_path) - + + def save_images(self,z,filename): + filepath = self.config["log_path"] + "rec_images/" + if not os.path.isdir(filepath): + os.mkdir(filepath) + filename = [name.split("/")[-1].split('.')[0] for name in filename] + for ele in range(int(z.shape[0])): + z_path = filepath + filename[ele] + "_rec.jpg" + save_image(z[ele],z_path) + def check_path_status(self, path): """experiment_path = None if auto: # This is to not duplicate work already done and to continue running experiments print("silently skipping experiment", self.config.get('experiment_name')) - return None""" + eeturn None""" print("Experiment {} already present".format(self.config.get("experiment_name"))) inp = input("Press e to exit, r to replace it, c to continue training: ") if inp == "e": From bd4440616b3c46e0696fa7a24fc1fbfabe179884 Mon Sep 17 00:00:00 2001 From: john-m24 Date: Thu, 17 Mar 2022 22:15:43 +0000 Subject: [PATCH 05/10] gaussian_blur fix --- src/algos/gaussian_blur.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/algos/gaussian_blur.py b/src/algos/gaussian_blur.py index 63d0250..f4847c6 100644 --- a/src/algos/gaussian_blur.py +++ b/src/algos/gaussian_blur.py @@ -21,7 +21,7 @@ class GaussianSmoothing(nn.Module): def __init__(self, channels, kernel_size, sigma, device, dim=2): super(GaussianSmoothing, self).__init__() if isinstance(kernel_size, numbers.Number): - kernel_size = [kernel_size] * dim + kernel_size = [kernel_size*math.sqrt(sigma)] * dim if isinstance(sigma, numbers.Number): sigma = [sigma] * dim @@ -36,8 +36,7 @@ def __init__(self, channels, kernel_size, sigma, device, dim=2): ) for size, std, mgrid in zip(kernel_size, sigma, meshgrids): mean = (size - 1) / 2 - kernel *= 1 / (std * math.sqrt(2 * math.pi)) * \ - torch.exp(-((mgrid - mean) / std) ** 2 / 2) + kernel *= 1 / (std * math.sqrt(2 * math.pi)) * torch.exp(-((mgrid - mean) / std) ** 2 / 2) # Make sure sum of values in gaussian kernel equals 1. kernel = kernel / torch.sum(kernel) From fd3cc85e8f46f22559b8d9d1ee9fa7f564723aff Mon Sep 17 00:00:00 2001 From: john-m24 Date: Sat, 2 Apr 2022 16:31:26 +0000 Subject: [PATCH 06/10] resolve conflicts --- src/configs/maxentropy.json | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/configs/maxentropy.json diff --git a/src/configs/maxentropy.json b/src/configs/maxentropy.json new file mode 100644 index 0000000..bbaccaa --- /dev/null +++ b/src/configs/maxentropy.json @@ -0,0 +1,18 @@ +{ + "method": "maxentropy", + "client": {"model_name": "resnet18", "split_layer": 6, + "pretrained": false, "optimizer": "adam", "lr": 3e-4}, + "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, + "lr": 3e-4, "optimizer": "adam"}, + "learning_rate": 0.01, + "total_epochs": 150, + "training_batch_size": 256, + "dataset": "fairface", + "protected_attribute": "data", + "prediction_attribute": "gender", + "img_size": 128, + "split": false, + "test_batch_size": 64, + "exp_id": "1", + "exp_keys": ["client.optimizer"] +} \ No newline at end of file From 88caea4c206fe85028addb81cfe3ed39c3f93669 Mon Sep 17 00:00:00 2001 From: john-m24 Date: Sat, 2 Apr 2022 16:33:53 +0000 Subject: [PATCH 07/10] resolve_conflicts --- src/algos/maxentropy.py | 49 +++++++++++++++++++++++++++++++++ src/algos/supervised_decoder.py | 2 ++ src/interface.py | 5 +++- src/models/image_decoder.py | 2 -- src/models/model_zoo.py | 6 ++-- src/scheduler.py | 4 ++- src/utils/utils.py | 10 +++++-- 7 files changed, 69 insertions(+), 9 deletions(-) diff --git a/src/algos/maxentropy.py b/src/algos/maxentropy.py index e69de29..66287ee 100644 --- a/src/algos/maxentropy.py +++ b/src/algos/maxentropy.py @@ -0,0 +1,49 @@ +from algos.simba_algo import SimbaDefence +import torch +from torchvision import models +import torch.nn as nn +import torch.nn.functional as F +from torch.nn.modules.loss import _Loss +torch.autograd.set_detect_anomaly(True) +distance = nn.CrossEntropyLoss() + +class EntropyLoss(_Loss): + def __init__(self, size_average=None, reduce=None, reduction='mean'): + super(EntropyLoss, self).__init__(size_average, reduce, reduction) + + # input is probability distribution of output classes + def forward(self, input): + if (input < 0).any() or (input > 1).any(): + print(input) + raise Exception('Entropy Loss takes probabilities 0<=input<=1') + + input = input + 1e-16 # for numerical stability while taking log + H = torch.mean(torch.sum(input * torch.log(input), dim=0)) + + return H + +class MaxEntropy(SimbaDefence): + def __init__(self, config, utils) -> None: + super(MaxEntropy, self).__init__(utils) + self.initialize(config, utils.device) + + def initialize(self, config, device): + self.client_model = self.init_client_model(config) + self.put_on_gpus() + self.utils.register_model("client_model", self.client_model) + self.client_optim = self.init_optim(config, self.client_model) + self.entropy_loss_fn = EntropyLoss() + + def forward(self, items): + x = items["x"] + self.z = self.client_model(x) + z = self.z.detach() + z.requires_grad = True + return z + + def backward(self, items): + entropy_loss = self.entropy_loss_fn(items["pred_lbls"]) + entropy_loss.requires_grad = True + entropy_loss.backward() + self.z.backward(items["server_grads"]) + self.client_optim.step() diff --git a/src/algos/supervised_decoder.py b/src/algos/supervised_decoder.py index a740c47..b100365 100644 --- a/src/algos/supervised_decoder.py +++ b/src/algos/supervised_decoder.py @@ -54,6 +54,8 @@ def forward(self, items): self.utils.logger.add_entry(self.mode + "/" + self.loss_tag, self.loss.item()) + return self.x + def backward(self, items): if self.mode == "val" and self.attribute == "data": prefix = "val/" diff --git a/src/interface.py b/src/interface.py index bedf12f..bbd3768 100644 --- a/src/interface.py +++ b/src/interface.py @@ -6,9 +6,10 @@ from algos.pca_embedding import PCAEmbedding from algos.deepobfuscator import DeepObfuscator from algos.pan import PAN +from algos.complex_nn import ComplexNN from algos.gaussian_blur import GaussianBlur from algos.linear_correlation import LinearCorrelation - +from algos.maxentropy import MaxEntropy from algos.supervised_decoder import SupervisedDecoder from data.loaders import DataLoader @@ -55,6 +56,8 @@ def load_algo(config, utils, dataloader=None): algo = GaussianBlur(config["client"], utils) elif method == "linear_correlation": algo = LinearCorrelation(config["client"], utils) + elif method == "maxentropy": + algo = MaxEntropy(config["client"], utils) elif method == "supervised_decoder": item = next(iter(dataloader)) z = item["z"] diff --git a/src/models/image_decoder.py b/src/models/image_decoder.py index 5a9375a..b0066f1 100644 --- a/src/models/image_decoder.py +++ b/src/models/image_decoder.py @@ -64,7 +64,6 @@ def __init__(self, config): input_nc = config["channels"] img_size = config["img_size"] patch_size = config["patch_size"] - # Because usually images get downsampled by a factor of 2 feat_map_size = img_size feat_map_list = [] @@ -77,7 +76,6 @@ def __init__(self, config): patch_channels.append(patch_channels[-1] * 2) # remove the last element to ensure the closest match is smallest patch_channels.pop() - # Find closest feature map index = closest(feat_map_list, patch_size) index_channel = closest(patch_channels, input_nc) diff --git a/src/models/model_zoo.py b/src/models/model_zoo.py index 02fcb67..3a36de2 100644 --- a/src/models/model_zoo.py +++ b/src/models/model_zoo.py @@ -79,13 +79,13 @@ def compute_loss(self, preds, y): (preds, y), "acc") def optimize(self): - if self.config["model_name"] != "resnet20complex": + if self.config["model_name"] == "resnet20complex": self.optim.zero_grad() - self.loss.backward() + self.h.backward(self.decoder_grads) self.optim.step() else: self.optim.zero_grad() - self.h.backward(self.decoder_grads) + self.loss.backward() self.optim.step() def backward(self,y,decoder_grads=None): diff --git a/src/scheduler.py b/src/scheduler.py index 548d64a..6091b01 100644 --- a/src/scheduler.py +++ b/src/scheduler.py @@ -57,6 +57,7 @@ def defense_train(self) -> None: for _, sample in enumerate(self.dataloader.train): items = self.utils.get_data(sample) z = self.algo.forward(items) + # self.utils.save_images((items["x"],z),items["filename"]) data = self.model.forward(z) items["decoder_grads"] = self.algo.infer(data,items["pred_lbls"]) items["server_grads"] = self.model.backward(items["pred_lbls"],items["decoder_grads"]) @@ -68,6 +69,7 @@ def defense_test(self) -> None: for _, sample in enumerate(self.dataloader.test): items = self.utils.get_data(sample) z = self.algo.forward(items) + # self.utils.save_images((items["x"],z),items["filename"]) data = self.model.forward(z) self.algo.infer(data,items["pred_lbls"]) self.model.compute_loss(data,items["pred_lbls"]) @@ -84,7 +86,7 @@ def attack_test(self): for _, sample in enumerate(self.dataloader.test): items = self.utils.get_data(sample) z = self.algo.forward(items) - self.utils.save_images(z,items["filename"]) + self.utils.save_images((items["x"],z),items["filename"]) def epoch_summary(self): self.utils.logger.flush_epoch() diff --git a/src/utils/utils.py b/src/utils/utils.py index 7b8503a..f8578eb 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -91,14 +91,20 @@ def save_data(self, z, filename, challenge_dir): z_path = challenge_dir + filename[ele] + '.pt' torch.save(z[ele].detach().cpu(), z_path) - def save_images(self,z,filename): + def save_images(self,x_and_z,filename): + x,z = x_and_z filepath = self.config["log_path"] + "rec_images/" if not os.path.isdir(filepath): os.mkdir(filepath) filename = [name.split("/")[-1].split('.')[0] for name in filename] for ele in range(int(z.shape[0])): - z_path = filepath + filename[ele] + "_rec.jpg" + path = filepath + filename[ele] + "/" + if not os.path.isdir(path): + os.mkdir(path) + z_path = path + filename[ele] + "_rec.jpg" + x_path = path + filename[ele] + "_orig.jpg" save_image(z[ele],z_path) + save_image(x[ele],x_path) def check_path_status(self, path): """experiment_path = None From 74bbfe51369dc6ccbb005fd88a86e487e906874d Mon Sep 17 00:00:00 2001 From: john-m24 Date: Sat, 2 Apr 2022 16:50:44 +0000 Subject: [PATCH 08/10] resolves --- src/algos/maxentropy.py | 5 ----- src/algos/simba_algo.py | 6 ------ src/configs/decoder_attack.json | 2 +- src/configs/deep_obfuscator.json | 2 +- src/configs/nopeek.json | 2 +- src/configs/pan.json | 2 +- src/configs/siamese_embedding.json | 4 ++-- src/configs/system_config.json | 6 +++--- src/configs/uniform_noise.json | 2 +- src/data/loaders.py | 3 --- src/main.py | 2 +- src/utils/utils.py | 2 +- 12 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/algos/maxentropy.py b/src/algos/maxentropy.py index 1420072..2b5720a 100644 --- a/src/algos/maxentropy.py +++ b/src/algos/maxentropy.py @@ -7,10 +7,8 @@ from torch.nn.modules.loss import _Loss torch.autograd.set_detect_anomaly(True) distance = nn.CrossEntropyLoss() -======= from algos.deepobfuscator import DeepObfuscator from utils.metrics import MetricLoader ->>>>>>> 4fe1a5313a2fb315687c46f251d869c3c3a44f66 class EntropyLoss(_Loss): def __init__(self, size_average=None, reduce=None, reduction='mean'): @@ -23,7 +21,6 @@ def forward(self, input): raise Exception('Entropy Loss takes probabilities 0<=input<=1') input = input + 1e-16 # for numerical stability while taking log -<<<<<<< HEAD H = torch.mean(torch.sum(input * torch.log(input), dim=0)) return H @@ -53,7 +50,6 @@ def backward(self, items): entropy_loss.backward() self.z.backward(items["server_grads"]) self.client_optim.step() -======= H = torch.mean(torch.sum(input * torch.log(input), dim=1)) return H @@ -74,4 +70,3 @@ def update_loss(self): def get_adv_loss(self): # Since it is L1, it has to be minimized return self.adv_loss ->>>>>>> 4fe1a5313a2fb315687c46f251d869c3c3a44f66 diff --git a/src/algos/simba_algo.py b/src/algos/simba_algo.py index 86748fd..6479a17 100644 --- a/src/algos/simba_algo.py +++ b/src/algos/simba_algo.py @@ -104,9 +104,3 @@ def train(self): def eval(self): self.mode = "val" self.model.eval() -<<<<<<< HEAD -======= - - - ->>>>>>> 4fe1a5313a2fb315687c46f251d869c3c3a44f66 diff --git a/src/configs/decoder_attack.json b/src/configs/decoder_attack.json index 2328faf..059b091 100644 --- a/src/configs/decoder_attack.json +++ b/src/configs/decoder_attack.json @@ -5,7 +5,7 @@ "optimizer": "adam", "lr": 0.01, "attribute": "data"}, "total_epochs": 150, "training_batch_size": 128, - "challenge_experiment": "uniform_noise_fairface_data_resnet18_split6_1_distribution_gaussian_mean_0_sigma_0", + "challenge_experiment": "pan_fairface_data_resnet18_split6_1_alpha_0.9", "protected_attribute": "data", "dataset": "fairface", "exp_id": "1", diff --git a/src/configs/deep_obfuscator.json b/src/configs/deep_obfuscator.json index e739015..dcb4d32 100644 --- a/src/configs/deep_obfuscator.json +++ b/src/configs/deep_obfuscator.json @@ -2,7 +2,7 @@ "method": "deep_obfuscator", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.5, + "alpha": 0.9, "proxy_adversary" : {"img_size": 128}}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, diff --git a/src/configs/nopeek.json b/src/configs/nopeek.json index ce47e24..620bc88 100644 --- a/src/configs/nopeek.json +++ b/src/configs/nopeek.json @@ -2,7 +2,7 @@ "method": "nopeek", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.8}, + "alpha": 0.9}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, "learning_rate": 0.01, diff --git a/src/configs/pan.json b/src/configs/pan.json index f37a7dc..380b76b 100644 --- a/src/configs/pan.json +++ b/src/configs/pan.json @@ -2,7 +2,7 @@ "method": "pan", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.92, + "alpha": 0.9, "proxy_adversary" : {"img_size": 128}}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, diff --git a/src/configs/siamese_embedding.json b/src/configs/siamese_embedding.json index 70105d5..1d35bc2 100644 --- a/src/configs/siamese_embedding.json +++ b/src/configs/siamese_embedding.json @@ -2,7 +2,7 @@ "method": "siamese_embedding", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "alpha": 0.005, "margin": 2}, + "alpha": 0.9, "margin": 2}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, "learning_rate": 0.01, @@ -11,7 +11,7 @@ "dataset": "fairface", "protected_attribute": "data", "prediction_attribute": "gender", - "img_size": 32, + "img_size": 128, "split": false, "test_batch_size": 64, "exp_id": "1", diff --git a/src/configs/system_config.json b/src/configs/system_config.json index f8e785c..f077de0 100644 --- a/src/configs/system_config.json +++ b/src/configs/system_config.json @@ -1,5 +1,5 @@ { - "dataset_path": "/u/mosej24/CyberUROP/proj/datasets/fairface/", - "experiments_folder": "/u/mosej24/CyberUROP/Simba/experiments/", - "gpu_devices":[2,3] + "dataset_path": "/u/abhi24/Datasets/Faces/fairface/", + "experiments_folder": "/u/abhi24/Workspace/simba/experiments/", + "gpu_devices": [2,3] } diff --git a/src/configs/uniform_noise.json b/src/configs/uniform_noise.json index 64ad80a..77962c2 100644 --- a/src/configs/uniform_noise.json +++ b/src/configs/uniform_noise.json @@ -2,7 +2,7 @@ "method": "uniform_noise", "client": {"model_name": "resnet18", "split_layer": 6, "pretrained": false, "optimizer": "adam", "lr": 3e-4, - "distribution": "gaussian", "mean": 0, "sigma": 20000}, + "distribution": "gaussian", "mean": 0, "sigma": 30}, "server": {"model_name": "resnet18", "split_layer":6, "logits": 2, "pretrained": false, "lr": 3e-4, "optimizer": "adam"}, "learning_rate": 0.01, diff --git a/src/data/loaders.py b/src/data/loaders.py index b50b060..9a2e9d9 100644 --- a/src/data/loaders.py +++ b/src/data/loaders.py @@ -1,11 +1,8 @@ import numpy as np import torch from torchvision import transforms -<<<<<<< HEAD from data.dataset_utils import FairFace,Cifar10, CelebA, Cifar10_2, LFW#, UTKFace -======= from data.dataset_utils import FairFace, CelebA, Cifar10, LFW#, UTKFace, Cifar10_2 ->>>>>>> 4fe1a5313a2fb315687c46f251d869c3c3a44f66 from data.dataset_utils import Challenge class DataLoader(): diff --git a/src/main.py b/src/main.py index 5d9f048..5126591 100644 --- a/src/main.py +++ b/src/main.py @@ -1,7 +1,7 @@ import argparse from scheduler import Scheduler -b_default = "./configs/decoder_attack.json" +b_default = "./configs/split_inference.json" s_default = "./configs/system_config.json" parser = argparse.ArgumentParser(description='Run SIMBA benchmark') diff --git a/src/utils/utils.py b/src/utils/utils.py index f8578eb..ea48e83 100644 --- a/src/utils/utils.py +++ b/src/utils/utils.py @@ -111,7 +111,7 @@ def check_path_status(self, path): if auto: # This is to not duplicate work already done and to continue running experiments print("silently skipping experiment", self.config.get('experiment_name')) - eeturn None""" + return None""" print("Experiment {} already present".format(self.config.get("experiment_name"))) inp = input("Press e to exit, r to replace it, c to continue training: ") if inp == "e": From 85d0afc6ce23d96f0e602769892df7483ee81524 Mon Sep 17 00:00:00 2001 From: john-m24 Date: Sat, 2 Apr 2022 16:52:05 +0000 Subject: [PATCH 09/10] resolves --- src/algos/gaussian_blur.py | 3 ++- src/algos/maxentropy.py | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algos/gaussian_blur.py b/src/algos/gaussian_blur.py index f4847c6..9c5fa6a 100644 --- a/src/algos/gaussian_blur.py +++ b/src/algos/gaussian_blur.py @@ -36,7 +36,8 @@ def __init__(self, channels, kernel_size, sigma, device, dim=2): ) for size, std, mgrid in zip(kernel_size, sigma, meshgrids): mean = (size - 1) / 2 - kernel *= 1 / (std * math.sqrt(2 * math.pi)) * torch.exp(-((mgrid - mean) / std) ** 2 / 2) + kernel *= 1 / (std * math.sqrt(2 * math.pi)) * \ + torch.exp(-((mgrid - mean) / std) ** 2 / 2) # Make sure sum of values in gaussian kernel equals 1. kernel = kernel / torch.sum(kernel) diff --git a/src/algos/maxentropy.py b/src/algos/maxentropy.py index 2b5720a..bfc29ea 100644 --- a/src/algos/maxentropy.py +++ b/src/algos/maxentropy.py @@ -1,4 +1,3 @@ -<<<<<<< HEAD from algos.simba_algo import SimbaDefence import torch from torchvision import models From 197cd69e26221ec5bafe841ee228f595dcd16f7c Mon Sep 17 00:00:00 2001 From: john-m24 Date: Sat, 2 Apr 2022 16:54:04 +0000 Subject: [PATCH 10/10] resolves --- src/main.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main.py b/src/main.py index 5126591..b382ad5 100644 --- a/src/main.py +++ b/src/main.py @@ -14,7 +14,3 @@ scheduler = Scheduler(args) scheduler.run_job() -<<<<<<< HEAD -======= - ->>>>>>> 4fe1a5313a2fb315687c46f251d869c3c3a44f66