arcticoneai commited on
Commit
8af9cd0
Β·
verified Β·
1 Parent(s): c11ed2b

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +88 -83
README.md CHANGED
@@ -1,25 +1,18 @@
1
  ---
2
- base_model: no_multiplication_model
 
3
  tags:
4
- - experimental
5
- - inference
6
- - feature-selection
7
- - bayesian
8
- - Transformers
9
- - Safetensors
10
- - open-source
11
- - language-model
12
- - compression
13
- - quantisation
14
-
15
-
16
  ---
17
 
18
- # **I made Qwen2-0.5B run 100Γ— smaller with no matrix multiplications and almost no RAM usage β€” adaptive sparse selection at inference time, and it actually works.**
19
 
20
- # contact: Twitter: https://x.com/liberal17th email: bogunusov@gmail.com
21
-
22
- **Status: experimental / work in progress.** This is a research test, not a production release, not a compression method, and not a claim of a new architecture. Numbers below are placeholders β€” real plots and stats will be added once benchmark runs are complete.Currently, according to tests, it doesn't use any RAM at all, but there may be errors. With this compression, we compressed by about 30%, but the main matrices are not multiplied.
23
 
24
  ## What this actually is
25
 
@@ -27,87 +20,69 @@ During autoregressive generation, this repo tracks a small set of statistical fe
27
 
28
  The output metric is simple: **what fraction of tracked features get flagged as informative per step**, averaged over a generation. That's it. It's an exploration of whether activation statistics carry sparse, structured signal during inference β€” not a finished result and not a benchmark win yet.
29
 
 
30
 
 
31
 
32
- ## Why this might be interesting anyway
 
 
33
 
34
- Most work on transformer internals looks at weights (pruning, quantization, low-rank decomposition). This script instead asks: at inference time, does the *activation* stream flowing through each layer have a small, identifiable subset of statistics that matter more than the rest at any given step? If that subset is small and stable, it's a hint (not proof) that there's structure worth digging into β€” for interpretability, for adaptive compute, or just as a diagnostic tool for understanding what a layer is "paying attention to" numerically.
35
 
 
36
 
 
37
 
38
- <div style="background: #ffffff; padding: 30px; border-radius: 12px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 650px; margin: 20px auto; border: 1px solid #e8e8e8;">
39
 
40
- <h3 style="margin: 0 0 20px 0; font-size: 18px; font-weight: 600; color: #1a1a1a; text-align: center;">πŸ“¦ Model Size Comparison</h3>
 
 
 
 
 
 
41
 
42
- <div style="margin-bottom: 16px;">
43
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
44
- <span style="font-size: 14px; color: #333; font-weight: 500;">Qwen2-0.5B</span>
45
- <span style="font-size: 14px; color: #555; font-weight: 600;">900 MB</span>
46
- </div>
47
- <div style="width: 100%; height: 24px; background: #f0f0f0; border-radius: 6px; overflow: hidden;">
48
- <div style="width: 100%; height: 100%; background: #e74c3c; border-radius: 6px;"></div>
49
- </div>
50
- </div>
51
 
52
- <div style="margin-bottom: 20px;">
53
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
54
- <span style="font-size: 14px; color: #333; font-weight: 500;">Adaptive Sparse (this)</span>
55
- <span style="font-size: 14px; color: #555; font-weight: 600;">10 MB</span>
56
- </div>
57
- <div style="width: 100%; height: 24px; background: #f0f0f0; border-radius: 6px; overflow: hidden;">
58
- <div style="width: 1.1%; height: 100%; background: #3498db; border-radius: 6px;"></div>
59
- </div>
60
- </div>
61
 
62
- <div style="display: flex; gap: 12px; justify-content: center; border-top: 1px solid #eee; padding-top: 16px;">
63
- <span style="font-size: 13px; color: #666;"><span style="display: inline-block; width: 12px; height: 12px; background: #e74c3c; border-radius: 3px; vertical-align: middle; margin-right: 4px;"></span> Original</span>
64
- <span style="font-size: 13px; color: #666;"><span style="display: inline-block; width: 12px; height: 12px; background: #3498db; border-radius: 3px; vertical-align: middle; margin-right: 4px;"></span> This model</span>
65
- <span style="font-size: 13px; font-weight: 600; color: #2c3e50;">90Γ— smaller</span>
66
- </div>
67
 
