Skip to content

Split View: 26B 모델을 2GB 램으로 돌리는 원리 — 상주 메모리와 워킹셋은 같은 숫자가 아니다

✨ Learn with Quiz
|

26B 모델을 2GB 램으로 돌리는 원리 — 상주 메모리와 워킹셋은 같은 숫자가 아니다

들어가며 — "2GB"는 무엇을 세는 숫자인가

2026년 7월 29일 Show HN에 TurboFieldfare라는 프로젝트가 올라왔습니다. Swift와 Metal로 짠 추론 런타임인데, Gemma 4 26B-A4B를 M 시리즈 맥에서 약 2GB 램으로 돌린다는 주장이 붙어 있습니다. 저장소 README가 적은 수치는 M2 MacBook Air 8GB에서 초당 5.1~6.3 토큰, M5 Pro 24GB에서 31~35 토큰입니다.

"26B를 2GB에"라는 문장은 반사적으로 의심하게 됩니다. 그런데 이 프로젝트의 숫자들은 서로 잘 맞물립니다. 실제로 계산해 보면 대부분 정확합니다. 흥미로운 지점은 주장이 틀렸다는 데 있지 않고, 2GB가 무엇을 세는 숫자인지에 있습니다. 그건 프로세스 상주 메모리이고, 시스템이 실제로 쓰는 메모리와는 다른 값입니다. 그리고 이 차이가 M2 Air와 M5 Pro 사이 6배 성능 차이의 상당 부분을 설명합니다.

이 글은 README와 HN 스레드의 수치를 그대로 받아들이는 대신 직접 유도해서 맞춰 봅니다. 산수가 맞는 항목과, 맞지 않아서 다른 설명이 필요한 항목을 나눠서 보겠습니다.

14.3GB는 어디서 나오나 — 저장 용량 산수부터

먼저 디스크입니다. README는 텍스트 전용 모델 설치 용량을 약 14.3GB로, 양자화 방식을 "MLX affine 4비트, 그룹 64, 라우터는 8비트"로 적고 있습니다. Gemma 4 모델 카드 기준으로 26B-A4B는 총 25.2B 파라미터, 활성 3.8B, 컨텍스트 256K입니다.

4비트인데 왜 25.2B의 절반인 12.6GB가 아닐까요. 그룹 단위 아핀 양자화는 가중치만 저장하지 않기 때문입니다.

그룹 64 아핀 4비트의 실제 저장 비용

  가중치 64개  x 4비트          = 32 바이트
  스케일 1개   x fp16           =  2 바이트
  영점 1개     x fp16           =  2 바이트
  ------------------------------------------
  합계                          = 36 바이트 / 64 가중치

  가중치당 비트 수 = 36 x 8 / 64 = 4.5 bpw

  모델 전체 = 25.2e9 x 4.5 / 8 = 14.18e9 바이트 = 약 14.2 GB

보고된 14.3GB와 1% 안쪽으로 맞습니다. 남는 0.1GB는 8비트 라우터, 임베딩 처리 방식의 차이, 메타데이터로 설명하면 충분합니다.

여기서 이미 하나의 교훈이 나옵니다 — "4비트 양자화"라는 표현은 파일 크기를 파라미터 수의 절반으로 만들어 주지 않습니다. 그룹 크기가 작을수록 품질은 좋아지고 오버헤드는 커집니다. 그룹 32였다면 bpw는 5.0이 되어 파일이 15.8GB가 됩니다. 로컬 실행 계획을 세울 때 이 0.5비트가 곧 1.5GB의 차이입니다. 가중치와 KV 캐시를 공식으로 계산하는 법은 로컬에서 LLM 돌리려면 VRAM이 얼마나 필요한가 편에 정리해 두었습니다.

MoE가 만드는 두 종류의 가중치

이제 램에 상주하는 1.35GB가 무엇인지 봅니다. README는 그것을 "공유 코어"라고 부릅니다. MoE 구조에서 파라미터는 두 부류로 갈립니다.

  • 모든 토큰이 쓰는 것 — 임베딩, 어텐션, 공유 전문가, 라우터. 이건 상주시켜야 합니다.
  • 토큰마다 골라 쓰는 것 — 라우티드 전문가. 레이어마다 128개 중 8개꼴로 활성화됩니다.

