01 / 14

Kísérleti napló · 2026-05-28

Kidobjuk a soha-nem-
használt szakértőket?

Egy 35 milliárd paraméteres MoE-modellt szabunk a saját otthoni munkámra. Egy éjszaka. Két reboot. Egy bug, amit ha nem találunk meg, az egész kísérlet hamis konklúzióval végződött volna.

Görgess lejjebb
Laikusoknak02 / 14

Két egyszerű kérdés egy bonyolult modellről

A

Beégethetjük a system promptot?

Minden hívásnál ugyanazt a hosszú utasítást küldjük. Be lehet ezt sütni a modell súlyaiba, hogy ne kelljen mindig elküldenünk?

B

Kidobhatjuk amit nem használunk?

Ha mindig hasonló dolgokat csinálok vele (kódolás, projektmenedzsment, családi nyaralás), van-e olyan rész a modellben, amit szinte sosem ébresztek fel?

A poszt mindkettőre választ ad — de a B kérdést jártuk körül komolyabban.

Laikusoknak03 / 14

Mi az a 'Mixture of Experts'?

Képzelj el egy konferenciatermet 256 specialistával. Mindegyikük valamire jó: egy a hibakeresésre, másik a magyar nyelvre, harmadik a Python-syntaxra, és így tovább.

Amikor a modellnek el kell döntenie a következő szót, egy 'router' kiválasztja közülük a 8 legrelevánsabbat, és csak ők szólalnak meg. A többi 248 specialista pihen azon a szón.

Ez a trükk teszi lehetővé, hogy egy 35 milliárd paraméteres modell olyan gyorsan fusson, mintha 3 milliárd lenne — mert minden szóra effektíve csak 3 milliárd 'aktív' paraméter számol.

A kérdés tehát: van-e 256 specialista közül olyan, akit én — az én jellegzetes munkámban — szinte sosem hívok meg?

Laikusoknak04 / 14

Az éjszakai program

A

Bake — a system prompt beégetése

Egy rövid finetuning-menet (úgynevezett LoRA): a modellnek megmutatjuk hogyan reagáljon mint Aemie, miközben elhagyjuk a system promptot az inputból. Idővel a stílus a súlyokba költözik.

B

Prune — kivágni a hideg experteket

Megmérjük melyik specialistát mennyit hívom, majd a legritkábban használtakat egyszerűen kihasítjuk a modellfájlból. Kisebb fájl, gyorsabb betöltés, ugyanolyan minőség (remélhetőleg).

Spoiler: A bake-hez NVIDIA GPU kell — itthon csak inferenciára való iGPU-m van —, úgyhogy azt csak előkészítettük. A prune lefutott. Erről a maradék slide-ok.

Laikusoknak05 / 14

A főeredmény

Negyedével kisebb modell, alig érzékelhető minőségvesztés

VariánsMéretMinőség (PPL)Prefill
Eredeti (256 expert)22 GB8.82353 t/s
K=224 (12.5% kivágva)19 GB (−14%)8.83 (+0.12%)371 (+5%)
K=192 sweet spot17 GB (−23%)8.92 (+1.13%)387 (+10%)
K=128 (fele kivágva)12 GB (−45%)9.33 (+5.83%)464 (+32%)

A K=192 a sweet spot: a modell 23%-kal kisebb, miközben a minősége gyakorlatilag változatlan (1.13% növekedés a perplexitásban — az 'mennyire bizonytalan a következő szóban' mérőszámban). Ez ingyen-pénz.

Laikusoknak06 / 14

Hogy néz ki a 'használat' egy rétegen?

Egy reprezentatív réteg 256 expertje, használatra rendezve. A bal oldali kevés sztár csinálja a munka nagy részét, a jobb oldal felé a hidegebb tail.

1. expert (legtöbbet használt)256.

Az enyhén meglepő: nincs olyan expert, ami SOHA nem szólal meg. A modell-tréning szándékosan szétkeni a munkát. Viszont a farok éppen elég vékony, hogy levághassuk.