68
- </div>
 
 
 
69
 
70
- ---
71
 
72
- <div style="background: #ffffff; padding: 30px; border-radius: 12px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 650px; margin: 20px auto; border: 1px solid #e8e8e8;">
73
 
74
- <h3 style="margin: 0 0 20px 0; font-size: 18px; font-weight: 600; color: #1a1a1a; text-align: center;">🧠 RAM Usage During Inference(testing on google colab)</h3>
75
 
76
- <div style="margin-bottom: 16px;">
77
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
78
- <span style="font-size: 14px; color: #333; font-weight: 500;">Qwen2-0.5B (original)</span>
79
- <span style="font-size: 14px; color: #555; font-weight: 600;">4 GB</span>
80
- </div>
81
- <div style="width: 100%; height: 24px; background: #f0f0f0; border-radius: 6px; overflow: hidden;">
82
- <div style="width: 100%; height: 100%; background: #e74c3c; border-radius: 6px;"></div>
83
- </div>
84
- </div>
85
 
86
- <div style="margin-bottom: 20px;">
87
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px;">
88
- <span style="font-size: 14px; color: #333; font-weight: 500;">Adaptive Sparse (this)</span>
89
- <span style="font-size: 14px; color: #555; font-weight: 600;">~0 GB</span>
90
- </div>
91
- <div style="width: 100%; height: 24px; background: #f0f0f0; border-radius: 6px; overflow: hidden;">
92
- <div style="width: 0%; height: 100%; background: #3498db; border-radius: 6px;"></div>
93
- </div>
94
- </div>
95
 
96
- <div style="display: flex; gap: 12px; justify-content: center; border-top: 1px solid #eee; padding-top: 16px;">
97
- <span style="font-size: 13px; color: #666;"><span style="display: inline-block; width: 12px; height: 12px; background: #e74c3c; border-radius: 3px; vertical-align: middle; margin-right: 4px;"></span> Original</span>
98
- <span style="font-size: 13px; color: #666;"><span style="display: inline-block; width: 12px; height: 12px; background: #3498db; border-radius: 3px; vertical-align: middle; margin-right: 4px;"></span> This model</span>
99
- <span style="font-size: 13px; font-weight: 600; color: #2c3e50;">4 GB β†’ 0 GB</span>
100
- </div>
101
 
102
- </div>
103
 
 
 
 
 
 
104
 
105
  ## Files
106
 
107
  | File | What it does |
108
- |------|--------------|
109
  | `terminal_chat_bayesian.py` | Main experiment. Loads Qwen2-0.5B, hooks every attention/FFN weight's input activations, runs the Bayesian feature selector during generation, prints the fraction of flagged features per response. Requires `bayes_analysis.safetensors` (see below). |
110
  | `storage_reconstruction_test.py` | Secondary test. Splits weight tensors into `(mean_scalar, residual_tensor)` across a JSON + safetensors file, reconstructs on load. Included for transparency β€” this is a loading mechanics test, not a result. |
 
111
 
112
  ## Requirements
113
 
@@ -144,16 +119,38 @@ python storage_reconstruction_test.py
144
 
145
  This will strip attention/FFN weights from the loaded model and reconstruct them from the two files, then start a basic chat loop. Reconstruction is exact by construction β€” see the "What this is not" section above for why.
146
 
147
- ### 3. compression with Bayes
148
-
149
- Show on R2 test 100% score with compression.Compressed approximately 30%
150
 
151
  ```bash
152
- python bayes_compression.py
153
  ```
154
 
 
 
 
 
 
 
 
 
 
155
 
 
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
  ## Code
159
 
@@ -661,9 +658,7 @@ if __name__ == "__main__":
661
  run_fast_terminal_chat()
662
  ```
663
 
664
- ## Code
665
-
666
- ### `bayes_compression.py`
667
 
668
  ```python
669
  from __future__ import annotations
@@ -734,6 +729,10 @@ def _packetize(raw: bytes, packet_size: int) -> List[bytes]:
734
 
735
 
736
  def _bayes_features(raw: bytes) -> Dict[str, float]:
 
 
 
 
737
  if not raw:
