(self, model, criterion, x, y)
| 11 | self.ascending = ascending |
| 12 | |
| 13 | def perturb(self, model, criterion, x, y): |
| 14 | if self.steps==0 or self.radius==0: |
| 15 | return x.clone() |
| 16 | |
| 17 | adv_x = x.clone() |
| 18 | if self.random_start: |
| 19 | if self.norm_type == 'l-infty': |
| 20 | adv_x += 2 * (torch.rand_like(x) - 0.5) * self.radius |
| 21 | else: |
| 22 | adv_x += 2 * (torch.rand_like(x) - 0.5) * self.radius / self.steps |
| 23 | self._clip_(adv_x, x) |
| 24 | |
| 25 | ''' temporarily shutdown autograd of model to improve pgd efficiency ''' |
| 26 | model.eval() |
| 27 | for pp in model.parameters(): |
| 28 | pp.requires_grad = False |
| 29 | |
| 30 | for step in range(self.steps): |
| 31 | adv_x.requires_grad_() |
| 32 | _y = model(adv_x) |
| 33 | loss = criterion(_y, y) |
| 34 | grad = torch.autograd.grad(loss, [adv_x])[0] |
| 35 | |
| 36 | with torch.no_grad(): |
| 37 | if not self.ascending: grad.mul_(-1) |
| 38 | |
| 39 | if self.norm_type == 'l-infty': |
| 40 | adv_x.add_(torch.sign(grad), alpha=self.step_size) |
| 41 | else: |
| 42 | if self.norm_type == 'l2': |
| 43 | grad_norm = (grad.reshape(grad.shape[0],-1)**2).sum(dim=1).sqrt() |
| 44 | elif self.norm_type == 'l1': |
| 45 | grad_norm = grad.reshape(grad.shape[0],-1).abs().sum(dim=1) |
| 46 | grad_norm = grad_norm.reshape( -1, *( [1] * (len(x.shape)-1) ) ) |
| 47 | scaled_grad = grad / (grad_norm + 1e-10) |
| 48 | adv_x.add_(scaled_grad, alpha=self.step_size) |
| 49 | |
| 50 | self._clip_(adv_x, x) |
| 51 | |
| 52 | ''' reopen autograd of model after pgd ''' |
| 53 | for pp in model.parameters(): |
| 54 | pp.requires_grad = True |
| 55 | |
| 56 | return adv_x.data |
| 57 | |
| 58 | def _clip_(self, adv_x, x): |
| 59 | adv_x -= x |
no test coverage detected