Text Generation
Transformers
Safetensors
GGUF
English
bitnet
bitnet-b1.58
ternary
cpu
tinydialogues
conversational
Instructions to use zerolimites/BitNet-TinyDialogues-1.58b with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use zerolimites/BitNet-TinyDialogues-1.58b with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="zerolimites/BitNet-TinyDialogues-1.58b") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("zerolimites/BitNet-TinyDialogues-1.58b") model = AutoModelForCausalLM.from_pretrained("zerolimites/BitNet-TinyDialogues-1.58b", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=256) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use zerolimites/BitNet-TinyDialogues-1.58b with llama.cpp:
Install (macOS, Linux)
curl -LsSf https://llama.app/install.sh | sh # Start a local OpenAI-compatible server with a web UI: llama serve -hf zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0 # Run inference directly in the terminal: llama cli -hf zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0 # Run inference directly in the terminal: llama cli -hf zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
Build from source code
git clone https://github.com/ggml-org/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-app # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama serve -hf zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0 # Run inference directly in the terminal: ./build/bin/llama cli -hf zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
Use Docker
docker model run hf.co/zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
- Llama new
- LM Studio
- Jan
- vLLM
How to use zerolimites/BitNet-TinyDialogues-1.58b with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "zerolimites/BitNet-TinyDialogues-1.58b" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "zerolimites/BitNet-TinyDialogues-1.58b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
- SGLang
How to use zerolimites/BitNet-TinyDialogues-1.58b with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "zerolimites/BitNet-TinyDialogues-1.58b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "zerolimites/BitNet-TinyDialogues-1.58b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "zerolimites/BitNet-TinyDialogues-1.58b" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "zerolimites/BitNet-TinyDialogues-1.58b", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Ollama
How to use zerolimites/BitNet-TinyDialogues-1.58b with Ollama:
ollama run hf.co/zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
- Unsloth Desktop
- Docker Model Runner
How to use zerolimites/BitNet-TinyDialogues-1.58b with Docker Model Runner:
docker model run hf.co/zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
- Lemonade
How to use zerolimites/BitNet-TinyDialogues-1.58b with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull zerolimites/BitNet-TinyDialogues-1.58b:TQ1_0
Run and chat with the model
lemonade run user.BitNet-TinyDialogues-1.58b-TQ1_0
List all available models
lemonade list
- Atomic Chat
Download scripts/train_bitnet.py from zerolimites/BitNet-TinyDialogues-1.58b: direct link, hf CLI and curl.
- Browser
- Download file 8.18 kB
-
https://huggingface.co/zerolimites/BitNet-TinyDialogues-1.58b/resolve/main/scripts/train_bitnet.py
- Command line
-
hf download hf://zerolimites/BitNet-TinyDialogues-1.58b/scripts/train_bitnet.py
-
curl -L -o train_bitnet.py https://huggingface.co/zerolimites/BitNet-TinyDialogues-1.58b/resolve/main/scripts/train_bitnet.py
8.18 kB
| #!/usr/bin/env python3 | |
| """Train a tiny native-ternary BitNet b1.58-style causal LM on CPU. | |
| Weights are ternary {-1,0,+1} in the forward pass (absmean, per tensor) with | |
| straight-through gradients; activations are 8-bit absmax per token. Master | |
| weights are kept in FP32 for the optimizer. The exported GGUF stores the | |
| ternary weights (TQ1_0/TQ2_0). | |
| """ | |
| import argparse, json, math, os, random, time | |
| from pathlib import Path | |
| import numpy as np | |
| import sentencepiece as spm | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from transformers import BitNetConfig, BitNetForCausalLM | |
| torch.set_num_threads(int(os.environ.get('TORCH_THREADS', '2'))) | |
| try: | |
| torch.set_num_interop_threads(1) | |
| except RuntimeError: | |
| pass | |
| torch.manual_seed(42) | |
| random.seed(42) | |
| np.random.seed(42) | |
| def weight_quant(w): | |
| scale = w.abs().mean().clamp(min=1e-5) | |
| q = (w / scale).round().clamp(-1, 1) * scale | |
| return w + (q - w).detach() | |
| def act_quant(x): | |
| scale = x.abs().amax(dim=-1, keepdim=True).clamp(min=1e-5) / 127.0 | |
| q = (x / scale).round().clamp(-127, 127) * scale | |
| return x + (q - x).detach() | |
| class BitLinear(nn.Module): | |
| def __init__(self, lin: nn.Linear): | |
| super().__init__() | |
| self.weight = nn.Parameter(lin.weight.detach().clone()) | |
| self.bias = None if lin.bias is None else nn.Parameter(lin.bias.detach().clone()) | |
| def forward(self, x): | |
| return F.linear(act_quant(x), weight_quant(self.weight), self.bias) | |
| def bitnetize(model): | |
| for layer in model.model.layers: | |
| for attn in [layer.self_attn]: | |
| for name in ['q_proj', 'k_proj', 'v_proj', 'o_proj']: | |
| setattr(attn, name, BitLinear(getattr(attn, name))) | |
| for name in ['gate_proj', 'up_proj', 'down_proj']: | |
| setattr(layer.mlp, name, BitLinear(getattr(layer.mlp, name))) | |
| return model | |
| def load_tokens(path, sp): | |
| import array | |
| bin_path = str(path) + '.u16.bin' | |
| if not os.path.exists(bin_path): | |
| arr = array.array('H') | |
| with open(path, encoding='utf-8') as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line: | |
| continue | |
| arr.append(sp.bos_id()) | |
| arr.extend(sp.encode(line, out_type=int)) | |
| arr.append(sp.eos_id()) | |
| with open(bin_path, 'wb') as f: | |
| arr.tofile(f) | |
| del arr | |
| return np.memmap(bin_path, dtype=np.uint16, mode='r') | |
| def get_batch(tokens, bs, seq, device): | |
| ix = np.random.randint(0, len(tokens) - seq - 1, size=(bs,)) | |
| idx = ix[:, None] + np.arange(seq + 1)[None, :] | |
| batch = torch.from_numpy(tokens[idx].astype(np.int64)).to(device) | |
| return batch[:, :-1], batch[:, 1:] | |
| def evaluate(model, tokens, bs, seq, device, n=16): | |
| model.eval() | |
| losses = [] | |
| for _ in range(n): | |
| x, y = get_batch(tokens, bs, seq, device) | |
| logits = model(x).logits | |
| losses.append(F.cross_entropy(logits.reshape(-1, logits.size(-1)), y.reshape(-1)).item()) | |
| model.train() | |
| return float(np.mean(losses)) | |
| def sample(model, sp, device, prompt='User: Hello Assistant:', max_new_tokens=60): | |
| model.eval() | |
| ids = [sp.bos_id()] + sp.encode(prompt, out_type=int) | |
| x = torch.tensor([ids], dtype=torch.long, device=device) | |
| out = model.generate(x, max_new_tokens=max_new_tokens, do_sample=True, temperature=0.8, | |
| top_p=0.9, eos_token_id=sp.eos_id(), pad_token_id=sp.pad_id()) | |
| model.train() | |
| return sp.decode(out[0].tolist()) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument('--data', required=True) | |
| ap.add_argument('--out', required=True) | |
| ap.add_argument('--steps', type=int, default=6000) | |
| ap.add_argument('--batch-size', type=int, default=16) | |
| ap.add_argument('--seq', type=int, default=128) | |
| ap.add_argument('--lr', type=float, default=1e-3) | |
| ap.add_argument('--warmup', type=int, default=200) | |
| ap.add_argument('--hidden', type=int, default=256) | |
| ap.add_argument('--layers', type=int, default=4) | |
| ap.add_argument('--intermediate', type=int, default=512) | |
| ap.add_argument('--heads', type=int, default=4) | |
| ap.add_argument('--kv-heads', type=int, default=2) | |
| ap.add_argument('--eval-every', type=int, default=250) | |
| ap.add_argument('--log-every', type=int, default=25) | |
| args = ap.parse_args() | |
| data = Path(args.data); out = Path(args.out); out.mkdir(parents=True, exist_ok=True) | |
| device = torch.device('cpu') | |
| sp = spm.SentencePieceProcessor(model_file=str(data / 'tokenizer.model')) | |
| train_tokens = load_tokens(data / 'formatted_train.txt', sp) | |
| val_tokens = load_tokens(data / 'formatted_val.txt', sp) | |
| print('train tokens', len(train_tokens), 'val tokens', len(val_tokens), flush=True) | |
| cfg = BitNetConfig( | |
| vocab_size=sp.get_piece_size(), hidden_size=args.hidden, intermediate_size=args.intermediate, | |
| num_hidden_layers=args.layers, num_attention_heads=args.heads, num_key_value_heads=args.kv_heads, | |
| max_position_embeddings=args.seq, hidden_act='relu2', rms_norm_eps=1e-5, | |
| rope_theta=10000.0, tie_word_embeddings=True, attention_bias=False, attention_dropout=0.0, | |
| bos_token_id=sp.bos_id(), eos_token_id=sp.eos_id(), pad_token_id=sp.pad_id(), | |
| initializer_range=0.02, | |
| ) | |
| model = bitnetize(BitNetForCausalLM(cfg)).to(device) | |
| n_params = sum(p.numel() for p in model.parameters()) | |
| print('parameters', n_params, flush=True) | |
| decay, no_decay = [], [] | |
| for name, p in model.named_parameters(): | |
| if p.ndim < 2 or 'embed' in name or 'norm' in name: | |
| no_decay.append(p) | |
| else: | |
| decay.append(p) | |
| opt = torch.optim.AdamW([ | |
| {'params': decay, 'weight_decay': 0.01}, | |
| {'params': no_decay, 'weight_decay': 0.0}, | |
| ], lr=args.lr, betas=(0.9, 0.95)) | |
| def lr_at(step): | |
| if step < args.warmup: | |
| return args.lr * (step + 1) / args.warmup | |
| t = (step - args.warmup) / max(1, args.steps - args.warmup) | |
| return args.lr * (0.1 + 0.9 * 0.5 * (1 + math.cos(math.pi * t))) | |
| best = float('inf') | |
| history = [] | |
| t0 = time.time() | |
| model.train() | |
| for step in range(args.steps): | |
| lr = lr_at(step) | |
| for g in opt.param_groups: | |
| g['lr'] = lr | |
| x, y = get_batch(train_tokens, args.batch_size, args.seq, device) | |
| logits = model(x).logits | |
| loss = F.cross_entropy(logits.reshape(-1, logits.size(-1)), y.reshape(-1)) | |
| opt.zero_grad(set_to_none=True) | |
| loss.backward() | |
| torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) | |
| opt.step() | |
| if step % args.log_every == 0 or step == args.steps - 1: | |
| dt = time.time() - t0 | |
| tok_s = (step + 1) * args.batch_size * args.seq / max(dt, 1e-9) | |
| print(f'step {step:5d} loss {loss.item():.4f} lr {lr:.2e} tok/s {tok_s:.0f}', flush=True) | |
| if step % args.eval_every == 0 or step == args.steps - 1: | |
| val = evaluate(model, val_tokens, args.batch_size, args.seq, device) | |
| txt = sample(model, sp, device) | |
| rec = {'step': step, 'train_loss': loss.item(), 'val_loss': val, 'sample': txt, | |
| 'elapsed_s': time.time() - t0} | |
| history.append(rec) | |
| print('EVAL', json.dumps(rec, ensure_ascii=False), flush=True) | |
| if val < best: | |
| best = val | |
| ref = BitNetForCausalLM(cfg) | |
| ref.load_state_dict(model.state_dict(), strict=True) | |
| ref.save_pretrained(out / 'best_model') | |
| for f in ['tokenizer.model', 'tokenizer.vocab', 'tokenizer_config.json', | |
| 'special_tokens_map.json', 'chat_template.jinja']: | |
| src = data / f | |
| if src.exists(): | |
| (out / 'best_model' / f).write_bytes(src.read_bytes()) | |
| (out / 'best.json').write_text(json.dumps(rec, indent=2, ensure_ascii=False)) | |
| (out / 'history.json').write_text(json.dumps(history, indent=2, ensure_ascii=False)) | |
| print('DONE best_val', best, flush=True) | |
| if __name__ == '__main__': | |
| main() | |