738
  return {
739
  "n": 0,
@@ -751,7 +750,7 @@ def _bayes_features(raw: bytes) -> Dict[str, float]:
751
  n = int(u8.numel())
752
 
753
  counts = torch.bincount(u8.to(torch.int64), minlength=256).to(torch.float32)
754
- posterior = counts + 1.0
755
  total = float(posterior.sum().item())
756
  probs = posterior / total
757
 
@@ -1096,7 +1095,9 @@ if __name__ == "__main__":
1096
 
1097
  ## Results
1098
 
1099
- *Placeholder β€” to be filled in with real numbers from benchmark runs.*
 
 
1100
 
1101
  - [ ] Fraction of features flagged per layer, averaged across a test set of prompts
1102
  - [ ] How the flagged fraction changes over the course of a generation (early tokens vs. late tokens)
@@ -1107,4 +1108,8 @@ if __name__ == "__main__":
1107
 
1108
  - Does the flagged feature subset stay stable across different prompts, or does it change drastically session to session?
1109
  - Is there a relationship between which features get flagged and attention patterns in the same layer?
1110
- - Right now `BAYES_EVERY_N = 8` and the deviation threshold (`> 1.0` std) are picked without tuning β€” sweeping these would show whether the flagged fraction is a real signal or just a threshold artifact.
 
 
 
 
 
1
  ---
2
+ license: apache-2.0
3
+ base_model: Qwen/Qwen2-0.5B
4
  tags:
5
+ - experimental
6
+ - inference
7
+ - feature-selection
8
+ - bayesian
9
+ - compression
10
+ - lossless
 
 
 
 
 
 
11
  ---
12
 
13
+ # Adaptive Sparse Feature Selection at Inference Time (Qwen2-0.5B)
14
 
15
+ **Status: experimental / work in progress.** This is a research test, not a production release, not a compression method, and not a claim of a new architecture. Numbers below are placeholders β€” real plots and stats will be added once benchmark runs are complete.
 
 
16
 
17
  ## What this actually is
18
 
 
20
 
21
  The output metric is simple: **what fraction of tracked features get flagged as informative per step**, averaged over a generation. That's it. It's an exploration of whether activation statistics carry sparse, structured signal during inference β€” not a finished result and not a benchmark win yet.
22
 
23
+ ## What this is *not*
24
 
25
+ To be upfront about scope, since it's easy to over-read either script:
26
 
27
+ - **Not a compression method.** There is a second script in this repo (`storage_reconstruction_test.py`) that splits a weight tensor into a scalar mean and a residual tensor stored in two separate files, then reconstructs the original by adding them back together. This is a **storage/loading split test** β€” reconstruction is mathematically exact by construction (`mean + (original - mean) = original`), so the RΒ²=1.0 you'll see is expected and is not a compression result. No compression ratio is claimed anywhere in this repo.
28
+ - **Not a new computation method.** The Bayesian selector changes *what gets measured and tracked* during inference, not *how the forward pass computes logits*. The underlying Qwen2-0.5B forward pass is untouched.
29
+ - **Not validated against a baseline yet.** There's no side-by-side comparison here (yet) showing that the selected feature subset actually predicts anything useful about output quality, speed, or attention patterns. Right now this is instrumentation, not a proven technique.
30
 
31
+ If any of that changes as testing continues, this README will be updated to reflect it β€” the goal is to keep the claims here matched to what's actually been measured.
32
 
33
+ ## A third script: entropy-gated lossless compression
34
 
35
+ Separate from the two experiments above, this repo also includes `entropy_gated_compression.py`, which applies **standard lossless compression to raw model weight bytes**, using a per-packet entropy check to decide whether compression is worth attempting.
36
 
37
+ ### Measured result (single run, self-reported)
38
 
39
+ ```
40
+ Model: Qwen2-0.5B, model.safetensors
41
+ Original: 988,807,168 bytes (943 MB)
42
+ Compressed: 793,772,032 bytes (757 MB)
43
+ Space saved: 19.7%
44
+ Compression ratio: 1.246x
45
+ ```
46
 
47
+ This is **lossless** β€” decompression was verified to reproduce every tensor bit-for-bit (SHA256 match on 100% of checked tensors, see "Integrity verification" below). There is no approximation, no quantization, and no information discarded. It's exact round-trip storage in less space, not a compressed *representation* of the model in the sense pruning or quantization would give you.
 
 
 
 
 
 
 
 
48
 
49
+ ### How the entropy gate works
 
 
 
 
 
 
 
 
50
 
51
+ For every 8 MB packet of raw tensor bytes, the packet is treated as a stream of 256 possible byte values (0–255) and a frequency histogram is built. From that histogram:
 
 
 
 
52
 
53
+ ```
54
+ p(v) = (count(v) + 1) / (total_bytes + 256) # Laplace-smoothed frequency
55
+ H = - Sum p(v) * log2 p(v) # Shannon entropy, bits/byte
56
+ ```
57
 
58
+ The `+1` in the numerator (and `+256` in the denominator to keep it a valid distribution) is **Laplace smoothing** β€” a standard fix so that byte values with zero observed occurrences don't produce `log2(0)`. This keeps every probability strictly positive. To be precise about terminology: this smoothing is a Bayesian-flavored technique (it's equivalent to placing a uniform Dirichlet prior over the byte distribution and taking a posterior mean), but the compression *decision* itself is a simple **entropy threshold**, not a Bayesian inference procedure over model parameters. If `H >= 7.90` bits/byte, the packet is treated as high-entropy (close to indistinguishable from random noise) and stored raw β€” attempting `zlib` on it would cost CPU time for little or no space savings. If `H < 7.90`, the packet goes through `zlib` at compression level 1, and the result is kept only if it's actually smaller than the raw packet.
59
 
