보이는 딥러닝 part 12 of 13

블록을 96개 쌓아 보면 무엇이 무너지나

guide / / 4 sections

부품은 다 봤다. 어텐션, 위치, 여러 머리, 피드포워드. 이제 이것들을 블록으로 묶어 쌓는다. 묶는 방법이 두 줄인데, 그 두 줄이 20층과 96층을 가른다.

x = LN(x + Attn(x));   x = LN(x + FFN(x))     # Post-LN, 원 논문
x = x + Attn(LN(x));   x = x + FFN(LN(x))     # Pre-LN, 요즘 기본

차이는 정규화가 잔차 이냐 이냐 하나뿐이다. 4편에서 했던 것을 그대로 한다 - 쌓아 놓고 층별 기울기를 잰다. d=128, 머리 4개, 확장 4배, 초기값은 PyTorch 기본이고 float64 다.

먼저 20층에서는 아무 일도 안 일어난다

            1층 기울기   20층 기울기   비(시드 0)   비(시드 6개 중앙값)
Post-LN      1.78e-01    3.45e-01      0.516            0.595
Pre-LN       1.89e-01    1.15e-01      1.646            1.618
잔차 없음     2.99e-01    9.86e-01      0.303            0.360

셋 다 3배 안쪽이다. 잔차를 통째로 빼도 마찬가지고, 시드를 바꾸면 순위조차 흔들린다. 4편에서 초기값을 잘못 두면 1e9 배가 벌어졌던 것과 비교하면 아무것도 아니다.

이유는 6편에 있다. 정규화가 이미 스케일을 매 층 리셋한다. 잔차가 없어도 LN 이 붙어 있으면 순전파가 죽지 않는다. 그러니 20층짜리로는 이 세 가지를 구분할 수 없다.

깊이를 올려야 한다.

96층까지 올린다

1층 기울기를 끝 층 기울기로 나눈 값이다. 1 이면 앞뒤가 같고, 작으면 앞 층이 굶고, 크면 끝 층이 굶는다. 시드 6개의 중앙값이다.

   L   Post-LN   Pre-LN   잔차 없음
   6     0.671     1.20      0.773
  24     0.534     1.69      0.432
  48     0.372     2.23      0.245
  96     0.306     2.89      0.031
1e0 1e-1 1e-2 1 25 49 73 96 블록 기울기 크기 잔차 없음 Post-LN Pre-LN
블록 96개를 쌓았을 때 블록별 기울기 크기. 잔차를 빼면 앞쪽 블록이 0.026 까지 가라앉아 끝 블록의 33분의 1이 된다. 잔차가 있으면 LN 을 앞에 두든 뒤에 두든 3배 안에서 평평하다.

세 줄이 서로 다른 이야기를 한다.

잔차 없음이 유일하게 무너진다. 0.773 에서 0.031 로, 96층에서 앞 층이 끝 층의 32분의 1을 받는다. 게다가 가속한다 - 48층까지는 0.245 로 견디다가 그 뒤에 급격히 떨어진다. LN 이 순전파는 살려도 역전파의 층간 균형까지 살리지는 못한다.

Post-LN 과 Pre-LN 은 반대로 기운다. Post-LN 은 0.306 이라 앞 층이 3.3배 적게 받고, Pre-LN 은 2.89 이라 끝 층이 2.9배 적게 받는다. 둘 다 깊이를 따라 커지지만, 96층에서도 3배 안쪽이다.

깊이를 버티게 하는 것은 잔차 연결이고, 정규화 위치는 그 위에서 기울기를 어느 쪽으로 기울일지 정하는 손잡이다. 크기가 한 자릿수 다르다.

Post-LN 이 앞 층을 굶긴다는 것이 실제로 학습 초기에 문제가 되고, 학습률 워밍업이 필요하다고 알려진 이유가 이것이다. 다만 여기서 잰 것은 초기값에서의 기울기 분포뿐이다. 학습이 진행되면서 어떻게 달라지는지는 이 실험이 답하지 않는다.

잔차 흐름은 자란다

Pre-LN 에는 딸린 성질이 하나 있다. 블록마다 결과를 더하기만 하므로 흐름이 계속 커진다.

   L      1층 sd    끝 층 sd    배수    sqrt(L)
   6        1.04       1.21    1.17       2.45
  24        1.03       1.91    1.85       4.90
  96        1.04       3.59    3.46       9.80

흔히 sqrt(L) 로 자란다고 한다. 독립인 것들을 L 개 더하면 분산이 L 배가 되니 표준편차가 sqrt(L) 배라는 계산이다. 그런데 재 보면 3.46 이지 9.80 이 아니다. 지수로 0.272 로, 0.5 의 절반쯤이다.

전제가 안 맞기 때문이다. sqrt(L) 은 더해지는 것이 흐름과 비슷한 크기일 때의 계산인데, 기본 초기값에서 부분층 출력은 흐름보다 훨씬 작다. 확인은 간단하다. WoW2 의 초기값만 키워 보면 된다.

  출력 배율 1     배수  3.46   지수 0.272
  출력 배율 3     배수  9.21   지수 0.487
  출력 배율 10    배수 14.19   지수 0.581

3배로 키우니 지수가 0.4870.5 에 붙는다. sqrt(L) 은 틀린 게 아니라 조건부이고, 실제 초기값에서는 그 조건이 성립하지 않는다.

그래도 흐름이 자라는 것 자체는 사실이고, 그래서 Pre-LN 망은 마지막에 LN 을 하나 더 둔다. 위 실험에도 그게 들어가 있다. 없으면 커진 채로 출력이 나간다.

그래서

  • 20층으로는 아무것도 구분 못 한다. 정규화가 스케일을 매 층 리셋해서 잔차가 없어도 멀쩡해 보인다
  • 96층에서 갈린다. 잔차를 빼면 앞 층 기울기가 끝 층의 1/32 이고, 48층을 넘기면서 급격해진다
  • Post-LN 과 Pre-LN 은 반대로 기운다. 0.3062.89. 방향은 반대지만 크기는 둘 다 3배 안쪽 - 잔차의 32배와는 자릿수가 다르다
  • Pre-LN 흐름은 자라지만 sqrt(L) 만큼은 아니다. 실측 지수 0.272. 부분층 출력을 3배로 키우면 0.487 이 되어 계산과 맞는다
  • 잰 것은 초기값에서의 기울기 분포다. 학습 과정은 다른 질문이다

다음 편에서는 이 모든 것을 한 번 굴린다. 지금까지 부품과 배선을 봤으니, 실제로 글자를 예측하는 가장 작은 것을 처음부터 끝까지 돌려 본다.

Comments