문서

Laya MLX 성능 연구

연구 날짜: 2026-09-19. 대상: Apple M3 Max, GPU 코어 40개, 통합 메모리 128 GiB, MLX/MLX Metal 0.32.2. 이것은 네이티브 런타임, 설치된 MLX 구현, 공식 문서, 기존 벤치마크 JSON에 대한 정적 검토입니다. 이 연구를 위해 GPU 벤치마크나 모델 추론을 실행하지 않았습니다. 아래 제안한 최적화 중 이 보고서에서 속도 향상을 측정한 것은 하나도 없습니다.

첫 실험은 전체 모델 컴파일과 대표적인 배치 스케줄링이어야 하고, 그다음이 선택적 양자화 행렬 곱셈입니다. 이들은 지배적인 반복 작업을 다룹니다. 전용 지역 어텐션 커널은 장문 입력을 위한 신뢰할 만한 장기 프로젝트입니다. 마지막 결정 헤드 레이어의 정확한 프루닝은 실행 가능하지만, 전체 모델 산술 절감은 몇 퍼센트에 불과합니다. 체크포인트를 바꾸지 않고 큰 개선을 얻으려면 dense 백본을 개선하거나, 진짜 중복되는 요청을 제거하거나, 측정된 구현 병목을 찾아야 합니다. 활성화 함수를 바꾸거나 어텐션 플래그를 하나 더 켜는 것만으로 충분할 가능성은 낮습니다.

기존 측정이 입증하는 것

다음은 프롬프트 준비와 결과 포매팅을 포함하고, GPU 완료 동기화, 워밍업 5회, 측정 반복 50회를 거친 기존 엔드투엔드 중앙값 지연 시간입니다. 모델 로딩과 다운로드는 제외됩니다. 벤치마크는 질문 64개 배치를 허용하며, 공개 런타임 기본값은 16이므로 질문 50개 결과는 기본 API 구성이 아닙니다.

체크포인트 / 정밀도 짧은 질문 1개 짧은 질문 10개 짧은 질문 50개 긴 질문 1개 긴 질문 10개
Laya MLX FP16 13.421 ms 71.068 ms 336.030 ms 44.927 ms 420.987 ms
Laya MLX FP32 15.954 ms 98.820 ms 450.712 ms 61.331 ms 534.242 ms
Laya stock Torch MPS FP32 24.918 ms 95.265 ms 497.856 ms 65.581 ms 586.594 ms
Multilingual MLX FP16 7.390 ms 27.386 ms 127.565 ms 37.635 ms 389.487 ms
Multilingual MLX FP32 7.988 ms 32.337 ms 151.387 ms 47.208 ms 451.331 ms
Multilingual stock Torch MPS FP32 19.349 ms 43.158 ms 194.171 ms 52.939 ms 534.492 ms

출처: Laya FP16, Laya FP32, Laya MPS, 다국어 FP16, 다국어 FP32, 다국어 MPS. 긴 입력은 Laya가 512토큰, 다국어가 1024토큰이므로, 두 긴 입력 지연 시간을 비교하는 것은 같은 시퀀스 길이에서의 비교가 아닙니다. 짧은 패딩 길이는 각각 93과 91입니다. Torch 비교는 FP32 레이블을 반드시 유지해야 합니다. MLX FP16과 비교하면 백엔드 변경과 정밀도 변경이 함께 일어난 것이기 때문입니다.

실행 변동이 상당합니다. 예를 들어 다국어 FP16 긴 질문 10개 실행은 p50 389.487 ms, p95 462.319 ms, 최대 619.663 ms입니다. 같은 구성의 짧은 질문 1개 포워드 중앙값은 8.023 ms인데, 독립적으로 측정한 엔드투엔드 중앙값은 7.390 ms입니다. 이 중앙값들을 빼면 말이 안 되는 음수 전처리 시간이 나옵니다. 현재 파일들은 토크나이저, Python 디스패치, 개별 GPU 커널, 동기화 비용을 분리하지 않습니다. 유용한 기준선을 세울 뿐, 커널 수준의 병목 진단은 아닙니다.

검증 보고서는 FP32와 FP16에서 세 체크포인트 각각의 argmax 일치 63/63과, 변형마다 유한하고 결정적인 반복 호출 100회를 기록합니다: 답 일치 378/378, 총 반복 호출 600회. 이는 반복 질문을 포함한 작은 픽스처 코퍼스에 대한 회귀 검사입니다. 향후 양자화나 아키텍처 변경이 일반적인 작업 정확도를 보존한다는 증거는 아닙니다.