60
+ ### Why weight tensors compress at all
61
 
62
+ Raw `float16`/`bfloat16` weights are not uniformly random at the byte level, even though they look noise-like in aggregate. Mantissa bits tend to be close to high-entropy, but:
63
 
64
+ - Normalization layer weights (`input_layernorm`, `post_attention_layernorm`) and biases occupy a narrower value range than general weight matrices, which tends to concentrate their byte-value histograms and lower measured entropy.
65
+ - Repeated or near-repeated byte patterns across a large tensor give `zlib`'s LZ77-style matching something to exploit, independent of the entropy gate.
 
 
 
 
 
 
 
66
 
67
+ A 19.7% reduction is consistent with the range generally reported for applying generic lossless compressors (gzip/zlib-class) directly to raw transformer weight bytes β€” typically single-digit to ~25%, varying by layer type and model. This is **not a novel compression ratio** by research standards; it's roughly what's expected from entropy-aware lossless compression on this kind of data. The contribution here, if there is one, is the packet-level entropy gate deciding *where* to spend compression effort rather than applying `zlib` uniformly β€” this mainly saves CPU time on incompressible packets rather than improving the ratio itself.
 
 
 
 
 
 
 
 
68
 
69
+ ### Integrity verification
 
 
 
 
70
 
71
+ Every packet is SHA256-hashed before compression and checked again after decompression. The proof-of-correctness run showed **100.0000% match across all checked tensors** β€” every layer's weight, bias, and normalization tensor was recovered bit-identical to the source file. This is the expected outcome for a correctly implemented lossless codec with a working verification step, not a measured quality metric β€” it confirms the round-trip is correct, the same way a working checksum is expected to match rather than being a research result in itself.
72
 
73
+ ## Why this might be interesting anyway
74
+
75
+ Most work on transformer internals looks at weights (pruning, quantization, low-rank decomposition). This script instead asks: at inference time, does the *activation* stream flowing through each layer have a small, identifiable subset of statistics that matter more than the rest at any given step? If that subset is small and stable, it's a hint (not proof) that there's structure worth digging into β€” for interpretability, for adaptive compute, or just as a diagnostic tool for understanding what a layer is "paying attention to" numerically.
76
+
77
+ That's the honest pitch. No claims beyond it yet.
78
 
79
  ## Files
80
 
81
  | File | What it does |
82
+ |---|---|
83
  | `terminal_chat_bayesian.py` | Main experiment. Loads Qwen2-0.5B, hooks every attention/FFN weight's input activations, runs the Bayesian feature selector during generation, prints the fraction of flagged features per response. Requires `bayes_analysis.safetensors` (see below). |
84
  | `storage_reconstruction_test.py` | Secondary test. Splits weight tensors into `(mean_scalar, residual_tensor)` across a JSON + safetensors file, reconstructs on load. Included for transparency β€” this is a loading mechanics test, not a result. |
