Slow is better than NOTHING

적대적 공격(Adversarial Attack)

[PyTorch] 적대적 공격(Adversarial Attack) - FGSM/PGD

Jeff_Kang 2021. 7. 2. 02:57
반응형

적대적 공격(Adversarial Attack)은 딥러닝 모델의 내부적 취약점을 이용하여 만든 특정 노이즈(Noise or Perturbation)값을 이용해 의도적으로 오분류를 이끌어내는 입력값을 만들어내는것을 의미합니다. 적대적 공격으로 특별히 machine learning system을 속이기 위해 제작된 입력 값을 적대적 예제(Adversarial Example)라고 하며, 대표적인 공격 방법으로 FGSM(Fast Gradient Sign Method), PGD(Projected Gradient Descent) 방법이 있습니다. 두 개의 공격은 주어진 모델의 Weight값을 이용해 Gradient값을 계산하여 입력값을 조작할 수 있다는 점에서 생성된 적대적 예제는 해당 모델의 'Worst-case input'이라고 생각될 수 있습니다. 이번 글에서는, 적대적 공격 분야를 Image Classification Task에 적용시켜보고 코드로 직접 구현하여 그 영향력을 살펴보고자 합니다. 사람의 눈으로는 인지할 수 없는 작은 변화를 준 입력값이 최종적으로 어떤 결과를 가져오는지 Pytorch 기반의 코드와 함께 설명하겠습니다.

적대적 공격 예시, PGD 공격방법을 통해 생성된 노이즈를 첨가하여 완전히 다른 예측 결과를 가져옴


FGSM(Fast Gradient Sign Method)

FGSM 공격 방법은, 적대적 예제의 시초로서 GAN의 아버지인 Ian Goodfellow 가 제안한 딥러닝 모델의 근본적인 취약점을 다룬 공격 방법입니다. [1] 논문에서는 Unseen data에 대해 모델의 일반화 성능을 강화시키는 정규화 방법(e.g., dropout, weight decay) 으로는 다룰 수 없는 특별한 입력 값인 'Adversarial Example' 의 존재에 대해 다루고 있습니다. 

We hypothesize that neural networks are too linear to resist linear adversarial perturbation

저자는 딥러닝 모델이 적대적 공격에 취약성을 갖는 이유로 모델이 지나치게 선형적이라는 주장을 합니다. Cross Entropy Loss를 활용해 이미지 분류 문제를 다루는 모델을 훈련시키면, 우리는 훈련데이터에 적합하게 훈련된 모델의 의사결정경계(Decision Boundary)를 얻을 수 있습니다. 아래의 그림처럼 적대적 예제는 이 Decision boundary를 넘을 수 있는 최소한의 노이즈 분포를 찾는 것이 목표인데, 모델이 지나치게 선형적이라면 경계를 넘기가 상대적으로 쉬울 수 있습니다. 

적대적 공격의 목표

적대적 공격을 이용해 적대적 예제를 만드는 로직을 일반화 시키면 다음과 같습니다. $\delta$ 는 적대적 공격을 통해 생성된 노이즈를 의미하며, $x$ 원본 이미지에 element-wise 덧셈을 통해 새로운 적대적 예제 $x_{adv}$ 를 생성할 수 있습니다. 단, $\delta$ 는 $L_{infty}$ Norm constraint* 안에서 특정 값을 넘을 수 없도록 제한되어있습니다. 

*$L_{infty}$ 제한이란, 생성된 노이즈의 분포중 각 픽셀들의 절대값이 정해진 $\epsilon$ 크기보다 클 수 없음을 의미합니다. 예를 들어, $\epsilon$ 이 4인 경우 생성된 노이즈의 분포는 $-4 \leq \delta \leq 4$ 에서만 값을 가질 수 있습니다.

저자는 오분류를 일으킬 수 있는 노이즈 $\delta$ 를 찾기 위해 아래와 같은 수식을 제안하며 이를 FGSM으로 명명합니다. $\epsilon$는 노이즈의 크기를 의미하며, cost function $L$ 이 주어졌을 때 딥러닝 모델의 파라미터 $\theta$를 이용하여 정답 라벨 $y$에 반대되는 방향으로 Gradient를 업데이트하여 오분류를 초래하는 적대적 예제를 생성하게 됩니다.

일반적으로, 이미지 분류 문제에서 Cost function은 Crossentropy가 사용됩니다. 해당 cost function을 이용해 위 내용을 구현한 코드는 아래와 같습니다. 

  • 주어진 input $x$ 를 model 에 입력값으로 준다.
  • 입력 값에 따른 gradient를 계산한다.
  • target class가 정해지지 않은 경우 ground-truth class의 반대되는 gradient ascent를 수행한다.
  • target class가 정해진 경우 target class로 gradient descent를 수행한다.