왜 dense 행렬 곱셈이 우선순위를 가져야 하는가

모델 구현은 패딩된 모든 토큰에 QKV와 출력 투영, 게이트가 있는 인코더 MLP, 두 개의 일반적인 transformer 결정 헤드 레이어를 적용합니다. D를 은닉 크기, I를 인코더 중간 크기, N을 인코더 레이어 수, H를 결정 헤드 레이어 수라고 합시다. 이 블록들에서 토큰당 쓰이는 행렬 가중치 수는 다음과 같습니다:

A = N * (4 * D^2 + 3 * D * I) + H * 12 * D^2
dense FLOPs per batch ~= 2 * B * L * A
dense attention FLOPs ~= 4 * B * (N + H) * L^2 * D

이 추정치는 곱셈과 덧셈을 따로 세며, 정규화, 활성화, 임베딩, 스코어링, 마스킹, 메모리 이동, 커널 오버헤드를 제외합니다. 산술 모델이며 런타임 프로파일이 아닙니다.

체크포인트 계열 D / I / 인코더 레이어 토큰 임베딩 가중치 주요 토큰별 행렬 가중치 A 인코더 전역 / 지역 레이어
Laya / typed decisions 1024 / 2624 / 28 51,576,832 368,312,320 10 / 18
Multilingual 768 / 1152 / 22 196,608,000 124,452,864 8 / 14

다국어 체크포인트의 총 파라미터 약 3억 2,200만 개에는 임베딩 파라미터 1억 9,660만 개가 포함됩니다. 추론 시에는 선택된 임베딩 행만 모으며, 전체 어휘 투영이 아닙니다. 주요 토큰별 행렬 작업량은 영어 모델의 약 1/3인데, 총 파라미터 수는 훨씬 비슷해 보입니다. 이는 측정된 짧은 배치 지연 시간 격차와 일관되지만, 특정 하드웨어 병목을 입증하지는 않습니다. 임베딩만 양자화하면 특히 다국어에서 상주 가중치 크기를 주로 줄일 뿐, 추론 지연 시간을 개선할 필요는 없습니다.

현재 dense 어텐션 경로에서 어텐션 곱은 Laya의 L=93에서 모델링된 FLOPs의 약 1.5%, Laya의 L=512에서 7.9%, 다국어의 L=1024에서 23.3%를 차지합니다. 실제 시간에서의 비중은 상당히 다를 수 있습니다. 맞춤형 Metal 작업에 착수하기 전에 프로파일러로 행렬 커널, 어텐션 커널, 요소별 커널, CPU 그래프 구성, 유휴 간격을 구분해야 합니다.

우선순위별 실험

우선순위 실험 최적 대상 주요 트레이드오프 / 수용 조건
P0 짧은 형상 하나와 긴 형상 하나를 프로파일링; 모델 또는 인코더 블록 컴파일 단일 요청 지연 시간과 Python 디스패치 기존 정밀도 허용 범위 안에서 동일한 출력 유지; 첫 사용 컴파일은 따로 측정
P0 실제 토큰 예산과 길이 분포로 배칭 튜닝 서로 다른 질문이 많고 길이가 섞인 트래픽 p95 지연 시간과 메모리 예산을 조건으로 처리량 최적화; 큐잉 고려
P1 선택된 백본 선형 레이어 양자화, 8비트부터 시작해 4비트로 가중치 트래픽과 잠재적 dense 추론 품질과 캘리브레이션 게이트; 실제 M3 Max 속도는 퇴행할 수 있음
P1 공유 상태 토크나이즈와 안정적인 질문 템플릿 캐시 상태나 반복 루브릭을 공유하는 질문 다수 정확한 토큰 동일성; 상한 있는 캐시; 캐시된 결과와 캐시되지 않은 결과 분리
P1 마지막 헤드 레이어에서 필요한 출력만 계산 모든 작업 부하, 특히 긴 시퀀스 정확한 의존성 프루닝; 전체 모델 산술 절감은 소폭
P2 타일 경계를 쓰는 진짜 지역 윈도 어텐션 512/1024토큰 작업 부하 새 커널 복잡성; 양방향 윈도와 패딩 의미 보존
P2 프로파일이 정당화하는 곳에서만 잔차/정규화 또는 GELU/게이트 융합 소형 커널 오버헤드 또는 활성화 트래픽 기존 고속 커널이 이미 상당 부분을 처리; 정확한 GELU 의미 유지
별도 제품 기능 동일한 포워드 입력 중복 제거 실제로 질문을 반복하는 작업 부하 고유 추론 수와 캐시 적중을 보고; 일반 커널 속도 향상으로 제시하지 말 것

