밑바닥부터 시작하는 딥러닝 2 - 6장

Jajuna_99·2022년 9월 28일
0

6장 게이트가 추가된 RNN

RNN에 게이트가 추가된 LSTM, GRU 계층을 알아보고 구현하는 장이다.

RNN의 문제점(p.238)

  • RNN은 시계열 데이터의 장기 의존 관계를 학습하기 어렵다. -> 기울기 소실이나 폭발이 일어나기 때문이다.

  • 기울기 소실과 폭발의 이유

    • RNN 역전파 과정에서 'tanh', '+', 'MatMul' 계층을 지나게 된다.
    • 'tanh'계층의 경우 이 계층의 미분 함수를 지날 때 마다 (그래프 p.242에) 값이 계속 작아지게 된다. -> ReLU 함수로 대체해 개선 가능
    • 'MatMul'계층의 경우 시계열 데이터의 시간 크기만큼 반복해서 가중치dhWhTdh W_h^T를 행렬 곱으로 계산한다. (구현 코드 p.243) -> 행렬 곱이여서 지수적으로 학습하기 때문에 이 경우 행렬의 특이값(p.245)이 1이상이면 폭발하고, 1이하이면 소실한다.
  • 기울기 폭발 대책

    • 기울기 클리핑(gradient clipping)을 사용하면 된다. 의사 코드:

      if gbarthreshold:\vert\vert g-bar\vert\vert \ge threshold:
      gbar=g-bar = thresholdgbarthreshold \over \vert\vert g-bar\vert\vertgbar\vert\vert g-bar\vert\vert

    • gbarg-bar는 L2 노름을 의미, L2 노름이 문턱값을 초과하면 두 번쨰 줄의 수식과 같이 기울기를 수정하는 기법이다. (기울기 클리핑 구현 p.246)

기울기 소실과 LSTM(p.247)

기울기 소실도 대책을 마련해야 하는데 이는 RNN 아키텍처를 전부 수정해야 가능하다. -> 이렇게 해서 나온 모델이 LSTMGRU이겠다.

RNN과 LSTM의 차이

  • (p.248)에 인터페이스를 시각화해놓은 그림을 보면 둘의 차이점은 LSTM에는 RNN에 없는 C라는 LSRM 전용의 기억 메커니즘인 기억 셀(memory cell)이 있다.
  • 기억 셀의 특징은 데이터를 자기 자신으로만(LSTM 계층 내에서만) 주고받는다는 것이다. -> 다른 계층으로 출력하지 않는다.
  • ctc_t에는 시각 tt에서의 LSRM의 과거로부터 시각 tt까지에 필요한 모든 정보가 저장돼 있다고 가정한다. -> 이 기억을 갖고 은닉 상태 hth_t를 출력한다.
    • ht=tanh(ct)h_t = tanh(c_t)
  • 은닉 상태 hh는 RNN 계층과 마찬가지로 다른 계층으로 출력한다.
  • 여기서 중요한 점은 이따 나올 게이트들에게 '중요도'를 알아서 학습하게 한다는 것이다.

LSTM의 게이트들

  • output 게이트

    • 위에서 말한 tanh(ct)tanh(c_t)의 각 원소에 대해 '그것이 다음 시각의 은닉 상태에 얼마나 중요한가'를 게이트에 적용해봐야겠다.

    • 다음 은닉 상태 hth_t의 출력을 담당하는 게이트이겠으므로 output 게이트라고 하자.

    • 게이트의 열림 상태 (얼마나 보낼까)는 입력 xtx_t와 이전 상태 $h_{t-1}로부터 구한다

      • o=σ(xtWx(o)+ht1Wh(o)+b(o))o = \sigma(x_tW_x^{(o)} + h_{t-1}W_h^{(o)} + b^{(o)})

        • xtx_t 입력과 가중치Wx(o)W_x^{(o)}가, 이전 시각 은닉 상태 ht1h_{t-1}와 가중치 Wh(o)W_h^{(o)}가 행렬 곱, 그리고 편향 b(o)b^{(o)}를 모두 더한 다음 시그모이드 함수를 거치면 게이트 출력 oo를 구할 수 있다.
        • 그리고 이 ootanh(ct)tanh(c_t)의 원소별 곱을 hth_t로 출력하는 것이다.
    • 위에 곱은 행렬의 원소별 곱이고 이 곱을 아다마르 곱(hadamard product)라고 한다. -> ⊙

    • 최종 출력은 아래 수식과 같겠다.

      • ht=otanh(ct)h_t = o ⊙ tanh(c_t)
  • forget 게이트

    • '기억 셀에서 무엇을 잊을까' 또한 게이트로 구현한다.

      • f=σ(xtWx(f)+ht1Wh(f)+b(f))f = \sigma(x_tW_x^{(f)} + h_{t-1}W_h^{(f)} + b^{(f)})

        • f와 이전 기억 셀인 ct1c_{t-1}과의 원소별 곱, 즉 ct=fct1c_t = f ⊙ c_{t-1}을 계산해야 한다.
  • 새로운 기억 셀

    • 위에 forget 게이트로는 기억 삭제 밖에 못한다. 그래서 새로운 기억 셀 tanh 노드를 추가해줘야 한다.
      • g=tanh(xtWx(g)+ht1Wh(g)+b(g))g = tanh(x_tW_x^{(g)} + h_{t-1}W_h^{(g)} + b^{(g)})
  • input 게이트
    • g의 각 원소가 새로 추가되는 정보로써의 가치가 얼마나 큰지 판단할 게이트이다.

    • 새 정보를 무작정 받아들이는게 아니라 선택해서 받는다는 뜻.

      • i=σ(xtWx(i)+ht1Wh(i)+b(i))i = \sigma(x_tW_x^{(i)} + h_{t-1}W_h^{(i)} + b^{(i)})

