Instructions to use h2loop-ai/gemma-4-e2b-hexagon with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- llama.cpp
How to use h2loop-ai/gemma-4-e2b-hexagon 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 h2loop-ai/gemma-4-e2b-hexagon # Run inference directly in the terminal: llama cli -hf h2loop-ai/gemma-4-e2b-hexagon
Install from WinGet (Windows)
winget install llama.cpp # Start a local OpenAI-compatible server with a web UI: llama serve -hf h2loop-ai/gemma-4-e2b-hexagon # Run inference directly in the terminal: llama cli -hf h2loop-ai/gemma-4-e2b-hexagon
Use pre-built binary
# Download pre-built binary from: # https://github.com/ggerganov/llama.cpp/releases # Start a local OpenAI-compatible server with a web UI: ./llama-server -hf h2loop-ai/gemma-4-e2b-hexagon # Run inference directly in the terminal: ./llama-cli -hf h2loop-ai/gemma-4-e2b-hexagon
Build from source code
git clone https://github.com/ggerganov/llama.cpp.git cd llama.cpp cmake -B build cmake --build build -j --target llama-server llama-cli # Start a local OpenAI-compatible server with a web UI: ./build/bin/llama-server -hf h2loop-ai/gemma-4-e2b-hexagon # Run inference directly in the terminal: ./build/bin/llama-cli -hf h2loop-ai/gemma-4-e2b-hexagon
Use Docker
docker model run hf.co/h2loop-ai/gemma-4-e2b-hexagon
- LM Studio
- Jan
- Ollama
How to use h2loop-ai/gemma-4-e2b-hexagon with Ollama:
ollama run hf.co/h2loop-ai/gemma-4-e2b-hexagon
- Unsloth Studio
How to use h2loop-ai/gemma-4-e2b-hexagon with Unsloth Studio:
Install Unsloth Studio (macOS, Linux, WSL)
curl -fsSL https://unsloth.ai/install.sh | sh # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for h2loop-ai/gemma-4-e2b-hexagon to start chatting
Install Unsloth Studio (Windows)
irm https://unsloth.ai/install.ps1 | iex # Run unsloth studio unsloth studio -H 0.0.0.0 -p 8888 # Then open http://localhost:8888 in your browser # Search for h2loop-ai/gemma-4-e2b-hexagon to start chatting
Using HuggingFace Spaces for Unsloth
# No setup required # Open https://huggingface.co/spaces/unsloth/studio in your browser # Search for h2loop-ai/gemma-4-e2b-hexagon to start chatting
- Pi
How to use h2loop-ai/gemma-4-e2b-hexagon with Pi:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf h2loop-ai/gemma-4-e2b-hexagon
Configure the model in Pi
# Install Pi: npm install -g @mariozechner/pi-coding-agent # Add to ~/.pi/agent/models.json: { "providers": { "llama-cpp": { "baseUrl": "http://localhost:8080/v1", "api": "openai-completions", "apiKey": "none", "models": [ { "id": "h2loop-ai/gemma-4-e2b-hexagon" } ] } } }Run Pi
# Start Pi in your project directory: pi
- OpenClaw new
How to use h2loop-ai/gemma-4-e2b-hexagon with OpenClaw:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf h2loop-ai/gemma-4-e2b-hexagon
Configure OpenClaw
# Install OpenClaw: npm install -g openclaw@latest # Register the local server and set it as the default model: openclaw onboard --non-interactive --mode local \ --auth-choice custom-api-key \ --custom-base-url http://127.0.0.1:8080/v1 \ --custom-model-id "h2loop-ai/gemma-4-e2b-hexagon" \ --custom-provider-id llama-cpp \ --custom-compatibility openai \ --custom-text-input \ --accept-risk \ --skip-health
Run OpenClaw
openclaw agent --local --agent main --message "Hello from Hugging Face"
- Docker Model Runner
How to use h2loop-ai/gemma-4-e2b-hexagon with Docker Model Runner:
docker model run hf.co/h2loop-ai/gemma-4-e2b-hexagon
- Lemonade
How to use h2loop-ai/gemma-4-e2b-hexagon with Lemonade:
Pull the model
# Download Lemonade from https://lemonade-server.ai/ lemonade pull h2loop-ai/gemma-4-e2b-hexagon
Run and chat with the model
lemonade run user.gemma-4-e2b-hexagon-{{QUANT_TAG}}List all available models
lemonade list
- Hermes Agent
How to use h2loop-ai/gemma-4-e2b-hexagon with Hermes Agent:
Start the llama.cpp server
# Install llama.cpp: brew install llama.cpp # Start a local OpenAI-compatible server: llama serve -hf h2loop-ai/gemma-4-e2b-hexagon
Configure Hermes
# Install Hermes: curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash hermes setup # Point Hermes at the local server: hermes config set model.provider custom hermes config set model.base_url http://127.0.0.1:8080/v1 hermes config set model.default h2loop-ai/gemma-4-e2b-hexagon
Run Hermes
hermes
- Atomic Chat
| #!/usr/bin/env python3 | |
| """Host orchestrator for the A16W8 v79 correctness gate. | |
| Runs the autoregressive decode loop by driving qnn-net-run on-device once per token. | |
| KV (~288MB) stays resident on device as files; only tiny per-step tensors cross adb. | |
| Prereqs on device (staged by push_gate.sh): | |
| /data/local/tmp/gemma/{bin,lib,dsp,artifacts,step,kv,out} | |
| Host math from hostlib.py (gemma3n scaling, tied softcapped lm_head). | |
| Usage: | |
| python run_gate.py --prompt "The capital of France is" --ntokens 15 [--adb-serial X] | |
| Optionally --hf-check to compare against HF greedy on host (needs full model; heavy). | |
| """ | |
| import argparse, os, subprocess, sys, time, pathlib, numpy as np | |
| sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent)) | |
| import hostlib | |
| BASE = "/data/local/tmp/gemma" | |
| STEP = f"{BASE}/step" | |
| KV = f"{BASE}/kv" | |
| OUTR = f"{BASE}/out/Result_0" | |
| LOCAL_STEP = pathlib.Path("/tmp/gemma_step") | |
| CTX = hostlib.CTX | |
| H = hostlib.H | |
| KV_HD = hostlib.KV_HD | |
| def adb(args, serial=None, **kw): | |
| cmd = ["adb"] + (["-s", serial] if serial else []) + args | |
| return subprocess.run(cmd, capture_output=True, text=True, **kw) | |
| def adb_shell(script, serial=None, timeout=600): | |
| return adb(["shell", script], serial=serial, timeout=timeout) | |
| def push(local, remote, serial=None): | |
| r = adb(["push", str(local), remote], serial=serial, timeout=300) | |
| if r.returncode != 0: | |
| raise RuntimeError(f"push failed {local}->{remote}: {r.stderr}") | |
| def pull(remote, local, serial=None): | |
| r = adb(["pull", remote, str(local)], serial=serial, timeout=300) | |
| if r.returncode != 0: | |
| raise RuntimeError(f"pull failed {remote}->{local}: {r.stderr}") | |
| def seed_kv(serial, wgqa=False): | |
| """Zero the 15 past_k/v buffers on device. | |
| Created ON DEVICE with dd rather than pushed: they are ~144MB of zeros, and pushing | |
| them over the QDC tunnel took minutes and was the flakiest part of the run (a reset | |
| mid-seed leaves a partial buffer and silently corrupts the whole generation). | |
| WGQA uses a WIN-entry ring for sliding layers, so buffer depth is per-layer. | |
| """ | |
| LOCAL_STEP.mkdir(exist_ok=True) | |
| adb_shell(f"mkdir -p {KV} {STEP} {BASE}/out", serial=serial) | |
| depths = hostlib.KV_BUF if wgqa else [CTX] * hostlib.NC | |
| cmds = [f"rm -f {KV}/*.raw"] | |
| for i in range(hostlib.NC): | |
| nbytes = depths[i] * KV_HD[i] * 4 # [1,1,depth,hd] float32 | |
| for kind in ("k", "v"): | |
| cmds.append(f"dd if=/dev/zero of={KV}/past_{kind}_{i}.raw bs=4096 " | |
| f"count={nbytes // 4096} 2>/dev/null") | |
| r = adb_shell(" && ".join(cmds), serial=serial, timeout=600) | |
| if r.returncode != 0: | |
| raise RuntimeError(f"on-device KV seed failed: {r.stderr}") | |
| def write_step_inputs(m, token_id, pos, serial, wgqa=False): | |
| ie, ple = m.embeds(token_id) | |
| full, slide = m.masks_wgqa(pos) if wgqa else m.masks(pos) | |
| files = { | |
| "inputs_embeds": ie.astype(np.float32), | |
| "per_layer_inputs": ple.astype(np.float32), | |
| "position_ids": np.array([[pos]], np.int32), | |
| "cache_position": np.array([pos], np.int32), | |
| "full_mask": full.astype(np.float32), | |
| "sliding_mask": slide.astype(np.float32), | |
| } | |
| for name, arr in files.items(): | |
| p = LOCAL_STEP / f"{name}.raw" | |
| arr.tofile(p) | |
| push(p, f"{STEP}/{name}.raw", serial=serial) | |
| def run_step(serial, script="gate_ondevice.sh"): | |
| r = adb_shell(f"sh {BASE}/{script}", serial=serial, timeout=600) | |
| if "STEP_OK" not in r.stdout: | |
| raise RuntimeError(f"net-run step failed:\nSTDOUT:{r.stdout}\nSTDERR:{r.stderr}") | |
| return r | |
| def fetch_hidden(serial): | |
| pull(f"{OUTR}/hidden.raw", LOCAL_STEP / "hidden.raw", serial=serial) | |
| return np.fromfile(LOCAL_STEP / "hidden.raw", dtype=np.float32).reshape(H) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--prompt", default="The capital of France is") | |
| ap.add_argument("--ntokens", type=int, default=15) | |
| ap.add_argument("--adb-serial", default=os.environ.get("ADB_SERIAL")) | |
| ap.add_argument("--hf-check", action="store_true") | |
| ap.add_argument("--wgqa", action="store_true", | |
| help="target the windowed + broadcast-GQA decode graph (512-entry ring " | |
| "buffers on sliding layers, 512-wide sliding mask)") | |
| ap.add_argument("--script", default=None, | |
| help="override the on-device step script (e.g. gate_ondevice_int8kv.sh)") | |
| ap.add_argument("--chat", action="store_true", | |
| help="wrap the prompt in the Gemma-4 chat template (required for coherent " | |
| "output from the -it model; raw completion format degenerates)") | |
| args = ap.parse_args() | |
| print("loading host model (embeddings + tokenizer)...", flush=True) | |
| m = hostlib.HostModel() | |
| ids = m.encode_chat(args.prompt) if args.chat else m.encode(args.prompt) | |
| print(f"prompt: {args.prompt!r} (chat_template={args.chat})\nids: {ids}", flush=True) | |
| print("seeding KV buffers on device...", flush=True) | |
| seed_kv(args.adb_serial, wgqa=args.wgqa) | |
| seq = ids[:] | |
| gen_ids = [] | |
| pos = 0 | |
| t_steps = [] | |
| # prefill+decode: feed prompt tokens one-by-one (pos advances), then greedy-generate | |
| total = len(seq) + args.ntokens | |
| nxt = None | |
| for step in range(total): | |
| t = seq[step] if step < len(seq) else nxt | |
| write_step_inputs(m, t, pos, args.adb_serial, wgqa=args.wgqa) | |
| t0 = time.time() | |
| run_step(args.adb_serial, (args.script or ("gate_ondevice_wgqa.sh" if args.wgqa else "gate_ondevice.sh"))) | |
| dt = time.time() - t0 | |
| t_steps.append(dt) | |
| hidden = fetch_hidden(args.adb_serial) | |
| pos += 1 | |
| if step >= len(seq) - 1: # last prompt token onward -> predict next | |
| nxt = m.argmax_next(hidden) | |
| gen_ids.append(nxt) | |
| print(f" step {step:2d} pos {pos-1:2d} {dt*1000:7.1f}ms -> id {nxt:6d} {m.decode([nxt])!r}", flush=True) | |
| if nxt in hostlib.STOP_IDS: | |
| print(" (stop token reached)", flush=True) | |
| break | |
| text = m.decode([t for t in gen_ids if t not in hostlib.STOP_IDS]) | |
| print("\n=== GENERATION ===") | |
| print("continuation:", repr(text)) | |
| print(f"per-step wall (incl adb+netrun init): mean {1000*np.mean(t_steps):.0f}ms min {1000*min(t_steps):.0f}ms") | |
| print("NOTE: this wall time is NOT throughput (net-run reloads context each step). Coherence/accuracy only.") | |
| if args.hf_check: | |
| hf_compare(m, ids, gen_ids) | |
| def hf_compare(m, ids, gen_ids): | |
| print("\n=== HF greedy reference (host, CPU) ===", flush=True) | |
| import torch | |
| from transformers import AutoModelForCausalLM | |
| tok = (pathlib.Path.home() / ".cache/huggingface/token").read_text().strip() | |
| mdl = AutoModelForCausalLM.from_pretrained("google/gemma-4-E2B-it", token=tok, | |
| torch_dtype=torch.float32, device_map="cpu").eval() | |
| with torch.no_grad(): | |
| out = mdl.generate(torch.tensor([ids]), max_new_tokens=len(gen_ids), do_sample=False) | |
| hf = out[0][len(ids):].tolist() | |
| print("HF :", repr(m.decode(hf))) | |
| print("NPU :", repr(m.decode(gen_ids))) | |
| match = sum(a == b for a, b in zip(hf, gen_ids)) | |
| print(f"token match: {match}/{len(gen_ids)}") | |
| if __name__ == "__main__": | |
| main() | |