class FGSM(Attacker):
    def __init__(self, model, config, target=None):
        super(FGSM, self).__init__(model, config)
        self.target = target

    def forward(self, x, y):
        x_adv = x.detach().clone()

        if self.config['random_init']: # Random Start Flag
            x_adv = self._random_init(x_adv)

        x_adv.requires_grad=True
        self.model.zero_grad()

        logit = self.model(x_adv) # Projection
        if self.target is None:
            cost = -F.cross_entropy(logit, y) # Gradient ascent
        else:
            cost = F.cross_entropy(logit, self.target) # Gradient descent to the specific label
        
        if x_adv.grad is not None:
            x_adv.grad.data.fill_(0)
        cost.backward()

        x_adv.grad.sign_()                            # applying sign function
        x_adv = x_adv - self.config['eps']*x_adv.grad # x_adv = x + delta
        x_adv = torch.clamp(x_adv,*self.clamp)        # Clamping the example
        return x_adv

 


PGD(Projected Gradient Descent)

PGD [2] 공격은 FGSM의 등장 이후 약 3년 뒤에 나온 공격방법으로 현재까지도 universal first-order adversary로 알려져있어 많은 논문들의 baseline 공격방법으로 차용이되고 있습니다. 위에서 소개한 FGSM방법을 조금 응용한 것으로, $n$번의 step만큼 공격을 반복하여 정해진 $L_{infty}$ norm 아래에서 inner maximization을 수행하는 것입니다. step수의 변화 이외에도 learning rate라고 하는 step의 크기 $\alpha$를 이용해 한 번의 step마다 이동 크기를 지정해주기도 했습니다. 

 

논문에서 소개된 PGD 기반의 공격을 통해 찾아낸 local maxima는 모델, 데이터셋에 상관없이 비슷한 손실값으로 수렴하는 것을 실험적으로 증명하였습니다. 이 사실을 바탕으로 모델의 오분류를 유도하기 위한 local maxima를 찾는 최적해를 구하기위해 first-order만을 사용한 공격 중에서 PGD를 이용하는 것이 가장 효과적이라는 주장을 합니다. 실제로 여러 논문에서 PGD example을 훈련시킨 Adversraial training 모델은 어떠한 공격에도 일관된 성능을 보여주는 것을 확인할 수 있습니다. 아래는 pytorch기반의 PGD adversary를 생성하는 코드입니다.

FGSM adversary는 optimal $\delta$를 찾기 위해 1 step gradient를 계산하지만, PGD의 경우 step 수 $n$에 따라 공격강도가 강해집니다. 일반적으로, 7, 40 등이 사용되고 더 정교한 local optima를 찾기 위해 step 수를 증가시킬 수도 있습니다. 하지만, 본문에 나왔듯 손실함수 값이 특정 값이 빠르게 수렴하는 것으로 볼때 step수가 커질 수록 그 영향력 정도가 감소하기 때문에 적절한 step수를 조절해주는것도 중요합니다.

class PGD(Attacker):
    def __init__(self, model, config, target=None):
        super(PGD, self).__init__(model, config)
        self.target = target

    def forward(self, x, y):
    
        x_adv = x.detach().clone()
        if self.config['random_init'] :
            x_adv = self._random_init(x_adv)

        for step in range(self.config['attack_steps']):
            x_adv.requires_grad = True
            self.model.zero_grad()
            logits = self.model(x_adv) #f(T((x))
            if self.target is None:
                # Untargeted attacks - gradient ascent
                loss = F.cross_entropy(logits, y,  reduction="sum")
                loss.backward()
                grad = x_adv.grad.detach()
                grad = grad.sign()
                x_adv = x_adv + self.config['attack_lr'] * grad
            else:
                # Targeted attacks - gradient descent
                assert self.target.size() == y.size()
                loss = F.cross_entropy(logits, target)
                loss.backward()
                grad = x_adv.grad.detach()
                grad = grad.sign()
                x_adv = x_adv - self.config['attack_lr'] * grad

            # Projection
            x_adv = x + torch.clamp(x_adv - x, min=-self.config['eps'], max=self.config['eps'])
            x_adv = x_adv.detach()
            x_adv = torch.clamp(x_adv, *self.clamp)

        return x_adv

Adversarial Training

GAN을 공부해보신 분이라면 익숙할 단어인 적대적 훈련(Adversarial Training) 은 Adversarial Attack분야에서는 조금 다르게 사용됩니다. 원본 이미지 $x$에 대한 손실함수를 계산하는 것이 아닌 $x_{adv}$에 대해 손실함수를 계산하여 이미지 분류 모델을 훈련시키는 것입니다. 즉, 적대적 예제를 학습시키는 훈련(Adversarial Training)입니다. 각각, FGSM PGD를 활용하여 모델을 훈련시킬 수 있으며, 적대적 예제의 특징을 학습한 모델은 적대적 예제에 대한 강건성을 보장받고 입력값에 대해 Sensitivity를 줄이는 방향으로 학습이 될 수 있습니다. 즉, 해당 모델의 worst case인 적대적 예제를 입력값으로 주어도 원본 모델보다 우수한 성능을 보여줄 수 있습니다. 아래의 그림 (a)는 일반적인 이미지 분류 모델을 학습시키는 것이며, 그림 (b)는 훈련 중간에 $x_{adv}$를 생성하여 함께 훈련시키는 것입니다. 