평가된 전체 추론 경로 컴파일

Agent.forward()는 현재 배열을 만들고, self.model을 호출하고, 결과를 평가합니다. 모델이나 블록 수준에 감싸는 mx.compile이 없습니다. 고정 형상 컴파일은 Python 그래프 구성을 줄이고 지원되는 연산을 융합할 수 있습니다. MLX는 형상 특화와 명시적 상태 캡처를 문서화하며, shapeless 컴파일이 임의의 형상 의존 Python 연산을 안전하게 보존할 수 없다고 경고합니다. 공식 컴파일 가이드를 참고하십시오.

가중치를 로딩·캐스팅·평가한 뒤 일반적인 형상 특화로 만든 컴파일된 콜러블로 시작하십시오. 동등성 비교와 CPU 호환성을 위해 기존의 컴파일되지 않은 콜러블을 남겨 두십시오. 고정된 추론 모델에서는 그 모델 인스턴스에 대해 가중치를 캡처한 상태로 둘 수 있습니다. 가중치나 모듈 구조가 바뀌면 콜러블을 다시 만들거나 관련 상태를 명시적으로 캡처하십시오. 체크포인트 교체를 넘어 컴파일된 클로저를 재사용하지 마십시오.

전체 모델 래퍼를 테스트하고, 트레이싱 제약이나 컴파일 비용 때문에 매력적이지 않다면 인코더 블록과 헤드를 따로 컴파일하십시오. 현재 코드는 x.shape를 Python 정수로 읽고, 명시적인 배치/길이 값으로 reshape하며, arange(length) 마스크를 만들고, 형상에서 유도한 행 범위로 마커를 인덱싱합니다. 재설계 없이 이 전체 그래프에 shapeless=True를 적용하는 것은 안전하지 않습니다. 동적 마스크 생성을 컴파일 블록 밖으로 옮기고 형상 독립적인 flatten/unflatten 연산을 쓰면 나중에 shapeless 변형을 가능하게 할 수 있습니다. B, L, 마커 수를 바꿔가며 검증하십시오.

형상 버킷은 재트레이싱을 제한할 수 있지만, 패딩에는 연산 비용이 따릅니다. L=93을 96으로 패딩하면 토큰 단위 작업이 약 3.2% 늘고, 128로 패딩하면 약 37.6% 늘어납니다. 정확 형상 컴파일과, 작은 길이 배수 및 작업 부하에 기반한 상한 있는 버킷 집합을 비교하십시오. 캐시 정책 결정에는 (batch size, padded length, marker slots, dtype, device/model instance)를 포함하고, 형상 변동 상황에서 콜드 컴파일 지연 시간과 잔류 메모리를 측정하십시오.

worker.py의 독립 forward 벤치마크는 agent.model을 직접 호출합니다. Agent.forward에만 컴파일을 추가하면, 현재 포워드 벤치마크는 이를 우회하고 엔드투엔드 벤치마크는 이를 씁니다. 의미 있는 비교를 위해서는 두 경로가 같은 후보 구현을 명시적으로 선택해야 합니다. 타이밍 절차에 mx.eval과 GPU 동기화를 유지하십시오. 그래프 구성만 측정하면 추론을 측정하는 것이 아닙니다.

유용한 토큰 기준으로 배칭한 뒤 행렬 스케줄링 점검

collate_items는 각 청크를 가장 긴 시퀀스에 맞춰 오른쪽 패딩하고, 런타임은 질문을 삽입 순서로 묶습니다. 이질적인 트래픽에서는 준비된 길이로 정렬하거나 버킷을 나누고, 질문 수 상한에 더해 토큰 예산을 쓰고, 원래 질문 ID와 출력 순서를 복원하십시오. 배치 1, 2, 4, 8, 16, 32, 64 비교는 서비스를 대표하는 경우에만 하십시오. 온라인 요청에서는 배치를 기다린 시간을 포함하십시오. 오프라인 질문/초만 보면 용납할 수 없는 지연 시간을 숨길 수 있습니다.

현재 짧은 질문 50개 작업 부하는 Laya에서 패딩 토큰의 약 8.9%, 다국어에서 5.8%를 낭비합니다. 긴 벤치마크 행에는 패딩 낭비가 없습니다. 따라서 패딩 제거나 정렬만으로는 이 픽스처들에서 산술적 이득이 제한적입니다. 프로덕션 이득을 드러내려면 짧은 질문 다수 사이에 긴 질문 하나가 섞인 길이 혼합 분포가 필요합니다. 패딩 제거는 예시별 RoPE 위치, 마커 위치, 어텐션 경계를 보존해야 합니다. 격리 마스크 없이 예시들을 하나의 시퀀스로 이어 붙이면 모델이 바뀝니다.

