def __init__(self, num_classes, resnet_backbone='ResNet50', pretrained=True, mode=None): super(Saliency_noskip, self).__init__() self.mode = mode self.num_classes = num_classes self.resnet_backbone = resnet_backbone if resnet_backbone == 'ResNet18': layers = [2, 2, 2, 2] elif resnet_backbone == 'ResNet50': layers = [3, 4, 6, 3] else: print('given Resnet backbone does not exist') self.pretrained = pretrained # build the network architecture # encoder --Resnet50 without final pooling and fc self.pretrained_resnet = resnet50(pretrained=self.pretrained) self._modify_resnet(num_classes) # either set to bilinear or nearest and allign corners self.upsample = Upsample(scale_factor=8, mode='bilinear', align_corners=True) #reduce to num_classes self.onexone = torch.nn.Conv2d(in_channels=2048, out_channels=self.num_classes, kernel_size=1) # use a softmax if dataset is mutually exclusive. self.sigmoid = nn.Sigmoid() #todo: make these layers overridable, such that parameters can be set from training script. # self.softmax = nn.Softmax(dim=1) self.pooling = CustomPooling(beta=1, r_0=10, dim=(-1, -2), mode='Three') self.norm = CustomNorm(1)
def __init__(self, num_classes, resnet_backbone='ResNet50', pretrained=True, mode=None): super(Saliency_simple, self).__init__() self.mode = mode self.num_classes = num_classes self.resnet_backbone = resnet_backbone if resnet_backbone == 'ResNet18': layers = [2, 2, 2, 2] elif resnet_backbone == 'ResNet50': layers = [3, 4, 6, 3] else: print('given Resnet backbone does not exist') self.pretrained = pretrained # build the network architecture # encoder --Resnet50 without final pooling and fc self.pretrained_resnet = resnet50(pretrained=self.pretrained) self._modify_resnet(num_classes) # either set to bilinear or nearest and allign corners self.upsample = Upsample(scale_factor=2, mode='bilinear', align_corners=True) #reduce to num_classes self.onexone = torch.nn.Conv2d(in_channels=3840, out_channels=self.num_classes, kernel_size=1) # Decoder path with skip connections, only upsampling and concatenation if self.mode is not None: if self.mode == 'mode1': # # 1x1 conv2@d to reduce filters from 2048 - 1024 self.onexone1 = torch.nn.Conv2d(2048, 512, 1) self.onexone2 = torch.nn.Conv2d(1024, 256, 1) self.onexone3 = torch.nn.Conv2d(512, 128, 1) self.onexone4 = torch.nn.Conv2d(256, 64, 1) self.activation = torch.nn.ReLU() # reduce to num_classes self.onexone = torch.nn.Conv2d(in_channels=960, out_channels=self.num_classes, kernel_size=1) elif self.mode == 'mode2': self.onexone1 = torch.nn.Conv2d(2048, 20, 1) self.onexone2 = torch.nn.Conv2d(1024, 20, 1) self.onexone3 = torch.nn.Conv2d(512, 20, 1) self.onexone4 = torch.nn.Conv2d(256, 20, 1) self.activation = torch.nn.ReLU() # reduce to num_classes self.onexone = torch.nn.Conv2d(in_channels=80, out_channels=self.num_classes, kernel_size=1) #upsample to increase spatial resolution from 8x8 to 16x16 # use a softmax if dataset is mutually exclusive. self.sigmoid = nn.Sigmoid() #todo: make these layers overridable, such that parameters can be set from training script. # self.softmax = nn.Softmax(dim=1) self.pooling = CustomPooling(beta=1, r_0=10, dim=(-1, -2), mode='Three') self.norm = CustomNorm(1)
def __init__(self, num_classes, resnet_backbone='ResNet50', pretrained=True, mode=None): super(SaliencyUNet, self).__init__() self.num_classes = num_classes self.mode = mode self.resnet_backbone = resnet_backbone if resnet_backbone == 'ResNet18': layers = [2, 2, 2, 2] elif resnet_backbone =='ResNet50': layers = [3, 4, 6, 3] else: print('given Resnet backbone does not exist') self.pretrained = pretrained # build the network architecture # encoder --Resnet50 without final pooling and fc self.pretrained_resnet = resnet50(pretrained=self.pretrained) self._modify_resnet(num_classes) # Decoder path with skip connections # 1x1 conv2@d to reduce filters from 2048 - 1024 self.onexone1 = torch.nn.Conv2d(2048, 1024, 1) self.activation = torch.nn.ReLU() #upsample to increase spatial resolution from 8x8 to 16x16 # either set to bilinear or nearest and allign corners self.upsample = Upsample(scale_factor=2, mode='bilinear', align_corners=True) #concat the upsampled featurespace with the encoder feature space at resolution level 16x16 # convolution with 3x3 filter and reduction of channels 2048 - 512 self.conv1 = ConvRelu(2048, 512) #upsample 16 --> 32 # concat with 512 res feature space # convolution with 3x3 filter and reduction of channels 1024 - 256 self.conv2 = ConvRelu(1024, 256) #upsample 32 --> 64 # concat with 512 res feature space # convolution with 3x3 filter and reduction of channels 1024 - 256 self.conv3 = ConvRelu(512, 128) #reduce to num_classes self.onexone = torch.nn.Conv2d(in_channels=128, out_channels=self.num_classes, kernel_size=1) # use a softmax if dataset is mutually exclusive. self.sigmoid = nn.Sigmoid() #todo: make these layers overridable, such that parameters can be set from training script. # self.softmax = nn.Softmax(dim=1) self.pooling = CustomPooling(beta=1, r_0=10, dim=(-1, -2), mode='Three') self.norm = CustomNorm(1)
def _perturb_image(self, image, noise): """Given an image and a noise, generate a perturbed image. First, resize the noise with the size of the image. Then, add the resized noise to the image. Args: image: numpy array of size [1, 299, 299, 3], an original image noise: numpy array of size [1, 256, 256, 3], a noise Returns: adv_iamge: numpy array with size [1, 299, 299, 3], a perturbed image """ upsampler = Upsample(size=(self.width, self.height)) noise = upsampler(torch.tensor(noise)) adv_image = np.clip(image + noise, 0., 1.) return adv_image
def upsample_maker(target_h, target_w): """ makes an upsampler which takes a numpy tensor of the form minibatch x channels x h x w and casts to minibatch x channels x target_h x target_w :param target_h: int to specify the desired height :param target_w: int to specify the desired width :return: """ _upsampler = Upsample(size=(target_h, target_w)) def upsample_fct(xs): if ch.is_tensor(xs): return _upsampler(xs) else: return _upsampler(ch.from_numpy(xs)).numpy() return upsample_fct
def bandit(self, input_xi, label, epsilon, eta, TARGETED): img_dim = input_xi.size(-1) #channel = input_xi.size(0) batch_size = input_xi.size(0) upsampler = Upsample(size=(img_dim, img_dim)) prior = torch.zeros(input_xi.size()).cuda() dim = prior.numel() / batch_size prior_step = gd_prior_step if self.mode == 'l2' else eg_step image_step = l2_image_step if self.mode == 'l2' else linf_step proj_maker = l2_proj if self.mode == 'l2' else linf_proj image = input_xi.detach().clone() print(image.max(), image.min()) proj_step = proj_maker(image, epsilon) orig_classes = self.model.predict_prob(input_xi).argmax(1).cuda() correct_classified_mask = (orig_classes == label).float() for _ in range(1000): exp_noise = self.exploration * torch.randn_like(prior) / (dim**0.5) exp_noise = exp_noise.cuda() # Query deltas for finite difference estimator q1 = upsampler(prior + exp_noise).cuda() q2 = upsampler(prior - exp_noise).cuda() # Loss points for finite difference estimator #print(q1.size()) l1 = self.get_loss(image + self.fd_eta * q1 / norm(q1), label) l2 = self.get_loss(image + self.fd_eta * q2 / norm(q2), label) #print(l1.data.item()) #l1 = L(image + args.fd_eta*q1/norm(q1)) # L(prior + c*noise) #l2 = L(image + args.fd_eta*q2/norm(q2)) # L(prior - c*noise) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (self.fd_eta * self.exploration) # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # Update the prior with the estimated gradient prior = prior_step(prior, est_grad, self.online_lr) new_im = image_step( image, upsampler(prior * correct_classified_mask.view(-1, 1, 1, 1)), eta) image = proj_step(new_im) image = torch.clamp(image, 0, 1) return image
def make_adversarial_examples(image, true_label, model_to_fool, nes=False, loss="xent", mode="linf", epsilon=8. / 256, max_queries=50000, gradient_iters=1, fd_eta=0.1, image_lr=0.0001, online_lr=100, exploration=0.01, prior_size=15, targeted=False, log_progress=True, device='cpu'): ''' The main process for generating adversarial examples with priors. ''' with torch.no_grad(): # Initial setup batch_size = image.size(0) total_queries = torch.zeros(batch_size).to(device) upsampler = Upsample(size=(image.size(2), image.size(2))) prior = torch.zeros(batch_size, 3, prior_size, prior_size).to(device) dim = prior.nelement() / batch_size prior_step = gd_prior_step if mode == 'l2' else eg_step image_step = l2_image_step if mode == 'l2' else linf_step proj_maker = l2_proj if mode == 'l2' else linf_proj proj_step = proj_maker(image, epsilon) # Loss function if targeted: criterion = -torch.nn.CrossEntropyLoss(reduction='none') else: criterion = torch.nn.CrossEntropyLoss(reduction='none') losses = criterion(model_to_fool(image), true_label) # Original classifications orig_images = image.clone() orig_classes = model_to_fool(image).argmax(1).to(device) correct_classified_mask = ( orig_classes == true_label).to(device).float() total_ims = correct_classified_mask.to(device).sum() not_dones_mask = correct_classified_mask.to(device).clone() t = 0 while not torch.any(total_queries > max_queries): t += gradient_iters * 2 if t >= max_queries: break if not nes: # Updating the prior: # Create noise for exporation, estimate the gradient, and take a PGD step exp_noise = exploration * torch.randn_like(prior) / (dim**0.5) exp_noise = exp_noise.to(device) # Query deltas for finite difference estimator q1 = upsampler(prior + exp_noise) q2 = upsampler(prior - exp_noise) # Loss points for finite difference estimator l1 = criterion(model_to_fool(image + fd_eta * q1 / norm(q1)), true_label) # L(prior + c*noise) l2 = criterion(model_to_fool(image + fd_eta * q2 / norm(q2)), true_label) # L(prior - c*noise) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (fd_eta * exploration) # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # Update the prior with the estimated gradient prior = prior_step(prior, est_grad, online_lr) else: prior = torch.zeros_like(image) for _ in range(gradient_iters): exp_noise = torch.randn_like(image) / (dim**0.5) exp_noise = exp_noise.to(device) est_deriv = ( criterion(model_to_fool(image + fd_eta * exp_noise), true_label) - criterion(model_to_fool(image - fd_eta * exp_noise), true_label)) / fd_eta prior += est_deriv.view(-1, 1, 1, 1) * exp_noise # Preserve images that are already done, # Unless we are specifically measuring gradient estimation prior = prior * not_dones_mask.view(-1, 1, 1, 1) # Update the image: # take a pgd step using the prior new_im = image_step( image, upsampler( prior * correct_classified_mask.to(device).view(-1, 1, 1, 1)), image_lr) image = proj_step(new_im) image = torch.clamp(image, 0, 1) # Continue query count total_queries += 2 * gradient_iters * not_dones_mask not_dones_mask = not_dones_mask * ( (model_to_fool(image).argmax(1) == true_label).to(device).float()) # Logging stuff if loss == "xent": new_losses = criterion(model_to_fool(image), true_label).to(device) elif loss == "cw": output = model_to_fool(image) output = torch.nn.functional.softmax(output) y_onehot = to_one_hot(true_label, num_classes=image.shape[1]) real = (y_onehot.float().to(device) * output.float().to(device)) real = real.sum(dim=1) other = ((1.0 - y_onehot.float().to(device)) * output.float().to(device) - (y_onehot.float().to(device) * 10000000)).max(1)[0] new_losses = torch.log(real + 1e-10) - torch.log(other + 1e-10) success_mask = (1 - not_dones_mask) * correct_classified_mask num_success = success_mask.to(device).sum() current_success_rate = ( num_success / correct_classified_mask.sum()).to(device).item() success_queries = ((success_mask * total_queries).sum() / num_success).to(device).item() not_done_loss = ((new_losses * not_dones_mask).to(device).sum() / not_dones_mask.sum()).item() max_curr_queries = total_queries.max().to(device).item() if log_progress: print( "Queries: %d | Success rate: %f | Average queries: %f" % (max_curr_queries, current_success_rate, success_queries)) if current_success_rate == 1.0: break if batch_size == 1: return { "image_adv": image.cpu().numpy(), "prediction": model_to_fool(image).argmax(1), "elapsed_budget": total_queries.cpu().numpy()[0], "success": success_mask.cpu().numpy()[0] == True } return { 'average_queries': success_queries, 'num_correctly_classified': correct_classified_mask.sum().cpu().item(), 'success_rate': current_success_rate, 'images_orig': orig_images.cpu().numpy(), 'images_adv': image.cpu().numpy(), 'all_queries': total_queries.cpu().numpy(), 'correctly_classified': correct_classified_mask.cpu().numpy(), 'success': list(success_mask.cpu().numpy()), "elapsed_budget": list(total_queries.cpu().numpy()), }
def make_adversarial_examples(image, true_label, args, model_to_fool, IMAGENET_SL): ''' The main process for generating adversarial examples with priors. ''' # Initial setup prior_size = IMAGENET_SL if not args.tiling else args.tile_size upsampler = Upsample(size=(IMAGENET_SL, IMAGENET_SL)) total_queries = ch.zeros(args.batch_size) prior = ch.zeros(args.batch_size, 3, prior_size, prior_size) dim = prior.nelement() / args.batch_size prior_step = gd_prior_step if args.mode == 'l2' else eg_step image_step = l2_image_step if args.mode == 'l2' else linf_step proj_maker = l2_proj if args.mode == 'l2' else linf_proj proj_step = proj_maker(image, args.epsilon) print(image.max(), image.min()) # Loss function criterion = ch.nn.CrossEntropyLoss(reduction='none') def normalized_eval(x): x_copy = x.clone() x_copy = ch.stack([F.normalize(x_copy[i], [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) \ for i in range(args.batch_size)]) return model_to_fool(x_copy) L = lambda x: criterion(normalized_eval(x), true_label) losses = L(image) # Original classifications orig_images = image.clone() orig_classes = model_to_fool(image).argmax(1).cuda() correct_classified_mask = (orig_classes == true_label).float() total_ims = correct_classified_mask.sum() not_dones_mask = correct_classified_mask.clone() t = 0 while not ch.any(total_queries > args.max_queries): t += args.gradient_iters * 2 if t >= args.max_queries: break if not args.nes: ## Updating the prior: # Create noise for exporation, estimate the gradient, and take a PGD step exp_noise = args.exploration * ch.randn_like(prior) / (dim**0.5) # Query deltas for finite difference estimator q1 = upsampler(prior + exp_noise) q2 = upsampler(prior - exp_noise) # Loss points for finite difference estimator l1 = L(image + args.fd_eta * q1 / norm(q1)) # L(prior + c*noise) l2 = L(image + args.fd_eta * q2 / norm(q2)) # L(prior - c*noise) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (args.fd_eta * args.exploration) # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # Update the prior with the estimated gradient prior = prior_step(prior, est_grad, args.online_lr) else: prior = ch.zeros_like(image) for _ in range(args.gradient_iters): exp_noise = ch.randn_like(image) / (dim**0.5) est_deriv = (L(image + args.fd_eta * exp_noise) - L(image - args.fd_eta * exp_noise)) / args.fd_eta prior += est_deriv.view(-1, 1, 1, 1) * exp_noise # Preserve images that are already done, # Unless we are specifically measuring gradient estimation prior = prior * not_dones_mask.view(-1, 1, 1, 1) ## Update the image: # take a pgd step using the prior new_im = image_step( image, upsampler(prior * correct_classified_mask.view(-1, 1, 1, 1)), args.image_lr) image = proj_step(new_im) image = ch.clamp(image, 0, 1) if args.mode == 'l2': if not ch.all(norm(image - orig_images) <= args.epsilon + 1e-3): pdb.set_trace() else: if not (image - orig_images).max() <= args.epsilon + 1e-3: pdb.set_trace() ## Continue query count total_queries += 2 * args.gradient_iters * not_dones_mask not_dones_mask = not_dones_mask * ( (normalized_eval(image).argmax(1) == true_label).float()) ## Logging stuff new_losses = L(image) success_mask = (1 - not_dones_mask) * correct_classified_mask num_success = success_mask.sum() current_success_rate = (num_success / correct_classified_mask.sum()).cpu().item() success_queries = ((success_mask * total_queries).sum() / num_success).cpu().item() not_done_loss = ((new_losses * not_dones_mask).sum() / not_dones_mask.sum()).cpu().item() max_curr_queries = total_queries.max().cpu().item() if args.log_progress: print("Queries: %d | Success rate: %f | Average queries: %f" % (max_curr_queries, current_success_rate, success_queries)) if current_success_rate == 1.0: break return { 'average_queries': success_queries, 'num_correctly_classified': correct_classified_mask.sum().cpu().item(), 'success_rate': current_success_rate, 'images_orig': orig_images.cpu().numpy(), 'images_adv': image.cpu().numpy(), 'all_queries': total_queries.cpu().numpy(), 'correctly_classified': correct_classified_mask.cpu().numpy(), 'success': success_mask.cpu().numpy() }
def make_adversarial_examples(image, true_label, args): ''' The main process for generating adversarial examples with priors. ''' # Initial setup prior_size = IMAGENET_SL if not args.tiling else args.tile_size upsampler = Upsample(size=(IMAGENET_SL, IMAGENET_SL)) total_queries = ch.zeros(args.batch_size) prior = ch.zeros(args.batch_size, 3, prior_size, prior_size) dim = prior.nelement() / args.batch_size prior_step = gd_prior_step if args.mode == 'l2' else eg_step image_step = l2_image_step if args.mode == 'l2' else linf_step proj_maker = l2_proj if args.mode == 'l2' else linf_proj proj_step = proj_maker(image, args.epsilon) # Loss function criterion = ch.nn.CrossEntropyLoss(reduction='none') L = lambda x: criterion(model_to_fool(x), true_label) losses = L(image) # Original classifications orig_images = image.clone() orig_classes = model_to_fool(image).argmax(1).cuda() correct_classified_mask = (orig_classes == true_label).float() total_ims = correct_classified_mask.sum() not_dones_mask = correct_classified_mask.clone() while not ch.any(total_queries > args.max_queries): if not args.nes: ## Updating the prior: # Create noise for exporation, estimate the gradient, and take a PGD step exp_noise = args.exploration * ch.randn_like(prior) / (dim**0.5) # Query deltas for finite difference estimator q1 = upsampler(prior + exp_noise) q2 = upsampler(prior - exp_noise) # Loss points for finite difference estimator l1 = L(image + args.fd_eta * q1 / norm(q1)) # L(prior + c*noise) l2 = L(image + args.fd_eta * q2 / norm(q2)) # L(prior - c*noise) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (args.fd_eta * args.exploration) # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # Update the prior with the estimated gradient prior = prior_step(prior, est_grad, args.online_lr) else: prior = ch.zeros_like(image) for _ in range(args.gradient_iters): exp_noise = ch.randn_like(image) / (dim**0.5) est_deriv = (L(image + args.fd_eta * exp_noise) - L(image - args.fd_eta * exp_noise)) / args.fd_eta prior += est_deriv.view(-1, 1, 1, 1) * exp_noise # Preserve images that are already done prior = prior * not_dones_mask.view(-1, 1, 1, 1) ## Update the image: # take a pgd step using the prior new_im = image_step(image, upsampler(prior), args.image_lr) image = proj_step(new_im) image = ch.clamp(image, 0, 1) if args.mode == 'l2': if not ch.all(norm(image - orig_images) <= args.epsilon + 1e-3): raise ValueError("OOB") else: if not (image - orig_images).max() <= args.epsilon + 1e-3: raise ValueError("OOB") ## Continue query count not_dones_mask = not_dones_mask * ( (model_to_fool(image).argmax(1) == true_label).float()) total_queries += 2 * args.gradient_iters * not_dones_mask ## Logging stuff new_losses = L(image) success_mask = (1 - not_dones_mask) * correct_classified_mask num_success = success_mask.sum() current_success_rate = (num_success / correct_classified_mask.sum()).cpu().item() success_queries = ((success_mask * total_queries).sum() / num_success).cpu().item() not_done_loss = ((new_losses * not_dones_mask).sum() / not_dones_mask.sum()).cpu().item() max_curr_queries = total_queries.max().cpu().item() if args.log_progress: print("Queries: %d | Success rate: %f | Average queries: %f" % (max_curr_queries, current_success_rate, success_queries)) if current_success_rate == 1.0: break # Return results return { 'average_queries': success_queries, # Average queries for this batch 'num_correctly_classified': correct_classified_mask.sum().cpu().item( ), # Number of originally correctly classified images 'success_rate': current_success_rate, # Success rate 'images_orig': orig_images.cpu().numpy(), # Original images 'images_adv': image.cpu().numpy(), # Adversarial images 'all_queries': total_queries.cpu().numpy(), # Number of queries used for each image 'correctly_classified': correct_classified_mask.cpu().numpy( ), # 0/1 mask for whether image was originally classified 'success': success_mask.cpu().numpy( ) # 0/1 mask for whether the attack succeeds on each image }
def DFOattack(net, x, y, criterion=F.cross_entropy, eps=0.1, optimizer="DE", budget=10000, prior_size=5): x = x.cuda() upsampler = Upsample(size=(224, 224)) s = prior_size def convert_individual_to_image(individual): perturbation = torch.from_numpy(eps * individual.astype(numpy.float32)) perturbation = perturbation.view(1, 3, s, s) perturbation = upsampler(perturbation) perturbation = perturbation.cuda() x_adv = x + perturbation x_adv = torch.clamp(x_adv, 0, 1) return x_adv def loss(abc): if optimizer in ['cGA', 'PBIL']: individual = 2 * abc - 1 else: abc = abc.reshape((-1, 2)) abc = softmax(abc, axis=1) individual = 2 * (numpy.random.uniform(size=abc.shape[0]) < abc[:, 0]) - 1 x_adv = convert_individual_to_image(individual) netx_adv = net(x_adv) _, predicted = torch.max(netx_adv.data, 1) result = (-criterion(netx_adv, y)).detach().cpu().numpy() return result, predicted, x_adv # def loss(a): # a=1/(1+numpy.exp(a)) # individual = 2*(numpy.random.uniform(size=a.shape)<a)-1 # x_adv = convert_individual_to_image(individual) # netx_adv = net(x_adv) # _,predicted = torch.max(netx_adv.data, 1) # result = (-criterion(netx_adv,y)).detach().cpu().numpy() # return result, predicted,x_adv done = False if optimizer in ['cGA', 'PBIL']: optimizerer = optimizerlib.registry[optimizer](instrumentation=s * s * 3, budget=budget) else: optimizerer = optimizerlib.registry[optimizer](instrumentation=s * s * 3 * 2, budget=budget) ebudget = 0 for u in range(budget): if u % 100 == 0: print(u, "/", budget) curr_value = optimizerer.ask() values, predicted, x_adv = loss(numpy.array(curr_value.args[0])) ebudget += 1 if predicted != y: # print(y,predicted) print('win', ebudget) done = True break optimizerer.tell(curr_value, float(values)) return { "image_adv": x_adv.cpu().numpy(), "prediction": predicted, "elapsed_budget": ebudget, "success": done }
def attack_all_images(self, args, arch, tmp_dump_path, result_dump_path): # subset_pos用于回调函数汇报汇总统计结果 model = StandardModel(args.dataset, arch, no_grad=True) model.cuda() model.eval() # 带有缩减功能的,攻击成功的图片自动删除掉 for data_idx, data_tuple in enumerate(self.dataset_loader): if os.path.exists(tmp_dump_path): with open(tmp_dump_path, "r") as file_obj: json_content = json.load(file_obj) resume_batch_idx = int(json_content["batch_idx"]) # resume for key in [ 'query_all', 'correct_all', 'not_done_all', 'success_all', 'success_query_all' ]: if key in json_content: setattr( self, key, torch.from_numpy(np.asarray( json_content[key])).float()) if data_idx < resume_batch_idx: # resume continue if args.dataset == "ImageNet": if model.input_size[-1] >= 299: images, true_labels = data_tuple[1], data_tuple[2] else: images, true_labels = data_tuple[0], data_tuple[2] else: images, true_labels = data_tuple[0], data_tuple[1] if images.size(-1) != model.input_size[-1]: images = F.interpolate(images, size=model.input_size[-1], mode='bilinear', align_corners=True) # skip_batch_index_list = np.nonzero(np.asarray(chunk_skip_indexes[data_idx]))[0].tolist() selected = torch.arange( data_idx * args.batch_size, min((data_idx + 1) * args.batch_size, self.total_images)) # 选择这个batch的所有图片的index img_idx_to_batch_idx = ImageIdxToOrigBatchIdx(args.batch_size) images, true_labels = images.cuda(), true_labels.cuda() first_finetune = True finetune_queue = FinetuneQueue(args.batch_size, args.meta_seq_len, img_idx_to_batch_idx) prior_size = model.input_size[ -1] if not args.tiling else args.tile_size assert args.tiling == (args.dataset == "ImageNet") if args.tiling: upsampler = Upsample(size=(model.input_size[-2], model.input_size[-1])) else: upsampler = lambda x: x with torch.no_grad(): logit = model(images) pred = logit.argmax(dim=1) query = torch.zeros(images.size(0)).cuda() correct = pred.eq(true_labels).float() # shape = (batch_size,) not_done = correct.clone() # shape = (batch_size,) if args.targeted: if args.target_type == 'random': target_labels = torch.randint( low=0, high=CLASS_NUM[args.dataset], size=true_labels.size()).long().cuda() invalid_target_index = target_labels.eq(true_labels) while invalid_target_index.sum().item() > 0: target_labels[invalid_target_index] = torch.randint( low=0, high=logit.shape[1], size=target_labels[invalid_target_index].shape ).long().cuda() invalid_target_index = target_labels.eq(true_labels) elif args.target_type == 'least_likely': target_labels = logit.argmin(dim=1) elif args.target_type == "increment": target_labels = torch.fmod(true_labels + 1, CLASS_NUM[args.dataset]) else: raise NotImplementedError('Unknown target_type: {}'.format( args.target_type)) else: target_labels = None prior = torch.zeros(images.size(0), IN_CHANNELS[args.dataset], prior_size, prior_size).cuda() prior_step = self.gd_prior_step if args.norm == 'l2' else self.eg_prior_step image_step = self.l2_image_step if args.norm == 'l2' else self.linf_step proj_step = self.l2_proj_step if args.norm == 'l2' else self.linf_proj_step # 调用proj_maker返回的是一个函数 criterion = self.cw_loss if args.data_loss == "cw" else self.xent_loss adv_images = images.clone() for step_index in range(1, args.max_queries + 1): # Create noise for exporation, estimate the gradient, and take a PGD step dim = prior.nelement() / images.size( 0) # nelement() --> total number of elements exp_noise = args.exploration * torch.randn_like(prior) / ( dim**0.5 ) # parameterizes the exploration to be done around the prior exp_noise = exp_noise.cuda() q1 = upsampler( prior + exp_noise ) # 这就是Finite Difference算法, prior相当于论文里的v,这个prior也会更新,把梯度累积上去 q2 = upsampler( prior - exp_noise) # prior 相当于累积的更新量,用这个更新量,再去修改image,就会变得非常准 # Loss points for finite difference estimator q1_images = adv_images + args.fd_eta * q1 / self.norm(q1) q2_images = adv_images + args.fd_eta * q2 / self.norm(q2) predict_by_target_model = False if (step_index <= args.warm_up_steps or (step_index - args.warm_up_steps) % args.meta_predict_steps == 0): log.info("predict from target model") predict_by_target_model = True with torch.no_grad(): q1_logits = model(q1_images) q2_logits = model(q2_images) q1_logits = q1_logits / torch.norm( q1_logits, p=2, dim=-1, keepdim=True) # 加入normalize q2_logits = q2_logits / torch.norm( q2_logits, p=2, dim=-1, keepdim=True) finetune_queue.append(q1_images.detach(), q2_images.detach(), q1_logits.detach(), q2_logits.detach()) if step_index >= args.warm_up_steps: q1_images_seq, q2_images_seq, q1_logits_seq, q2_logits_seq = finetune_queue.stack_history_track( ) finetune_times = args.finetune_times if first_finetune else random.randint( 3, 5) # FIXME log.info("begin finetune for {} times".format( finetune_times)) self.meta_finetuner.finetune( q1_images_seq, q2_images_seq, q1_logits_seq, q2_logits_seq, finetune_times, first_finetune, img_idx_to_batch_idx) first_finetune = False else: with torch.no_grad(): q1_logits, q2_logits = self.meta_finetuner.predict( q1_images, q2_images, img_idx_to_batch_idx) q1_logits = q1_logits / torch.norm( q1_logits, p=2, dim=-1, keepdim=True) q2_logits = q2_logits / torch.norm( q2_logits, p=2, dim=-1, keepdim=True) l1 = criterion(q1_logits, true_labels, target_labels) l2 = criterion(q2_logits, true_labels, target_labels) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (args.fd_eta * args.exploration ) # 方向导数 , l1和l2是loss # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # B, C, H, W, # Update the prior with the estimated gradient prior = prior_step( prior, est_grad, args.online_lr) # 注意,修正的是prior,这就是bandit算法的精髓 grad = upsampler(prior) # prior相当于梯度 ## Update the image: adv_images = image_step( adv_images, grad * correct.view(-1, 1, 1, 1), # 注意correct也是删减过的 args.image_lr) # prior放大后相当于累积的更新量,可以用来更新 adv_images = proj_step(images, args.epsilon, adv_images) adv_images = torch.clamp(adv_images, 0, 1) with torch.no_grad(): adv_logit = model(adv_images) # adv_pred = adv_logit.argmax(dim=1) adv_prob = F.softmax(adv_logit, dim=1) adv_loss = criterion(adv_logit, true_labels, target_labels) ## Continue query count if predict_by_target_model: query = query + 2 * not_done if args.targeted: not_done = not_done * ( 1 - adv_pred.eq(target_labels).float() ).float() # not_done初始化为 correct, shape = (batch_size,) else: not_done = not_done * adv_pred.eq( true_labels).float() # 只要是跟原始label相等的,就还需要query,还没有成功 success = (1 - not_done) * correct success_query = success * query not_done_loss = adv_loss * not_done not_done_prob = adv_prob[torch.arange(adv_images.size(0)), true_labels] * not_done log.info('Attacking image {} - {} / {}, step {}'.format( data_idx * args.batch_size, (data_idx + 1) * args.batch_size, self.total_images, step_index)) log.info(' not_done: {:.4f}'.format( len( np.where(not_done.detach().cpu().numpy().astype( np.int32) == 1)[0]) / float(args.batch_size))) log.info(' fd_scalar: {:.9f}'.format( (l1 - l2).mean().item())) if success.sum().item() > 0: log.info(' mean_query: {:.4f}'.format( success_query[success.byte()].mean().item())) log.info(' median_query: {:.4f}'.format( success_query[success.byte()].median().item())) if not_done.sum().item() > 0: log.info(' not_done_loss: {:.4f}'.format( not_done_loss[not_done.byte()].mean().item())) log.info(' not_done_prob: {:.4f}'.format( not_done_prob[not_done.byte()].mean().item())) not_done_np = not_done.detach().cpu().numpy().astype(np.int32) done_img_idx_list = np.where(not_done_np == 0)[0].tolist() delete_all = False if done_img_idx_list: for skip_index in done_img_idx_list: # 两次循环,第一次循环先汇报出去,第二次循环删除 batch_idx = img_idx_to_batch_idx[skip_index] pos = selected[batch_idx].item() # 先汇报被删减的值self.query_all for key in [ 'query', 'correct', 'not_done', 'success', 'success_query', 'not_done_loss', 'not_done_prob' ]: value_all = getattr(self, key + "_all") value = eval(key)[skip_index].item() value_all[pos] = value images, adv_images, prior, query, true_labels, target_labels, correct, not_done = \ self.delete_tensor_by_index_list(done_img_idx_list, images, adv_images, prior, query, true_labels, target_labels, correct, not_done) img_idx_to_batch_idx.del_by_index_list(done_img_idx_list) delete_all = images is None if delete_all: break # report to all stats the rest unsuccess for key in [ 'query', 'correct', 'not_done', 'success', 'success_query', 'not_done_loss', 'not_done_prob' ]: for img_idx, batch_idx in img_idx_to_batch_idx.proj_dict.items( ): pos = selected[batch_idx].item() value_all = getattr(self, key + "_all") value = eval(key)[img_idx].item() value_all[ pos] = value # 由于value_all是全部图片都放在一个数组里,当前batch选择出来 img_idx_to_batch_idx.proj_dict.clear() tmp_info_dict = { "batch_idx": data_idx + 1, "batch_size": args.batch_size } for key in [ 'query_all', 'correct_all', 'not_done_all', 'success_all', 'success_query_all' ]: value_all = getattr(self, key).detach().cpu().numpy().tolist() tmp_info_dict[key] = value_all with open(tmp_dump_path, "w") as result_file_obj: json.dump(tmp_info_dict, result_file_obj, sort_keys=True) log.info('Saving results to {}'.format(result_dump_path)) meta_info_dict = { "avg_correct": self.correct_all.mean().item(), "avg_not_done": self.not_done_all[self.correct_all.byte()].mean().item(), "mean_query": self.success_query_all[self.success_all.byte()].mean().item(), "median_query": self.success_query_all[self.success_all.byte()].median().item(), "max_query": self.success_query_all[self.success_all.byte()].max().item(), "correct_all": self.correct_all.detach().cpu().numpy().astype(np.int32).tolist(), "not_done_all": self.not_done_all.detach().cpu().numpy().astype(np.int32).tolist(), "query_all": self.query_all.detach().cpu().numpy().astype(np.int32).tolist(), "not_done_loss": self.not_done_loss_all[self.not_done_all.byte()].mean().item(), "not_done_prob": self.not_done_prob_all[self.not_done_all.byte()].mean().item(), "args": vars(args) } with open(result_dump_path, "w") as result_file_obj: json.dump(meta_info_dict, result_file_obj, sort_keys=True) log.info("done, write stats info to {}".format(result_dump_path)) self.query_all.fill_(0) self.correct_all.fill_(0) self.not_done_all.fill_(0) self.success_all.fill_(0) self.success_query_all.fill_(0) self.not_done_loss_all.fill_(0) self.not_done_prob_all.fill_(0) model.cpu()
def __init__(self, num_classes, gr=32, resnet_backbone='ResNet50', dense_config='normal', pretrained=True): super(SaliencyMapNet, self).__init__() self.num_classes = num_classes self.resnet_backbone = resnet_backbone self.gr = gr if resnet_backbone == 'ResNet18': layers = [2, 2, 2, 2] elif resnet_backbone =='ResNet50': layers = [3, 4, 6, 3] else: print('given Resnet backbone does not exist') if dense_config == 'normal': block_config = [6, 12, 24, 16] self.pretrained = pretrained self.pretrained_resnet = resnet50(pretrained=self.pretrained) self._modify_resnet(num_classes) # added resnet Block to downsample to 8x 8 # todo: fix the last layer so that it only downsamples once. done in _modifyresnet # too many weights in last layer, reduce planes, and use more blacks. # self.layer5 = self._make_layer(inplanes=2048, block=resnet.Bottleneck, planes=1024, blocks=1, stride=2, # dilate=False) ## normal pretrainable resnet: # model prior to Unet shape: self.d1 = DenseNet(growth_rate=self.gr, block_config=6, num_init_features=256, num_output=256) self.d2 = DenseNet(growth_rate=self.gr, block_config=12, num_init_features=512, num_output=512) self.d3 = DenseNet(growth_rate=self.gr, block_config=24, num_init_features=1024, num_output=1024) # self.d4 = DenseNet(growth_rate=self.gr, block_config=12, # num_init_features=2048, num_output=2048) # upwards path # self.upsample0 = Upsample(scale_factor=2, mode='nearest') # # self.upsample1 = MyUpsampler(num_init_features =8*self.num_classes, num_out_features=4*self.num_classes) # from [bs, 8k, 8, 8] --> [bs, 4k, 16, 16] # # self.updense0 = DenseNet(growth_rate=self.gr, block_config=12, # num_init_features=4096+2048, # num_output=2048) # self.mixdense0 = DenseNet(growth_rate=self.gr, block_config=12, # num_init_features=2048, num_output=2048) self.upsample = Upsample(scale_factor=2, mode='bilinear', align_corners=True) # self.upsample1 = MyUpsampler(num_init_features =8*self.num_classes, num_out_features=4*self.num_classes) # from [bs, 8k, 8, 8] --> [bs, 4k, 16, 16] self.updense1 = DenseNet(growth_rate=self.gr, block_config=2, num_init_features=2048+1024, num_output=1024) self.mixdense1 = DenseNet(growth_rate=self.gr, block_config=2, num_init_features=1024, num_output=1024) self.updense2 = DenseNet(growth_rate=self.gr, block_config=2, num_init_features=1024+512, num_output=512) self.mixdense2 = DenseNet(growth_rate=self.gr, block_config=2, num_init_features=512, num_output=512) self.updense3 = DenseNet(growth_rate=self.gr, block_config=2, num_init_features=512+256, num_output=256) self.mixdense3 = DenseNet(growth_rate=self.gr, block_config=2, num_init_features=256, num_output=256) self.onexone = torch.nn.Conv2d(in_channels=256, out_channels=self.num_classes, kernel_size=1) # use a softmax if dataset is mutually exclusive. self.sigmoid = nn.Sigmoid() # self.softmax = nn.Softmax(dim=1) self.pooling = CustomPooling(beta=1, r_0=10, dim=(-1, -2), mode=None) self.norm = CustomNorm(1)
def __init__(self, args, nor_type = 'sp', img_size=256,recursive_num=4,fusion_strategy = 0, upsample_strategy = 0 ,res_par_tag = False, depthwise_tag = False, att_tag = True): super(DenseMODEL, self).__init__() # hyper-params self.args = args self.res_par_tag = res_par_tag self.lstm_tags = True self.fusion_strategy = fusion_strategy self.upsample_strategy = upsample_strategy self.recursive_num = recursive_num self.img_size = img_size if res_par_tag: self.res_scale = nn.Parameter(torch.ones(1)) else : self.res_scale = 1 scale = args.upscale_factor n_resblocks = args.n_resblocks n_feats = args.n_feats # n_feats = 64 kernel_size = 3 act = nn.ReLU(True) if nor_type == 'sp': wn = SpectralNorm elif nor_type == 'wn': wn = lambda x: torch.nn.utils.weight_norm(x) elif nor_type == 'none': wn = lambda x: x if args.n_colors == 3: self.rgb_mean = nn.Parameter(torch.FloatTensor([args.r_mean, args.g_mean, args.b_mean])).view([1, 3, 1, 1]).cuda() else: self.rgb_mean = nn.Parameter(torch.FloatTensor([args.r_mean])).view([1, 1, 1, 1]).cuda() # define head module head = [] # head.append(wn(nn.Conv2d(args.n_colors, n_feats, 3, padding=3//2))) head.append(wn(nn.Conv2d(args.n_colors, n_feats, 3, padding=3//2))) # define body module body = [] for i in range(n_resblocks): body.append( Block(n_feats, kernel_size, act=act, res_scale=args.res_scale, wn=wn, res_par=res_par_tag, depthwise_tag=depthwise_tag)) # define LSTM height = self.img_size//scale width = self.img_size//scale self.converge = BiConvLSTM(input_size=(height, width), input_dim=n_feats, hidden_dim=[ n_feats//2, n_feats//2], kernel_size=(1, 1), num_layers=2, bias=True, return_all_layers=False, return_fl = False) # define tail module tail = [] out_feats = scale*scale*args.n_colors if self.fusion_strategy == 2: tail.append( wn(nn.Conv2d(n_feats*self.recursive_num, out_feats, 1))) elif self.fusion_strategy == 0: tail.append( wn(nn.Conv2d(self.recursive_num*n_feats//2, out_feats, 1))) else: tail.append( wn(nn.Conv2d(n_feats, out_feats, 1))) tail.append(nn.PixelShuffle(scale)) self.tail = nn.Sequential(*tail) # make object members self.head = nn.Sequential(*head) # self.body = nn.Sequential(*body) self.body1 = DenseBlock(n_feats, kernel_size, act=act, res_scale=args.res_scale, wn=wn, res_par=res_par_tag, depthwise_tag=depthwise_tag).cuda() # self.body1 = Block(n_feats, kernel_size, act=act, res_scale=args.res_scale, wn=wn, res_par=res_par_tag, depthwise_tag=depthwise_tag).cuda() # self.body2 = DenseBlock(n_feats, kernel_size, act=act, res_scale=args.res_scale, wn=wn, res_par=res_par_tag, depthwise_tag=depthwise_tag).cuda() # self.body3 = DenseBlock(n_feats, kernel_size, act=act, res_scale=args.res_scale, wn=wn, res_par=res_par_tag, depthwise_tag=depthwise_tag).cuda() # self.body4 = DenseBlock(n_feats, kernel_size, act=act, res_scale=args.res_scale, wn=wn, res_par=res_par_tag, depthwise_tag=depthwise_tag).cuda() # self.skip = nn.Sequential(*skip) skip = [] skip.append( wn(nn.Conv2d(args.n_colors, out_feats, 5, padding=5//2)) ) skip.append(nn.PixelShuffle(scale)) if self.upsample_strategy == 0: self.skip = Upsample(scale_factor=scale) elif self.upsample_strategy == 1: self.skip = nn.Sequential(*skip) self.att_tag = att_tag
def make_adversarial_examples(cls, image, true_label, target_label, args, attack_norm, model_to_fool): ''' The attack process for generating adversarial examples with priors. ''' # Initial setup orig_images = image.clone() prior_size = IMAGE_SIZE[ args.dataset][0] if not args.tiling else args.tile_size assert args.tiling == (args.dataset == "ImageNet") if args.tiling: upsampler = Upsample(size=(IMAGE_SIZE[args.dataset][0], IMAGE_SIZE[args.dataset][1])) else: upsampler = lambda x: x total_queries = torch.zeros(args.batch_size).cuda() prior = torch.zeros(args.batch_size, IN_CHANNELS[args.dataset], prior_size, prior_size).cuda() dim = prior.nelement( ) / args.batch_size # nelement() --> total number of elements prior_step = BanditAttack.gd_prior_step if attack_norm == 'l2' else BanditAttack.eg_step image_step = BanditAttack.l2_image_step if attack_norm == 'l2' else BanditAttack.linf_step proj_maker = BanditAttack.l2_proj if attack_norm == 'l2' else BanditAttack.linf_proj # 调用proj_maker返回的是一个函数 proj_step = proj_maker(orig_images, args.epsilon) # Loss function criterion = BanditAttack.cw_loss if args.loss == "cw" else BanditAttack.xent_loss # Original classifications orig_classes = model_to_fool(image).argmax(1).cuda() correct_classified_mask = (orig_classes == true_label).float() not_dones_mask = correct_classified_mask.clone() # 分类分对的mask log.info("correct ratio : {:.3f}".format( correct_classified_mask.mean())) normalized_q1 = deque(maxlen=100) normalized_q2 = deque(maxlen=100) images = deque(maxlen=100) logits_q1_list = deque(maxlen=100) logits_q2_list = deque(maxlen=100) # 有选择的选择一个段落,比如说从中间开始截取一个段落 assert args.max_queries // 2 >= 100 slice_iteration_end = random.randint(100, args.max_queries // 2) for i in range(slice_iteration_end): if not args.nes: ## Updating the prior: # Create noise for exporation, estimate the gradient, and take a PGD step exp_noise = args.exploration * torch.randn_like(prior) / ( dim**0.5 ) # parameterizes the exploration to be done around the prior exp_noise = exp_noise.cuda() # Query deltas for finite difference estimator q1 = upsampler( prior + exp_noise ) # 这就是Finite Difference算法, prior相当于论文里的v,这个prior也会更新,把梯度累积上去 q2 = upsampler( prior - exp_noise) # prior 相当于累积的更新量,用这个更新量,再去修改image,就会变得非常准 # Loss points for finite difference estimator logits_q1 = model_to_fool(image + args.fd_eta * q1 / BanditAttack.norm(q1)) logits_q2 = model_to_fool(image + args.fd_eta * q2 / BanditAttack.norm(q2)) l1 = criterion(logits_q1, true_label, target_label) l2 = criterion(logits_q2, true_label, target_label) if i >= slice_iteration_end - 100: images.append(image.detach().cpu().numpy()) normalized_q1.append( (args.fd_eta * q1 / BanditAttack.norm(q1)).detach().cpu().numpy()) normalized_q2.append( (args.fd_eta * q2 / BanditAttack.norm(q2)).detach().cpu().numpy()) logits_q1_list.append(logits_q1.detach().cpu().numpy()) logits_q2_list.append(logits_q2.detach().cpu().numpy()) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (args.fd_eta * args.exploration ) # 方向导数 , l1和l2是loss # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # B, C, H, W, # Update the prior with the estimated gradient prior = prior_step( prior, est_grad, args.online_lr) # 注意,修正的是prior,这就是bandit算法的精髓 else: # NES方法 prior = torch.zeros_like(image).cuda() for grad_iter_t in range(args.gradient_iters): exp_noise = torch.randn_like(image) / (dim**0.5) logits_q1 = model_to_fool(image + args.fd_eta * exp_noise) logits_q2 = model_to_fool(image - args.fd_eta * exp_noise) l1 = criterion(logits_q1, true_label, target_label) l2 = criterion(logits_q2, true_label, target_label) est_deriv = (l1 - l2) / args.fd_eta prior += est_deriv.view(-1, 1, 1, 1) * exp_noise if i * args.gradient_iters + grad_iter_t >= slice_iteration_end - 100: images.append(image.detach().cpu().numpy()) normalized_q1.append( (args.fd_eta * exp_noise).detach().cpu().numpy()) normalized_q2.append( (-args.fd_eta * exp_noise).detach().cpu().numpy()) logits_q1_list.append(logits_q1.detach().cpu().numpy()) logits_q2_list.append(logits_q2.detach().cpu().numpy()) # Preserve images that are already done, # Unless we are specifically measuring gradient estimation prior = prior * not_dones_mask.view(-1, 1, 1, 1).cuda() ## Update the image: # take a pgd step using the prior new_im = image_step( image, upsampler(prior * correct_classified_mask.view(-1, 1, 1, 1)), args.image_lr) # prior放大后相当于累积的更新量,可以用来更新 image = proj_step(new_im) image = torch.clamp(image, 0, 1) ## Continue query count total_queries += 2 * args.gradient_iters * not_dones_mask # gradient_iters是一个int值 with torch.no_grad(): adv_pred = model_to_fool(image).argmax(1) if args.targeted: not_dones_mask = not_dones_mask * ( 1 - adv_pred.eq(target_label).float() ).float() # not_done初始化为 correct, shape = (batch_size,) else: not_dones_mask = not_dones_mask * adv_pred.eq( true_label).float() # 只要是跟原始label相等的,就还需要query,还没有成功 ## Logging stuff success_mask = (1 - not_dones_mask) * correct_classified_mask num_success = success_mask.sum() current_success_rate = ( num_success.detach().cpu() / correct_classified_mask.detach().cpu().sum()).cpu().item() if num_success == 0: success_queries = 0 else: success_queries = ((success_mask * total_queries).sum() / num_success).cpu().item() max_curr_queries = total_queries.max().cpu().item() # log.info("%d-th: Queries: %d | Success rate: %f | Average queries: %f" % (i, max_curr_queries, current_success_rate, success_queries)) # if current_success_rate == 1.0: # break normalized_q1 = np.ascontiguousarray( np.transpose(np.stack(list(normalized_q1)), axes=(1, 0, 2, 3, 4))) normalized_q2 = np.ascontiguousarray( np.transpose(np.stack(list(normalized_q2)), axes=(1, 0, 2, 3, 4))) images = np.ascontiguousarray( np.transpose(np.stack(list(images)), axes=(1, 0, 2, 3, 4))) logits_q1_list = np.ascontiguousarray( np.transpose(np.stack(list(logits_q1_list)), axes=(1, 0, 2))) # B,T,#class logits_q2_list = np.ascontiguousarray( np.transpose(np.stack(list(logits_q2_list)), axes=(1, 0, 2))) # B,T,#class return { 'average_queries': success_queries, 'num_correctly_classified': correct_classified_mask.sum().cpu().item(), 'success_rate': current_success_rate, 'images_orig': orig_images.cpu().numpy(), 'images_adv': image.cpu().numpy(), 'all_queries': total_queries.cpu().numpy(), 'correctly_classified': correct_classified_mask.cpu().numpy(), 'success': success_mask.cpu().numpy(), "q1": normalized_q1, "q2": normalized_q2, "images": images, "logits_q1": logits_q1_list, "logits_q2": logits_q2_list }
def make_adversarial_examples(image, true_label, args): ''' The main process for generating adversarial examples with priors. ''' # added. initialize adam adam_step = 1 adam_first = ch.zeros_like(image) adam_second = ch.zeros_like(image) beta1, beta2 = 0.9, 0.999 # initialize image lr image_lr = args.image_lr * np.ones_like(true_label.cpu().numpy()) image_lr_ch = ch.from_numpy(image_lr).view(-1, 1, 1, 1).type(ch.FloatTensor).cuda() last_losses = [] plateau_length = args.plateau_length min_lr = args.image_lr / args.min_ratio # Initial setup batch_size = list(image.size())[0] prior_size = IMAGENET_SL if not args.tiling else args.tile_size print("prior size:", prior_size) upsampler = Upsample(size=(IMAGENET_SL, IMAGENET_SL)) total_queries = ch.zeros(batch_size) prior = ch.zeros(batch_size, 3, prior_size, prior_size) dim = prior.nelement() / batch_size prior_step = gd_prior_step if args.mode == 'l2' else eg_step image_step = l2_image_step if args.mode == 'l2' else linf_step proj_maker = l2_proj if args.mode == 'l2' else linf_proj proj_step = proj_maker(image, args.epsilon) # Loss function criterion = ch.nn.CrossEntropyLoss(reduction='none') L = lambda x: criterion(model_to_fool(batch_norm(x)), true_label) losses = L(image) # Original classifications orig_images = image.clone() orig_classes = model_to_fool(batch_norm(image)).argmax(1).cuda() if args.targeted: correct_classified_mask = (orig_classes != true_label).float() else: correct_classified_mask = (orig_classes == true_label).float() total_ims = correct_classified_mask.sum() print('initially correct images:', total_ims.cpu().numpy()) not_dones_mask = correct_classified_mask.clone() if args.targeted: max_queries = 100000 else: max_queries = args.max_queries while not ch.any(total_queries > max_queries): if not args.nes: ## Updating the prior: # Create noise for exporation, estimate the gradient, and take a PGD step exp_noise = args.exploration * ch.randn_like(prior) / (dim**0.5) # Query deltas for finite difference estimator q1 = upsampler(prior + exp_noise) q2 = upsampler(prior - exp_noise) # Loss points for finite difference estimator l1 = L(image + args.fd_eta * q1 / norm(q1)) # L(prior + c*noise) l2 = L(image + args.fd_eta * q2 / norm(q2)) # L(prior - c*noise) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (args.fd_eta * args.exploration) # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # Update the prior with the estimated gradient prior = prior_step(prior, est_grad, args.online_lr) else: prior = ch.zeros_like(image) for _ in range(args.gradient_iters): exp_noise = ch.randn_like(image) / (dim**0.5) est_deriv = (L(image + args.fd_eta * exp_noise) - L(image - args.fd_eta * exp_noise)) / args.fd_eta prior += est_deriv.view(-1, 1, 1, 1) * exp_noise # Preserve images that are already done prior = prior * not_dones_mask.view(-1, 1, 1, 1) ## Update the image: # take a pgd step using the prior # added. adam update if args.adam: g = upsampler(prior) adam_first = beta1 * adam_first + (1 - beta1) * g adam_second = beta2 * adam_second + (1 - beta2) * g * g first_unbias = adam_first / (1 - beta1**adam_step) second_unbias = adam_second / (1 - beta2**adam_step) adam_step += 1 if args.targeted: new_im = image - image_lr_ch * ch.sign( first_unbias / (ch.sqrt(second_unbias) + 1e-7)) else: new_im = image + image_lr_ch * ch.sign( first_unbias / (ch.sqrt(second_unbias) + 1e-7)) else: new_im = image_step(image, upsampler(prior), image_lr_ch) image = proj_step(new_im) image = ch.clamp(image, 0, 1) if args.mode == 'l2': if not ch.all(norm(image - orig_images) <= args.epsilon + 1e-3): raise ValueError("OOB") else: if not (image - orig_images).max() <= args.epsilon + 1e-3: raise ValueError("OOB") ## Continue query count (modified) total_queries += 2 * args.gradient_iters * not_dones_mask if args.targeted: not_dones_mask = not_dones_mask * ((model_to_fool( batch_norm(image)).argmax(1) != true_label).float()) else: not_dones_mask = not_dones_mask * ((model_to_fool( batch_norm(image)).argmax(1) == true_label).float()) ## Logging stuff new_losses = L(image) success_mask = (1 - not_dones_mask) * correct_classified_mask num_success = success_mask.sum() current_success_rate = (num_success / correct_classified_mask.sum()).cpu().item() success_queries = ((success_mask * total_queries).sum() / num_success).cpu().item() not_done_loss = ((new_losses * not_dones_mask).sum() / not_dones_mask.sum()).cpu().item() max_curr_queries = total_queries.max().cpu().item() if args.log_progress and max_curr_queries % 100 == 0: print("Queries: %d | Success rate: %f | Average queries: %f" % (max_curr_queries, current_success_rate, success_queries)) #print("curr loss:", np.mean(new_losses.cpu().numpy())) if current_success_rate == 1.0: break # learning rate decay if args.decay: last_losses.append(new_losses.cpu().numpy()) last_losses = last_losses[-plateau_length:] if len(last_losses) == plateau_length: if args.targeted: image_lr = np.where( last_losses[-1] < last_losses[0], np.maximum(image_lr / args.plateau_drop, min_lr), image_lr) else: image_lr = np.where( last_losses[-1] > last_losses[0], np.maximum(image_lr / args.plateau_drop, min_lr), image_lr) # Return results return { 'average_queries': success_queries, # Average queries for this batch 'num_correctly_classified': correct_classified_mask.sum().cpu().item( ), # Number of originally correctly classified images 'success_rate': current_success_rate, # Success rate 'images_orig': orig_images.cpu().numpy(), # Original images 'images_adv': image.cpu().numpy(), # Adversarial images 'all_queries': total_queries.cpu().numpy(), # Number of queries used for each image 'correctly_classified': correct_classified_mask.cpu().numpy( ), # 0/1 mask for whether image was originally classified 'success': success_mask.cpu().numpy( ), # 0/1 mask for whether the attack succeeds on each image }
def make_adversarial_examples(image, true_label, model_to_fool, nes=True, mode="linf", epsilon=0.04, max_queries=10000, gradient_iters=50, fd_eta=0.05, image_lr=0.0001, online_lr=100, exploration=1, prior_size=50, log_progress=True): ''' The main process for generating adversarial examples with priors. ''' # Initial setup batch_size = image.size(0) total_queries = ch.zeros(batch_size) upsampler = Upsample(size=(image.size(2), image.size(2))) prior = ch.zeros(batch_size, 3, prior_size, prior_size).cuda() dim = prior.nelement() / batch_size prior_step = gd_prior_step if mode == 'l2' else eg_step image_step = l2_image_step if mode == 'l2' else linf_step proj_maker = l2_proj if mode == 'l2' else linf_proj proj_step = proj_maker(image, epsilon) def normalized_eval(x): x_copy = x.clone() x_copy = ch.stack([F.normalize(x_copy[i], [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) \ for i in range(batch_size)]) return model_to_fool(x_copy) # Loss function criterion = ch.nn.CrossEntropyLoss(reduction='none') losses = criterion(normalized_eval(image), true_label) # Original classifications orig_images = image.clone() orig_classes = normalized_eval(image).argmax(1).cuda() correct_classified_mask = (orig_classes == true_label).cpu().float() total_ims = correct_classified_mask.cpu().sum() not_dones_mask = correct_classified_mask.cpu().clone() t = 0 while not ch.any(total_queries > max_queries): t += gradient_iters * 2 if t >= max_queries: break if not nes: ## Updating the prior: # Create noise for exporation, estimate the gradient, and take a PGD step exp_noise = exploration * ch.randn_like(prior) / (dim**0.5) # Query deltas for finite difference estimator q1 = upsampler(prior + exp_noise) q2 = upsampler(prior - exp_noise) # Loss points for finite difference estimator l1 = criterion(normalized_eval(image + fd_eta * q1 / norm(q1)), true_label) # L(prior + c*noise) l2 = criterion(normalized_eval(image + fd_eta * q2 / norm(q2)), true_label) # L(prior - c*noise) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (fd_eta * exploration) # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # Update the prior with the estimated gradient prior = prior_step(prior, est_grad, online_lr) else: prior = ch.zeros_like(image) for _ in range(gradient_iters): exp_noise = ch.randn_like(image) / (dim**0.5) est_deriv = ( criterion(normalized_eval(image + fd_eta * exp_noise), true_label) - criterion(normalized_eval(image - fd_eta * exp_noise), true_label)) / fd_eta prior += est_deriv.view(-1, 1, 1, 1) * exp_noise # Preserve images that are already done, # Unless we are specifically measuring gradient estimation prior = prior * not_dones_mask.view(-1, 1, 1, 1) ## Update the image: # take a pgd step using the prior new_im = image_step( image, upsampler(prior * correct_classified_mask.cuda().view(-1, 1, 1, 1)), image_lr) image = proj_step(new_im) image = ch.clamp(image, 0, 1) ## Continue query count total_queries += 2 * gradient_iters * not_dones_mask not_dones_mask = not_dones_mask * ( (normalized_eval(image).argmax(1) == true_label).cpu().float()) ## Logging stuff new_losses = criterion(normalized_eval(image), true_label).cpu() success_mask = (1 - not_dones_mask) * correct_classified_mask num_success = success_mask.cpu().sum() current_success_rate = (num_success / correct_classified_mask.sum()).cpu().item() success_queries = ((success_mask * total_queries).sum() / num_success).cpu().item() not_done_loss = ((new_losses * not_dones_mask).cpu().sum() / not_dones_mask.sum()).item() max_curr_queries = total_queries.max().cpu().item() if log_progress: print("Queries: %d | Success rate: %f | Average queries: %f" % (max_curr_queries, current_success_rate, success_queries)) if current_success_rate == 1.0: break if batch_size == 1: return { "image_adv": image.cpu().numpy(), "prediction": normalized_eval(image).argmax(1), "elapsed_budget": total_queries.cpu().numpy()[0], "success": success_mask.cpu().numpy()[0] == True } return { 'average_queries': success_queries, 'num_correctly_classified': correct_classified_mask.sum().cpu().item(), 'success_rate': current_success_rate, 'images_orig': orig_images.cpu().numpy(), 'images_adv': image.cpu().numpy(), 'all_queries': total_queries.cpu().numpy(), 'correctly_classified': correct_classified_mask.cpu().numpy(), 'success': success_mask.cpu().numpy() }
def make_adversarial_examples(self, batch_index, images, true_labels, args, target_model): ''' The attack process for generating adversarial examples with priors. ''' prior_size = target_model.input_size[-1] if not args.tiling else args.tile_size assert args.tiling == (args.dataset == "ImageNet") if args.tiling: upsampler = Upsample(size=(target_model.input_size[-2], target_model.input_size[-1])) else: upsampler = lambda x: x with torch.no_grad(): logit = target_model(images) pred = logit.argmax(dim=1) query = torch.zeros(args.batch_size).cuda() correct = pred.eq(true_labels).float() # shape = (batch_size,) not_done = correct.clone() # shape = (batch_size,) selected = torch.arange(batch_index * args.batch_size, min((batch_index + 1) * args.batch_size, self.total_images)) # 选择这个batch的所有图片的index if args.targeted: if args.target_type == 'random': target_labels = torch.randint(low=0, high=CLASS_NUM[args.dataset], size=true_labels.size()).long().cuda() invalid_target_index = target_labels.eq(true_labels) while invalid_target_index.sum().item() > 0: target_labels[invalid_target_index] = torch.randint(low=0, high=logit.shape[1], size=target_labels[invalid_target_index].shape).long().cuda() invalid_target_index = target_labels.eq(true_labels) elif args.target_type == 'least_likely': target_labels = logit.argmin(dim=1) elif args.target_type == "increment": target_labels = torch.fmod(true_labels + 1, CLASS_NUM[args.dataset]) else: raise NotImplementedError('Unknown target_type: {}'.format(args.target_type)) else: target_labels = None prior = torch.zeros(args.batch_size, IN_CHANNELS[args.dataset], prior_size, prior_size).cuda() dim = prior.nelement() / args.batch_size # nelement() --> total number of elements prior_step = self.gd_prior_step if args.norm == 'l2' else self.eg_prior_step image_step = self.l2_image_step if args.norm == 'l2' else self.linf_image_step proj_maker = self.l2_proj if args.norm == 'l2' else self.linf_proj # 调用proj_maker返回的是一个函数 proj_step = proj_maker(images, args.epsilon) criterion = self.cw_loss if args.loss == "cw" else self.xent_loss # Loss function adv_images = images.clone() for step_index in range(args.max_queries // 2): # Create noise for exporation, estimate the gradient, and take a PGD step exp_noise = args.exploration * torch.randn_like(prior) / (dim ** 0.5) # parameterizes the exploration to be done around the prior # Query deltas for finite difference estimator exp_noise = exp_noise.cuda() q1 = upsampler(prior + exp_noise) # 这就是Finite Difference算法, prior相当于论文里的v,这个prior也会更新,把梯度累积上去 q2 = upsampler(prior - exp_noise) # prior 相当于累积的更新量,用这个更新量,再去修改image,就会变得非常准 # Loss points for finite difference estimator q1_images = adv_images + args.fd_eta * q1 / self.norm(q1) q2_images = adv_images + args.fd_eta * q2 / self.norm(q2) with torch.no_grad(): q1_logits = target_model(q1_images) q2_logits = target_model(q2_images) l1 = criterion(q1_logits, true_labels, target_labels) l2 = criterion(q2_logits, true_labels, target_labels) # Finite differences estimate of directional derivative est_deriv = (l1 - l2) / (args.fd_eta * args.exploration) # 方向导数 , l1和l2是loss # 2-query gradient estimate est_grad = est_deriv.view(-1, 1, 1, 1) * exp_noise # B, C, H, W, # Update the prior with the estimated gradient prior = prior_step(prior, est_grad, args.online_lr) # 注意,修正的是prior,这就是bandit算法的精髓 grad = upsampler(prior) # prior相当于梯度 ## Update the image: # take a pgd step using the prior adv_images = image_step(adv_images, grad * correct.view(-1, 1, 1, 1), args.image_lr) # prior放大后相当于累积的更新量,可以用来更新 adv_images = proj_step(adv_images) adv_images = torch.clamp(adv_images, 0, 1) with torch.no_grad(): adv_logit = target_model(adv_images) adv_pred = adv_logit.argmax(dim=1) adv_prob = F.softmax(adv_logit, dim=1) adv_loss = criterion(adv_logit, true_labels, target_labels) ## Continue query count query = query + 2 * not_done if args.targeted: not_done = not_done * (1 - adv_pred.eq(target_labels).float()).float() # not_done初始化为 correct, shape = (batch_size,) else: not_done = not_done * adv_pred.eq(true_labels).float() # 只要是跟原始label相等的,就还需要query,还没有成功 success = (1 - not_done) * correct success_query = success * query not_done_loss = adv_loss * not_done not_done_prob = adv_prob[torch.arange(args.batch_size), true_labels] * not_done log.info('Attacking image {} - {} / {}, step {}, max query {}'.format( batch_index * args.batch_size, (batch_index + 1) * args.batch_size, self.total_images, step_index + 1, int(query.max().item()) )) log.info(' correct: {:.4f}'.format(correct.mean().item())) log.info(' not_done: {:.4f}'.format(not_done[correct.byte()].mean().item())) log.info(' fd_scalar: {:.9f}'.format((l1 - l2).mean().item())) if success.sum().item() > 0: log.info(' mean_query: {:.4f}'.format(success_query[success.byte()].mean().item())) log.info(' median_query: {:.4f}'.format(success_query[success.byte()].median().item())) if not_done.sum().item() > 0: log.info(' not_done_loss: {:.4f}'.format(not_done_loss[not_done.byte()].mean().item())) log.info(' not_done_prob: {:.4f}'.format(not_done_prob[not_done.byte()].mean().item())) if not not_done.byte().any(): # all success break for key in ['query', 'correct', 'not_done', 'success', 'success_query', 'not_done_loss', 'not_done_prob']: value_all = getattr(self, key+"_all") value = eval(key) value_all[selected] = value.detach().float().cpu() # 由于value_all是全部图片都放在一个数组里,当前batch选择出来