Traditional Training과 Adversarial Training 비교

 

적대적 훈련방법은 등장 초기 원본 이미지와 적대적 이미지를 weighted sum 을 이용해 동시에 학습시키고자 했습니다. 각 샘플이 훈련에 미치는 기여 정도를 조절하기 위해 $\alpha$ 라는 밸런싱 파라미터를 두었고, 이를 적절하게 찾기 위한 방법론들을 [1] 에 제시하였습니다.

 

하지만, [2] 에서는 적대적 훈련을 적용하기 위해 Inner maximization (정해진 $L_{infty}$ norm에서 최적의 local optima를 찾아 loss를 극대화시켜 오분류를 유도하고) 후 outer minimization(생성된 오분류 특징을 학습한 $x_{adv}$를 모델이 정답 클래스를 찾을 수 있도록 파라미터 $\theta$를 업데이트) 을 수행하는 방법으로 원본 이미지는 훈련 중간에 사용하지 않습니다. 

 

이렇게 오로지 $x_{adv}$를 이용해 학습된 모델은 $x_{adv}$를 만들기 위해 현재 모델의 weight값 $\theta$를 이용해 inner maximization을 수행하고, maximization을 이용해 생성된 샘플을 crossentropy loss를 이용해 outer minimization 문제를 해결하여 $x_{adv}$를 가장 잘 나타낼 수 있는 파라미터 $\theta'$을 학습합니다. [2] 논문에서는 소개한 적대적 훈련 방법의 효과를 ResNet, WideResNet 2개의 모델을 이용해 비교하였습니다. 

아래의 실험 결과에 따르면, (a) Standard Training의 경우 FGSM, PGD 공격에 의해 정확도가 상당히 감소하는 것을 확인할 수 있습니다. 반면, 소개한 적대적 훈련법을 이용해 훈련한 네트워크 (b), (c)의 결과는 공격에도 상대적으로 좋은 accuracy를 보여주고 있습니다. 하지만 한가지 주목할 점은, Natural accuracy 역시 같이 감소했다는 점입니다. WideResNet을 사용했을때와 일반 ResNet을 사용했을 때 PGD에 대한 adversarial robustness는 큰 차이가 없지만 Natural accuracy에서 큰 차이를 보이고 있습니다. 이는 네트워크의 Capacity(수용력)이 높아질 수록 adversarial accuracy과 Natural accuracy 사이의 trade-off관계를 어느정도 완화시켜주는 것을 알 수 있습니다. (자세한 trade-off관계에 대한 이론적 설명은 [3] 참고)

Simple : ResNet(width=1), Wide : WideResNet(width=10)

 

본 글은 FGSM, PGD, 그리고 adversarial training을 소개하는 글이므로 이외 논문에서 소개한 자세한 실험적 관찰 부분들은 모두 생략하겠습니다. [1],[2] 논문을 읽어보시고 이를 코드로 구현하여 직접 implementation해보시고 싶은 분들은 아래의 깃헙 링크를 참고 바랍니다.


위에서 소개한 공격방법과 실험을 Pytorch기반의 코드로 구현한 내용은 아래 github에서 확인해보실 수 있습니다. 

 

Jeffkang-94/pytorch-adversarial-attack

Implementation of gradient-based adversarial attack(FGSM,MI-FGSM,PGD) - Jeffkang-94/pytorch-adversarial-attack

github.com

 


[1] https://arxiv.org/abs/1412.6572

 

Explaining and Harnessing Adversarial Examples

Several machine learning models, including neural networks, consistently misclassify adversarial examples---inputs formed by applying small but intentionally worst-case perturbations to examples from the dataset, such that the perturbed input results in th

arxiv.org

[2] https://arxiv.org/abs/1706.06083

 

Towards Deep Learning Models Resistant to Adversarial Attacks

Recent work has demonstrated that deep neural networks are vulnerable to adversarial examples---inputs that are almost indistinguishable from natural data and yet classified incorrectly by the network. In fact, some of the latest findings suggest that the

arxiv.org

[3] http://proceedings.mlr.press/v97/zhang19p.html

 

Theoretically Principled Trade-off between Robustness and Accuracy

We identify a trade-off between robustness and accuracy that serves as a guiding principle in the design of defenses against adversarial examples. Although this problem has been widely studied empi...

proceedings.mlr.press

 

반응형