dense 커널에서는 실제 형상과 스트라이드를 점검하십시오. QKV는 이미 단일 투영이고, 인코더 MLP의 두 입력 분기는 이미 하나의 투영을 공유합니다. 그것들을 무분별하게 쪼개면 런치만 늘어납니다. 프로파일러나 MLX 디스패치 트레이스가 바람직하지 않은 배치 GEMM을 보여줄 때만, 연속적인 [B,L,D] 입력을 [B*L,D]로 명시적으로 평탄화하는 것을 비교하십시오. 프레임워크가 이미 효율적으로 평탄화하고 있을 수 있습니다. 소스만 보고 놓친 GEMM 최적화를 주장할 수는 없습니다.

프로덕션 구현에서 레이어마다 동기화를 넣지 마십시오. 현재 런타임은 청크마다 한 번 평가합니다. 추가 대기는 CPU/GPU 겹침을 없애고 스케줄링 개선을 가릴 수 있습니다. 레이어 수준 프로파일링은 별도의 진단 실행이어야 합니다.

양자화: 백본을 겨냥하고 저장 계약을 구현

설치된 MLX 0.32.2 양자화 레이어 구현은 nn.quantize(..., class_predicate=...)와 QuantizedLinear를 제공하며, mx.quantized_matmul을 통한 가중치 전용 행렬 곱셈을 지원합니다. 그룹 아핀 양자화는 8비트와 4비트 실험을 지원합니다. 그룹 크기 64로 인코더 선형 레이어부터 시작하고, 활성화, 정규화, 타입 임베딩, 스코어러, 액션 헤드는 FP16으로 유지하십시오. 그런 다음 결정 헤드 선형 레이어를 독립적으로 추가하고, 선택적으로 임베딩 양자화를 더하십시오. 각 변형을 측정하십시오. 가중치 전용 커널은 토큰 수가 많을 때 FP16 GEMM에 질 수 있습니다.

현재 로더와 모델에는 구체적인 통합 위험이 있습니다:

  1. Agent.__init__은 모든 저장 가중치를 부동 dtype으로 캐스팅하고, 엄격 로딩 전에는 dense 모듈만 인스턴스화합니다. 양자화 체크포인트에는 선택된 모듈, 그룹 크기, 비트 폭, 모드를 설명하는 메타데이터가 필요합니다. 로딩 전에 일치하는 양자화 모듈을 인스턴스화하고, 패킹된 정수 가중치를 보존하십시오. 패킹된 가중치의 부동 캐스팅은 유효한 로딩이 아닙니다.
  2. 첫 액션 헤드 선형 레이어의 입력 폭은 D+4, 즉 1028 또는 772이며, 아핀 그룹 크기 32, 64, 128로 나누어떨어지지 않습니다. 따라서 일괄 양자화 호출은 적합하지 않습니다. 변환 전에 선택한 모든 레이어의 입력 폭을 확인하십시오.
  3. DecisionModel.__call__은 self.act_head.layers[0].weight.dtype에서 액션 헤드 입력 dtype을 고릅니다. 양자화 레이어에서 그 가중치는 원하는 활성화 dtype이 아니라 패킹된 정수 저장입니다. 액션 헤드를 제외하면 처음에는 이 경로를 피할 수 있고, 나중에 지원하려면 명시적인 활성화-dtype 계약이 필요합니다.
  4. 양자화는 로짓과 캘리브레이션된 확률을 바꿉니다. 기존의 작은 FP16 픽스처 일치는 4비트 품질의 충분한 증거가 아닙니다. 홀드아웃으로 레이블된 choice, score, noul 작업, 다국어 입력, 근소한 결정, 다양한 선택지 수, 에스컬레이션 예시를 쓰십시오. argmax 일치, 작업 정확도, 점수 오차, 확률 드리프트, 캘리브레이션, 액션 확률을 추적하십시오. 포화된 액션 출력은 큰 액션-로짓 변화를 숨길 수 있습니다.

그룹 크기 64의 FP16 아핀 스케일과 오프셋에서, 대략적인 행렬 저장량은 파라미터당 bits/8 + 4/64바이트입니다: 8비트에서 1.0625바이트, 4비트에서 0.5625바이트이며, FP16의 2바이트와 비교됩니다. 이는 양자화 행렬의 저장 추정치로, 다른 텐서와 패키징 오버헤드를 제외하며, 속도 향상 추정치가 아닙니다. 공식 quantize API는 그룹 나눗셈과 형식을 설명합니다.

