Notice
Recent Posts
Recent Comments
Link
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
Tags
more
Archives
Today
Total
관리 메뉴

TechY

[간단 정리] Gradient Clipping against Gradient exploding 본문

[간단 정리]

[간단 정리] Gradient Clipping against Gradient exploding

hskimim 2020. 11. 28. 16:44

본 포스팅은 해당 블로그 를 참조하고 나름대로 번역하여 만들어졌습니다. 

 

RNN 기반의 sequence model 의 코드를 보다보면,  torch.nn.utils.clip_grad_norm_(model.parameters(), clip)

와 같은 코드 라인을 만나게 됩니다. 과연 어떤 것을 위한 것이고 어떻게 작용하는 것일까요?

 

RNN(recurrent neural net)을 공부하다보면, 자연스레 long term dependency를 해결하기 위해 LSTM , GRU 를 공부하게 되는데, 이유는 vanishing gradient로 인해서, 멀리 떨어져있는 단어들 간의 관계성을 잃어간다는 것에 있었습니다.

그 이유는, RNN의 특성 상, 계속 recurrent 해갔기 때문인데, 여기서 recurrent 는 이전의 state가 다음 번의 state를 결정하는 데에 기여하는 아키텍쳐를 따르게 되기 때문입니다. 따라서, activation function의 derivation이 1보다 작은 수가 많이 나오는 sigmoid나 tanh function을 사용한 상태에서, sequence의 길이가 길어진다면 기울기값이 0이 되어 앞단의 weight가 학습이 되지 않는 gradient vanish 가 발생하게 됩니다. 또한 gradient overflow 와 같은 맥락으로 gradient overflow 문제도 activation function이나 normalize 되지 않은 logit 값에 따라 발생할 수 있습니다. 

 

gradient 가 underflow 또는 overflow 되면, network가 불안정하다는 것을 의미하고, 이러한 경우 학습이 느려지거나 안될 수 있기 때문에, 이를 조정해주는 과정이 필요합니다.

 

gradient exploding 은 아래의 세 가지 이유로 발생할 수 있습니다.

  • learning rate을 너무 크게 잡아서, 가중치의 업데이트가 너무 산발적일 때(large weight updates)
  • 데이터의 전처리가 충분히 되지 않았을 때
  • loss function을 선택이 부적합해서, loss의 크기가 너무 크게 잡힐 때(large error values)

위의 원인을 잘 조정해준다면, exploding gradient 문제를 어느정도 잡아줄 수 있지만, recurrent neural net 과 같은 모델의 경우, time steps 즉, sequence length 가 길게 되면, accumulated operation 이 많아지게 되고, 이에 따라 explding 의 가능성이 높아지게 됩니다. 대표적으로 LSTM 모델이 이러한 경우가 됩니다.

이러한 경우에는 back-propagation 연산을 하기 전에, loss(error)의 미분값(derivative)를 조정해주는 과정이 들어가게 되는데, 조정하는 방법에는 두 가지가 있습니다.

 

  • Gradient Scaling : error derivative 를 rescaling 해주는 것입니다. 그레디언트 벡터를 1로 normalizing 하는 경우가 일반적입니다.
  • Gradient Clipping : gradient value 를 특정 minimum value 로 줄이거나 특정 maximum value로 크게 하는 방법입니다.

만약 gradient value가 너무 커지게 되는 overflow 현상이 발생하게 된다고 가정을 해봅시다. 하나의 모델 안에는 수많은 파라미터들이 있고 이에 따라 각각의 gradient 가 존재하게 되겠지요. 이들을 모아 gradient vector 를 형성하고, 이러한 값들은 back forward 방향으로 cumulative prod (ex. np.cumprod) 가 됩니다.

 

이런 업데이트를 해주기 전에, gradient vector가 [0.7,1.1,3.4] 와 같이 존재한다고 했을 때, 이를 normalizing하게 되면, 평균과 분산을 사용해 나눠주면, [-0.73, -0.45, 1.18] 와 같은 값이 나오게 됩니다. 3.4라는 큰 gradient 가 1.18로 줄어든 것을 확인할 수 있습니다.

 

추가적으로 clipping 은 clip을 1로 두고 [0.7,1.1,3.4] 을 놓게 되면 min(x,1) 이 적용됩니다. normalizing 기법과는 다르게 확실히 강제적으로(forcing) 그래디언트의 상방을 truncate 해주는 방법입니다.

 

간단하지만, 효과적으로 gradient 의 scale을 조절해줄 수 있는 방법이라고 생각이 드네요:)