활성 파라미터가 3.8B이고 총 25.2B라는 두 숫자에서 이 분할을 역산할 수 있습니다.

S = 항상 쓰는 파라미터, R = 라우티드 전문가 파라미터
활성 비율 f = 활성 전문가 수 / 전체 전문가 수

  S + R       = 25.2B
  S + f x R   =  3.8B      (f = 8/128 = 0.0625 가정)

  0.9375 R = 21.4B  ->  R = 22.8B,  S = 2.4B

  S를 4.5 bpw로 저장하면
  2.4e9 x 4.5 / 8 = 1.35e9 바이트 = 1.35 GB

README가 밝힌 공유 코어 1.35GB와 정확히 일치합니다. 활성 전문가 8 대 128이라는 구조 가정이 맞았다는 뜻이고, 동시에 이 설계의 핵심을 보여 줍니다. 전체의 5%만 상주시키면 나머지 95%는 토큰마다 필요한 조각만 가져오면 됩니다.

여기서 강조할 점은 이 방식이 Gemma 4가 MoE이기 때문에 성립한다는 것입니다. 같은 크기의 밀집(dense) 모델이었다면 토큰마다 25.2B 전부를 읽어야 하고, 그건 어떤 SSD로도 감당이 안 됩니다. 스트리밍 추론은 양자화 기법이 아니라 아키텍처가 열어 준 문입니다.

mmap을 버리고 pread로 간 이유

가중치를 지연 로딩할 때 가장 먼저 떠오르는 방법은 mmap입니다. 파일을 주소 공간에 매핑해 두고 접근하면 커널이 알아서 페이지를 가져옵니다. 코드가 단순하고, llama.cpp를 포함한 대부분의 로컬 추론 엔진이 이 방식을 씁니다.

그런데 HN 스레드에서 저자가 밝힌 바로는 mmap 구현이 초당 0.5토큰에 머물렀고, 병렬 pread 호출로 바꾸면서 약 4토큰으로 올라갔습니다. 여덟 배입니다. 이유는 두 방식의 동시성 모델이 다르기 때문입니다.

mmap으로 접근한 페이지가 아직 램에 없으면 페이지 폴트가 나고, 그 스레드는 폴트가 해결될 때까지 멈춥니다. 커널의 선행 읽기(readahead)는 순차 접근을 가정하는데, 전문가 라우팅이 만들어 내는 접근 패턴은 파일 전체에 흩어진 무작위 읽기입니다. 예측이 틀리니 매번 한 번에 하나씩 기다리게 됩니다. 반면 pread는 명시적인 요청이라 필요한 오프셋 목록을 한꺼번에 던져 놓고 SSD의 큐 깊이를 채울 수 있습니다. NVMe는 요청 하나를 빨리 처리하는 장치가 아니라 수십 개를 동시에 처리해 대역폭을 채우는 장치라서, 이 차이가 그대로 여덟 배로 나타납니다.

실제 구현은 여기에 두 가지를 더 얹었습니다. 레이어마다 16칸짜리 LFU 캐시를 두어 자주 쓰이는 전문가를 붙잡아 두고, 프리필 단계에서는 최대 128토큰씩 묶어 처리해 한 번 가져온 전문가가 여러 토큰을 처리하게 만듭니다. 그리고 CPU가 다음 전문가를 읽어 오는 동안 Metal은 공유 전문가 분기를 계산합니다 — 입출력과 연산을 겹치는 고전적인 기법입니다.

토큰당 285MB — 대역폭이 상한을 정한다

이제 성능의 상한을 계산할 수 있습니다.

라우티드 전문가 전체 = 22.8e9 x 4.5 / 8 = 12.8 GB
토큰당 활성 비율     = 8 / 128 = 6.25%

  캐시가 전혀 없을 때 토큰당 읽어야 할 양
  12.8 GB x 0.0625 = 800 MB

  HN에서 저자가 보고한 실측: 토큰당 250~320 MB

  역산한 캐시 적중률 = 1 - (250~320) / 800 = 60% ~ 69%

