def detect(self, **kwargs): super().detect(**kwargs) target_class = self.attack.target_class self.attack.mark.random_pos = False self.attack.mark.height_offset = 0 self.attack.mark.width_offest = 0 if not self.random_pos: self.real_mask = self.attack.mark.mask mark_list, mask_list, loss_list = self.get_potential_triggers() mask_norms = mask_list.flatten(start_dim=1).norm(p=1, dim=1) print('mask norms: ', mask_norms) print('mask MAD: ', normalize_mad(mask_norms)) print('loss: ', loss_list) print('loss MAD: ', normalize_mad(loss_list)) if not self.random_pos: overlap = jaccard_idx(mask_list[self.attack.target_class], self.real_mask, select_num=self.attack.mark.mark_height * self.attack.mark.mark_width) print(f'Jaccard index: {overlap:.3f}') if not os.path.exists(self.folder_path): os.makedirs(self.folder_path) mark_list = [to_numpy(i) for i in mark_list] mask_list = [to_numpy(i) for i in mask_list] loss_list = [to_numpy(i) for i in loss_list] np.savez(self.folder_path + self.get_filename(target_class=target_class) + '.npz', mark_list=mark_list, mask_list=mask_list, loss_list=loss_list) print('Defense results saved at: ' + self.folder_path + self.get_filename(target_class=target_class) + '.npz')
def grad_cam(self, _input: torch.FloatTensor, _class: list[int]) -> np.ndarray: if isinstance(_class, int): _class = [_class] * len(_input) _class = torch.tensor(_class).to(_input.device) feats = self._model.get_fm(_input).detach() # (N,C,H,W) feats.requires_grad_() _output: torch.FloatTensor = self._model.pool(feats) _output: torch.FloatTensor = self._model.flatten(_output) _output: torch.FloatTensor = self._model.classifier(_output) _output: torch.FloatTensor = _output.gather( dim=1, index=_class.unsqueeze(1)).sum() grad: torch.FloatTensor = torch.autograd.grad(_output, feats)[0] # (N,C,H,W) feats.requires_grad_(False) weights: torch.FloatTensor = grad.mean(dim=-2, keepdim=True).mean( dim=-1, keepdim=True) # (N,C,1,1) heatmap: torch.FloatTensor = (feats * weights).sum(dim=1).clamp( 0) # (N,H,W) heatmap.sub_( heatmap.min(dim=-2, keepdim=True)[0].min(dim=-1, keepdim=True)[0]) heatmap.div_( heatmap.max(dim=-2, keepdim=True)[0].max(dim=-1, keepdim=True)[0]) heatmap = (to_numpy(heatmap).transpose(1, 2, 0) * 255).astype(np.uint8) heatmap = Image.fromarray(heatmap).resize(_input.shape[-2:], resample=Image.BICUBIC) heatmap = np.array(heatmap) if len(heatmap.shape) == 2: heatmap = heatmap.reshape(heatmap.shape[0], heatmap.shape[1], 1) heatmap = heatmap.transpose(2, 0, 1).astype(float) / 255 # (N, H, W) return heatmap
def poly_fit(x: np.ndarray, y: np.ndarray, x_grid: np.ndarray, degree: int = 1) -> np.ndarray: fit_data = to_numpy(y) z = np.polyfit(x, fit_data, degree) y_grid = np.polyval(z, x_grid) return y_grid
def atan_fit(x: np.ndarray, y: np.ndarray, x_grid: np.ndarray, degree: int = 1, mean_bias: float = 0.0, scale_multiplier: float = 1.0) -> np.ndarray: mean = (max(y) + min(y)) / 2 + mean_bias scale = max(abs(y - mean)) * scale_multiplier fit_data = to_numpy(torch.as_tensor((y - mean) / scale).tan()) z = np.polyfit(x, fit_data, degree) y_grid = np.tanh(np.polyval(z, x_grid)) * scale + mean return y_grid
def normalize(x: np.ndarray, _min: float = None, _max: float = None, tgt_min: float = 0.0, tgt_max: float = 1.0) -> np.ndarray: x = to_numpy(x) if _min is None: _min = x.min() if _max is None: _max = x.max() x = (x - _min) / (_max - _min) * (tgt_max - tgt_min) + tgt_min return x
def avg_smooth(x: np.ndarray, window: int = 3) -> np.ndarray: _x = torch.as_tensor(x) new_x = torch.zeros_like(_x) for i in range(len(_x)): if i < window // 2: new_x[i] = (_x[0] * (window // 2 - i) + _x[:i + (window + 1) // 2].sum()) / window elif i >= len(_x) - (window - 1) // 2: new_x[i] = (_x[-1] * ((window + 1) // 2 - len(_x) + i) + _x[i - window // 2:].sum()) / window else: new_x[i] = _x[i - window // 2:i + 1 + (window - 1) // 2].mean() return to_numpy(new_x) if isinstance(x, np.ndarray) else new_x
def detect(self, **kwargs): super().detect(**kwargs) clean_entropy = [] poison_entropy = [] loader = self.dataset.loader['valid'] if env['tqdm']: loader = tqdm(loader) for i, data in enumerate(loader): _input, _label = self.model.get_data(data) poison_input = self.attack.add_mark(_input) clean_entropy.append(self.check(_input, _label)) poison_entropy.append(self.check(poison_input, _label)) clean_entropy = torch.cat(clean_entropy).flatten().sort()[0] poison_entropy = torch.cat(poison_entropy).flatten().sort()[0] _dict = { 'clean': to_numpy(clean_entropy), 'poison': to_numpy(poison_entropy) } result_file = f'{self.folder_path}{self.get_filename()}.npy' np.save(result_file, _dict) print('File Saved at : ', result_file) print('Entropy Clean Median: ', float(clean_entropy.median())) print('Entropy Poison Median: ', float(poison_entropy.median())) threshold_low = float(clean_entropy[int(0.05 * len(clean_entropy))]) threshold_high = float(clean_entropy[int(0.95 * len(clean_entropy))]) y_true = torch.cat( (torch.zeros_like(clean_entropy), torch.ones_like(poison_entropy))) entropy = torch.cat((clean_entropy, poison_entropy)) y_pred = torch.where(((entropy < threshold_low).int() + (entropy > threshold_high).int()).bool(), torch.ones_like(entropy), torch.zeros_like(entropy)) print(f'Threshold: ({threshold_low:5.3f}, {threshold_high:5.3f})') print("f1_score:", metrics.f1_score(y_true, y_pred)) print("precision_score:", metrics.precision_score(y_true, y_pred)) print("recall_score:", metrics.recall_score(y_true, y_pred)) print("accuracy_score:", metrics.accuracy_score(y_true, y_pred))
def get_dominant_colour(self, img: torch.Tensor, k_means_num=None): """[summary] Args: img (torch.Tensor): # (C, H, W) k_means_num (int, optional): Defaults to 3. """ if k_means_num is None: k_means_num = self.k_means_num img = to_numpy(img.transpose(0, -1).flatten(end_dim=-2)) # (*, C) kmeans_result = KMeans(n_clusters=k_means_num).fit(img) unique, counts = np.unique(kmeans_result.labels_, return_counts=True) center = kmeans_result.cluster_centers_[unique[np.argmax(counts)]] return torch.tensor(center)
def save_npz(self, npz_path: str): _dict = {} if not self.mark_distributed: _dict |= {'org_mark': to_numpy(self.org_mark), 'org_mask': to_numpy(self.org_mask), 'org_alpha_mask': to_numpy(self.org_alpha_mask)} if not self.random_pos: _dict |= {'mark': to_numpy(self.mark), 'mask': to_numpy(self.mask), 'alpha_mask': to_numpy(self.alpha_mask)} np.savez(npz_path, **_dict)
def get_potential_triggers(self, neuron_dict: dict[int, list[dict]], _input: torch.Tensor, _label: torch.Tensor, use_mask=True) -> dict[int, list[dict]]: losses = AverageMeter('Loss', ':.4e') norms = AverageMeter('Norm', ':6.2f') jaccard = AverageMeter('Jaccard Idx', ':6.2f') score_list = [0.0] * len(list(neuron_dict.keys())) result_dict = {} for label, label_list in neuron_dict.items(): print('label: ', label) best_score = 100.0 for _dict in reversed(label_list): layer = _dict['layer'] neuron = _dict['neuron'] value = _dict['value'] # color = ('{red}' if label == self.attack.target_class else '{green}').format(**ansi) # _str = f'layer: {layer:<20} neuron: {neuron:<5d} label: {label:<5d}' # prints('{color}{_str}{reset}'.format(color=color, _str=_str, **ansi), indent=4) mark, mask, loss = self.remask(_input, layer=layer, neuron=neuron, label=label, use_mask=use_mask) self.attack.mark.mark = mark self.attack.mark.alpha_mask = mask self.attack.mark.mask = torch.ones_like(mark, dtype=torch.bool) self.attack.target_class = label attack_loss, attack_acc = self.model._validate( verbose=False, get_data_fn=self.attack.get_data, keep_org=False) _dict['loss'] = loss _dict['attack_acc'] = attack_acc _dict['attack_loss'] = attack_loss _dict['mask'] = to_numpy(mask) _dict['mark'] = to_numpy(mark) _dict['norm'] = float(mask.norm(p=1)) score = attack_loss + 7e-2 * float(mask.norm(p=1)) if score < best_score: best_score = score result_dict[label] = _dict if attack_acc > 90: losses.update(loss) norms.update(mask.norm(p=1)) _str = f' layer: {layer:20s} neuron: {neuron:5d} value: {value:.3f}' _str += f' loss: {loss:10.3f}' f' ATK Acc: {attack_acc:.3f}' f' ATK Loss: {attack_loss:10.3f}' f' Norm: {mask.norm(p=1):.3f}' f' Score: {score:.3f}' if not self.attack.mark.random_pos: overlap = jaccard_idx(mask, self.real_mask) _dict['jaccard'] = overlap _str += f' Jaccard: {overlap:.3f}' if attack_acc > 90: jaccard.update(overlap) else: _dict['jaccard'] = 0.0 print(_str) if not os.path.exists(self.folder_path): os.makedirs(self.folder_path) np.save( self.folder_path + self.get_filename(target_class=self.target_class) + '.npy', neuron_dict) np.save( self.folder_path + self.get_filename(target_class=self.target_class) + '_best.npy', result_dict) print( f'Label: {label:3d} loss: {result_dict[label]["loss"]:10.3f} ATK loss: {result_dict[label]["attack_loss"]:10.3f} Norm: {result_dict[label]["norm"]:10.3f} Jaccard: {result_dict[label]["jaccard"]:10.3f} Score: {best_score:.3f}' ) score_list[label] = best_score print('Score: ', score_list) print('Score MAD: ', normalize_mad(score_list)) return neuron_dict