더 새로운 저비트 형식은 이후 Apple 칩의 하드웨어를 쓴다고 가정하지 말고 실제 M3 Max 백엔드에서 평가해야 합니다. MLX의 NAX 가용성 검사는 기록된 applegpu_g15s 장치보다 새로운 아키텍처 세대를 요구합니다. MLX 0.32.2 장치 검사를 참고하십시오.

입력이 실제로 동일할 때 CPU 준비 재사용

build_sequence는 질문마다 같은 상태를 따로 직렬화·정리·토크나이즈합니다. 또한 각 지시문과 선택지를 따로 토크나이즈합니다. Rust 토크나이저는 이미 직접 쓰이고 있으므로, Transformers 토크나이즈를 대체하는 것은 남은 최적화가 아닙니다.

prepare 호출마다 상태를 한 번 직렬화·정리하고, 한 번 인코딩한 뒤, 각 질문이 쓸 수 있는 여유에 맞춰 토큰 ID를 잘라 쓰십시오. 같은 루브릭이 상태들에 걸쳐 쓰일 때는 불변의 준비된 질문 프리픽스를 캐시하되, 키에 토크나이저 정체성/리비전, 질문 유형, 순서 있는 기준, 지시문 직렬화, 특수 토큰 정리, 토큰 예산을 포함하십시오. 상한이 있는 캐시는 토크나이저나 구성이 바뀐 뒤 결과를 재사용해서는 안 됩니다. 배치 토크나이저 인코딩도 또 하나의 실험이며, 그 출력이 현재의 독립 인코딩 시퀀스와 정확히 일치해야 합니다.

독립적으로 인코딩한 조각들을 이어 붙이는 대신 새로 이어 붙인 프롬프트를 토크나이즈하지 마십시오: 서브워드 경계가 바뀔 수 있습니다. 입력 ID, 어텐션 마스크, 마커 위치, qtypes, 절단 동작, 구조화된 기준, 마스크 리터럴, 빈 입력, 출력 매핑을 바이트 단위로 검증하십시오.

긴 벤치마크에서 상태는 절단 전에 한 문장을 200번 반복합니다. N번 반복되는 상태 인코딩을 피하면 CPU 준비에 도움이 될 수 있지만, 기존의 엔드투엔드/포워드 타이밍 차이는 그 절감을 측정하지 않습니다. prepare, collate/배열 구성, 포워드, 후처리를 독립적으로 벤치마크한 뒤, 반복 없는 홀드아웃 코퍼스로 엔드투엔드 결과를 확인하십시오.

디코더 KV 캐시는 이 인코더에 적용되지 않습니다. 첫 레이어가 전역 양방향 어텐션이며, 상태 토큰 표현은 질문, 선택지, 그 위치에 의존합니다. 상태 은닉 상태나 K/V를 서로 다른 질문들 사이에서 재사용하면 결과가 바뀝니다. 토크나이즈와 동일한 전체 입력 결과는 캐시할 수 있지만, 임의의 문맥적 인코더 상태는 캐시할 수 없습니다.

마지막 결정 헤드 출력을 정확히 프루닝

마지막 HeadLayer 이후에는 [CLS] 토큰과 선택지 마커 토큰만 소비됩니다. 마지막 레이어가 그 K/V를 읽기 때문에, 이전 헤드 레이어들은 여전히 모든 토큰을 만들어야 합니다. 마지막 레이어에서만:

  1. 모든 입력 토큰을 정규화하고 모든 K/V를 계산합니다.
  2. [CLS]와 유효한 선택지 위치에서 Q를 모으고, 그 쿼리들을 완전한 마스킹된 K/V 시퀀스에 대해 실행합니다.
  3. 출력 투영, 잔차, 두 번째 정규화, 피드포워드 네트워크를 그 선택된 위치에만 적용합니다.
  4. 선택된 [CLS] 출력은 액션 헤드에, 선택된 마커 출력은 스코어링에 씁니다. 마커 패딩과 원래 순서를 보존하십시오.

첫 구현은 융합된 전체 QKV 투영을 유지하고 Q를 나중에 모을 수 있습니다. 더 공격적인 변형은 가중치를 전체 길이 KV 투영과 선택 토큰 Q 투영으로 쪼갭니다. 이는 산술을 더 아끼지만 GEMM 스케줄링 효율을 떨어뜨릴 수 있습니다. 중복된 패딩 마커 인덱스는 마스킹된 결과가 관측되지 않을 때만 무해합니다. 선택지 1개, 선택지 다수, 가변 마커 경우에는 명시적인 동등성 검사가 필요합니다. 쿼리가 적어지면 다른 SDPA 커널이 선택될 수 있으므로, 수학적 동등성이 부동소수점 결과의 비트 단위 동일성을 뜻하지는 않습니다.