LSTM의 기울기 흐름

  • 기억 셀의 역전파에서는 '+'와 'x' 노드는 지나게 됩니다. -> 여기서 곱하기 노드는 행렬 곱이 아닌 아다마르 곱니다.
  • 이 원소 별 곱 때문에 곱셈의 효과가 누적되지 않아 기울기 소실이 일어나기 굉장히 힘들게 만든다.
  • 또한 forget 게이트가 곱하기 노드의 계산을 제어한다. -> forget 게이트의 판단에 따라 기울기가 작아지거나 유지된다.

LSTM 구현(p.257)

LSTM에서 수행하는 계산을 정리한 수식들

  • o=σ(xtWx(o)+ht1Wh(o)+b(o))o = \sigma(x_tW_x^{(o)} + h_{t-1}W_h^{(o)} + b^{(o)})
  • f=σ(xtWx(f)+ht1Wh(f)+b(f))f = \sigma(x_tW_x^{(f)} + h_{t-1}W_h^{(f)} + b^{(f)})
  • g=tanh(xtWx(g)+ht1Wh(g)+b(g))g = tanh(x_tW_x^{(g)} + h_{t-1}W_h^{(g)} + b^{(g)})
  • i=σ(xtWx(i)+ht1Wh(i)+b(i))i = \sigma(x_tW_x^{(i)} + h_{t-1}W_h^{(i)} + b^{(i)})
  • ct=fct1+gic_t = f ⊙ c_{t-1} + g ⊙ i
  • ht=otanh(ct)h_t = o ⊙ tanh(c_t)

위에 4개의 식은 아핀 변환이라는 성질을 갖고 있어서 계산 속도를 빠르게 할 수 있다. (p.258)
이렇게 구현하면 된다... (p.259)

LSTM을 사용한 언어 모델(p.265)

전 장에서 RNN 을 언어모델 RNNLM로 만든것 처럼 LSTM을 언어 모델로 구현하고 성능을 확인해보는 절이다.

RNNLM 추가 개선(p.272)

다음 3가지 방법으로 추가적으로 RNNLM을 개선하는 절이다.
LSTM 계층 다층화

  • LSTM 계층을 깊게 쌓아 효과를 올릴 수 있다.

드롭아웃에 의한 과적합 억제

  • 과적합 억제 기법 중 '훈련 데이터 양 늘리기'와 '모델의 복잡도 줄이기' 중에서 정규화(normalization)가 효과적이고, 드롭 아웃 또한 효과적이다.

가중치 공유

  • Embedding 계층과 Affine 계층의 가중치를 연결하는 기법이다.

위 기법으로 개선된 RNNLM 구현하는 절이다. (p.279)

요약

컴퓨터 구조 조합논리에서 봤던 게이트들이 이렇게 복잡해질수 있구나...^^

작가님도 헷갈릴 수 있는 파트라는 것을 인지 하셨는지 동의어 반복을 진짜 많이 하신다. 도움이 많이 됐는지는 모르겠다.

나 또한 이해 못한 부분이 많아 다시 돌아와 복습해보고 공부를 더 해야 될 것 같다.

profile
Learning bunch, mostly computer and language

0개의 댓글