writing

Series · 13 parts

훈련이 끝난 뒤

학습이 끝난 모델을 실제로 돌릴 때 붙는 것들을 잰다. 다음 글자를 고르는 규칙, 두 번 계산하지 않는 법, 정밀도를 버리고 남는 것 - 앞 시리즈에서 만든 모델을 그대로 쓴다.

Assumed 앞 시리즈 '보이는 딥러닝' 을 읽었거나, 트랜스포머가 무엇을 계산하는지 알면 된다.

  1. 01 모델은 다음 글자를 고르지 않는다 학습된 모델이 내놓는 것은 글자가 아니라 분포다. 고르는 일은 그 뒤에 따로 붙는 선택이고, 그 선택이 결과를 얼마나 바꾸는지 13편에서 만든 모델로 직접 잰다.
  2. 02 같은 계산을 n 번 반복하고 있었다 글자 하나를 뽑을 때마다 앞 문맥을 통째로 다시 계산한다. 캐시를 붙이면 산술이 130분의 1로 줄어드는데 실제 시간은 3배만 빨라진다. 그 격차가 어디서 오는지 잰다.
  3. 03 가중치를 4분의 1로 줄이면 무엇이 사라지나 2편의 캐시가 가중치보다 커졌다. 이번에는 가중치 쪽을 줄인다. float32 를 int8 로 바꾸면 손실이 0.0017 밖에 안 오르는데, 뽑은 글은 스물두 번째 글자에서 갈린다.
  4. 04 초안이 좋을수록 느려졌다 투기적 디코딩은 싼 모델이 여러 글자를 미리 쓰고 비싼 모델이 한 번에 검사한다. 출력 분포가 정말 안 변하는지 재고, 수락률이 0.9 인 초안이 왜 0.29 인 초안에게 지는지 본다.
  5. 05 배치 하나에 96%가 낭비였다 2편에서 값을 치르던 것은 곱셈이 아니라 오버헤드였다. 그 몫이 정확히 얼마인지 재고, 배치를 키워 그것을 처리량으로 바꾼다. 대가는 지연이다.
  6. 06 캐시를 자르면 맨 앞을 남겨야 한다 2편에서 캐시가 가중치보다 커졌다. 오래된 것부터 버리면 되는데, 무엇을 남기느냐가 결과를 가른다. 맨 앞 여덟 자리를 남기면 캐시의 19% 로 전체와 거의 같은 손실이 나온다.
  7. 07 읽는 글자와 쓰는 글자의 값이 40배 다르다 같은 모델, 같은 가중치인데 프롬프트를 읽을 때와 글자를 뽑을 때의 글자당 값이 40배 차이 난다. 5편의 a 와 b 로 그 이유가 설명되고, 서빙 시스템이 두 단계를 왜 갈라 놓는지도 같이 나온다.
  8. 08 0을 아무리 많이 만들어도 빨라지지 않는다 3편은 가중치를 int8 로 뭉갰다. 이번에는 아예 0으로 만든다. 어느 것을 0으로 만드느냐가 전부를 가르고, 같은 압축률에서 양자화에 진다. 그리고 99%를 0으로 만들어도 시간은 그대로다.
  9. 09 패딩 낭비는 배치 문제가 아니었다 5편은 요청 길이가 흩어지면 패딩 낭비가 50%로 수렴한다고 쟀다. 그 숫자는 요청을 온 순서대로 묶는다는 전제 위에 있었다. 순서를 바꿀 수 있으면 낭비를 정하는 것은 배치 크기가 아니라 몇 개나 모아 뒀느냐다.
  10. 10 빈 자리를 채웠더니 캐시가 길어졌다 9편은 길이순 정렬로 패딩 낭비를 47%에서 0.7%로 줄였다. 그 트릭은 생성 길이에는 안 통한다 - 미리 알 수가 없다. 연속 배치가 그 자리를 채우지만, 채운 대가로 어텐션이 읽는 캐시가 길어진다.
  11. 11 메모리를 1.6배 아끼고 시간을 1.7배 잃었다 10편은 조밀한 캐시 텐서의 길이를 제일 긴 행이 정한다는 데서 끝났다. 고정 크기 블록으로 쪼개면 최대 할당이 4,064에서 2,560 슬롯으로 준다. 그런데 흩어진 블록을 모아 오는 값이 아낀 것보다 컸다.
  12. 12 프리필을 세니 1.56배가 1.22배가 됐다 9편부터 11편까지 스케줄을 견주면서 디코드 스텝만 셌다. 프롬프트를 밀어 넣는 값을 넣으면 연속 배치의 이득이 절반으로 준다 - 자리가 하나씩 나는 탓에 프리필을 8번이 아니라 144번 나눠 내기 때문이다.
  13. 13 꼬리를 재니 12편의 k=8 이 47% 나쁘다 12편은 처리량으로 k=8 을 골랐다. 글자 사이 간격의 p99 를 재면 k=8 은 8.21ms 로 k=1 의 5.57ms 보다 47% 나쁘다. 12편이 이름만 대고 넘어간 프리필 조각내기도 재 봤는데, 프론티어 여섯 점 중 둘뿐이었다.