Tech mély07 / 14

A profilozó: egy llama.cpp eval-callback

Új példa az llama.cpp tree-ben, ami minden forward pass alatt elcsípi a router döntéseit.

// build_moe_ffn() in llama-graph.cpp:
//   cb(selected_experts->src[0], "ffn_moe_argsort", il);  // [256, n_tokens] I32, contiguous
//   cb(selected_experts,         "ffn_moe_topk",    il);  // [8, n_tokens] — VIEW (gotcha!)

static bool moe_cb_eval(ggml_tensor *t, bool ask, void *ud) {
    if (ask) return strncmp(t->name, "ffn_moe_argsort", 15) == 0;
    if (!is_argsort) return true;
    int il = atoi(strrchr(t->name, '-') + 1);
    int32_t *ids = (int32_t*) backend_get(t);             // contiguous parent
    for (int tok = 0; tok < n_tokens; ++tok)
        for (int rank = 0; rank < n_used; ++rank)         // top-8 per token
            counts[il][ ids[tok * n_expert + rank] ]++;
    return true;
}

Inputja a meglévő GGUF model + egy korpusz; outputja egy JSON: rétegenként × expertenként hány selection.

Tech mély08 / 14

Buktató — kis híján kísérlet-gyilkos

Amikor a tökéletes egyenlőség a hiba

ELSŐ FUTÁS · ELRONTOTT

Minden expert minden rétegen pontosan 1065–1068 selection-t kapott. std/mean = 0.001.

34 ezer tokenen statisztikailag képtelenség → biztos hogy bug.

JAVÍTOTT FUTÁS · VALÓDI

min=0, max=92, std/mean=2.66 a mélyebb rétegekben. Erősen ferde, valódi routing.

Ez a kép tette lehetővé az egész további pruningot.

Diagnózis és fix

A ffn_moe_topk egy nem-folytonos view a teljes argsort fölött. A ggml_backend_tensor_get folytonos bájtokat másol — így a teljes 0..255 permutációkat olvastam minden tokenre, ezért minden expert egyenletesen pontosan egyszer szerepelt. Fix: a folytonos parent ffn_moe_argsort ([256, n_tokens]) tensort olvasni, per-token az első 8 sort venni — ez a valódi top-8.

Tech mély09 / 14

A valódi routing-tömeg

Mennyit fed le a TOP-K expert a routing tömegnek per layer, összevont dev+pm+family korpuszra. A worst layer oszlop a kritikus: az limitálja az uniform GGUF pruningot.

Ktömeg(átlag)tömeg(worst layer)% expert
256100.00%100.00%100.0%
22499.31%95.13%87.5%
192 ★97.65%88.65%75.0%
16094.95%81.04%62.5%
12890.80%72.43%50.0%
9684.02%62.38%37.5%
  • · per-layer max/min expert-usage ratio: median 2810 (uniform = 1.0)
  • · deeper layers ferdébbek: layer 0 std/mean=1.75, layer 39 = 3.19
  • · 0 teljesen halott expert (load-balancing loss tervezett mellékhatása)
Tech mély10 / 14

Sebészet: raw-slab gather, nincs requant

A trükk ami miatt nem kell dequantálni: a 4 expert-hordozó tensorban az expert-index a legkülső ggml-tengely. A gguf-py numpy byte-shape-ben az axis 0 = expert → data[keep_indices] egy fancy-index és KÉSZ. A Q4_K/Q5_K/Q6_K blokk-kvantálás betűre megőrződik.