R = 1 + number of option slots일 때, 전체 QKV를 유지하면 마지막 헤드 레이어에서 약 18 * B * (L-R) * D^2 dense FLOPs와 4 * B * L * (L-R) * D 어텐션 FLOPs가 제거됩니다. Q/KV를 쪼개면 dense 계수가 18에서 20으로 바뀝니다. 위의 전체 모델 산술 추정치에 대해 R=5를 쓰면:

체크포인트 / 길이 융합된 전체 QKV 유지 선택된 Q만 추가 계산
Laya, L=93 2.44% 2.70%
Laya, L=512 2.60% 2.86%
Typed decisions, L=1024 2.66% 2.90%
Multilingual, L=93 4.03% 4.47%
Multilingual, L=1024 4.22% 4.58%

이는 정적 FLOP 절감이며, 예측된 지연 시간 절감이 아닙니다. 이 기법은 하나의 헤드 레이어에서 대부분의 작업을 없애는 것이지, 모델 전체 작업을 없애는 것이 아닙니다. 의존성을 보존하고 재학습 없이 구현할 수 있기 때문에 유용한 것이지, 전체 모델 속도의 배수를 약속하기 때문이 아닙니다.

기여도를 측정한 뒤에만 진짜 지역 어텐션 구축

모든 인코더 어텐션 호출은 이미 mx.fast.scaled_dot_product_attention을 쓰고, RoPE는 이미 mx.fast.rope이며, nn.LayerNorm은 고속 정규화 프리미티브를 호출합니다. MLX의 어텐션 API는 불리언 마스크를 받고 softmax를 FP32로 수행합니다. 현재 헤드 차원은 64입니다. MLX 0.32.2 Metal 디스패치는 배열 마스크로 이 형상을 지원하며, 추론 중에는 융합되지 않은 폴백을 선택하지 않습니다. Laya의 불리언 마스크가 융합 어텐션을 비활성화한다는 증거는 없습니다. 설치된 버전에서 쓸 수 있는 force_fused=True는 진단용 단언으로는 유용하지만, 여기서 새로운 고속 경로로 광고해서는 안 됩니다.

남은 한계는 구조적 희소성입니다. 구현은 [B,1,L,L] 형상의 dense 지역 불리언 마스크를 만듭니다. 일반적인 Metal 어텐션 커널에서 noncausal 루프는 전체 KV 타일 범위를 순회하며, 배열 마스크는 QK 곱셈 뒤 점수에 적용됩니다. 지역 어텐션 의미는 보존하지만 지역 타일 범위를 활용하지는 않습니다.

정확한 전용 커널은 각 쿼리 타일을 겹치는 K/V 윈도로 제한하고, FP32 softmax 누적을 유지하며, dense L×L 마스크를 피할 수 있습니다. 올바른 윈도는 양방향이며 양끝을 포함합니다: abs(query_position - key_position) <= 64. 내부 쿼리는 구성 이름이 local_attention=128임에도 129개 위치를 볼 수 있습니다. 전체 어텐션 레이어와 두 결정 헤드 레이어는 전역으로 남아야 합니다. 패딩된 키는 계속 제외되어야 하고, 쓰이지 않는 패딩 쿼리에는 정의된 유한 동작이 필요합니다.

더 적은 노력의 프로토타입은 겹치는 K/V 슬라이스로 쿼리 블록을 묶고, 더 작은 정확 마스크로 기존 SDPA를 호출할 수 있습니다. 이미 위치가 적용된 RoPE Q/K를 쓰거나, 절대 오프셋을 명시적으로 유지하십시오. 많은 Python 호출보다 배치 블록을 선호하고, 중복된 K/V 구체화를 고려하십시오. 이 프로토타입은 짧은 길이에서 현재 커널에 질 수 있습니다. 맞춤형 Metal을 유지하기 전의 정확성 및 손익분기 실험입니다.

금지된 모든 지역 어텐션 쌍을 제거했을 때 모델링된 전체 모델 FLOPs의 최대 절감은 짧은 입력에서 작고 긴 입력에서 더 유망합니다:

체크포인트 / 길이 정확한 지역 희소성으로 인한 이상적 총 FLOP 절감
Laya, L=93 0.086%
Laya, L=512 3.61%
Typed decisions, L=1024 7.69%
Multilingual, L=93 0.147%
Multilingual, L=1024 11.92%

