재귀와 합성곱 part 2 of 13

게이트를 꺼내 보니 망각 게이트가 안 움직였다

guide / / 7 sections

1편에서 글자 하나를 바꿔 보니 은닉 상태의 차이가 네 자 만에 절반으로 줄었다. 게이트가 있는 LSTM 도 GRU 도 게이트 없는 RNN 과 거의 같은 속도였다. 게이트가 붙어 있는데 왜 같은지 보려면 게이트를 직접 꺼내야 한다.

LSTM 한 걸음

RNN 은 상태를 통째로 갈아 치운다. LSTM 은 상태를 두 개로 나눠서, 셀 상태 c 는 조금씩만 고치고 은닉 상태 h 는 거기서 필요한 만큼 꺼내 쓴다. 고치는 양을 정하는 것이 게이트다.

z = W_ih @ x + b_ih + W_hh @ h + b_hh     # 한 번에 네 덩어리
i = sigmoid(z[0:H])      # 입력 게이트 - 새 것을 얼마나 넣나
f = sigmoid(z[H:2H])     # 망각 게이트 - 옛 것을 얼마나 남기나
g = tanh(z[2H:3H])       # 후보 - 넣을 내용 자체
o = sigmoid(z[3H:4H])    # 출력 게이트 - 셀에서 얼마나 꺼내 보이나

c = f * c + i * g
h = o * tanh(c)

i, f, osigmoid 라 0 과 1 사이다. 0 이면 잠그고 1 이면 연다.

c = f * c + i * g 한 줄이 핵심이다. 기울기가 뒤로 갈 때 걸음마다 f 가 곱해지므로, 얼마나 뒤까지 기억하느냐는 f 가 정한다 - 적어도 이론상은.

nn.LSTMh 만 돌려주고 게이트는 안 준다. 그래서 학습된 가중치로 위 줄을 손으로 돌렸고, 파이토치가 낸 h 와 최대 6.85e-07 차이로 같다. 아래 숫자는 전부 그렇게 꺼낸 것이다.

게이트 값을 꺼내면

1편에서 쓴 것과 같은 800걸음 LSTM 에, 검증 데이터 32줄 x 128자를 넣고 유닛 325개의 게이트 값을 다 모으면 1,331,200 개가 나온다.

             평균     5%     25%     50%     75%     95%
입력 i      0.661  0.294   0.515   0.684   0.828   0.946
망각 f      0.495  0.081   0.258   0.491   0.730   0.922
출력 o      0.587  0.178   0.392   0.597   0.798   0.947

망각 게이트 평균이 0.495 다. 파이토치는 바이어스를 0 에서 시작하므로 학습 전 망각 게이트는 sigmoid(0) = 0.5 다. 800걸음을 돌고 나서도 그 자리에서 거의 안 움직였다.

긴 기억을 맡은 유닛이 없다

평균이 0.5 라도 어떤 유닛은 0.95 로 오래 붙들고 어떤 유닛은 0.1 로 바로 버리는 식이면, 서로 다른 시간 규모를 나눠 맡은 셈이 된다. 흔히 그렇게 설명한다. 유닛별로 나눠 보면

유닛 325개의 평균 망각 게이트 (작은 것부터) 0.3 0.4 0.5 0.6 0.7 0.8 초기값 0.5 반감기(자) 0.7 1.4 2.9 글자 하나를 바꿨을 때 남는 셀 상태 차이 1 0.1 0.01 0.001 실제 망각 게이트로만 굴리면 0 4 8 16 24 32 바꾼 자리에서 뒤로 몇 자
위: 유닛 325개의 평균 망각 게이트를 작은 것부터 늘어놓은 것. 0.307 에서 0.793 사이에 다 들어가고 절반 넘는 172개가 초기값 0.5 아래다. 오른쪽 눈금은 그 값이 뜻하는 반감기(자)로, 제일 오래 붙드는 유닛도 3자다. 아래: 글자 하나를 바꿨을 때 셀 상태 차이. 망각 게이트로만 굴린 것보다 실제가 오래 남는다 - 32자 뒤에 11배다.
유닛 325개의 평균 망각 게이트
  최소 0.307   5% 0.377   중앙 0.494   95% 0.622   최대 0.793
