Text Generation
Transformers
Safetensors
MLX
code
llama
fill-in-the-middle
multi-token-prediction
speculative-decoding
apple-silicon
text-generation-inference
Instructions to use philipjohnbasile/wisp-coder-110m with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use philipjohnbasile/wisp-coder-110m with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="philipjohnbasile/wisp-coder-110m")# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("philipjohnbasile/wisp-coder-110m") model = AutoModelForCausalLM.from_pretrained("philipjohnbasile/wisp-coder-110m", device_map="auto") - MLX
How to use philipjohnbasile/wisp-coder-110m with MLX:
# Make sure mlx-lm is installed # pip install --upgrade mlx-lm # if on a CUDA device, also pip install mlx[cuda] # Generate text with mlx-lm from mlx_lm import load, generate model, tokenizer = load("philipjohnbasile/wisp-coder-110m") prompt = "Once upon a time in" text = generate(model, tokenizer, prompt=prompt, verbose=True) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- vLLM
How to use philipjohnbasile/wisp-coder-110m with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "philipjohnbasile/wisp-coder-110m" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "philipjohnbasile/wisp-coder-110m", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/philipjohnbasile/wisp-coder-110m
- SGLang
How to use philipjohnbasile/wisp-coder-110m 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 "philipjohnbasile/wisp-coder-110m" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "philipjohnbasile/wisp-coder-110m", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'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 "philipjohnbasile/wisp-coder-110m" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "philipjohnbasile/wisp-coder-110m", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - MLX LM
How to use philipjohnbasile/wisp-coder-110m with MLX LM:
Generate or start a chat session
# Install MLX LM uv tool install mlx-lm # Generate some text mlx_lm.generate --model "philipjohnbasile/wisp-coder-110m" --prompt "Once upon a time"
- Docker Model Runner
How to use philipjohnbasile/wisp-coder-110m with Docker Model Runner:
docker model run hf.co/philipjohnbasile/wisp-coder-110m
- Atomic Chat
| """ | |
| Export a Wisp checkpoint into a Hugging Face repository layout. | |
| The release is deliberately split in two, because the two halves have very | |
| different compatibility stories. | |
| * **The trunk** is an ordinary Llama decoder: RMSNorm, SwiGLU, grouped query | |
| attention, RoPE with the half split (neox) convention. Exported under Llama | |
| parameter names with a `LlamaForCausalLM` config, it loads in `transformers`, | |
| `mlx_lm`, and anything that converts from those, with no trust_remote_code and | |
| no custom modelling file. Somebody who just wants a small FIM completion model | |
| gets one that works in their existing runtime. | |
| * **The MTP module** has no standard home. It ships as a separate | |
| `mtp.safetensors` plus `mtp_config.json`, which the runtimes that can use it | |
| can load, and everything else can ignore without breaking. | |
| A model whose weights only load through a bespoke script is a model nobody runs. | |
| Verification is not optional here. Name mapping and RoPE convention are exactly | |
| the kind of silent conversion error that leaves a model quietly dumber rather | |
| than visibly broken, so `--verify` reloads the exported tensors back through the | |
| MLX model and asserts the logits are identical. That catches a wrong mapping. It | |
| does not catch a wrong RoPE convention, which needs a cross framework check | |
| against `transformers`; `scripts/verify_export_torch.py` does that when torch | |
| and transformers are installed. | |
| Usage: | |
| python scripts/export_hf.py --ckpt out/run1/ckpt_latest \\ | |
| --tokenizer tokenizer/code32k.json --out export/wisp-coder-110m \\ | |
| --repo-id YOUR_NAMESPACE/wisp-coder-110m \\ | |
| --validation-report out/run1/final_validation.json \\ | |
| --acceptance-comparison out/run1/acceptance.control-comparison.json \\ | |
| --format-ablation-report \ | |
| out/run2-no-fim/acceptance.format-ablation.json \\ | |
| --rollout-report out/run1/rollout.registered.v3.json --verify | |
| """ | |
| import argparse | |
| import json | |
| import os | |
| import shutil | |
| import sys | |
| import tempfile | |
| import mlx.core as mx | |
| from mlx.utils import tree_flatten, tree_unflatten | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from model import Wisp, ModelArgs, causal_mask # noqa: E402 | |
| from scripts.hf_metadata import ( # noqa: E402 | |
| development_evaluation_section, | |
| file_sha256, | |
| generation_config, | |
| llama_config, | |
| mtp_config, | |
| render_evaluation_section, | |
| render_model_card, | |
| special_tokens_map, | |
| tokenizer_config, | |
| validate_export_checkpoint, | |
| verify_export_manifest, | |
| write_export_manifest, | |
| write_json, | |
| ) | |
| def load_json_report(path, label): | |
| if not path: | |
| raise ValueError(f"final export requires --{label}") | |
| if not os.path.isfile(path): | |
| raise FileNotFoundError(f"{label} does not exist: {path}") | |
| with open(path, encoding="utf-8") as f: | |
| value = json.load(f) | |
| if not isinstance(value, dict): | |
| raise ValueError(f"{label} must contain a JSON object") | |
| return value, file_sha256(path) | |
| def map_trunk(flat, args): | |
| """Wisp parameter names to Llama parameter names.""" | |
| out = {} | |
| out["model.embed_tokens.weight"] = flat["tok_emb.weight"] | |
| out["model.norm.weight"] = flat["norm.weight"] | |
| if not args.tie_embeddings: | |
| out["lm_head.weight"] = flat["lm_head.weight"] | |
| pairs = [ | |
| ("attn_norm.weight", "input_layernorm.weight"), | |
| ("attn.wq.weight", "self_attn.q_proj.weight"), | |
| ("attn.wk.weight", "self_attn.k_proj.weight"), | |
| ("attn.wv.weight", "self_attn.v_proj.weight"), | |
| ("attn.wo.weight", "self_attn.o_proj.weight"), | |
| ("ffn_norm.weight", "post_attention_layernorm.weight"), | |
| ("ffn.w1.weight", "mlp.gate_proj.weight"), | |
| ("ffn.w3.weight", "mlp.up_proj.weight"), | |
| ("ffn.w2.weight", "mlp.down_proj.weight"), | |
| ] | |
| for i in range(args.n_layers): | |
| for ours, theirs in pairs: | |
| out[f"model.layers.{i}.{theirs}"] = flat[f"blocks.{i}.{ours}"] | |
| return out | |
| def verify_roundtrip(ckpt_dir, exported, args): | |
| """Reload the exported tensors into the MLX model and diff the logits.""" | |
| model = Wisp(args) | |
| master = tree_unflatten( | |
| list(mx.load(os.path.join(ckpt_dir, "master.safetensors")).items()) | |
| ) | |
| model.update(master) | |
| model.eval() | |
| mx.eval(model.parameters()) | |
| inverse = {} | |
| inverse["tok_emb.weight"] = exported["model.embed_tokens.weight"] | |
| inverse["norm.weight"] = exported["model.norm.weight"] | |
| pairs = [ | |
| ("attn_norm.weight", "input_layernorm.weight"), | |
| ("attn.wq.weight", "self_attn.q_proj.weight"), | |
| ("attn.wk.weight", "self_attn.k_proj.weight"), | |
| ("attn.wv.weight", "self_attn.v_proj.weight"), | |
| ("attn.wo.weight", "self_attn.o_proj.weight"), | |
| ("ffn_norm.weight", "post_attention_layernorm.weight"), | |
| ("ffn.w1.weight", "mlp.gate_proj.weight"), | |
| ("ffn.w3.weight", "mlp.up_proj.weight"), | |
| ("ffn.w2.weight", "mlp.down_proj.weight"), | |
| ] | |
| for i in range(args.n_layers): | |
| for ours, theirs in pairs: | |
| inverse[f"blocks.{i}.{ours}"] = exported[f"model.layers.{i}.{theirs}"] | |
| rebuilt = Wisp(args) | |
| rebuilt.update(tree_unflatten(list(inverse.items()))) | |
| # The MTP module is not part of the trunk export, so carry it across directly. | |
| rebuilt.mtp.update(model.mtp.parameters()) | |
| rebuilt.eval() | |
| mx.eval(rebuilt.parameters()) | |
| probe = mx.array([[1, 2, 3, 4, 5, 6, 7, 8]], dtype=mx.int32) | |
| mask = causal_mask(probe.shape[1], model.norm.weight.dtype) | |
| a, _, _ = model(probe, mask) | |
| b, _, _ = rebuilt(probe, mask) | |
| mx.eval(a, b) | |
| delta = float(mx.max(mx.abs(a - b))) | |
| return delta | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--ckpt", required=True) | |
| ap.add_argument("--tokenizer", required=True) | |
| ap.add_argument("--out", required=True) | |
| ap.add_argument("--repo-id", required=True) | |
| ap.add_argument("--model-card", default="MODEL_CARD.md") | |
| ap.add_argument("--license-file", default="LICENSE") | |
| ap.add_argument("--validation-report") | |
| ap.add_argument("--acceptance-comparison") | |
| ap.add_argument("--format-ablation-report") | |
| ap.add_argument("--rollout-report") | |
| ap.add_argument("--verify", action="store_true") | |
| ap.add_argument( | |
| "--allow-incomplete", | |
| action="store_true", | |
| help="permit a development export before max_steps, never for release", | |
| ) | |
| cli = ap.parse_args() | |
| meta_path = os.path.join(cli.ckpt, "meta.json") | |
| master_path = os.path.join(cli.ckpt, "master.safetensors") | |
| optimizer_path = os.path.join(cli.ckpt, "optimizer.safetensors") | |
| with open(meta_path) as f: | |
| meta = json.load(f) | |
| release_state = validate_export_checkpoint(meta, cli.allow_incomplete) | |
| if not os.path.isfile(master_path): | |
| raise FileNotFoundError(f"checkpoint weights do not exist: {master_path}") | |
| if not os.path.isfile(optimizer_path): | |
| raise FileNotFoundError( | |
| f"checkpoint optimizer state does not exist: {optimizer_path}" | |
| ) | |
| if not os.path.isfile(cli.tokenizer): | |
| raise FileNotFoundError(f"tokenizer does not exist: {cli.tokenizer}") | |
| if not os.path.isfile(cli.model_card): | |
| raise FileNotFoundError(f"model card does not exist: {cli.model_card}") | |
| if not os.path.isfile(cli.license_file): | |
| raise FileNotFoundError(f"license does not exist: {cli.license_file}") | |
| report_args = { | |
| "validation": ( | |
| cli.validation_report, | |
| "validation-report", | |
| ), | |
| "acceptance_comparison": ( | |
| cli.acceptance_comparison, | |
| "acceptance-comparison", | |
| ), | |
| "format_ablation": ( | |
| cli.format_ablation_report, | |
| "format-ablation-report", | |
| ), | |
| "rollout": ( | |
| cli.rollout_report, | |
| "rollout-report", | |
| ), | |
| } | |
| if release_state["complete"]: | |
| reports = {} | |
| evaluation_sources = {} | |
| for key, (path, label) in report_args.items(): | |
| report, digest = load_json_report(path, label) | |
| reports[key] = report | |
| evaluation_sources[key] = {"sha256": digest} | |
| evaluation_markdown = render_evaluation_section( | |
| reports["validation"], | |
| reports["acceptance_comparison"], | |
| reports["format_ablation"], | |
| reports["rollout"], | |
| ) | |
| else: | |
| supplied = [ | |
| label for path, label in report_args.values() if path is not None | |
| ] | |
| if supplied: | |
| raise ValueError( | |
| "development exports cannot claim final reports: " | |
| + ", ".join(supplied) | |
| ) | |
| evaluation_sources = None | |
| evaluation_markdown = development_evaluation_section( | |
| release_state["step"], | |
| release_state["max_steps"], | |
| ) | |
| model_card_template_sha256 = file_sha256(cli.model_card) | |
| rendered_card = render_model_card( | |
| cli.model_card, | |
| cli.repo_id, | |
| evaluation_markdown, | |
| ) | |
| out_dir = os.path.abspath(cli.out) | |
| if os.path.lexists(out_dir): | |
| raise FileExistsError( | |
| f"refusing to merge with or replace existing export: {out_dir}" | |
| ) | |
| parent = os.path.dirname(out_dir) | |
| os.makedirs(parent, exist_ok=True) | |
| checkpoint_hashes = { | |
| "meta_sha256": file_sha256(meta_path), | |
| "master_sha256": file_sha256(master_path), | |
| "optimizer_sha256": file_sha256(optimizer_path), | |
| } | |
| args = ModelArgs.from_dict(meta["model_args"]) | |
| master = mx.load(master_path) | |
| flat = dict(master) | |
| trunk = map_trunk(flat, args) | |
| missing = [k for k, v in trunk.items() if v is None] | |
| if missing: | |
| raise KeyError(f"unmapped trunk tensors: {missing[:5]}") | |
| trunk_bf16 = {k: v.astype(mx.bfloat16) for k, v in trunk.items()} | |
| mtp = {k: v.astype(mx.bfloat16) for k, v in flat.items() if k.startswith("mtp.")} | |
| n_trunk = sum(v.size for v in trunk.values()) | |
| n_mtp = sum(v.size for v in mtp.values()) | |
| staging = tempfile.mkdtemp( | |
| prefix=f".{os.path.basename(out_dir)}.staging.", dir=parent | |
| ) | |
| try: | |
| mx.save_safetensors( | |
| os.path.join(staging, "model.safetensors"), trunk_bf16 | |
| ) | |
| mx.save_safetensors(os.path.join(staging, "mtp.safetensors"), mtp) | |
| write_json(os.path.join(staging, "config.json"), llama_config(args)) | |
| write_json( | |
| os.path.join(staging, "mtp_config.json"), mtp_config(args, meta) | |
| ) | |
| write_json( | |
| os.path.join(staging, "tokenizer_config.json"), | |
| tokenizer_config(args), | |
| ) | |
| write_json( | |
| os.path.join(staging, "special_tokens_map.json"), | |
| special_tokens_map(), | |
| ) | |
| write_json( | |
| os.path.join(staging, "generation_config.json"), | |
| generation_config(), | |
| ) | |
| shutil.copy(cli.tokenizer, os.path.join(staging, "tokenizer.json")) | |
| with open( | |
| os.path.join(staging, "README.md"), "w", encoding="utf-8" | |
| ) as f: | |
| f.write(rendered_card) | |
| shutil.copy(cli.license_file, os.path.join(staging, "LICENSE")) | |
| write_export_manifest( | |
| staging, | |
| meta, | |
| n_trunk, | |
| n_mtp, | |
| cli.repo_id, | |
| checkpoint_hashes, | |
| release_state["complete"], | |
| evaluation_sources, | |
| model_card_template_sha256, | |
| ) | |
| verify_export_manifest(staging) | |
| if ( | |
| file_sha256(meta_path) != checkpoint_hashes["meta_sha256"] | |
| or file_sha256(master_path) != checkpoint_hashes["master_sha256"] | |
| or ( | |
| file_sha256(optimizer_path) | |
| != checkpoint_hashes["optimizer_sha256"] | |
| ) | |
| ): | |
| raise RuntimeError("source checkpoint changed during export") | |
| if cli.verify: | |
| delta = verify_roundtrip(cli.ckpt, trunk, args) | |
| status = "identical" if delta == 0.0 else f"max abs delta {delta:.3e}" | |
| print(f"roundtrip through the exported names: {status}") | |
| if delta != 0.0: | |
| raise RuntimeError( | |
| "export verification failed, the name mapping is wrong" | |
| ) | |
| print( | |
| "NOTE: this proves the name mapping, not the RoPE convention. " | |
| "Diff against transformers on the same prompt before publishing." | |
| ) | |
| if os.path.lexists(out_dir): | |
| raise FileExistsError( | |
| f"export target appeared during staging: {out_dir}" | |
| ) | |
| os.rename(staging, out_dir) | |
| staging = None | |
| finally: | |
| if staging is not None and os.path.isdir(staging): | |
| shutil.rmtree(staging) | |
| label = "final" if release_state["complete"] else "development snapshot" | |
| print( | |
| f"trunk: {len(trunk)} tensors, {n_trunk/1e6:.1f}M params " | |
| "-> model.safetensors" | |
| ) | |
| print( | |
| f"mtp: {len(mtp)} tensors, {n_mtp/1e6:.1f}M params " | |
| "-> mtp.safetensors" | |
| ) | |
| print(f"atomic {label} package plus export_manifest.json -> {out_dir}") | |
| if __name__ == "__main__": | |
| main() | |