저자가 따로 보고한 값은 M2에서 59~69%, 16칸 캐시로 약 67%였습니다. 제가 유도한 60~69%와 맞아떨어집니다. 즉 README와 HN에 흩어진 숫자들은 하나의 일관된 모델에서 나옵니다. 토큰당 실질 전송량을 285MB 정도로 잡고 기기별 상한을 계산하면 이렇게 됩니다.

기기인용된 SSD 순차 읽기토큰당 285MB 기준 이론 상한 (유도)보고된 토큰당 디스크 시간보고된 처리량
M2 Air8 GB확인하지 못함83 ms5.1~6.3 tok/s
M4 (대역폭 참고용)2,031 MB/s약 7 tok/s
M5 Pro24 GB6,323 MB/s약 22 tok/s12 ms31~35 tok/s

M2 Air 쪽은 계산이 잘 맞습니다. 토큰당 83밀리초의 디스크 시간이면 초당 12토큰이 상한이고, 나머지 연산 시간을 더하면 실측 5~6토큰이 자연스럽습니다.

문제는 M5 Pro 줄입니다. 인용된 SSD 대역폭으로 계산한 상한이 약 22토큰인데 실측이 31~35토큰입니다. 토큰당 12밀리초에 285MB를 읽으려면 초당 23.75GB가 필요한데, 이건 어떤 소비자용 NVMe도 내지 못하는 속도입니다. 산수가 안 맞는 것이 아니라, 그 읽기의 상당 부분이 SSD에서 오지 않는다는 뜻입니다.

상주 메모리와 워킹셋 — 2GB가 참인 지점과 오도하는 지점

답은 macOS의 통합 버퍼 캐시입니다. pread로 읽은 파일 페이지는 커널이 램에 보관하고, 같은 오프셋을 다시 읽으면 SSD를 건드리지 않습니다. 24GB 머신에서 14.3GB짜리 모델 파일은 상당 부분이 캐시에 남을 수 있습니다. 워밍업이 끝난 뒤의 "디스크 읽기"는 실제로는 램 복사에 가까워집니다.

그런데 이 페이지들은 프로세스의 상주 메모리로 집계되지 않습니다. 파일 기반 페이지는 커널의 페이지 캐시에 속하고, 메모리 압박이 오면 커널이 회수합니다. 그래서 Activity Monitor에서 프로세스는 여전히 2GB로 보입니다. 주장은 거짓이 아닙니다 — 다만 세는 대상이 다릅니다.

정리하면 이렇습니다.

  • 참인 부분: 이 런타임이 자기 힙에 붙잡아 두는 가중치는 공유 코어 1.35GB에 4K KV 캐시를 더한 정도이고, 프로세스 RSS는 2GB 근처입니다. 램이 8GB뿐인 기기에서 26B급 모델이 아예 돌아간다는 사실 자체가 이 설계의 성과입니다.
  • 오도하는 부분: 시스템 전체가 쓰는 메모리는 2GB가 아닙니다. 성능을 내려면 커널 페이지 캐시가 모델 파일의 큰 조각을 들고 있어야 하고, 그 메모리는 다른 앱과 경쟁합니다. 브라우저 탭을 스무 개 열어 캐시가 밀려나면 처리량은 SSD 대역폭 상한으로 떨어집니다. M2 Air의 5~6토큰과 M5 Pro의 31~35토큰 사이 격차는 칩 성능만의 차이가 아니라 캐시로 쓸 수 있는 여유 램의 차이이기도 합니다.
  • 따라서 의심할 부분: HN에서 나온 "이득이 기법이 아니라 OS 캐싱에서 오는 것 아니냐"는 지적은 절반 맞습니다. 다만 mmap에서 pread로 바꿔 여덟 배가 난 것은 캐시로 설명되지 않으니, 기법의 기여도 실재합니다. 두 요인이 함께 있습니다.

