훈련이 끝난 뒤 part 10 of 13

빈 자리를 채웠더니 캐시가 길어졌다

guide / / 8 sections

9편은 요청을 길이순으로 정렬해서 패딩 낭비를 47.4% 에서 0.7% 로 줄였다. 그 편의 마지막 문단은 정렬이 한 번 묶고 나면 끝이라고, 요청마다 끝나는 시점이 다르면 짧은 요청이 비운 자리가 그대로 남는다고 적었다. 그 자리를 바로 채우는 것이 연속 배치다.

거기 재지 않은 것이 두 개 있었다. 연속 배치가 실제로 얼마를 버는지, 그리고 애초에 요청 길이가 어떻게 흩어지는지. 9편이 쓴 분포는 1에서 128 사이 균등인데 그건 내가 고른 것이지 잰 것이 아니다.

길이부터 잰다

모델에게 물어보면 된다. 검증 데이터에서 8에서 64자 사이 프롬프트를 뽑아 이어 쓰게 하고 개행이 나오면 멈춘다. 요청마다 자기 난수 시드를 줘서, 어느 배치에 들어가든 같은 길이가 나오게 했다. 그래야 스케줄만 바꿔 가며 비교할 수 있다.

요청 256개, 개행에서 정지, 상한 64
  평균 37.6   중앙값 37   최소 1   최대 64   표준편차 21.3
  분위  10%     8
  분위  25%    19
  분위  50%    37
  분위  75%    64
  상한에 걸린 것  69개

균등분포가 아니다. 절반이 37자 아래인데 27%는 상한까지 갔다. 9편이 걱정한 “짧은 쪽에 몰리고 꼬리가 긴” 모양이 맞다.

9편의 손잡이가 여기서는 안 돌아간다

프롬프트 길이는 요청이 도착하는 순간 안다. 생성 길이는 다 끝나야 안다. 둘 사이 상관은 -0.076 이다.

그래서 프롬프트 길이로 정렬해도 자리 낭비는 하나도 안 준다.

                     스텝    행-스텝   행 점유   캐시 점유   평균 캐시
고정, 도착순           512   16,384    58.8%     61.7%        93.3
고정, 프롬프트순        512   16,384    58.8%     82.3%        70.0
고정, 생성길이순(신탁)   332   10,624    90.6%     67.7%        87.9
연속, 도착순           336    9,630   100.0%     56.2%       104.1
연속, 프롬프트순        339    9,630   100.0%     70.8%        87.2

위 두 줄의 행-스텝이 소수점까지 같다. 512 = 8 x 64, 여덟 묶음의 최대가 전부 정확히 64 였다는 뜻이다. 256개 중 69개가 상한에 걸렸으니 32개를 아무렇게나 집어도 그중 하나는 거의 확실히 64 다. 순서를 바꿔도 그건 안 바뀐다.

생성 길이를 미리 아는 신탁에게 정렬을 맡기면 90.6% 가 된다. 9편이 가지고 있던 것은 알고리즘이 아니라 정보였다. 프롬프트 길이는 도착할 때 손에 쥐어지고 생성 길이는 안 쥐어진다.

자리를 비워 두지 않기

정렬을 못 하면 다른 쪽으로 간다. 묶음이 다 끝날 때까지 기다리지 말고, 요청 하나가 끝나면 그 자리에 대기 중인 다음 요청을 바로 넣는다.

고정 배치 - 끝난 자리는 묶음이 끝날 때까지 빈다 연속 배치 - 빈 자리에 다음 요청이 바로 들어온다 슬롯 32 슬롯 32 336 에서 끝 그 스텝에 어텐션이 읽어야 하는 캐시 길이 0 64 128 고정연속 128 256 336 512 스텝
요청 256개를 배치 32로 돌린 실제 트레이스. 위는 고정 배치로, 묶음마다 오른쪽 끝이 톱니처럼 비고 512 스텝이 걸린다. 가운데는 연속 배치로 빈틈이 없고 336 스텝에서 끝난다. 아래는 그 스텝에 어텐션이 읽어야 하는 캐시 길이 - 고정 배치는 묶음마다 내려앉지만 연속 배치는 한 번 올라가면 안 내려온다.

행-스텝이 16,384 에서 9,630 으로, 스텝 수가 512 에서 336 으로 준다.

점유율 100.0% 는 발견이 아니라 정의다. 끝난 행을 그 즉시 텐서에서 빼는 스케줄이니 낭비된 행이 0인 게 당연하다. 볼 것은 그 옆의 두 숫자다.

채운 값은 캐시로 나간다

평균 캐시 길이 칸을 보면 연속 배치가 104.1제일 길다. 도착순 고정 배치의 93.3 보다 길다.

당연하다. 연속 배치는 오래 도는 긴 요청 옆에 갓 들어온 짧은 요청을 일부러 붙여 놓는다. 캐시를 하나의 조밀한 텐서로 들고 있으면 그 텐서의 길이는 항상 제일 긴 놈이 정한다. 자리를 채운 대가가 여기로 나온다.

행-스텝은 41% 줄었는데 어텐션이 실제로 읽는 양 - 행 x 캐시 를 다 더한 것 - 은 1,528,896 에서 1,009,60134% 만 줄었다. 7 포인트가 캐시 쪽으로 새어 나갔다.

시간으로 옮기면

스텝 하나의 값을 행 수와 캐시 길이의 격자에서 재고 t = a + b·R + d·R·C 로 맞췄다.

