훈련이 끝난 뒤 part 12 of 13

프리필을 세니 1.56배가 1.22배가 됐다

guide / / 6 sections

9편은 패딩 낭비를, 10편은 슬롯 점유를, 11편은 캐시 할당을 쟀다. 셋 다 스텝을 세는 방식이 같았다. 요청이 다 도착해 있고, 캐시는 이미 프롬프트로 채워져 있고, 거기서부터 한 글자씩 뽑는 걸음만 셌다.

프롬프트를 캐시에 밀어 넣는 값은 한 번도 안 쟀다. 재 보니 그게 세 편의 결론을 바꾼다.

프리필은 이차식이다

디코드는 한 번에 토큰 하나를 밀어 넣지만 프리필은 프롬프트 전체를 한 번에 넣는다. 어텐션이 P x P 짜리가 되니 길이의 제곱이 붙는다. 배치 32에서

프롬프트   프리필(us)   디코드 한 걸음 몇 개어치
      8        2,461               1.34
     16        3,836               2.09
     32        6,205               3.38
     64       13,728               7.48

t = a + b·P + c·P² 로 맞추면 a = 1,677 us, b = 101.0 us/토큰, c = 1.3607 us/토큰² 다. P = 64 에서 이차항이 전체의 40.6% 다. 길이를 두 배로 하면 값이 두 배보다 더 든다.

10편의 요청은 프롬프트가 8에서 64 사이였고 생성이 평균 37.6 글자였다. 프리필 한 번이 디코드 서너 걸음 값이니, 서른일곱 걸음짜리 요청에서 프리필은 십분의 일쯤이다. 무시해도 될 것 같았다.

연속 배치는 프리필을 쪼갠다

그런데 프리필을 몇 번에 나눠 내느냐가 다르다.

고정 배치는 묶음을 통째로 시작하니 32개를 한 번에 밀어 넣는다. 여덟 묶음이면 프리필 여덟 번이다.

연속 배치는 요청 하나가 끝날 때마다 그 자리를 채운다. 자리는 하나씩, 가끔 둘씩 난다.

                   프리필 횟수   묶음 크기 분포
고정 배치                    8   32개 x 8
연속 배치, 자리 나는 대로       144   32개x1  11개x1  4개x4  3개x9  2개x41

같은 256개 프롬프트를 144 번에 나눠 낸다. 평균 묶음이 1.78 개다. 프리필 비용의 a = 1,677 us 는 행이 몇이든 붙는 고정분이니, 두 개씩 144번 내면 서른두 개씩 여덟 번 낼 때보다 그 고정분을 훨씬 많이 낸다.

프리필만 떼어 재면 연속 배치가 고정 배치의 2.011 배다 (사분위 1.890~2.086, 21회 전승).

그래서 표가 이렇게 바뀐다

10편은 연속 배치가 고정 배치보다 1.58 배 빠르다고 적었다. 그 숫자는 디코드만 센 것이다. 같은 트레이스를 프리필까지 넣고 끝까지 돌리면

                        중앙값    사분위          21회 중
디코드만 세면             1.560   1.472 ~ 1.689     21 승
프리필까지 넣으면          1.218   1.154 ~ 1.283     20 승
요청 256개를 끝내는 데 걸린 시간, 고정 배치를 1 로 프리필디코드프리필 횟수 고정 배치 13% 8 연속 k=1 32% 144 연속 k=2 27% 88 연속 k=4 24% 48 연속 k=8 21% 27 연속 k=16 18% 15 연속 k=32 17% 8 프리필을 빼면 여기 (1.56 배)
막대 길이는 요청 256개를 끝내는 데 걸린 시간, 고정 배치를 1 로 놓았다. 어두운 쪽이 프리필 몫이고 오른쪽 숫자는 프리필을 몇 번에 나눠 냈는지다. 연속 배치가 자리 나는 대로 받으면 프리필이 144번으로 쪼개져 몫이 32%까지 부푼다. 세로선은 프리필을 빼고 쟀을 때 그 막대가 서는 자리 - 10편이 본 지점이다.

1.561.22 가 된다. 이득의 절반 넘게가 프리필로 나간다. 프리필이 전체에서 차지하는 몫이 고정 배치는 13.1% 인데 연속 배치는 32.0% 다.

10편의 1.58 이 틀린 것은 아니다. 디코드 스텝을 세면 그게 맞다. 다만 그 표 어디에도 프리필이 없었고, 나는 그걸 적지 않았다.

모아서 넣으면

고칠 데가 보인다. 자리가 나자마자 넣지 말고, k 개가 모일 때까지 기다렸다 한 번에 넣으면 프리필 횟수가 준다. 대신 기다리는 동안 그 자리는 비어 있다.

   k    프리필 횟수   평균 묶음   디코드 스텝   프리필 몫   고정 대비 배속
   1          144      1.78         336      32.0%          1.218
   2           88      2.91         338      27.4%          1.333
   4           48      5.33         348      24.4%          1.350
   8           27      9.48         364      21.1%          1.357
  16           15     17.07         410      18.2%          1.316
  32            8     32.00         512      16.6%          1.199

뒤집힌 U자다. k = 8 에서 1.357 로 제일 좋고 양 끝이 나쁘다.

k = 1 이 나쁜 이유는 위에서 본 대로다. k = 32 가 나쁜 이유는 디코드 스텝 칸에 있다 - 512 로 고정 배치와 똑같아진다. 32개가 모일 때까지 기다리면 자리가 다 빌 때까지 기다린다는 뜻이고, 그건 연속 배치를 안 하는 것이다. 프리필을 여덟 번으로 줄이는 대신 10편이 없앤 자리 낭비를 도로 들여왔다.

k 를 올릴수록 한 묶음 안의 최대 프롬프트도 길어진다 - 41.1 에서 62.8 로. 9편에서 본 패딩이 프리필 쪽에도 그대로 있다.

남는 것

여기서 프리필과 디코드는 번갈아 돈다. 프리필이 도는 동안 디코드는 멈춰 있다. 긴 프롬프트 하나가 들어오면 이미 돌고 있는 요청 서른한 개가 그만큼 기다린다. 프롬프트를 조각내서 디코드 걸음 사이에 끼워 넣는 방법이 있는데, 재지 않았다.

프롬프트 길이도 8에서 64 사이 균등이다. 이차항이 P = 64 에서 40.6% 니까 프롬프트가 수백 수천으로 가는 쪽에서는 프리필이 전체를 삼킬 것이고, 그러면 이 편의 비율도 다 달라진다.

그리고 k = 8 이 최적이라는 것은 이 워크로드에서다. 생성 길이가 길어지면 디코드 쪽이 무거워져 프리필 횟수가 덜 중요해지고, 최적 k 는 내려갈 것이다.

그래서

  • 프리필은 프롬프트 길이의 이차식이다. P = 64 에서 이차항이 40.6%
  • 배치 32의 프리필 한 번이 디코드 1.34~7.48 걸음 값이다
  • 고정 배치는 프리필을 8 번에, 연속 배치는 144 번에 나눠 낸다. 평균 묶음 1.78
  • 그래서 연속 배치의 프리필이 고정 배치의 2.011 배다
  • 10편의 1.58 은 디코드만 센 값이다. 프리필을 넣으면 1.218
  • 프리필 몫이 고정 13.1%, 연속 32.0%
  • k 개씩 모아 넣으면 k = 8 에서 1.357 로 회복된다. k = 32 는 자리 낭비를 도로 들여와 1.199

Comments