그리고 산수가 닫히지 않는 항목이 하나 더 있습니다. 레이어당 16칸 캐시는 전체 128개 중 12.5%이므로, 전 레이어에 걸쳐 온전히 상주한다면 12.8GB의 12.5%인 약 1.6GB가 됩니다. 공유 코어 1.35GB와 합치면 2GB를 넘습니다. 실제 구현이 슬롯을 다르게 세거나, 그 버퍼의 상당 부분이 파일 기반이라 RSS에 잡히지 않거나 둘 중 하나일 텐데, 저는 어느 쪽인지 소스를 읽어 확인하지 못했습니다. 어느 쪽이든 결론은 같은 방향입니다 — 2GB는 프로세스 회계장부의 숫자입니다.

4비트의 품질 비용, 그리고 이 방식이 맞는 자리

마지막으로 공짜가 아닌 부분입니다. 4비트 양자화의 품질 손실에 대해 널리 인용되는 정리는, FP16 대비 퍼플렉시티가 1~3% 나빠지고 총 파라미터가 클수록 손실이 작다는 것입니다. MoE는 총 파라미터가 크므로 활성이 작아도 4비트를 비교적 잘 견딘다는 주장도 있습니다. 다만 이것들은 집계 글에서 반복되는 일반론이고, 이 특정 빌드에 대한 측정은 아닙니다.

정확히 말하면 이렇습니다. Gemma 4 26B-A4B의 공개 벤치마크는 양자화되지 않은 모델의 것입니다. 모델 카드가 싣는 MMLU Pro 82.6, GPQA Diamond 82.3, LiveCodeBench v6 77.1 같은 숫자는 4.5 bpw로 누른 이 빌드의 점수가 아닙니다. 그리고 이 빌드의 점수를 잰 사람은 아직 없습니다. README도 "모델이 반복하거나 틀린 답을 낼 수 있으니 중요한 결과는 확인하라"는 문장을 달아 놓았을 뿐입니다. 양자화된 로컬 모델의 품질을 이야기할 때 원본 모델 카드 숫자를 인용하는 것은, 이 글이 하지 말자고 주장하는 종류의 일입니다.

그러면 이 방식은 어디에 맞을까요.

  • 맞는 자리: 램이 모자란 기기에서 오프라인으로, 지연에 민감하지 않은 작업. 문서 요약, 로컬 코드 설명, 네트워크가 없는 환경. 초당 5토큰은 대화형으로는 답답하지만 백그라운드 배치로는 충분합니다. 데이터를 밖으로 보내면 안 되는 상황이라면 대안이 별로 없습니다.
  • 안 맞는 자리: 램이 충분한 기기. 24GB 이상이면 14.3GB짜리 모델을 그냥 통째로 올리는 편이 단순하고 빠릅니다. 이 방식의 존재 이유는 램 부족이지 성능이 아닙니다. 그리고 상시 가동하는 서버는 더더욱 아닙니다 — 이 런타임은 인스턴스당 단일 프로세스만 모델을 소유하고 동시 실행을 지원하지 않는다고 명시돼 있습니다.
  • 확인되지 않은 것: SSD 수명에 대한 정량 자료가 없습니다. 읽기 중심이라 쓰기 마모는 크지 않을 것으로 보이지만, 저장소도 이를 수치화하지 않았다고 밝힙니다. 또 macOS 26과 Metal 4가 요구 사항이고, macOS 15에서 쓰려면 2.4배 프리필 가속을 포기하는 우회가 필요합니다. M1부터 M5까지 전 세대에서 같은 결과가 나온다는 근거도 아직 없습니다.

마치며 — 숫자가 세는 대상을 먼저 확인하면 대부분의 마법은 설명된다

"26B를 2GB에"는 과장이 아니었습니다. 4비트 그룹 64가 만드는 4.5 bpw, 총 25.2B와 활성 3.8B에서 역산되는 공유 코어 1.35GB, 라우티드 전문가 12.8GB의 6.25%인 토큰당 800MB, 캐시로 285MB까지 줄어드는 실전송량 — 이 네 숫자가 한 줄로 이어지고 보고된 값들과 맞습니다. 좋은 엔지니어링입니다.

