Text Generation
Transformers
Safetensors
English
fuse2
Mixture of Experts
code
qwen3
deepseek
speculative-decoding
4-bit precision
consumer-gpu
conversational
custom_code
bitsandbytes
Instructions to use Akahsizrr/Mini-Whale-1-12B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Akahsizrr/Mini-Whale-1-12B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="Akahsizrr/Mini-Whale-1-12B", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForCausalLM model = AutoModelForCausalLM.from_pretrained("Akahsizrr/Mini-Whale-1-12B", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use Akahsizrr/Mini-Whale-1-12B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "Akahsizrr/Mini-Whale-1-12B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "Akahsizrr/Mini-Whale-1-12B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/Akahsizrr/Mini-Whale-1-12B
- SGLang
How to use Akahsizrr/Mini-Whale-1-12B 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 "Akahsizrr/Mini-Whale-1-12B" \ --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": "Akahsizrr/Mini-Whale-1-12B", "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 "Akahsizrr/Mini-Whale-1-12B" \ --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": "Akahsizrr/Mini-Whale-1-12B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use Akahsizrr/Mini-Whale-1-12B with Docker Model Runner:
docker model run hf.co/Akahsizrr/Mini-Whale-1-12B
|
Download LOCAL_INFERENCE_GUIDE.md from Akahsizrr/Mini-Whale-1-12B: direct link, hf CLI and curl.
- Browser
- Download file 10.4 kB
-
https://huggingface.co/Akahsizrr/Mini-Whale-1-12B/resolve/751b152aa83fbc7b8eb4963abf0869f2caafef2d/LOCAL_INFERENCE_GUIDE.md
- Command line
-
hf download hf://Akahsizrr/Mini-Whale-1-12B@751b152aa83fbc7b8eb4963abf0869f2caafef2d/LOCAL_INFERENCE_GUIDE.md
-
curl -L -o LOCAL_INFERENCE_GUIDE.md https://huggingface.co/Akahsizrr/Mini-Whale-1-12B/resolve/751b152aa83fbc7b8eb4963abf0869f2caafef2d/LOCAL_INFERENCE_GUIDE.md
10.4 kB
| # Mini Whale 1 12B β Local Inference Guide | |
| This guide walks you through running Mini Whale 1 12B on a consumer GPU (RTX 3060 12GB or equivalent). | |
| ## Prerequisites | |
| ### Hardware | |
| | Component | Minimum | Recommended | | |
| |-----------|---------|-------------| | |
| | GPU VRAM | 12 GB | 16 GB+ | | |
| | System RAM| 16 GB | 32 GB | | |
| | Disk | 25 GB | 50 GB SSD | | |
| Tested on: RTX 3060 12GB, 16GB RAM, Windows 11. | |
| ### Software | |
| ```bash | |
| # Python 3.10+ | |
| python --version | |
| # Create virtual environment | |
| python -m venv fuse2-venv | |
| # Activate (Windows) | |
| fuse2-venv\Scripts\activate | |
| # Activate (Linux/Mac) | |
| source fuse2-venv/bin/activate | |
| # Install dependencies | |
| pip install torch --index-url https://download.pytorch.org/whl/cu126 | |
| pip install transformers==5.14.1 bitsandbytes==0.49 peft==0.20 accelerate safetensors | |
| ``` | |
| ## Step 1: Download the Model | |
| ```bash | |
| pip install huggingface_hub | |
| huggingface-cli download Akahsizrr/Mini-Whale-1-12B --local-dir ./mini-whale-1-12b | |
| ``` | |
| This downloads ~23.4 GB (5 safetensors shards + tokenizer + model code). | |
| ## Step 2: Basic Inference (4-bit, ~5 tok/s) | |
| This is the simplest way to run the model. All linear layers are quantized to 4-bit NF4. | |
| ```python | |
| import torch, json, os, sys, gc | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from transformers import AutoConfig, AutoTokenizer | |
| from accelerate import init_empty_weights | |
| from safetensors import safe_open | |
| import bitsandbytes as bnb | |
| MODEL_PATH = "./mini-whale-1-12b" | |
| DEVICE = "cuda:0" | |
| sys.path.insert(0, MODEL_PATH) | |
| import fuse2_model_local | |
| # ββ Step 2a: Load config ββ | |
| config = AutoConfig.from_pretrained(MODEL_PATH, trust_remote_code=True) | |
| config._attn_implementation = "sdpa" # Critical: use SDPA, not eager | |
| # ββ Step 2b: Create model on meta device (saves RAM) ββ | |
| with init_empty_weights(): | |
| model = fuse2_model_local.Fuse2ForCausalLM(config) | |
| # ββ Step 2c: Load weights with 4-bit quantization ββ | |
| quant_suffixes = ("q_proj.weight", "k_proj.weight", "v_proj.weight", "o_proj.weight", | |
| "gate_proj.weight", "up_proj.weight", "down_proj.weight") | |
| with open(f"{MODEL_PATH}/model.safetensors.index.json") as f: | |
| index = json.load(f) | |
| weight_map = index["weight_map"] | |
| def nav(model, key): | |
| parts = key.split(".") | |
| obj = model | |
| for p in parts[:-1]: | |
| obj = obj[int(p)] if p.isdigit() else getattr(obj, p) | |
| return obj, parts[-1] | |
| def find_linear(model, key): | |
| parts = key.split(".") | |
| obj = model | |
| for p in parts[:-2]: | |
| obj = obj[int(p)] if p.isdigit() else getattr(obj, p) | |
| return obj, parts[-2] | |
| param_names = set(dict(model.named_parameters()).keys()) | |
| replaced = {} | |
| for shard_name in sorted(set(weight_map.values())): | |
| with safe_open(os.path.join(MODEL_PATH, shard_name), framework="pt", device="cpu") as f: | |
| for key in [k for k, v in weight_map.items() if v == shard_name]: | |
| if key not in param_names: | |
| continue | |
| tensor = f.get_tensor(key) | |
| if any(key.endswith(s) for s in quant_suffixes): | |
| owner, attr = find_linear(model, key) | |
| old = getattr(owner, attr) | |
| new = bnb.nn.Linear4bit(old.in_features, old.out_features, | |
| bias=False, quant_type="nf4", | |
| compute_dtype=torch.bfloat16, device=DEVICE) | |
| new.weight = bnb.nn.Params4bit(tensor.to(torch.bfloat16), | |
| requires_grad=False, quant_type="nf4").cuda(0) | |
| setattr(owner, attr, new) | |
| else: | |
| parent, pname = nav(model, key) | |
| parent._parameters[pname] = nn.Parameter( | |
| tensor.to(torch.bfloat16).to(DEVICE), requires_grad=False) | |
| del tensor | |
| gc.collect() | |
| torch.cuda.empty_cache() | |
| # ββ Step 2d: Fix tied embeddings ββ | |
| if model.lm_head.weight.device.type == 'meta': | |
| model.lm_head.weight = nn.Parameter( | |
| model.model.embed_tokens.weight.data.clone(), requires_grad=False) | |
| # ββ Step 2e: Apply runtime fixes (SwiGLU clamp + router stability) ββ | |
| from fuse2_model_local import Fuse2AugmentedLayer | |
| for layer in model.model.layers: | |
| if not isinstance(layer, Fuse2AugmentedLayer): | |
| continue | |
| if hasattr(layer, 'coding_gate') and layer.coding_gate.device.type == 'meta': | |
| layer.coding_gate = nn.Parameter(torch.tensor(-2.0, device=DEVICE)) | |
| if hasattr(layer, 'coding_norm') and layer.coding_norm.weight.device.type == 'meta': | |
| layer.coding_norm = nn.RMSNorm( | |
| layer.coding_norm.weight.shape[0], eps=1e-6).to(DEVICE) | |
| experts = getattr(layer, "experts", None) | |
| if experts: | |
| for expert in experts: | |
| gp, up, dp = expert.gate_proj, expert.up_proj, expert.down_proj | |
| def make_fwd(g, u, d, lim=10.0): | |
| def forward(x): | |
| return d(torch.clamp(F.silu(g(x)) * u(x), -lim, lim)) | |
| return forward | |
| expert.forward = make_fwd(gp, up, dp) | |
| router = getattr(layer, "router", None) | |
| if router: | |
| gate, top_k = router.gate, router.top_k | |
| def make_router(g, tk): | |
| def forward(h): | |
| logits = g(h) | |
| scores = torch.clamp(F.softplus(logits), min=1e-6).sqrt() | |
| w, idx = scores.topk(tk, dim=-1) | |
| return w / (w.sum(dim=-1, keepdim=True) + 1e-8), idx, logits | |
| return forward | |
| router.forward = make_router(gate, top_k) | |
| # ββ Step 2f: Finalize model ββ | |
| model.set_coding_enabled(True) | |
| model.to(DEVICE) | |
| model.eval() | |
| # Fix norm dtypes (float32 β bfloat16 for fused kernels) | |
| for module in model.modules(): | |
| if hasattr(module, 'weight') and hasattr(module, 'eps'): | |
| if module.weight.dtype == torch.float32: | |
| module.weight.data = module.weight.data.to(torch.bfloat16) | |
| print(f"VRAM: {torch.cuda.memory_allocated(0)/1e9:.1f} GB") | |
| # ββ Step 2g: Generate ββ | |
| tok = AutoTokenizer.from_pretrained(MODEL_PATH, trust_remote_code=True) | |
| messages = [{"role": "user", "content": "Write a Python fizzbuzz."}] | |
| text = tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | |
| input_ids = tok(text, return_tensors="pt").input_ids.to(DEVICE) | |
| with torch.inference_mode(): | |
| out = model.generate(input_ids, max_new_tokens=512, do_sample=False, | |
| repetition_penalty=1.3) | |
| print(tok.decode(out[0], skip_special_tokens=True)) | |
| ``` | |
| **Expected output:** | |
| ``` | |
| VRAM: 8.9 GB | |
| Okay, I need to write a Python fizzbuzz. Let me think about this... | |
| ``` | |
| ## Step 3: DSpark Speculative Decoding (~10 tok/s) | |
| For 2x speedup, use the included `fuse2_dspark_fast.py` script: | |
| ```bash | |
| python fuse2_dspark_fast.py "Write a Python function to check if a number is prime." 512 | |
| ``` | |
| This requires the DSpark drafter model. The drafter is a 5-layer Qwen3 model that predicts 7 tokens per block. | |
| ### How DSpark works | |
| ``` | |
| βββββββββββββββ ββββββββββββββββ | |
| β Drafter ββββββΆβ Target β | |
| β (5 layers) β β (36 layers) β | |
| β Predicts β β Verifies β | |
| β 7 tokens β β in 1 pass β | |
| βββββββββββββββ ββββββββββββββββ | |
| ~32ms ~330ms | |
| ``` | |
| 1. Drafter predicts 7 tokens using target's hidden states | |
| 2. Target verifies all 7 in a single forward pass | |
| 3. Accept the longest matching prefix (greedy argmax) | |
| 4. Target produces 1 bonus token | |
| 5. Repeat | |
| **Acceptance rate**: 2.3-3.4/7 (33-49%), giving 1.8x speedup on average. | |
| ### DSpark VRAM optimization | |
| The drafter is quantized to 4-bit and shares the embedding layer with the target: | |
| | Component | VRAM | | |
| |-----------|------| | |
| | Target (BF16 attention + 4-bit MLP) | 10.3 GB | | |
| | Drafter (4-bit, shared embedding) | 0.6 GB | | |
| | KV cache + activations | ~0.5 GB | | |
| | **Total** | **~10.9 GB (fits in 12 GB)** | | |
| ## Step 4: Sliding Window KV Cache | |
| For long sequences (512+ tokens), the KV cache grows and slows down generation. The DSpark script includes a sliding window that limits the KV cache to 512 tokens: | |
| ```python | |
| MAX_KV_CACHE = 512 # tokens | |
| cache_len = target_cache.get_seq_length() | |
| if cache_len > MAX_KV_CACHE: | |
| crop_to = cache_len - MAX_KV_CACHE | |
| for layer in target_cache.layers: | |
| if hasattr(layer, 'keys') and layer.keys.numel() > 0: | |
| layer.keys = layer.keys[:, :, crop_to:, :] | |
| layer.values = layer.values[:, :, crop_to:, :] | |
| ``` | |
| This keeps speed constant at ~10 tok/s regardless of sequence length. | |
| ## Troubleshooting | |
| ### "CUDA out of memory" | |
| - Check `torch.cuda.memory_reserved(0)` β if it's >11.5 GB on a 12 GB card, you're spilling to system RAM | |
| - Make sure ALL linear layers are 4-bit (including attention) | |
| - Use `gc.collect(); torch.cuda.empty_cache()` after loading each shard | |
| - Reduce `max_new_tokens` to 256 | |
| ### "TritonMissing" error | |
| - `torch.compile` is not supported on Windows (no triton) | |
| - The model code already disables this β make sure you're using the latest `fuse2_model_local.py` | |
| ### "expandable_segments not supported" | |
| - This is a harmless warning on Windows | |
| - The model works fine without it | |
| ### Generation is garbage / repetitive | |
| - Use `do_sample=False` (greedy decoding) β sampling can produce NaN | |
| - Use `repetition_penalty=1.3` | |
| - Make sure `coding_enabled=True` (the experts need to be on) | |
| - Check that SwiGLU clamping is applied (limit=10.0) | |
| ### Speed is 1-2 tok/s instead of 10 | |
| - **This means VRAM is overflowing to system RAM** | |
| - Check `torch.cuda.memory_reserved(0)` β it should be <11.5 GB | |
| - Switch to 4-bit quantization for ALL layers (including attention) | |
| - Quantize the drafter to 4-bit | |
| - Share the embedding between target and drafter | |
| ## Performance Summary | |
| | Mode | Speed | VRAM | Best for | | |
| |------|-------|------|----------| | |
| | Basic 4-bit | 5.5 tok/s | 8.9 GB | Simple tasks, max VRAM headroom | | |
| | DSpark (4-bit all) | 8.5 tok/s | 10.3 GB | Balanced | | |
| | DSpark (BF16 attn + shared) | 10.0 tok/s | 10.9 GB | **Best speed** | | |