출처가 명시되어 있지 않은 모든 이미지의 지식재산권은 재단법인 네이버 커넥트에 귀속됩니다.
Exercise. Autograd
Saliency test again
Saliency map을 구하기 위해 필요한 기본적인 디테일에 대해서 살펴볼 예정이다.
Saliency map 을 구하기 위해서는
- Class score에서부터 gradient를 구해서 Input domain에 gradient를 구한다.
- 이렇게 Bacpropagation 된 gradient를 accumulation 한다던지 아니면 gradient 자체를 visulization을 해서 얻을 수 있다.

그럼 이제 gradient를 구하는 법을 알아야 한다.
= Autograd를 활용해서 구할 수 있다.
Auto grad
- Automatic gradient의 약자로 fucntion들의 집합을 의미한다.
- Automatic differentiation이라고도 불리며 Deep Learning Library 들의 고유한 기능을 얘기한다.
- 기본적으로는 행렬 연산을 하는 Library이다.
- forward와 backward pass가 가능하게 만들어준다.
- 아래 그림과 같은 Computational graph라는 편리한 데이터 구조를 사용해서 구현이 가능하게 했다.
- 덕분에 딥러닝을 사용하는 유저의 난이도를 낮춰주었다.
- 아래 그림을 보면 a에서부터 L까지 연산이 되는 전 과정을 따로 저장하고 있다.
- (backpropagation을 할 때 L에서부터 타고 a로 가는 과정을 진행해야 하기 때문이다)

x에 대한 y 의 gradients를 계산하는 예제를 보자

x.grad를 하게 되면 원래는 $\frac{\partial y}{\partial x}$이므로 3이 나와야한다.
하지만 y.backward 안에 gradients가 있으므로 다르다.
x.grad를 하게되면 $gradients\cdot \frac{\partial y}{\partial x}$연산이 수행된다.
그러므로 출력이 tensor([300.000, 0.3000]) 이렇게 나오게 된 것이다.
굳이 이렇게 설계한 이유는 Chain rule을 적용시켜서 복잡한 식도 계산 해내기 위함이다.
이렇게 들어가는 값이 행렬일 경우는 gradients를 넣어줘야 하고, 행렬이 아니라면 1을 넣어줘도 무방하다.

requires_grad = True로 해준 이유는 x를 grad를 저장할수 있게 하기 위해서다.

위에 처럼 backward를 두번 하게 되면 첫번째 미분값과 두번째 미분값이 더해져서 accumulation된다.
하지만 이렇게 RuntimeError가 나오게 되는데 이 이유는 아래와 같이 백워드내의 동작 때문에 그렇다.
원래는 중간 결과들을 다 버리게 되는데 이 부분을 retain_graph = True로 설정하면 해결이 된다.

이전에 했던 미분결과와 두번째에 한 결과가 더해져서 나옴을 알 수 있다.( = Gradient accumulate )
다음으로 Autograd - Tutorial (grad_fn) 에 대해서 살펴보겠다.
아래와 같이 x를 사용해서 y,z,w를 만들었다.
이때 이 구현이 grad_fn으로 구현이 되어 있다.

다음으로는 Class activation mapping (CAM) 에 대해서 살펴보겠다.
중간에서 gradient를 얻는 방법에는 여러가지가 있겠지만, hooking 이라는 방법이 있다.
register_forward_hook:
- 어떤 function call을 했을때 오가는 message를 낚아채는 것이다.
- backward할때 오는 정보를 낙아채서 오는것이다.
- 때문에 gradient 계산을 할때마다 gradient를 받아 올 수 있다
아래 Simple model 구조를 통해 실습해보자.

hooking을 할때 어떤걸 수행해야 하는지 Signature of hook fuction - forward 를 정의 해야 한다.
프로토 타입이 있어서 이 구조에 맞게 해줘야 한다. (input , output)

hooking을 걸고 싶은곳에 아래와 같이 register를 등록을 해준다.
등록만 하면 아직 아무일도 일어나지 않는다.

이후에 forward pass를 할때 hook function이 작동하면서 아래와 같이 자동으로 프린팅이 된다.

register_forward_pre_hook 이란것도 존재한다.
pre_hook은 forward pass 하기 바로 직전에 hook을 하라고 지정해주는 것이다.
아래와 같이 사용하면 된다.

다음으로 backward 할때 사용되는 register_backward_hook이 있다.
아래와 같이 error를 다 계산한 후에 backward를 호출하게 되면 그때 동작한다.

위에서 사용된 hook_grad를 자세히 한번 살펴보겠다.
앞서 본바와 같이 grad_input, grad_output을 넣어주는게 중요하다.
만약 gradient 값을 변형하고 싶다면 return 을 주어서 원하는 변형값이 return으로 나가도록 할 수 있다.

매번 이렇게 출력이 찍힌다면 곤란할 수 있을텐데 지우는 방법은 remove()를 사용해 주면 된다.
register hook을 호출할때 아래와 같이 return값을 받는다 (h)
이것을 핸들러 라고 한다.
출력을 원하지 않을때는 아래와같이 h.remove()를 통해 register를 지워줄 수 있다.

다음으로는 register_hook을 사용해서 activation을 어떻게 가져오는지 살펴보겠다.
앞에서와 마찬가지로 hooking function을 정의 해야한다.
hook function의 역할은 feature가 들어왔을때 이를 저장하는것이다.
이때 변수를 전역변수로 저장해서 다른곳에서도 볼 수 있도록 하는것이다.
이후에 모델에서 모든 모듈을 하나씩 불러오면서 만약 모듈의 이름이 우리가 원하는 타겟이면
그 모듈에 register를 적용시켜줄 수 있다.
그다음 인풋이 들어오면 forward call을 하는것이다.

'Deeplearning > Computer Vision' 카테고리의 다른 글
| [Computer Vision] 03. Image classification (0) | 2023.03.30 |
|---|---|
| Computer Vision 9. Multi-modal (0) | 2022.10.21 |
| Computer Vision 8. Conditional Generative Model (0) | 2022.10.20 |
| Computer Vision 7. Instance Panoptic Segmentation (0) | 2022.10.19 |