# prune_gguf.py — the core
for t in reader.tensors:
    data = t.data
    if expert_tensor_re.match(t.name):          # ffn_{gate,up,down}_exps
        il = layer_from_name(t.name)
        data = np.ascontiguousarray(data[keepset(il)])   # axis 0 = expert
    elif router_re.match(t.name):                # ffn_gate_inp
        data = np.ascontiguousarray(data[keepset(il)])
    writer.add_tensor_info(t.name, data.shape, data.dtype, data.nbytes, t.tensor_type)
    # *_shexp (shared expert) -> copied verbatim, never pruned
  • · 4 érintett tensor / MoE layer: gate_exps + up_exps + down_exps + gate_inp (router)
  • · *_shexp (shared expert, mindig aktív) érintetlenül átmásolva
  • · globális metadata: expert_count = K, expert_used_count marad 8
  • · 23 GB → pruneolt GGUF: ~12 másodperc lemezírással együtt
Tech mély11 / 14

Sebesség: prefill skálázódik, generation nem

llama-bench gfx1150 Vulkan-on, ngl=99. Érdekes minta: a prefill (prompt processing) szépen skálázódik K-val — de a generation lényegében változatlan, mert per-token mindenképpen csak 8 expert aktív.

modellméretparamspp256 t/stg64 t/s
baseline (256)21.3 GiB35.5 B352.8 ± 7.622.85
22418.9 GiB31.4 B371.0 +5%22.80
192 ★16.6 GiB27.2 B386.8 +10%21.86
12811.9 GiB19.0 B464.3 +32%23.43

Mellesleg: K=128 modell ugyanolyan sebességgel generál (23 t/s), mint a baseline 35 B — viszont a fele méreten. Bizonyos use-case-ekre (gyors draft MTP-hez, telefonra) ez érdekes.

Tech mély12 / 14

Egy darab nyitva maradt rejtély

K=128 + llama-perplexity + Vulkan = GPU-fagyás

A K=128 fájl betöltése a perplexity-mérőben uninterruptible kernel-állapotba ragadt amdgpu-buffer-allokáció közben. kill -9 nem fogta. Két amdgpu_gpu_recover sem oldotta fel. Reboot kellett.

Name: llama-perplexit

State: D (disk sleep)

VmRSS: 12057500 kB

wchan: drm_suballoc_new

De érdekes:

A llama-bench ugyanazt a K=128 fájlt Vulkan-on PROBLÉMA NÉLKÜL betölti és futtatja (32% gyorsabb prefill, 23 t/s gen). Vagyis nem K=128 fájl-corrupt; egy specifikus tool×Vulkan×ez-a-shape interakció triggerel valami amdgpu-buffer-deadlock-ot. PPL méréshez K=128-on a CPU út (-ngl 0) biztonságos — onnan jött a 9.33 érték.

Laikusoknak13 / 14

Két reboot egy éjszaka — és a stack mindkettő után magától visszaállt

Az első reboot az volt, amit én indítottam el a K=128 GPU-fagyás miatt. A második — egy órával később — egy klasszikus áramszünet. (Tényleg.)

Mindkét boot után a teljes stack magától felállt: az LLM-szerver (lemond), 7 user service, 13 cron-timer, 11 docker konténer. Manuális restore-script nem kellett.

A systemd enabled + linger + docker restart-unless-stopped trifecta a defense-in-depth megéri-érzet. (És most már UPS-t is veszek.)

14 / 14

Tanulság

A rossz kérdés és a jó kérdés

Az eredeti kérdésem így szólt: "Van-e olyan szakértő ebben a modellben, akit én SOHA nem használok?" Erre a válasz, kiderült, nincs — a load-balancing-loss-szal tanított modellben minden szakértő tüzel valahol.

A jó kérdés: "Mennyi minőségvesztést bírunk vesztni cserébe X% méretért?" Erre van pontos válasz: a K=192-vel 23% méretmegtakarítás, ~1% PPL ár, és ~ugyanolyan generation-sebesség. K=128-cal a fele méret, ~6% PPL áron — egy más felhasználási kategória (fast draft, mobil).

A bake (Track A) még előttünk áll — de már most látszik, hogy a bake és a prune együtt szinergikus: egy stílusra-betanított modell routingja koncentráltabb lesz → több kidobható expert.

Qwen3.6-35B-A3Bqwen35moegfx1150 (Radeon 890M)Vulkanllama.cpp