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