동시에 2GB는 프로세스 상주 메모리이지 시스템 워킹셋이 아닙니다. M5 Pro의 실측 처리량이 SSD 대역폭 상한을 넘는다는 사실이 그 증거이고, 그 차이를 메우는 것은 커널 페이지 캐시입니다. 그러니 이 프로젝트를 8GB 맥에 걸어 볼 때 기대해야 할 숫자는 31~35토큰이 아니라 5~6토큰입니다.

로컬 추론의 성능 주장을 읽을 때 던져야 할 질문은 늘 같습니다. 그 숫자는 무엇을 세고 있으며, 세지 않은 것은 어디에 있습니까.

How a 26B Model Runs in 2GB of RAM — Resident Memory and Working Set Are Not the Same Number

Intro — what number is "2GB" counting

On July 29, 2026, a project called TurboFieldfare went up on Show HN. It is an inference runtime written in Swift and Metal, and it comes with the claim that it runs Gemma 4 26B-A4B on M-series Macs in about 2GB of RAM. The figures the repository README lists are 5.1 to 6.3 tokens per second on an M2 MacBook Air with 8GB, and 31 to 35 on an M5 Pro with 24GB.

The sentence "26B in 2GB" makes you reflexively suspicious. And yet this project's numbers mesh well with one another. Work them out and most of them are correct. The interesting point is not that the claim is wrong; it is what number the 2GB is counting. It is the process resident set, and that is a different value from the memory the system actually uses. And this difference explains a good part of the sixfold performance gap between the M2 Air and the M5 Pro.

Rather than take the README and HN thread figures at face value, this post derives them and checks that they line up. Let us separate the items where the arithmetic works from the items where it does not and something else is needed to explain them.

Where does 14.3GB come from — start with the storage arithmetic

Disk first. The README lists the install size of the text-only model at about 14.3GB, and the quantization scheme as "MLX affine 4-bit, group 64, router at 8-bit." By the Gemma 4 model card, 26B-A4B has 25.2B total parameters, 3.8B active, and a 256K context.

It is 4-bit, so why is it not 12.6GB, half of 25.2B? Because group-wise affine quantization does not store only the weights.

Real storage cost of group-64 affine 4-bit

  64 weights   x 4 bits        = 32 bytes
  1 scale      x fp16          =  2 bytes
  1 zero point x fp16          =  2 bytes
  ------------------------------------------
  total                        = 36 bytes / 64 weights

  bits per weight = 36 x 8 / 64 = 4.5 bpw

  whole model = 25.2e9 x 4.5 / 8 = 14.18e9 bytes = about 14.2 GB

That comes within 1% of the reported 14.3GB. The leftover 0.1GB is adequately explained by the 8-bit router, differences in how embeddings are handled, and metadata.

One lesson already comes out here — the phrase "4-bit quantization" does not make the file size half the parameter count. The smaller the group, the better the quality and the larger the overhead. At group 32, bpw would be 5.0 and the file would be 15.8GB. When you are planning a local deployment, that 0.5 bit is a 1.5GB difference. How to compute weights and KV cache from formulas is laid out in How Much VRAM to Run an LLM Locally.

The two kinds of weights MoE creates

Now let us look at what the 1.35GB that stays resident in RAM actually is. The README calls it the "shared core." In an MoE structure, parameters split into two classes.

  • What every token uses — embeddings, attention, shared experts, the router. This has to stay resident.
  • What each token selects — the routed experts. Roughly 8 out of 128 are activated per layer.

From the two numbers 3.8B active and 25.2B total, this split can be worked out backwards.

S = always-used parameters, R = routed expert parameters
active ratio f = active experts / total experts

  S + R       = 25.2B
  S + f x R   =  3.8B      (assuming f = 8/128 = 0.0625)

  0.9375 R = 21.4B  ->  R = 22.8B,  S = 2.4B

  storing S at 4.5 bpw
  2.4e9 x 4.5 / 8 = 1.35e9 bytes = 1.35 GB

