Text Generation
Transformers
Safetensors
English
Korean
Motif
feature-extraction
motif
motif-3
mixture-of-experts
Mixture of Experts
fp8
block-fp8
e4m3
vllm
multilingual
conversational
custom_code
Instructions to use 0ppxnhximxr/Motif-3-FP8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use 0ppxnhximxr/Motif-3-FP8 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="0ppxnhximxr/Motif-3-FP8", trust_remote_code=True) messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("0ppxnhximxr/Motif-3-FP8", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use 0ppxnhximxr/Motif-3-FP8 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "0ppxnhximxr/Motif-3-FP8" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "0ppxnhximxr/Motif-3-FP8", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/0ppxnhximxr/Motif-3-FP8
- SGLang
How to use 0ppxnhximxr/Motif-3-FP8 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 "0ppxnhximxr/Motif-3-FP8" \ --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": "0ppxnhximxr/Motif-3-FP8", "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 "0ppxnhximxr/Motif-3-FP8" \ --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": "0ppxnhximxr/Motif-3-FP8", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use 0ppxnhximxr/Motif-3-FP8 with Docker Model Runner:
docker model run hf.co/0ppxnhximxr/Motif-3-FP8
| #!/usr/bin/env python3 | |
| import argparse | |
| import json | |
| import math | |
| import os | |
| import shutil | |
| import time | |
| import torch | |
| from safetensors import safe_open | |
| from safetensors.torch import save_file | |
| BLOCK = 128 | |
| FP8_MAX = 448.0 | |
| EXPERT_CHUNK = 96 | |
| SOURCE_COMMIT = "1695f5aa6d97cccc8623a03f93c9c7d5fbb14d45" # Motif-Technologies/Motif-3 commit used in this environment | |
| TARGET_SUFFIXES = (".moe.experts.gate_up_proj", ".moe.experts.down_proj") | |
| def is_quant_target(name, tensor_shape, tensor_dtype): | |
| if not name.startswith("model.layers."): | |
| return False | |
| if not name.endswith(TARGET_SUFFIXES): | |
| return False | |
| if len(tensor_shape) != 3: | |
| return False | |
| if tensor_dtype not in (torch.bfloat16, torch.float32, torch.float16): | |
| return False | |
| assert tensor_shape[1] % BLOCK == 0 and tensor_shape[2] % BLOCK == 0, \ | |
| f"{name}: {tensor_shape} not divisible by {BLOCK}" | |
| return True | |
| def quantize_block_fp8(w, device): | |
| E, N, K = w.shape | |
| nb, kb = N // BLOCK, K // BLOCK | |
| q_out = torch.empty((E, N, K), dtype=torch.float8_e4m3fn) | |
| s_out = torch.empty((E, nb, kb), dtype=torch.float32) | |
| sq_err_sum = 0.0 | |
| sq_ref_sum = 0.0 | |
| dot_sum = 0.0 | |
| qq_sum = 0.0 | |
| max_abs_err = 0.0 | |
| nan_inf = 0 | |
| for i in range(0, E, EXPERT_CHUNK): | |
| chunk = w[i : i + EXPERT_CHUNK].to(device, non_blocking=True).float() | |
| e = chunk.shape[0] | |
| blocks = chunk.reshape(e, nb, BLOCK, kb, BLOCK) | |
| amax = blocks.abs().amax(dim=(2, 4)) | |
| scale_inv = (amax / FP8_MAX).clamp(min=1e-12) | |
| q = (blocks / scale_inv[:, :, None, :, None]).clamp(-FP8_MAX, FP8_MAX) | |
| q_fp8 = q.to(torch.float8_e4m3fn) | |
| deq = q_fp8.float() * scale_inv[:, :, None, :, None] | |
| err = deq - blocks | |
| sq_err_sum += err.pow(2).sum().item() | |
| sq_ref_sum += blocks.pow(2).sum().item() | |
| dot_sum += (deq * blocks).sum().item() | |
| qq_sum += deq.pow(2).sum().item() | |
| max_abs_err = max(max_abs_err, err.abs().max().item()) | |
| nan_inf += int(torch.isnan(deq).sum().item() + torch.isinf(deq).sum().item()) | |
| nan_inf += int(torch.isnan(scale_inv).sum().item() + torch.isinf(scale_inv).sum().item()) | |
| q_out[i : i + e] = q_fp8.reshape(e, N, K).cpu() | |
| s_out[i : i + e] = scale_inv.cpu() | |
| del chunk, blocks, amax, scale_inv, q, q_fp8, deq, err | |
| stats = { | |
| "rel_rmse": math.sqrt(sq_err_sum / max(sq_ref_sum, 1e-30)), | |
| "cosine": dot_sum / max(math.sqrt(sq_ref_sum) * math.sqrt(qq_sum), 1e-30), | |
| "max_abs_err": max_abs_err, | |
| "nan_inf": nan_inf, | |
| } | |
| return q_out, s_out, stats | |
| def process_shard(src, dst, shard_name, device, manifest_dir): | |
| mpath = os.path.join(manifest_dir, shard_name + ".json") | |
| opath = os.path.join(dst, shard_name) | |
| if os.path.exists(mpath) and os.path.exists(opath): | |
| with open(mpath) as f: | |
| return json.load(f) | |
| t0 = time.time() | |
| out_tensors = {} | |
| entry = {"shard": shard_name, "tensors": {}, "quantized": [], "stats": {}} | |
| with safe_open(os.path.join(src, shard_name), framework="pt", device="cpu") as f: | |
| for name in f.keys(): | |
| t = f.get_tensor(name) | |
| if is_quant_target(name, tuple(t.shape), t.dtype): | |
| q, s, stats = quantize_block_fp8(t, device) | |
| out_tensors[name] = q | |
| out_tensors[name + "_scale_inv"] = s | |
| entry["quantized"].append(name) | |
| entry["stats"][name] = stats | |
| entry["tensors"][name] = {"dtype": "F8_E4M3", "shape": list(q.shape)} | |
| entry["tensors"][name + "_scale_inv"] = {"dtype": "F32", "shape": list(s.shape)} | |
| else: | |
| out_tensors[name] = t | |
| entry["tensors"][name] = {"dtype": str(t.dtype).replace("torch.", ""), "shape": list(t.shape)} | |
| tmp = opath + ".tmp" | |
| save_file(out_tensors, tmp, metadata={"format": "pt"}) | |
| os.replace(tmp, opath) | |
| entry["seconds"] = round(time.time() - t0, 2) | |
| entry["out_bytes"] = os.path.getsize(opath) | |
| os.makedirs(manifest_dir, exist_ok=True) | |
| with open(mpath, "w") as f: | |
| json.dump(entry, f) | |
| return entry | |
| def finalize(src, dst, entries): | |
| with open(os.path.join(src, "model.safetensors.index.json")) as f: | |
| old_index = json.load(f) | |
| weight_map = dict(old_index["weight_map"]) | |
| for e in entries: | |
| for qname in e["quantized"]: | |
| weight_map[qname + "_scale_inv"] = e["shard"] | |
| total = sum(e["out_bytes"] for e in entries) | |
| with open(os.path.join(dst, "model.safetensors.index.json"), "w") as f: | |
| json.dump({"metadata": {"total_size": total}, "weight_map": weight_map}, f, indent=2) | |
| with open(os.path.join(src, "config.json")) as f: | |
| config = json.load(f) | |
| config["quantization_config"] = { | |
| "quant_method": "fp8", | |
| "fmt": "e4m3", | |
| "activation_scheme": "dynamic", | |
| "weight_block_size": [BLOCK, BLOCK], | |
| "modules_to_not_convert": [ | |
| "model.embed_tokens", "lm_head", | |
| "model.layers.*.self_attn", "model.layers.*.mlp", | |
| "model.layers.*.input_layernorm", "model.layers.*.post_attention_layernorm", | |
| "model.layers.*.mhc_attn", "model.layers.*.mhc_ffn", | |
| "model.layers.*.moe.router", "model.layers.*.moe.shared_experts", | |
| "model.layers.*.moe.experts.act_fn", | |
| "model.mtp_layers.*", | |
| ], | |
| } | |
| with open(os.path.join(dst, "config.json"), "w") as f: | |
| json.dump(config, f, indent=2) | |
| for fn in os.listdir(src): | |
| if fn.endswith((".py", ".jinja", ".txt", ".md")) or fn in ( | |
| "tokenizer.json", "tokenizer_config.json", "generation_config.json", | |
| "special_tokens_map.json", "chat_template.json", | |
| ): | |
| src_f = os.path.join(src, fn) | |
| if os.path.isfile(src_f): | |
| shutil.copy2(src_f, os.path.join(dst, fn)) | |
| n_quant_params = sum( | |
| int(torch.tensor(e["tensors"][q]["shape"]).prod()) | |
| for e in entries for q in e["quantized"] | |
| ) | |
| all_stats = [s for e in entries for s in e["stats"].values()] | |
| summary = { | |
| "source_model": "Motif-Technologies/Motif-3", | |
| "source_commit": SOURCE_COMMIT, | |
| "recipe": { | |
| "method": "expert-only FP8 E4M3, 128x128 block, W8A16", | |
| "targets": list(TARGET_SUFFIXES), | |
| "scale_naming": "<param>_scale_inv (dequant = fp8_block * scale_inv)", | |
| }, | |
| "quantized_tensor_count": sum(len(e["quantized"]) for e in entries), | |
| "quantized_params": n_quant_params, | |
| "output_size_bytes": total, | |
| "nan_inf_total": sum(s["nan_inf"] for s in all_stats), | |
| "rel_rmse": { | |
| "mean": sum(s["rel_rmse"] for s in all_stats) / max(len(all_stats), 1), | |
| "max": max((s["rel_rmse"] for s in all_stats), default=0), | |
| }, | |
| "cosine": { | |
| "mean": sum(s["cosine"] for s in all_stats) / max(len(all_stats), 1), | |
| "min": min((s["cosine"] for s in all_stats), default=0), | |
| }, | |
| "max_abs_err": max((s["max_abs_err"] for s in all_stats), default=0), | |
| } | |
| with open(os.path.join(dst, "quantization_recipe.json"), "w") as f: | |
| json.dump(summary, f, indent=2) | |
| return summary | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--src", default="./Motif-3-Beta") | |
| ap.add_argument("--dst", default="./Motif-3-Beta-FP8") | |
| ap.add_argument("--only") | |
| ap.add_argument("--device", default="cuda:0") | |
| ap.add_argument("--skip-finalize", action="store_true") | |
| args = ap.parse_args() | |
| os.makedirs(args.dst, exist_ok=True) | |
| manifest_dir = os.path.join(args.dst, ".manifest") | |
| os.makedirs(manifest_dir, exist_ok=True) | |
| with open(os.path.join(args.src, "model.safetensors.index.json")) as f: | |
| shards = sorted(set(json.load(f)["weight_map"].values())) | |
| if args.only: | |
| shards = [args.only] | |
| print(f"[start] {len(shards)} shards, device={args.device}", flush=True) | |
| entries = [] | |
| t0 = time.time() | |
| for i, shard in enumerate(shards): | |
| e = process_shard(args.src, args.dst, shard, args.device, manifest_dir) | |
| entries.append(e) | |
| done_q = sum(len(x["quantized"]) for x in entries) | |
| print(f"[{i+1}/{len(shards)}] {shard} quantized={len(e['quantized'])} " | |
| f"({e.get('seconds', 0)}s) total_q={done_q}", flush=True) | |
| if not args.skip_finalize and not args.only: | |
| summary = finalize(args.src, args.dst, entries) | |
| print(json.dumps(summary, indent=2), flush=True) | |
| print(f"[done] {(time.time()-t0)/60:.1f} min", flush=True) | |
| if __name__ == "__main__": | |
| main() | |