Download qwen2.5-7b_c4_1B/scripts/bits_llm.py from bit2vec/bitsseal: direct link, hf CLI and curl.
- Browser
- Download file 5.26 kB
-
https://huggingface.co/bit2vec/bitsseal/resolve/main/qwen2.5-7b_c4_1B/scripts/bits_llm.py
- Command line
-
hf download hf://bit2vec/bitsseal/qwen2.5-7b_c4_1B/scripts/bits_llm.py
-
curl -L -o bits_llm.py https://huggingface.co/bit2vec/bitsseal/resolve/main/qwen2.5-7b_c4_1B/scripts/bits_llm.py
5.26 kB
| """ | |
| Bits-for-LLM encoder (extended): token id -> fixed random n-bit code -> encoder -> hidden. | |
| Backward compatible: defaults (enc_type='mlp', ffn_depth=2, out_scale=0) reproduce the | |
| original 2-layer MLP exactly. New encoder-only tuning knobs for the 7B sweep: | |
| - ffn_depth : number of Linear layers in the MLP (2 = original, 3 = deeper) | |
| - out_scale : if >0, rescale the final projection so output std ~= out_scale (init-scale match) | |
| - enc_type='tfenc' : small Transformer encoder over the bit-code (TF-Enc-H4-FFN512 replica) | |
| """ | |
| import torch, torch.nn as nn | |
| class BitsEmbedding(nn.Module): | |
| def __init__(self, vocab, hidden, nbits=64, W=256, seed=0, dtype=torch.bfloat16, | |
| enc_type='mlp', ffn_depth=2, out_scale=0.0): | |
| super().__init__() | |
| g = torch.Generator().manual_seed(seed) | |
| # plain attribute (NOT a buffer) so FSDP never shards it | |
| self._codes = torch.randint(0, 2, (vocab, nbits), generator=g).to(dtype) | |
| self.vocab, self.hidden, self.nbits, self.W = vocab, hidden, nbits, W | |
| self.enc_type, self.ffn_depth = enc_type, ffn_depth | |
| self.padding_idx = None | |
| if enc_type == 'tfenc': | |
| self.tok_bits = 16 | |
| assert nbits % self.tok_bits == 0, "nbits must be divisible by 16 for tfenc" | |
| self.seq = nbits // self.tok_bits | |
| self.in_proj = nn.Linear(self.tok_bits, W) | |
| self.pos = nn.Parameter(torch.zeros(self.seq, W)) | |
| layer = nn.TransformerEncoderLayer(d_model=W, nhead=4, dim_feedforward=512, | |
| activation='gelu', batch_first=True, norm_first=True) | |
| self.tfenc = nn.TransformerEncoder(layer, num_layers=2) | |
| self.out_proj = nn.Linear(W, hidden) | |
| self.to(dtype) | |
| else: # mlp with ffn_depth linear layers (>=2) | |
| layers = [nn.Linear(nbits, W), nn.GELU()] | |
| for _ in range(max(0, ffn_depth - 2)): | |
| layers += [nn.Linear(W, W), nn.GELU()] | |
| layers += [nn.Linear(W, hidden)] | |
| self.ffn = nn.Sequential(*layers).to(dtype) | |
| if out_scale and out_scale > 0: | |
| self._match_out_scale(out_scale) | |
| def _final(self): | |
| return self.out_proj if self.enc_type == 'tfenc' else self.ffn[-1] | |
| def _match_out_scale(self, target_std): | |
| # empirically rescale the final (linear) layer so the OUTPUT embedding std ~= target_std, | |
| # matching the standard embedding's init scale (~initializer_range). Output is linear in | |
| # the final layer for both mlp (ffn[-1]) and tfenc (out_proj), so scaling it scales output. | |
| with torch.no_grad(): | |
| idx = torch.randint(0, self.vocab, (4096,)) | |
| cur = self.forward(idx).float().std().item() | |
| if cur > 1e-8: | |
| k = target_std / cur | |
| last = self._final() | |
| last.weight.mul_(k) | |
| if last.bias is not None: | |
| last.bias.mul_(k) | |
| def forward(self, ids): | |
| if self._codes.device != ids.device: | |
| self._codes = self._codes.to(ids.device) | |
| codes = self._codes[ids] | |
| if self.enc_type == 'tfenc': | |
| *lead, n = codes.shape | |
| x = codes.reshape(-1, self.seq, self.tok_bits) | |
| x = self.in_proj(x) + self.pos | |
| x = self.tfenc(x).mean(dim=1) | |
| return self.out_proj(x).reshape(*lead, self.hidden) | |
| return self.ffn(codes) | |
| def n_params(self): | |
| return sum(p.numel() for p in self.parameters()) | |
| def swap_in_bits(model, nbits, W, seed, enc_type='mlp', ffn_depth=2, out_scale=0.0): | |
| cfg = model.config | |
| if getattr(cfg, "tie_word_embeddings", False): | |
| out = model.get_output_embeddings() | |
| if out is not None: | |
| new = nn.Linear(out.weight.shape[1], out.weight.shape[0], bias=False) | |
| new.weight = nn.Parameter(out.weight.detach().clone()) | |
| model.set_output_embeddings(new); cfg.tie_word_embeddings = False | |
| dtype = next(model.parameters()).dtype | |
| bits = BitsEmbedding(cfg.vocab_size, cfg.hidden_size, nbits, W, seed, dtype, | |
| enc_type=enc_type, ffn_depth=ffn_depth, out_scale=out_scale) | |
| dev = model.get_input_embeddings().weight.device | |
| model.set_input_embeddings(bits.to(dev)) | |
| orig = cfg.vocab_size * cfg.hidden_size | |
| print(f"[Bits enc={enc_type} depth={ffn_depth} W={W} nbits={nbits} scale={out_scale}] " | |
| f"table {orig/1e9:.3f}B -> encoder {bits.n_params()/1e6:.2f}M " | |
| f"= {orig/max(bits.n_params(),1):.0f}x compression", flush=True) | |
| return bits | |
| def get_dataset(tokenizer, max_len, n_tokens, split_stream): | |
| from datasets import load_dataset | |
| ds = load_dataset("allenai/c4", "en", split=split_stream, streaming=True) | |
| def gen(): | |
| buf = [] | |
| while True: | |
| for ex in ds: | |
| ids = tokenizer(ex["text"], add_special_tokens=False)["input_ids"] | |
| buf.extend(ids + [tokenizer.eos_token_id]) | |
| while len(buf) >= max_len: | |
| yield {"input_ids": buf[:max_len], "labels": buf[:max_len]} | |
| buf = buf[max_len:] | |
| from datasets import IterableDataset | |
| return IterableDataset.from_generator(gen) | |