def _verify_and_process_inputs(self, x, y): if self.targeted: assert y is not None if not self.targeted: if y is None: y = self._get_predicted_label(x) x = replicate_input(x) y = replicate_input(y) return x, y
def perturb_single(self, x, y): # x shape [C * H * W] if self.comply_with_foolbox is True: np.random.seed(233333) rand_np = np.random.permutation(x.shape[1] * x.shape[2]) pixels = torch.from_numpy(rand_np) else: pixels = torch.randperm(x.shape[1] * x.shape[2]) pixels = pixels.to(x.device) pixels = pixels[:self.max_pixels] for ii in range(self.max_pixels): row = pixels[ii] % x.shape[2] col = pixels[ii] // x.shape[2] for val in [self.clip_min, self.clip_max]: adv = replicate_input(x) for mm in range(x.shape[0]): adv[mm, row, col] = val out_label = self._get_predicted_label(adv.unsqueeze(0)) if self.targeted is True: if int(out_label[0]) == int(y): return adv else: if int(out_label[0]) != int(y): return adv return x
def _perturb_seed_pixel(self, x, p, row, col): x_pert = replicate_input(x) for ii in range(x.shape[0]): if x[ii, row, col] > 0: x_pert[ii, row, col] = p elif x[ii, row, col] < 0: x_pert[ii, row, col] = -1 * p else: x_pert[ii, row, col] = 0 return x_pert
def perturb(self, source, guide, delta=None): """ Given source, returns their adversarial counterparts with representations close to that of the guide. :param source: input tensor which we want to perturb. :param guide: targeted input. :param delta: tensor contains the random initialization. :return: tensor containing perturbed inputs. """ # Initialization if delta is None: delta = torch.zeros_like(source) if self.rand_init: delta = delta.uniform_(-self.eps, self.eps) else: delta = delta.detach() delta.requires_grad_() source = replicate_input(source) guide = replicate_input(guide) guide_ftr = self.predict(guide).detach() xadv = perturb_iterative(source, guide_ftr, self.predict, self.nb_iter, eps_iter=self.eps_iter, loss_fn=self.loss_fn, minimize=True, ord=np.inf, eps=self.eps, clip_min=self.clip_min, clip_max=self.clip_max, delta_init=delta) xadv = clamp(xadv, self.clip_min, self.clip_max) return xadv.data
def perturb(self, x, y=None): x, y = self._verify_and_process_inputs(x, y) # Initialization if y is None: y = self._get_predicted_label(x) x = replicate_input(x) batch_size = len(x) coeff_lower_bound = x.new_zeros(batch_size) coeff_upper_bound = x.new_ones(batch_size) * CARLINI_COEFF_UPPER loss_coeffs = torch.ones_like(y).float() * self.initial_const final_l2distsqs = [CARLINI_L2DIST_UPPER] * batch_size final_labels = [INVALID_LABEL] * batch_size final_advs = x x_atanh = self._get_arctanh_x(x) y_onehot = to_one_hot(y, self.num_classes).float() final_l2distsqs = torch.FloatTensor(final_l2distsqs).to(x.device) final_labels = torch.LongTensor(final_labels).to(x.device) # Start binary search for outer_step in range(self.binary_search_steps): delta = nn.Parameter(torch.zeros_like(x)) optimizer = optim.Adam([delta], lr=self.learning_rate) cur_l2distsqs = [CARLINI_L2DIST_UPPER] * batch_size cur_labels = [INVALID_LABEL] * batch_size cur_l2distsqs = torch.FloatTensor(cur_l2distsqs).to(x.device) cur_labels = torch.LongTensor(cur_labels).to(x.device) prevloss = PREV_LOSS_INIT if (self.repeat and outer_step == (self.binary_search_steps - 1)): loss_coeffs = coeff_upper_bound for ii in range(self.max_iterations): loss, l2distsq, output, adv_img = \ self._forward_and_update_delta( optimizer, x_atanh, delta, y_onehot, loss_coeffs) if self.abort_early: if ii % (self.max_iterations // NUM_CHECKS or 1) == 0: if loss > prevloss * ONE_MINUS_EPS: break prevloss = loss self._update_if_smaller_dist_succeed( adv_img, y, output, l2distsq, batch_size, cur_l2distsqs, cur_labels, final_l2distsqs, final_labels, final_advs) self._update_loss_coeffs( y, cur_labels, batch_size, loss_coeffs, coeff_upper_bound, coeff_lower_bound) return final_advs
def perturb(self, x, y=None): x, y = self._verify_and_process_inputs(x, y) # Initialization if y is None: y = self._get_predicted_label(x) x = replicate_input(x) batch_size = len(x) coeff_lower_bound = x.new_zeros(batch_size) coeff_upper_bound = x.new_ones(batch_size) * COEFF_UPPER loss_coeffs = torch.ones_like(y).float() * self.initial_const final_dist = [DIST_UPPER] * batch_size final_labels = [INVALID_LABEL] * batch_size final_advs = x.clone() y_onehot = to_one_hot(y, self.num_classes).float() final_dist = torch.FloatTensor(final_dist).to(x.device) final_labels = torch.LongTensor(final_labels).to(x.device) # Start binary search for outer_step in range(self.binary_search_steps): self.global_step = 0 # slack vector from the paper yy_k = nn.Parameter(x.clone()) xx_k = x.clone() cur_dist = [DIST_UPPER] * batch_size cur_labels = [INVALID_LABEL] * batch_size cur_dist = torch.FloatTensor(cur_dist).to(x.device) cur_labels = torch.LongTensor(cur_labels).to(x.device) prevloss = PREV_LOSS_INIT if (self.repeat and outer_step == (self.binary_search_steps - 1)): loss_coeffs = coeff_upper_bound lr = self.learning_rate for ii in range(self.max_iterations): # reset gradient if yy_k.grad is not None: yy_k.grad.detach_() yy_k.grad.zero_() # loss over yy_k with only L2 same as C&W # we don't update L1 loss with SGD because we use ISTA output = self.predict(yy_k) l2distsq = calc_l2distsq(yy_k, x) loss_opt = self._loss_fn(output, y_onehot, None, l2distsq, loss_coeffs, opt=True) loss_opt.backward() # gradient step yy_k.data.add_(-lr, yy_k.grad.data) self.global_step += 1 # ploynomial decay of learning rate lr = self.init_learning_rate * \ (1 - self.global_step / self.max_iterations)**0.5 yy_k, xx_k = self._fast_iterative_shrinkage_thresholding( x, yy_k, xx_k) # loss ElasticNet or L1 over xx_k output = self.predict(xx_k) l2distsq = calc_l2distsq(xx_k, x) l1dist = calc_l1dist(xx_k, x) if self.decision_rule == 'EN': dist = l2distsq + (l1dist * self.beta) elif self.decision_rule == 'L1': dist = l1dist loss = self._loss_fn(output, y_onehot, l1dist, l2distsq, loss_coeffs) if self.abort_early: if ii % (self.max_iterations // NUM_CHECKS or 1) == 0: if loss > prevloss * ONE_MINUS_EPS: break prevloss = loss self._update_if_smaller_dist_succeed(xx_k.data, y, output, dist, batch_size, cur_dist, cur_labels, final_dist, final_labels, final_advs) self._update_loss_coeffs(y, cur_labels, batch_size, loss_coeffs, coeff_upper_bound, coeff_lower_bound) return final_advs
def perturb_single(self, x, y): # x shape C * H * W rescaled_x = replicate_input(x) best_img = None best_dist = np.inf rescaled_x, lb, ub = self._rescale_to_m0d5_to_0d5(rescaled_x, vmin=self.clip_min, vmax=self.clip_max) if self.comply_with_foolbox is True: np.random.seed(233333) init_rand = np.random.permutation(x.shape[1] * x.shape[2]) else: init_rand = None # Algorithm 3 in v1 pxy = self._random_sample_seeds(x.shape[1], x.shape[2], seed_ratio=self.seed_ratio, max_nb_seeds=self.max_nb_seeds, init_rand=init_rand) pxy = pxy.to(x.device) ii = 0 if self.comply_with_foolbox: adv = rescaled_x while ii < self.round_ub: if not self.comply_with_foolbox: adv = replicate_input(rescaled_x) # Computing the function g using the neighbourhood if self.comply_with_foolbox: rand_np = np.random.permutation(len(pxy))[:self.max_nb_seeds] pxy = pxy[torch.from_numpy(rand_np)] else: pxy = pxy[torch.randperm(len(pxy))[:self.max_nb_seeds]] pert_lst = [ self._perturb_seed_pixel(adv, self.p, int(row), int(col)) for row, col in pxy ] # Compute the score for each pert in the list scores, curr_best_img, curr_best_dist = self._rescale_x_score( self.predict, pert_lst, y, x, best_dist) if curr_best_img is not None: best_img = curr_best_img best_dist = curr_best_dist _, indices = torch.sort(scores) indices = indices[:self.t] pxy_star = pxy[indices.data.cpu()] # Generation of the perturbed image adv for row, col in pxy_star: for b in range(x.shape[0]): adv[b, int(row), int(col)] = self._cyclic(self.r, lb, ub, adv[b, int(row), int(col)]) # Check whether the perturbed image is an adversarial image revert_adv = self._revert_rescale(adv) curr_lb = self._get_predicted_label(revert_adv.unsqueeze(0)) curr_dist = torch.sum((x - revert_adv)**2) if (is_successful(int(curr_lb), y, self.targeted) and curr_dist < best_dist): best_img = revert_adv best_dist = curr_dist return best_img elif is_successful(curr_lb, y, self.targeted): return best_img pxy = [(row, col) for rowcenter, colcenter in pxy_star for row in range( int(rowcenter) - self.d, int(rowcenter) + self.d + 1) for col in range( int(colcenter) - self.d, int(colcenter) + self.d + 1)] pxy = list( set((row, col) for row, col in pxy if (0 <= row < x.shape[2] and 0 <= col < x.shape[1]))) pxy = torch.FloatTensor(pxy) ii += 1 if best_img is None: return x return best_img