읽는 글자와 쓰는 글자의 값이 40배 다르다
지금까지 두 종류의 시간을 따로 쟀다. 2편은 글자를 하나씩 뽑는 시간을, 5편은 그 걸음을 배치로 쪼갠 값을 봤다. 아직 안 잰 것이 하나 있다. 프롬프트를 읽는 시간이다.
모델에 글을 주고 이어 쓰게 하면 두 단계가 있다. 먼저 준 글 전체를 한 번에 통과시켜 캐시를 채우고, 그 다음부터 한 글자씩 뽑는다. 같은 가중치, 같은 연산인데 글자당 값이 전혀 다르다.
한 번에 넣으면 싸다
프롬프트 P 글자를 한 번에 통과시키는 시간이다.
P 시간(us) 글자당(us)
1 405 404.7
4 489 122.3
16 564 35.3
64 902 14.1
128 1354 10.6
P 를 128배 키웠는데 시간은 3.3 배만 늘었다. 글자당으로 보면 404.7 에서
10.6 으로 떨어진다.
5편의 식이 그대로 읽힌다. t = a + b·B 에서 한 번에 넣는 글자 수가 B 자리에
들어간다. 고정 오버헤드 a 를 P 개가 나눠 내니 P 가 커질수록 글자당 값이
b 로 수렴한다. 프롬프트를 읽는 일은 배치가 큰 걸음 하나다.
하나씩 뽑으면 비싸다
같은 모델로 캐시가 찬 상태에서 글자 하나를 뽑으면
문맥 16 399 us
문맥 64 410 us
문맥 127 428 us
문맥이 길어져도 거의 안 변한다. 400 us 언저리인데, 5편이 배치 실험에서 뽑은
고정 오버헤드가 a = 456.4 us 였으니 그 자리다. 글자 하나를 뽑을 때마다
고정 오버헤드를 통째로 다시 낸다. 두 숫자가 딱 안 맞는 것은 따로 잰 값이라
그렇고, 이 노트북에서 절대 시간은 그 정도로는 예사로 벌어진다.
프롬프트 글자당 10.6 us
생성 글자당 428 us
비 40배
같은 모델, 같은 곱셈인데 읽는 글자가 쓰는 글자보다 40 배 싸다. 차이는 계산이
아니라 한 번에 몇 개를 넣었느냐뿐이다.
요청 하나가 어디에 시간을 쓰나
이 비율이 실제 요청에서 무엇을 뜻하는지 보자. 프롬프트 P 글자를 읽고 G 글자를
쓴다.
P G 첫 글자까지(ms) 전체(ms) 프롬프트 몫
128 16 1.35 8.21 16.5%
128 64 1.35 28.77 4.7%
128 128 1.35 56.19 2.4%
32 128 0.66 55.49 1.2%
8 128 0.51 55.35 0.9%
프롬프트가 아무리 길어도 첫 글자까지는 1.35 ms 다. 반면 128글자를 쓰는 데
55 ms 가 든다. 프롬프트를 128글자 읽는 값이 글자 두세 개 쓰는 값과 같다.
그래서 긴 프롬프트에 짧은 답을 하는 요청과 짧은 프롬프트에 긴 답을 하는 요청은
성격이 완전히 다르다. 앞의 것은 프롬프트가 16.5% 를 먹고, 뒤의 것은 0.9% 다.
이것이 서빙 시스템이 두 단계를 따로 이름 붙여 재는 이유다. 첫 글자까지의 시간과
그 뒤 글자당 시간은 다른 자원을 쓰고 다르게 최적화된다. 5편의 표현으로는
프롬프트 읽기는 b 가 지배하는 구간이고 글자 뽑기는 a 가 지배하는 구간이다.
그래서 배치가 생성 쪽에만 필요하다
5편에서 배치를 키우면 처리량이 오르는 것을 봤다. 이제 그것이 어느 단계 이야기인지 분명해진다.
프롬프트 읽기는 이미 P 개를 한 번에 넣고 있어서 스스로 배치가 크다. P=128 이면
5편의 a/b = 27 을 이미 넘었고, 오버헤드 몫이 작다. 더 묶어도 남는 게 적다.
반대로 글자 뽑기는 언제나 배치 1이다. 한 요청이 한 걸음에 글자 하나를
내놓으니 구조적으로 그렇다. 그래서 5편에서 잰 96.4% 오버헤드가 이 단계의
이야기이고, 여러 요청을 같은 걸음에 묶는 것이 여기서 값을 한다.
단서
이 편의 숫자는 전부 60회 중 최솟값이고, 세 표가 같은 추정량을 쓴다. 처음에는
표마다 최솟값과 중앙값을 섞어 써서 P=32 의 프롬프트 읽기가 P=128 보다 비싸게
나왔다. 같은 양을 두 방식으로 재면 비교가 무너진다.
a 와 b 를 프롬프트 읽기에 그대로 옮긴 것도 정확하지는 않다. 5편의 배치는
요청들이 서로를 안 보지만 프롬프트 안의 글자들은 서로를 본다. 어텐션이 P² 로
자라므로 P 가 크면 직선에서 벗어난다. 위 표에서도 P=64 에서 128 로 갈 때
시간이 1.5 배 늘어 완전한 상수 더하기 직선은 아니다.
그래서
- 프롬프트를 한 번에 넣으면 글자당 값이
404.7에서10.6 us로 떨어진다. 고정 오버헤드를P개가 나눠 내기 때문이다 - 글자를 뽑는 값은 문맥과 거의 무관하게
400 us언저리다. 매번 오버헤드를 통째로 다시 낸다 - 읽는 글자가 쓰는 글자보다
40배 싸다. 같은 가중치, 같은 곱셈이다 - 프롬프트 128글자를 읽는 값이 글자 두세 개를 쓰는 값이다. 첫 글자까지
1.35 ms, 128글자 쓰기55 ms - 배치는 생성 쪽 이야기다. 프롬프트 읽기는 이미 배치가 크고, 글자 뽑기는 구조적으로 배치 1이다
- 세 표가 같은 추정량을 쓴다. 섞어 쓰면
P=32가P=128보다 비싸게 나온다
다음 편은 3편으로 돌아간다. 거기서는 가중치를 거칠게 만들었는데, 이번에는 아예 없앤다. 어느 쪽이 더 남는지 같은 압축률에서 견줘 본다.
Comments