denseflux · Activation sparsity

denseflux: Skipping most of a dense LLM’s FFN on Apple Silicon

Activation sparsity, a Metal kernel, and what did not work along the way. On ProSparse-Llama-2-7B only 11.2% of FFN neurons fire per token; skipping the rest costs +0.44% perplexity and makes the FFN about 2.05× faster on an M4 Pro. SwiGLU models, fixed clusters and cheap predictors did not pay off.

Tran Sy Bao (Johnny) · Ho Chi Minh City · · 12 min read

xone tokenW_gateevery row readact(·)≈ 11% fireW_up · W_downfired rows onlyFFN(x)≈ 2.05× faster

one token through a sparse FFN: the gate reads every row, then up and down read only the rows whose neuron fired, a different set each token

Key numbers

11.2%
of FFN neurons active per token on ProSparse-Llama-2-7B
2.05×
faster FFN with exact gating
+0.44%
perplexity cost of skipping them
≈ 60%
active neurons where the kernel breaks even
On this page

    TL;DR

    The short version

    • Why the FFN: single-stream decoding is memory-bandwidth bound, and the FFN holds roughly two thirds of a dense transformer layer’s weights. Every FFN row we do not read is time saved.
    • Result: on a ReLU-sparse model (ProSparse-Llama-2-7B), only 11.2% of FFN neurons are active per token. Skipping the rest with exact gating costs +0.44% perplexity and makes the FFN about 2.05× faster.
    • Kernel: our Metal kernel for a 4-bit FFN at Qwen2.5-3B size breaks even at about 60% active neurons and reaches 1.93× at 10% active on an M4 Pro, about 77% of the ideal speedup implied by bytes saved.
    • What did not work: standard SwiGLU models (Qwen2.5) are a poor fit: activations are rarely zero, so cutting more than ~17% of neurons already hurts quality. Grouping neurons into fixed clusters fails on every model we tested, and cheap predictors fail at moderate sparsity.
    • Scope: this post reports per-FFN-layer numbers. End-to-end tokens per second, reasoning benchmarks and baseline comparisons come next (section 7).

    1 · Motivation

    Why the FFN

    When an LLM generates one token at a time, the GPU must stream every weight from memory once per token but does very little arithmetic per byte. Decode time is therefore close to proportional to the number of bytes read. This is the regime TEAL, Deja Vu and LLM in a Flash all target.

    A modern gated FFN computes

    ƒ(x)The gated FFN

    Each intermediate “neuron” owns row of , row of and column of . For Llama-2-7B (d_model = 4096, d_ff = 11008) a layer holds about 67M attention parameters (4 × 4096²) and about 135M FFN parameters (3 × 4096 × 11008), so the FFN is roughly two thirds of the bytes. Models with grouped-query attention have an even larger FFN share.

    If a neuron’s activation is zero for the current token, its row and column contribute nothing and do not need to be read. The questions this post answers are: how many neurons can we skip, at what quality cost, and can a real kernel on Apple Silicon turn that into wall-clock speed?

    2 · Prior work

    Prior work this builds on

    WorkIdea we reuse or test
    TEAL (ICLR 2025)Training-free magnitude thresholds per layer; 40–50% model-wide sparsity on Llama/Mistral; per-layer greedy budget
    CATS (COLM 2024)Threshold on SiLU(W_gate·x), then skip W_up/W_down rows
    Deja Vu (ICML 2023)Contextual-sparsity predictors with lookahead across layers
    LLM in a Flash (Apple)Row–column bundling and windowing for flash offload; relies on ReLU-style sparsity
    PowerInfer / PowerInfer-2Hot/cold neuron split; gate/up/down bundles; SiLU models gain only modestly
    ProSparse / Sparsing LawReLU-fied models with ~89% activation sparsity; ReLU vs SiLU sparsity trends
    SVDP, SparseInferTraining-free low-rank and sign-bit predictors evaluated on ReLU-fied models
    GRIFFIN, CoreInferPer-prompt core neuron sets selected during prefill
    Table 1. Prior work. Links are in the References section.

    3 · Setup

    How we measured

    • Hardware: Apple M4 Pro for the kernel benchmarks. All Python experiments run on Apple Silicon (MPS).
    • Models: Qwen2.5-0.5B and Qwen2.5-3B (SwiGLU); a ~1.3B ReGLU/SwiGLU pair trained identically except for the activation; ProSparse-Llama-2-7B (ReLU-fied).
    • Precision: 4-bit weights unless stated otherwise.
    • Quality metric: perplexity on 16,384 evaluation tokens. Prefill stays dense; sparsity is applied per token, as decode would see it.
    • Cost metric: share of FFN work (or FFN bytes) kept per token. The gate projection is counted in full when it is computed exactly, so exact gating keeps of the FFN, where is the active fraction.
    • Tools: a Python harness (cluster_ffn.py) that wraps every gated MLP, and a Swift/Metal micro-benchmark (ffnbench.swift) whose kernel outputs match a CPU reference within 0.04%.

    4 · Negative results

    What did not work

    Negative results shaped the final design, so they come first.

    4.1 SwiGLU activations are dense

    On Qwen2.5-0.5B we thresholded neuron by neuron (, the best case for skipping):

    Table 2. Per-neuron thresholds on Qwen2.5-0.5B.
    ThresholdNeurons keptFFN compute keptPerplexity change
    0.0296.8%97.9%+0.02%
    0.0591.9%94.6%−0.05%
    0.182.8%88.5%+1.4%
    0.259.0%72.7%+19%
    0.54.6%66.0% (chain order, k = 32)+1436%

    Only about 17% of neurons can be skipped (about 11% of FFN compute) before perplexity rises 1.4%. SiLU outputs are small but almost never zero, so every skip is an approximation. This agrees with PowerInfer-2’s note that SiLU models give only modest gains.

    A separate budget per layer helps a lot on SwiGLU. On Qwen2.5-3B, keeping 86.7% of neurons costs +1.39% perplexity with per-layer budgets versus +11.5% with one global threshold. Even so, 86.7% active is far above the kernel’s break-even point (section 5.3), so SwiGLU models gain nothing in practice.

    4.2 Fixed clusters stay almost fully active

    To read weights in larger contiguous chunks, we grouped neurons into clusters of and computed a cluster whenever any of its neurons was active, after reordering neurons by co-activation (a greedy chain in the style of Ripple).

    • On Qwen2.5-0.5B, 99.4–100% of clusters were active for = 16, 32 and 64 at every threshold up to 0.2. Chain ordering moved this only from 99.97% to 99.42% (threshold 0.2, ).
    • On the ~1.3B ReGLU model (38.8% of neurons active), 88.7% of clusters were active, versus about 98% with random grouping.

    The reason is arithmetic. If a fraction of neurons is active and they were independent, a cluster of neurons is needed with probability

    ƒ(x)Chance that a cluster must be read

    At and that is already above 98%. Clusters only pay off when most neurons are zero and active neurons gather together, which we did not observe.

    4.3 Cheap predictors fail at moderate sparsity

    Exact gating needs the full pass, a fixed third of the FFN. A predictor could skip that too. On the ~1.3B ReGLU model (38.8% active, ):

    Table 3. Predictor accuracy. “Read” is the share of neurons fetched; 38.8% is ideal. “Late” is the share of needed neurons the predictor missed.
    PredictorNeeds in RAMRecallPrecisionReadLate
    layer_in (lookahead)full W_gate91.5%89.5%39.6%3.3%
    layer_in + margin 0.1full W_gate95.0%85.1%43.3%1.9%
    layer_in + margin 0.2full W_gate97.0%80.0%47.0%1.2%
    prev_ffnfull W_gate87.5%88.6%39.2%5.0%
    prev_tokennothing58.2%58.1%38.8%16.2%
    SparseInfer α = 1.0sign bits77.5%65.8%45.7%8.7%
    SparseInfer α = 1.03sign bits93.6%53.2%68.2%2.5%
    SparseInfer α = 1.1sign bits99.9%40.3%96.1%0%
    • layer_in has the best recall, but it reads the full gate, so it saves no compute in RAM; it only helps prefetching from SSD. Its misses concentrate in early layers (recall 60% in layer 0, ~79% in layers 1–2, 99.6% in the last layers), where attention changes the input most.
    • prev_token shows that the active set changes a lot from token to token, so cross-token caching (windowing) helps little on this model.
    • SparseInfer reports precision above 99% on ~89%-sparse ProSparse models. At ~61% sparsity, many neurons sit near the cutoff, and raising α restores recall only by reading almost everything.

    When predicted misses are simply dropped, quality suffers:

    Table 4. Quality cost of predictor misses on the ~1.3B ReGLU model. The two cost measures come from two separate runs: “FFN bytes read” includes the predictor and gate bytes; “neurons read” is the share of neurons fetched (ideal 38.8%).
    PredictorCost per tokenCost measurePerplexity change
    Exact gate (no predictor)59.2%FFN bytes read+0%
    Low-rank r12840.8%FFN bytes read+15.8%
    Low-rank r256 + margin47.6%FFN bytes read+6.1%
    Low-rank r51250.2%FFN bytes read+3.8%
    SparseInfer54.2%FFN bytes read+4.6%
    SparseInfer α = 1.045.9%neurons read+4.83%
    SparseInfer α = 1.0368.2%neurons read+0.70%
    layer_in + margin 0.143.5%neurons read+2.93%
    layer_in + margin 0.247.2%neurons read+2.25%

    None beats exact gating on this model. The best untrained low-rank predictor saves about 9 points of bytes at +3.8% perplexity. The SVDP paper’s version adds whitening and greedy per-neuron bias calibration and was evaluated on ~89%-sparse models; retesting that full recipe on ProSparse is one of the next steps.

    4.4 No strong hot/cold split

    Keeping the most frequently used neurons in RAM only modestly lowers how often the rest fire:

    Table 5. Firing rate of the neurons left outside RAM.
    Share of neurons in RAMReGLU (average 38.8% active)SwiGLU (keep 0.5, average 50%)
    50%30.8% (×0.79 of average)45.6% (×0.91)
    90%22.5% (×0.58)41.1% (×0.82)

    5 · Results

    What worked

    5.1 ReLU sparsity is free

    With the ~1.3B pair trained identically except for the activation, the ReGLU model has only 38.8% of FFN neurons non-zero; the SwiGLU twin has 100%. Skipping exact zeros removes 61% of / work with no quality loss, keeping 59.2% of FFN compute. The non-zero share grows with depth, from 17.6% in layer 0 to 53.6% in the last layer.

    Table 6. Perplexity change when cutting further.
    Neuron keep (k = 1)ReGLUSwiGLU
    0.5−0.02% (natural sparsity already covers it)+5.8%
    0.3+1.3%+48.6%
    0.2+9.4%+158%

    The cost is model quality itself: the ReGLU model’s base perplexity is 21.78 versus 20.97 for SwiGLU, about 4% worse. This matches Sparsing Law’s finding that the activation function, not parameter count, drives the sparsity limit.

    5.2 ProSparse-Llama-2-7B: 11% active

    On ProSparse-Llama-2-7B, only 11.2% of FFN neurons are active per token, consistent with the 89.32% sparsity reported in the ProSparse paper. Exact gating changes perplexity by +0.44%, and the FFN runs about 2.05× faster with our kernel.

    Open item: if gating only skips exact zeros, outputs should match dense up to floating-point drift. The source of the +0.44% (activation threshold in the model, 4-bit quantization, or evaluation setup) has not been isolated yet.

    5.3 A Metal kernel that turns sparsity into speed

    We timed one 4-bit FFN layer at Qwen2.5-3B size on an M4 Pro, with random weights (only timing matters). Dense runs at 176 µs per layer, about 216 GB/s. If only a fraction of neurons is active, the bytes read fall to of dense, which sets the ceiling:

    ƒ(x)Ideal speedup from bytes saved
    Table 7. Sparse FFN kernel, M4 Pro, 4-bit, Qwen2.5-3B FFN dimensions. Ideal = 3 / (1 + 2a).
    Active neuronsµs per layerSpeedup vs denseIdeal from bytes saved
    dense1761.00×—
    100%2230.79×1.00×
    80%1890.93×—
    60%1631.08×—
    40%1361.30×1.67×
    20%1071.64×2.14×
    10%911.93×2.50×
    5%862.06×—
    1.0×1.5×2.0×2.5×3.0×100%80%60%40%20%0%active neurons →speedup vs densedense = 1.00×break-even ≈ 60%0.79×0.93×1.08×1.30×1.64×1.93×2.06×measured kernelideal, 3 / (1 + 2a)
    Figure 1. Table 7 plotted: measured kernel speedup against the ideal from bytes saved.
    • Break-even is about 60% active. At 100% active the sparse kernel is slower than dense (0.79×) because of its bookkeeping. Qwen 3B at 87% active gains nothing; the ReGLU model at ~39% would gain about 1.3× per FFN layer.
    • Indirect dispatch was the key fix. Launching the up step only for the active rows cut it from 36 µs to 10 µs at 10% active, lifting the 3B FFN from 1.56× to 1.93×.
    • The gate is now the floor. At 10% active it takes 59 of the 91 µs because every row is read. The down step and final sum take about 19 µs together and can still be tuned.

    5.4 Bigger layers get closer to the ideal

    At 10% active, the FFN speedup grows with layer size: 1.46× at 1B dimensions, 1.93× at 3B and 2.11× at 7B. Fixed per-dispatch costs matter less when each layer moves more bytes.

    5.5 Contiguous runs instead of fixed clusters

    For the later SSD path, we replaced fixed clusters with runs built at runtime from the actual active set, merging neighbouring reads when the gap is cheaper to read than a new request. This cut the share of FFN bytes read from 41% to 27.6%. The rule follows a latency–bandwidth model,

    ƒ(x)Read time for a run of s bytes

    which merges two runs when the gap is smaller than about bytes. and must be measured on the target device rather than assumed.

    6 · Limitations

    What these numbers do not show

    • Per-layer, not end-to-end. All speedups are for the FFN only. Attention, embeddings and the LM head are unchanged. As a rough bound, if the FFN takes two thirds of decode time and runs 2× faster, the whole model is about faster. This is an estimate, not a measurement.
    • One machine. Kernel timings are from an M4 Pro. The base M4 Mac mini has different memory bandwidth and must be measured separately.
    • Perplexity only. TEAL and Sirius show that math and long generation degrade before perplexity moves. Reasoning benchmarks are not yet run.
    • Random weights in the kernel benchmark. Timing does not depend on values, but end-to-end runs with real models are still needed.
    • ReLU models cost quality. ReLU-fied or ReLU-trained models are needed for large gains, and they can be weaker than their SwiGLU counterparts (about 4% perplexity in our ~1.3B pair).

    7 · Next

    Next steps

    • Measure end-to-end tokens per second with the kernel inside a full decode loop, dense versus sparse, on ProSparse-Llama-2-7B and ProSparse-MiniCPM-1B.
    • Measure the FFN’s share of decode time on the base M4 Mac mini.
    • Compare against llama.cpp and MLX on the same machine.
    • Run a reasoning benchmark (GSM8K or similar) alongside perplexity.
    • Explain the +0.44% perplexity change under exact gating.
    • Retest a full SVDP predictor (whitening plus bias calibration) on ProSparse, where the gate dominates the remaining cost.
    • Test a per-prompt core set, compacted once after prefill, plus a per-token predictor for neurons outside the core.

    References

    Sources

    1. Liu et al., Training-Free Activation Sparsity in Large Language Models (TEAL), ICLR 2025. arxiv.org/abs/2408.14690
    2. Lee et al., CATS: Contextually-Aware Thresholding for Sparsity in LLMs, COLM 2024. arxiv.org/abs/2404.08763
    3. Liu et al., Deja Vu: Contextual Sparsity for Efficient LLMs at Inference Time, ICML 2023. arxiv.org/abs/2310.17157
    4. Alizadeh et al., LLM in a Flash: Efficient LLM Inference with Limited Memory. arxiv.org/abs/2312.11514
    5. Song et al., PowerInfer: Fast LLM Serving with a Consumer-grade GPU. arxiv.org/abs/2312.12456
    6. Xue et al., PowerInfer-2: Fast LLM Inference on a Smartphone. arxiv.org/abs/2406.06282
    7. Song et al., ProSparse: Introducing and Enhancing Intrinsic Activation Sparsity within LLMs. arxiv.org/abs/2402.13516
    8. Luo et al., Sparsing Law: Towards LLMs with Greater Activation Sparsity, ICML 2025. arxiv.org/abs/2411.02335
    9. SVD Contextual Sparsity Predictors for Fast LLM Inference. arxiv.org/abs/2603.14110
    10. SparseInfer: Training-free Prediction of Activation Sparsity for Fast LLM Inference. arxiv.org/abs/2411.12692
    11. Dong et al., Prompt-prompted Adaptive Structured Pruning for Efficient LLM Generation (GRIFFIN). arxiv.org/abs/2404.01365
    12. CoreInfer: Accelerating LLM Inference with Semantics-Inspired Adaptive Sparse Activation. arxiv.org/abs/2410.18311
    13. Ripple / Neuralink: Fast LLM Inference on Smartphones with Neuron Co-Activation Linking. arxiv.org/abs/2410.19274
    14. Zhou et al., Sirius: Contextual Sparsity with Correction for Efficient LLMs, NeurIPS 2024. arxiv.org/abs/2409.03856
    ← All engineering postsThese are per-FFN-layer numbers. End-to-end tokens per second, reasoning benchmarks and baseline comparisons come next.