추정치는 L>r일 때 r=64로 local_pairs = L*(2*r+1) - r*(r+1)를 씁니다. 모든 dense 투영과 두 전체 어텐션 결정 헤드 레이어를 포함합니다. 마스크 생성과 메모리 트래픽은 제외합니다. 어텐션과 GEMM의 효율이 다르므로 런타임 이득은 FLOP 비율을 넘거나 밑돌 수 있으며, 프로파일링만이 이를 확립할 수 있습니다. 8192토큰에서는 트레이드오프가 다르겠지만, 배포된 에이전트는 입력을 512나 1024로 제한하므로 8192토큰 주장에는 별도로 지원되는 작업 부하가 필요합니다.

컴파일을 넘어선 융합

설치된 정확한 nn.gelu는 이미 shapeless 컴파일로 데코레이션되어 있고, nn.Linear는 적절할 때 이미 바이어스를 인식하는 addmm을 씁니다. 전체 블록 컴파일은 GELU를 게이트 곱셈, 잔차 덧셈, 캐스트, 마스크, 작은 스코어 특징 연산과 여전히 융합할 수 있습니다. 동등한 맞춤형 커널을 구현하기 전에 컴파일된 커널 그래프를 점검하십시오.

활성화 트래픽이 여전히 크다면, 정확한 GELU-게이트 또는 잔차-LayerNorm 융합을 프로토타입하십시오. 현재의 정확한 erf 기반 GELU를 보존하십시오. tanh나 sigmoid 근사는 모델을 바꾸므로 별도의 품질 측정이 필요합니다. 레이아웃 변환을 추가하기 전에 실제 Q/K/V 스트라이드와 복사를 점검하십시오. MLX의 전체 어텐션 구현은 다른 스트라이딩을 가진 연속 헤드 차원을 받고, 헤드 병합에 편리한 출력 레이아웃을 씁니다. 무조건적인 연속 복사는 작업을 늘릴 수 있습니다.

마커 softmax, 상위 2개 정렬, 엔트로피, 작은 액션 헤드, NumPy 결과 포매팅은 측정이 뒷받침될 때만 정당한 후속 대상입니다. 전체 폭 transformer 연산 수백 개에 비해 선택지 위치는 몇 개뿐이므로, 그것들을 먼저 최적화하는 것은 지배적인 경로를 다루지 못할 가능성이 큽니다.

공격적인 이득을 추구하면서도 벤치마크의 의미 보호

현재 작업 부하 생성기는 세 가지 질문 정의를 순환해 5, 10, 50개 질문을 만듭니다. 그 배치들에는 고유한 모델 입력이 최대 세 개뿐입니다. 호출별 정확 중복 제거는 실제 애플리케이션에서 중복 추론을 피할 수 있지만, 이 픽스처들은 지나치게 많이 개선할 것입니다. 이 기능은 커널 최적화와 분리해 두고 questions, unique_forward_inputs, 캐시 적중, 실제 평가된 토큰을 보고하십시오. 각 원래 답은 자기 자신의 레이블, 순서 있는 기준, 캘리브레이션 메타데이터로 재구성하십시오. 진짜 다른 질문 50개짜리 스위트와 의도적으로 중복된 입력 스위트를 남겨 두십시오.

주요 추론 벤치마크에 호출 간 결과 캐싱을 쓰지 마십시오: 그것은 정확히 같은 요청을 반복 호출합니다. 모든 캐시 실험은 그렇게 보고하십시오. 토크나이저 캐시 벤치마크는 반복 루브릭 시나리오와 새 입력 시나리오를 모두 포함해야 합니다.