a = 569 us        스텝마다 고정
b = 7.68 us       행 하나당
d = 0.1015 us     행 하나 x 캐시 한 칸당

3 x 3 격자에 대한 잔차가 최대 2.6% 다. 행 32, 캐시 104 에서 고정분이 49%, 행에 붙는 분이 21%, 어텐션이 29% 다.

그 값으로 다섯 스케줄을 매기고, 같은 라운드 안에서 짝지어 41회 실측했다.

                     예측 배속   실측 중앙값   하위25~상위75%
고정, 도착순             1.00       1.00
고정, 프롬프트순          1.07       1.06      0.94 ~ 1.13
고정, 생성길이순(신탁)     1.57       1.57      1.49 ~ 1.66
연속, 도착순             1.56       1.58      1.50 ~ 1.69
연속, 프롬프트순          1.64       1.65      1.54 ~ 1.78

정렬 한 줄은 사분위가 1.0 을 걸친다. 공통 기준선을 거치면서 묻힌 것이라, 두 설정만 같은 라운드 안에서 바로 나누고 순서도 번갈아 가며 61회 다시 쟀다.

고정, 프롬프트순 / 도착순    1.077   사분위 1.036 ~ 1.127   61회 중 54회 이김
연속, 프롬프트순 / 도착순    1.057   사분위 0.992 ~ 1.102   61회 중 44회 이김

셋이 나온다.

하나. 프롬프트순 정렬은 1.08 배다. 캐시 점유를 61.7% 에서 82.3% 로 20 포인트나 올렸는데 시간은 8% 준다. 어텐션이 걸음의 29% 뿐이라 그렇다. 9편의 “낭비를 다 없애도 시간은 절반만 준다” 가 여기서는 절반 근처도 아니다.

둘. 연속 배치 혼자서는 1.58 배다. 신탁 정렬의 1.57 과 사실상 같다. 미리 알 수 없는 것을 알아야 얻는 이득을, 아무것도 몰라도 얻는다.

셋. 둘을 같이 쓰면 1.65 배다. 연속 배치 위에 정렬을 얹으면 1.06 배가 더 붙는다 - 61회 중 44회라 작지만 한쪽으로 쏠린다. 겹치는 기법이 아니라서 그렇다. 정렬은 캐시 차원의 패딩을 고치고 연속 배치는 행 차원의 패딩을 고친다. 연속 + 프롬프트순의 행 x 캐시801,245 는 다섯 중 제일 작다.

9편과 안 맞는 데가 하나

9편은 배치 32에서 캐시를 1에서 128로 늘리며 675 us 가 붙는 것을 재고, 걸음의 48.3% 가 길이에 달렸다고 썼다. 이번 격자 적합은 같은 자리에서 412 us, 33.8% 를 준다.

같은 노트북이고 같은 모델인데 15 포인트가 갈린다. 9편은 캐시 길이만 훑는 한 줄짜리 측정이었고 (그 표는 16에서 32로 갈 때 오히려 줄어 있다), 이번 것은 3 x 3 격자를 라운드로빈 50회 돌려 맞춘 평면이다. 뒤엣것이 더 믿을 만하다고 보지만, 정직한 결론은 이 기계에서 그 비율이 30%대인지 40%대인지 못 박을 수 없다는 것이다. 위의 배속 표가 예측이 아니라 실측 짝비율인 이유다.

남는 것

상한 64에 걸린 요청이 27% 다. 진짜 꼬리는 잘려 있고, 자르지 않았다면 고정 배치가 더 나빠졌을 것이다. 연속 배치에 유리하게 자른 셈이니 위 숫자들은 보수적이다.

조밀한 캐시 텐서를 쓴다는 것도 선택이다. 캐시를 고정 크기 블록으로 쪼개 놓으면 행마다 필요한 만큼만 들고 있을 수 있고, 그러면 연속 배치가 캐시로 내는 값이 사라진다. 이 편은 거기까지 안 갔다.

값매김한 절대 시간은 실측보다 24~29% 낮다. 다섯 줄이 전부 같은 방향으로 비슷한 만큼 빗나가므로 비율은 쓰고 절대 시간은 안 쓴다.

이 표를 처음 잰 날에는 같은 트레이스가 1,581 ms 로 나왔다. 지금은 461 ms 다. 코드도 데이터도 그대로인데 3.4배 차이가 나는데, 그날 이 노트북이 다른 일로 바빴다. 그런데 그날의 배속 비율도 1.58 이었다. 같은 라운드 안에서 짝지어 나눈 숫자만 살아남은 것이고, 절대 시간을 결과로 적었다면 전부 틀렸을 것이다.

그래서

  • 생성 길이는 프롬프트 길이로 예측이 안 된다. 상관 -0.076
  • 그래서 프롬프트순 정렬은 행 낭비를 58.8% 에서 한 칸도 못 옮긴다. 여덟 묶음의 최대가 전부 64 였다
  • 생성 길이를 아는 신탁이 정렬하면 90.6%. 9편이 쥐고 있던 건 정보였다
  • 연속 배치는 행 점유를 100% 로 만든다. 그건 정의고, 볼 것은 스텝 수 512 -> 336
  • 채운 값은 캐시로 나간다. 평균 캐시 93.3 -> 104.1 로 다섯 중 제일 길다
  • 행-스텝은 41% 주는데 행 x 캐시 는 34% 만 준다
  • 실측 1.08 (정렬) / 1.58 (연속) / 1.65 (둘 다). 다른 낭비를 고치니 합쳐진다

Comments