That matches exactly the 1.35GB shared core the README states. It means the structural assumption of 8 active experts out of 128 was right, and at the same time it shows the core of this design. Keep only 5% of the whole resident, and the remaining 95% only has to be fetched a piece at a time, per token.

The point to stress here is that this approach works because Gemma 4 is an MoE. Had it been a dense model of the same size, every token would have to read all 25.2B, and no SSD could carry that. Streaming inference is not a quantization technique but a door the architecture opened.

Why they dropped mmap and went to pread

The first method that comes to mind for lazily loading weights is mmap. Map the file into the address space, access it, and the kernel fetches the pages on its own. The code is simple, and most local inference engines, llama.cpp included, use this approach.

But according to what the author stated in the HN thread, the mmap implementation stalled at 0.5 tokens per second, and switching to parallel pread calls brought it up to about 4 tokens. That is eight times. The reason is that the two approaches have different concurrency models.

If a page accessed through mmap is not in RAM yet, a page fault occurs and that thread stops until the fault is resolved. The kernel's readahead assumes sequential access, but the access pattern that expert routing produces is random reads scattered across the whole file. The prediction is wrong, so you end up waiting one at a time, every time. pread, by contrast, is an explicit request, so you can throw the whole list of needed offsets at it at once and fill the SSD's queue depth. NVMe is not a device that services one request quickly but one that services dozens concurrently to fill its bandwidth, so this difference shows up directly as eight times.

The actual implementation stacks two more things on top. It puts a 16-slot LFU cache on each layer to hold on to frequently used experts, and in the prefill stage it batches up to 128 tokens at a time so that an expert fetched once handles multiple tokens. And while the CPU reads in the next expert, Metal computes the shared expert branch — the classic technique of overlapping I/O with computation.

285MB per token — bandwidth sets the ceiling

Now the performance ceiling can be computed.

all routed experts   = 22.8e9 x 4.5 / 8 = 12.8 GB
active ratio / token = 8 / 128 = 6.25%

  bytes to read per token with no cache at all
  12.8 GB x 0.0625 = 800 MB

  measurement the author reported on HN: 250~320 MB per token

  back-derived cache hit rate = 1 - (250~320) / 800 = 60% ~ 69%

The value the author reported separately was 59 to 69% on the M2, about 67% with the 16-slot cache. That agrees with the 60 to 69% I derived. In other words, the numbers scattered across the README and HN come out of one consistent model. Take the effective transfer per token as about 285MB and the per-device ceiling works out like this.

DeviceRAMQuoted SSD sequential readTheoretical ceiling at 285MB per token (derived)Reported disk time per tokenReported throughput
M2 Air8 GBcould not confirm83 ms5.1~6.3 tok/s
M4 (bandwidth reference)2,031 MB/sabout 7 tok/s
M5 Pro24 GB6,323 MB/sabout 22 tok/s12 ms31~35 tok/s

The M2 Air side computes cleanly. At 83 milliseconds of disk time per token the ceiling is 12 tokens per second, and adding the remaining compute time makes the measured 5 to 6 tokens natural.

The problem is the M5 Pro row. The ceiling computed from the quoted SSD bandwidth is about 22 tokens, but the measurement is 31 to 35 tokens. Reading 285MB in 12 milliseconds per token would require 23.75GB per second, and that is a speed no consumer NVMe can deliver. It is not that the arithmetic is broken; it means a substantial part of that read is not coming from the SSD.

Resident memory and working set — where 2GB is true and where it misleads

The answer is macOS's unified buffer cache. File pages read with pread are held in RAM by the kernel, and reading the same offset again does not touch the SSD. On a 24GB machine, a large part of a 14.3GB model file can stay in cache. After warm-up, a "disk read" is really closer to a RAM copy.

But these pages are not counted in the process's resident memory. File-backed pages belong to the kernel's page cache, and the kernel reclaims them when memory pressure arrives. So in Activity Monitor the process still shows 2GB. The claim is not false — it is just counting something different.