85
+ | `entropy_gated_compression.py` | Lossless compression of raw safetensors weight bytes using an entropy-gated packet scheme. Measured 19.7% size reduction on Qwen2-0.5B with verified bit-exact decompression. See "A third script" section above for details. |
86
 
87
  ## Requirements
88
 
 
119
 
120
  This will strip attention/FFN weights from the loaded model and reconstruct them from the two files, then start a basic chat loop. Reconstruction is exact by construction β€” see the "What this is not" section above for why.
121
 
122
+ ### 3. Entropy-gated lossless compression
 
 
123
 
124
  ```bash
125
+ python entropy_gated_compression.py
126
  ```
127
 
128
+ By default this compresses `/content/Qwen2-0.5B` (edit `source_model_dir` at the bottom of the script for a different path) into a bundle directory, then immediately decompresses it back to verify correctness. Output:
129
+
130
+ ```
131
+ Compression finished.
132
+ Payload: qwen2_0_5b_bayes_zlib_bundle/payload.bin
133
+ Manifest: qwen2_0_5b_bayes_zlib_bundle/manifest.json
134
+ Packet: 8.0 MB
135
+ Restored to: qwen2_0_5b_restored
136
+ ```
137
 
138
+ To use the compression/decompression functions directly instead of running the full round-trip:
139
 
140
+ ```python
141
+ from entropy_gated_compression import compress_qwen2_safetensors_fast, decompress_qwen2_safetensors_fast
142
+
143
+ compress_qwen2_safetensors_fast(
144
+ model_dir="/path/to/Qwen2-0.5B",
145
+ output_bundle_dir="my_bundle",
146
+ packet_mb=8,
147
+ )
148
+
149
+ decompress_qwen2_safetensors_fast(
150
+ bundle_dir="my_bundle",
151
+ restored_model_dir="my_restored_model",
152
+ )
153
+ ```
154
 
155
  ## Code
156
 
 
658
  run_fast_terminal_chat()
659
  ```
660
 
661
+ ### `entropy_gated_compression.py`
 
 
662
 
663
  ```python
664
  from __future__ import annotations
 
729
 
730
 
731
  def _bayes_features(raw: bytes) -> Dict[str, float]:
732
+ # NOTE: named for the Laplace-smoothed histogram below, which is a
733
+ # Bayesian-flavored smoothing technique (equivalent to a uniform
734
+ # Dirichlet prior). The compression decision itself is a plain
735
+ # entropy threshold, not Bayesian inference over model parameters.
736
  if not raw:
737
  return {
738
  "n": 0,
 
750
  n = int(u8.numel())
751
 
752
  counts = torch.bincount(u8.to(torch.int64), minlength=256).to(torch.float32)
753
+ posterior = counts + 1.0 # Laplace smoothing (uniform Dirichlet prior, alpha=1)
754
  total = float(posterior.sum().item())
755
  probs = posterior / total
756
 
 
1095
 
1096
  ## Results
1097
 
1098
+ **Entropy-gated compression β€” measured, single run:** 19.7% size reduction (943 MB β†’ 757 MB) on Qwen2-0.5B, with 100% bit-exact decompression verified via SHA256. See "A third script" section above for the full breakdown. This has been run once β€” repeating across other model sizes and dtypes (fp16 vs bf16 vs fp32) would show whether 19.7% generalizes or is specific to this checkpoint.
1099
+
1100
+ **Bayesian feature selection during inference β€” still placeholder.** The activation-tracking experiment (main script) has not yet been benchmarked systematically:
1101
 
1102
  - [ ] Fraction of features flagged per layer, averaged across a test set of prompts
1103
  - [ ] How the flagged fraction changes over the course of a generation (early tokens vs. late tokens)
 
1108
 
1109
  - Does the flagged feature subset stay stable across different prompts, or does it change drastically session to session?
1110
  - Is there a relationship between which features get flagged and attention patterns in the same layer?
1111
+ - Right now `BAYES_EVERY_N = 8` and the deviation threshold (`> 1.0` std) are picked without tuning β€” sweeping these would show whether the flagged fraction is a real signal or just a threshold artifact.
1112
+
1113
+ ## License
1114
+
1115
+ Apache 2.0, matching the base model license. This repo builds on [Qwen/Qwen2-0.5B](https://huggingface.co/Qwen/Qwen2-0.5B).