각 후보에 대해 이 실험 설계를 쓰십시오:

  1. 대상을 일정하게 유지하십시오. 소스 리비전/해시, 모델 리비전, dtype, 컴파일 플래그, 선택된 양자화 모듈, 토큰 ID 또는 그 해시, 형상, 마커 수, 배칭 정책, 워밍업, 동기화, 장치를 기록하십시오. 기존 input_sha256은 실제 토큰 텐서가 아니라 상태/질문을 해시합니다. 토크나이저 간 텐서 동일성을 확립하지 못합니다. 과거 JSON 소스 해시가 다르므로, 같은 최종 소스 리비전에서 기준선을 다시 실행하십시오.
  2. 작업 부하 클래스를 분리하십시오. 통제된 커널 비교에는 고정 형상을, 스케줄링과 컴파일에는 실제 가변 길이를, 처리량에는 서로 다른 질문을, 정당한 CPU 캐싱에는 반복 루브릭을, 중복 제거에는 의도적으로 중복된 질문을 쓰십시오. 긴 길이 꼬리와 다양한 선택지 수를 포함하십시오. 각 백엔드 비교 안에서는 소스 텍스트와 절단을 동일하게 유지하십시오.
  3. 콜드와 워밍 동작을 측정하십시오. 모델 로딩과 최초 컴파일을 따로 기록하십시오. 준비, 그래프 구성, 동기화된 평가 포워드, 출력 변환, 엔드투엔드 지연 시간을 측정하되, 독립적인 중앙값들을 더할 수 있는 값으로 취급하지 마십시오. 트레이싱이 지연 시간을 교란할 수 있으므로, 커널은 별도 실행에서 프로파일링하십시오.
  4. 한 번에 하나의 최적화만 바꾸십시오. 기존 반복 횟수로 스크리닝한 뒤, 기준선/후보 블록을 번갈아 반복해 신뢰할 만한 p95를 얻을 만큼 표본을 모으십시오. 예를 들어 작업 부하당 최소 200개의 시간 측정 요청을 쓰십시오. 하나의 활성 GPU 벤치마크, 일관된 전력/열 조건을 쓰고 원시 표본을 보존하십시오. 측정된 실행 변동보다 큰 개선을 요구하십시오.
  5. 정확성과 안정성을 확인하십시오. 같은 dtype의 MLX 및 기존 FP32 기준과 비교하고, 스케줄링과 CPU 준비 변경에는 토큰 동일성을 강제하십시오. 길이 64, 128 및 버킷 경계 부근, 청크 한도 부근의 배치, 선택지 하나와 다수, 다국어 입력, 패딩, 컴파일 이후의 형상 변경을 시험하십시오. 형상이 바뀌는 요청을 반복하고, 워밍업 후 활성 메모리와 캐시 메모리를 모두 지켜보며, 각 구성 안에서 유한한 결정론적 결과를 검증하십시오.
  6. 근사 변경에는 더 강한 게이트를 적용하십시오. 양자화, 활성화 근사, 토큰 프루닝, 얼리 엑시트, 증류는 작은 회귀 픽스처를 넘어선 홀드아웃 작업 및 캘리브레이션 결과를 요구합니다. 훈련된 동작을 바꿀 때는 별도의 모델 정체성과 벤치마크 레이블을 유지하십시오. 더 빠른 다국어 체크포인트나 증류 모델은 다른 모델이며, 동일한 Laya 체크포인트의 속도 향상이 아닙니다.

엔드투엔드 시간의 비율 f를 차지하고 계수 s로 가속되는 측정된 핫스팟에 대해서는, 예상 총 영향을 평가하기 위해 암달의 한계 1 / (1 - f + f/s)를 쓰십시오. f에는 측정된 시간 비율을 쓰십시오. 위의 산술 비율은 대체물이 아닙니다. 다음 구체적인 엔지니어링 결정은 검증되지 않은 배수가 아니라, 컴파일/배칭 ablation과 짧은 대 긴 커널 프로파일을 따른 뒤에 내려야 합니다.

문서와 재현성 노트

문서 조회는 요구되는 Context7 워크플로를 썼습니다: library MLX 해석 한 번, 그다음 컴파일과 고속 어텐션에 대한 공식 문서 쿼리를 따로 하고, /websites/ml-explore_github_io_mlx_build_html을 사용했습니다(총 세 명령). 설치된 .pyi와 Python 소스를 점검해 force_fused, 양자화 API, 컴파일된 GELU, 고속 LayerNorm을 포함한 MLX 0.32.2 동작을 검증했습니다. 디스패치와 타일 루프 세부를 위해 버전이 고정된 업스트림 C++/Metal 소스를 읽었습니다. 이 연구를 위해 어떤 라이브러리도 업그레이드하지 않았습니다.

세부 관찰에 쓴 두 FP16 기준 파일은 점검 시점에 다음 SHA-256 다이제스트를 가졌습니다:

laya-mlx-float16.json
63146dd664d039dde1a728b17aad896e491bd01ea36ea0786953691180e55b09

laya-multilingual-mlx-float16.json
9af74bd5a11e4edc15e6a8c9dc929a7b9fd2d19cb06f348cd0e04a076f912473

주요 벤치마크 프로세스는 이 연구 중에도 추가 아티팩트를 계속 만들고 있었습니다. 표는 검토 시점에 이미 구할 수 있던 완전한 기준 파일을 의도적으로 인용하며, 측정하지 않은 후보 구현에 대해서는 어떤 주장도 하지 않습니다.