To sum up.

  • The true part: the weights this runtime holds in its own heap amount to the 1.35GB shared core plus roughly a 4K KV cache, and the process RSS is around 2GB. The bare fact that a 26B-class model runs at all on a machine with only 8GB of RAM is an achievement of this design.
  • The misleading part: the memory the whole system uses is not 2GB. To get performance, the kernel page cache has to be holding a large chunk of the model file, and that memory competes with other apps. Open twenty browser tabs, push the cache out, and throughput falls to the SSD bandwidth ceiling. The gap between the M2 Air's 5 to 6 tokens and the M5 Pro's 31 to 35 is not only a difference in chip performance but also a difference in how much spare RAM is available to use as cache.
  • So, the part to doubt: the objection raised on HN that the gain comes from OS caching rather than from the technique is half right. But the eightfold jump from mmap to pread is not explained by caching, so the technique's contribution is real too. Both factors are present.

And there is one more item where the arithmetic does not close. A 16-slot cache per layer is 12.5% of the 128 total, so if it were fully resident across all layers it would come to about 1.6GB, 12.5% of 12.8GB. Add the 1.35GB shared core and it goes past 2GB. Either the actual implementation counts slots differently, or a large part of that buffer is file-backed and therefore does not show up in RSS — but I could not read the source to confirm which. Either way the conclusion points the same direction — 2GB is a number from the process's accounting ledger.

The quality cost of 4-bit, and where this approach fits

Finally, the part that is not free. The widely quoted summary on the quality loss of 4-bit quantization is that perplexity gets 1 to 3% worse relative to FP16, and that the loss is smaller the larger the total parameter count. There is also a claim that because MoE has a large total parameter count it withstands 4-bit relatively well even with a small active count. But these are generalities repeated in aggregator posts, not measurements of this particular build.

To put it precisely. The public benchmarks for Gemma 4 26B-A4B are those of the unquantized model. Numbers the model card carries, such as MMLU Pro 82.6, GPQA Diamond 82.3, and LiveCodeBench v6 77.1, are not the scores of this build squeezed down to 4.5 bpw. And nobody has measured this build's scores yet. The README only attaches the sentence that the model may repeat itself or give wrong answers, so check important results. Quoting the original model card's numbers when discussing the quality of a quantized local model is exactly the kind of thing this post argues we should not do.

So where does this approach fit?

  • Where it fits: offline work on a RAM-starved machine, on tasks that are not latency-sensitive. Document summarization, local code explanation, environments with no network. Five tokens per second is frustrating for conversation but plenty for a background batch. If the data must not leave the machine, there are not many alternatives.
  • Where it does not fit: machines with enough RAM. At 24GB or more, simply loading the whole 14.3GB model is simpler and faster. The reason this approach exists is a RAM shortage, not performance. And an always-on server is even further from a fit — the runtime explicitly states that only a single process per instance owns the model and that concurrent execution is not supported.
  • What has not been confirmed: there is no quantitative data on SSD lifetime. Since it is read-heavy, write wear does not look like it will be large, but the repository also states that it has not quantified this. macOS 26 and Metal 4 are also requirements, and using it on macOS 15 needs a workaround that gives up the 2.4x prefill acceleration. There is also no evidence yet that the same results hold across every generation from M1 to M5.

Closing — check what a number counts first and most of the magic explains itself

"26B in 2GB" was not an exaggeration. The 4.5 bpw that 4-bit group 64 produces, the 1.35GB shared core derived backwards from 25.2B total and 3.8B active, the 800MB per token that is 6.25% of the 12.8GB of routed experts, and the effective transfer that caching brings down to 285MB — these four numbers connect in a single line and agree with the reported values. It is good engineering.

At the same time, 2GB is the process resident set, not the system working set. The fact that the measured M5 Pro throughput exceeds the SSD bandwidth ceiling is the evidence for that, and what fills the gap is the kernel page cache. So when you put this project on an 8GB Mac, the number to expect is not 31 to 35 tokens but 5 to 6.

The question to ask when reading performance claims about local inference is always the same. What is that number counting, and where is what it did not count?