그 값이 뜻하는 반감기 (자)
  최소 0.59    중앙 0.98              최대 2.99

325개 전부가 0.31 에서 0.79 사이에 들어간다. 반감기로 옮기면 제일 오래 붙드는 유닛도 3 자이고, 절반이 넘는 172 개는 초기값 0.5 아래다. 열 자 이상 붙드는 유닛은 하나도 없다.

시간 규모를 나눠 맡은 게 아니라, 다 같이 짧게 잊는다.

망각 게이트가 전부는 아니다

그런데 1편에서 잰 상태 차이의 반감기는 네 자였다. 유닛별 반감기 중앙값 0.98 자와 네 배가 어긋난다.

c = f * c + i * g 를 다시 보면 이유가 보인다. 교란이 f 로만 줄어드는 게 아니다. h 가 달라지면 다음 걸음의 ig 도 달라지고, 그 차이가 셀에 다시 들어온다. 그러니까 잊는 경로 말고 되돌아오는 경로가 있다.

갈라 본다. 교란 직후의 셀 차이를 그 뒤로 f 만 곱해 굴린 것과, 실제로 두 글을 끝까지 돌려 잰 것을 나란히 놓으면

   뒤로   실제 차이   망각 게이트로만
      1     0.711        0.574
      4     0.337        0.124
      8     0.144        0.022
     16     0.041        0.003
     32   0.0069     6.48e-04

반감기가 실제 4 자, 망각 게이트로만 굴리면 3 자다. 32자 뒤에는 실제가 11배 남아 있다.

망각 게이트는 잊는 속도의 일부만 정한다. 나머지는 매 걸음 입력 쪽으로 되돌아 들어오는 몫이고, 이게 기억을 게이트가 말하는 것보다 오래 끌고 간다.

게이트가 글자에 반응한다

게이트 값은 고정된 숫자가 아니라 xh 로 매 걸음 계산된다. 그러니 글자에 따라 달라져야 한다. 자리 4,096 개를 글자로 갈라 망각 게이트 평균을 내면

띄어쓰기    0.4623   (자리 865개)
개행        0.4597   (자리 105개)
나머지      0.5057   (자리 3,126개)

띄어쓰기와 개행에서 0.05 쯤 더 닫는다. 단어가 끝나는 자리에서 조금 더 버린다는 뜻이다. 큰 차이는 아니지만 방향은 뚜렷하다 - 경계에서 비운다.

남는 것

여기 숫자는 800걸음 학습한 모형이다. 7편에서 보듯 그 지점이 검증 손실의 바닥 인데, 더 오래 돌리면 게이트가 어디로 가는지는 안 봤다.

GRU 도 안 열었다. 게이트가 둘뿐이고 셀 상태가 따로 없는데 1편에서 잊는 속도가 LSTM 과 거의 같았다. 다음 편이 그것이다.

그리고 “긴 기억을 맡은 유닛이 없다” 는 이 코퍼스와 이 과제에 붙은 말이다. 8편에서 망각 바이어스를 열면 도달이 문맥 전체로 가지만 손실은 나빠졌다. 긴 기억이 필요한 과제였다면 학습이 게이트를 다른 데로 데려갔을 것이다.

그래서

  • LSTM 한 걸음은 c = f·c + i·gh = o·tanh(c) 두 줄이고, i·f·o 는 전부 0 과 1 사이의 문이다
  • nn.LSTM 은 게이트를 안 주므로 가중치로 손으로 돌렸다. 파이토치와 최대 6.85e-07 차이다
  • 망각 게이트 평균이 0.495 로 초기값 sigmoid(0) = 0.5 에서 거의 안 움직였다
  • 유닛 325개의 평균 망각 게이트가 전부 0.307~0.793 안이다. 반감기로는 최대 3 자이고 열 자 넘는 유닛은 없다. 시간 규모를 나눠 맡지 않았다
  • 그런데 실제 상태는 반감기 4 자로 더 오래 간다. 32자 뒤에 망각 게이트만 굴린 것의 11 배다 - 차이가 입력 쪽으로 되돌아 들어온다
  • 게이트는 글자에 반응한다. 띄어쓰기 0.4623, 개행 0.4597, 나머지 0.5057 로 경계에서 조금 더 버린다

Comments