mohammad-mozaffari commited on
Commit
4e2bc89
·
verified ·
1 Parent(s): a1f3a34

Release llama_2_7b-PATCH-35Sparse (mask only)

Browse files
Files changed (7) hide show
  1. .gitattributes +1 -0
  2. NOTICE +10 -0
  3. PATCH-Logo.png +3 -0
  4. PATCH-Pipeline.svg +0 -0
  5. README.md +132 -0
  6. load_patch_mask.py +93 -0
  7. mask.npz +3 -0
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ PATCH-Logo.png filter=lfs diff=lfs merge=lfs -text
NOTICE ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ This repository distributes ONLY a binary pruning mask (which weight
2
+ positions are kept vs. zeroed). It contains no weights from the base model.
3
+
4
+ The mask is a derivative of the base model listed in the model card and is
5
+ provided under that base model's license. You must independently obtain the base
6
+ model and comply with its license and acceptable-use policy.
7
+
8
+ Mask-generation code: MIT (https://github.com/Paramathic/patch).
9
+ MaskLLM baselines are our own re-implementation; the MaskLLM method is due to
10
+ Fang et al. (NVIDIA), NeurIPS 2024.
PATCH-Logo.png ADDED

Git LFS Details

  • SHA256: 430457921ee29986c0b20acbb15a7d3562a43e2da6a6eefb3634fdbd3671a38e
  • Pointer size: 132 Bytes
  • Size of remote file: 1.4 MB
PATCH-Pipeline.svg ADDED
README.md ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ base_model:
3
+ - meta-llama/Llama-2-7b-hf
4
+ library_name: transformers
5
+ license: llama2
6
+ tags:
7
+ - pruning
8
+ - sparsity
9
+ - 2:4-sparsity
10
+ - patch
11
+ - maskllm
12
+ - mask
13
+ pipeline_tag: text-generation
14
+ ---
15
+
16
+ <div align="center">
17
+ <img src="./PATCH-Logo.png" alt="PATCH" width="360">
18
+ </div>
19
+
20
+ # llama_2_7b-PATCH-35Sparse
21
+
22
+ > **This checkpoint** (LLaMA-2 7B, PATCH-Tile, 35% sparsity): **50.08%** average zero-shot accuracy, **6.18** WikiText2 perplexity.
23
+
24
+ [![Paper](https://img.shields.io/badge/arXiv-2509.23410-b31b1b.svg)](https://arxiv.org/abs/2509.23410) [![GitHub](https://img.shields.io/badge/GitHub-Paramathic%2Fpatch-black.svg?logo=github)](https://github.com/Paramathic/patch)
25
+
26
+ This repository hosts a **mask only** release for the paper
27
+ **[PATCH: Learnable Tile-level Hybrid Sparsity for LLMs](https://arxiv.org/abs/2509.23410)**.
28
+ PATCH (Pruning with a Learnable Tile-level Configuration for Hybrid Sparsity) learns a structured mask on **frozen** pretrained weights, assigning each tile as dense (0% sparsity) or 2:4 sparse (50% sparsity) to hit a flexible global sparsity target while staying hardware-friendly.
29
+
30
+ Because PATCH/MaskLLM keep the base weights **frozen**, we distribute *only the
31
+ binary keep/prune mask* (bit-packed in `mask.npz`) - **no weight values**. You
32
+ recover the sparse model by downloading the original base model and applying the
33
+ mask.
34
+
35
+ - Base model: [`meta-llama/Llama-2-7b-hf`](https://huggingface.co/meta-llama/Llama-2-7b-hf)
36
+ - Method: **PATCH-Tile** &nbsp;|&nbsp; Target sparsity: **35%** &nbsp;|&nbsp; Pattern: **Dense / 2:4 tiles**
37
+ - Measured mask sparsity: **35.08%** over 224 Linear layers (6,476,005,376 weights).
38
+
39
+ <div align="center">
40
+ <img src="./PATCH-Pipeline.svg" alt="PATCH pipeline" width="760">
41
+ </div>
42
+
43
+ ## Results (LLaMA-2 7B)
44
+
45
+ | Sparsity | Method | Pattern | Avg Acc (% ↑) | WikiText2 PPL (↓) |
46
+ |---|---|---|---|---|
47
+ | 0% | Dense | - | 54.61 | 5.12 |
48
+ | 50% | Magnitude | 2:4 | 43.44 | 54.39 |
49
+ | 50% | Wanda | 2:4 | 44.30 | 11.15 |
50
+ | 50% | SparseGPT | 2:4 | 45.09 | 10.12 |
51
+ | 50% | Thanos | 2:4 | 44.80 | 11.19 |
52
+ | 50% | ProxSparse | 2:4 | 45.92 | 9.18 |
53
+ | 50% | MaskLLM | 2:4 | 48.62 | 6.78 |
54
+ | 45% | PATCH-Tile | Dense/2:4 | 48.99 | 6.55 |
55
+ | 35% | **PATCH-Tile** ⭐ | Dense/2:4 | **50.08** | **6.18** |
56
+ | 25% | PATCH-Tile | Dense/2:4 | 51.58 | 5.86 |
57
+
58
+
59
+ Per-task zero-shot accuracy (%) for this checkpoint:
60
+
61
+ | MMLU | PIQA | ARC-E | ARC-C | WinoG. | OBQA | RACE | HellaS. | **Average** |
62
+ |---|---|---|---|---|---|---|---|---|
63
+ | 29.93 | 76.71 | 70.88 | 36.95 | 65.67 | 28.20 | 39.33 | 52.96 | **50.08** |
64
+
65
+ All numbers are from the PATCH paper ([arXiv:2509.23410](https://arxiv.org/abs/2509.23410)); accuracy
66
+ is the average over MMLU, PIQA, ARC-Easy, ARC-Challenge, Winogrande, OpenBookQA,
67
+ RACE and HellaSwag, evaluated with the LM-Evaluation-Harness. PPL is WikiText2.
68
+
69
+ ## Training hyper-parameters
70
+
71
+ | Hyper-parameter | Value |
72
+ |---|---|
73
+ | Fine-tuning dataset | SlimPajama (2B tokens) |
74
+ | Training steps | 2000 |
75
+ | Global batch size | 256 |
76
+ | Sequence length | 4096 |
77
+ | Mask tile size | 128 x 128 (hardware tiles: 128x128 / 128x64 / 64x128 / 64x64) |
78
+ | Logits init. | N(0, 0.014) |
79
+ | Tile-logit prior | SparseGPT (strength 3) |
80
+ | Regularization scope | Global (single target density) |
81
+ | Evaluation | LM-Eval-Harness (8 zero-shot tasks) + WikiText2 PPL @ seqlen 4096 |
82
+ | Hardware | 1 node x 4 GPUs, data parallel (HuggingFace Trainer) |
83
+ | Optimizer | Adam |
84
+ | Learning rate | 1e-4 |
85
+ | Gumbel scaling (kappa) | 100 -> 500 |
86
+ | Gumbel temp (tau) | 2 -> 0.05 |
87
+ | Sparsity reg. (lambda1) | 3 |
88
+ | Weight reg. (lambda2) | 0.1 |
89
+
90
+ ## How to use
91
+
92
+ ```python
93
+ from huggingface_hub import hf_hub_download
94
+ from transformers import AutoModelForCausalLM
95
+ import torch
96
+ from load_patch_mask import apply_patch_mask # shipped in this repo
97
+
98
+ npz = hf_hub_download(repo_id="mohammad-mozaffari/llama_2_7b-PATCH-35Sparse", filename="mask.npz")
99
+ model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", torch_dtype=torch.bfloat16)
100
+ apply_patch_mask(model, npz) # zeroes the pruned weights in place
101
+ ```
102
+
103
+ Or from the command line:
104
+
105
+ ```bash
106
+ python load_patch_mask.py --base_model meta-llama/Llama-2-7b-hf --mask_repo mohammad-mozaffari/llama_2_7b-PATCH-35Sparse
107
+ ```
108
+
109
+ Speedup on real hardware requires a 2:4-aware / hybrid sparse kernel; see the
110
+ [GitHub repository](https://github.com/Paramathic/patch) and [STOICC](https://github.com/Paramathic/stoicc).
111
+
112
+ ## License
113
+
114
+ The released mask is a derivative of the base model and is distributed under the
115
+ base model's license (**`llama2`**). You must comply with that license and
116
+ obtain access to the base model separately.
117
+
118
+ > Use governed by the Llama 2 Community License.
119
+
120
+ The mask-generation code is released under the MIT license (see the
121
+ [PATCH repository](https://github.com/Paramathic/patch)).
122
+
123
+ ## Citation
124
+
125
+ ```bibtex
126
+ @article{hourri2025patch,
127
+ title = {PATCH: Learnable Tile-level Hybrid Sparsity for LLMs},
128
+ author = {Hourri, Younes and Mozaffari, Mohammad and Mehri Dehnavi, Maryam},
129
+ year = 2025,
130
+ journal = {arXiv preprint arXiv:2509.23410}
131
+ }
132
+ ```
load_patch_mask.py ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Apply a released PATCH / MaskLLM sparsity mask to a base model.
3
+
4
+ The released repositories contain ONLY the binary keep/prune mask
5
+ (bit-packed in `mask.npz`) - no weight values. To materialize the sparse
6
+ model you download the original base model and zero out the pruned weights:
7
+
8
+ python load_patch_mask.py \
9
+ --base_model meta-llama/Llama-2-7b-hf \
10
+ --mask_repo mohammad-mozaffari/llama_2_7b-PATCH-45Sparse
11
+
12
+ or use `apply_patch_mask(...)` from your own code.
13
+ """
14
+
15
+ import argparse
16
+ import json
17
+
18
+ import numpy as np
19
+
20
+
21
+ def load_mask_npz(npz_path):
22
+ """
23
+ Load `mask.npz` and return {weight_name: bool_ndarray} plus metadata.
24
+
25
+ The archive stores, per masked weight:
26
+ * "<name>" : bit-packed uint8 array (np.packbits of the flat mask)
27
+ * "<name>.__shape__": original 2-D shape
28
+ and a single JSON blob under "__meta__".
29
+ """
30
+ data = np.load(npz_path, allow_pickle=False)
31
+ meta = json.loads(str(data["__meta__"])) if "__meta__" in data else {}
32
+ masks = {}
33
+ for key in data.files:
34
+ if key == "__meta__" or key.endswith(".__shape__"):
35
+ continue
36
+ shape = tuple(int(x) for x in data[f"{key}.__shape__"])
37
+ n = int(np.prod(shape))
38
+ flat = np.unpackbits(data[key], count=n).astype(bool)
39
+ masks[key] = flat.reshape(shape)
40
+ return masks, meta
41
+
42
+
43
+ def apply_patch_mask(model, npz_path):
44
+ """Zero out pruned weights of `model` in place using the mask archive."""
45
+ import torch
46
+
47
+ masks, meta = load_mask_npz(npz_path)
48
+ sd = dict(model.named_parameters())
49
+ applied = 0
50
+ for name, mask in masks.items():
51
+ if name not in sd:
52
+ raise KeyError(
53
+ f"Mask key '{name}' not found in model parameters. "
54
+ f"Is '{meta.get('base_model', '?')}' the correct base model?"
55
+ )
56
+ w = sd[name]
57
+ m = torch.from_numpy(mask).to(device=w.device)
58
+ if tuple(m.shape) != tuple(w.shape):
59
+ raise ValueError(f"Shape mismatch for {name}: mask {tuple(m.shape)} vs weight {tuple(w.shape)}")
60
+ with torch.no_grad():
61
+ w.mul_(m.to(w.dtype))
62
+ applied += 1
63
+ print(f"Applied mask to {applied} weight tensors "
64
+ f"(target sparsity {meta.get('sparsity', '?')}, pattern {meta.get('pattern', '?')}).")
65
+ return model
66
+
67
+
68
+ def _main():
69
+ from huggingface_hub import hf_hub_download
70
+ from transformers import AutoModelForCausalLM
71
+
72
+ p = argparse.ArgumentParser()
73
+ p.add_argument("--base_model", required=True, help="HF id of the original dense base model")
74
+ p.add_argument("--mask_repo", required=True, help="HF id of the released mask repo")
75
+ p.add_argument("--dtype", default="bfloat16")
76
+ args = p.parse_args()
77
+
78
+ import torch
79
+
80
+ npz_path = hf_hub_download(repo_id=args.mask_repo, filename="mask.npz")
81
+ model = AutoModelForCausalLM.from_pretrained(
82
+ args.base_model, torch_dtype=getattr(torch, args.dtype)
83
+ )
84
+ apply_patch_mask(model, npz_path)
85
+
86
+ total = sum(p.numel() for p in model.parameters())
87
+ nz = sum(int((p != 0).sum()) for p in model.parameters())
88
+ print(f"Overall model density after masking: {nz / total:.4f}")
89
+ return model
90
+
91
+
92
+ if __name__ == "__main__":
93
+ _main()
mask.npz ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5cfb1e7360b3108b60ea8dcc4b6af01872eb973beb3c66c07b152908a94736d6
3
+ size 405350657