Downloads · 30 days
0
Khabner/moondream-lora-v12
moondream-lora-v12 is a machine learning model from Khabner. Use it for the machine learning task on the model card, and read the license before you ship it in a product. It is set up for transformers. The card lists the license as apache-2.0.
LoRA adapter for Moondream2 (revision 2025-06-21) fine-tuned for UI click localization: given a screenshot and a textual target description, predict normalized click coordinates [0,1].
Downloads · 30 days
0
Access
Public
Updated May 7, 2026
Repo size
75.6 MB
Likes
0
Public
Click a slice to open those files.
.pt75.6 MB · 100%
From the Hugging Face model README
LoRA adapter for Moondream2 (revision 2025-06-21) fine-tuned for UI click localization: given a screenshot and a textual target description, predict normalized click coordinates [0,1].
Used as a self-hosted grounding backend in the Magnitude browser-testing framework.
+15.4 percentage points).| Param | Value |
|---|---|
| LoRA rank | 16 |
| LoRA alpha | 32 |
| LoRA dropout | 0.05 |
| Epochs | 2 |
| LR | 1e-4 |
| Schedule | warmup 10% + cosine decay |
| dtype | bfloat16 (GPU/MPS), float32 (CPU) |
The adapter is stored as a custom adapter.pt checkpoint with two parts: lora weights (applied via Moondream's native variant_state_dict mechanism) and an optional coord_decoder state dict.
import importlib
import torch
from huggingface_hub import hf_hub_download
from transformers import AutoModelForCausalLM
DEVICE = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
DTYPE = torch.float32 if DEVICE == "cpu" else torch.bfloat16
# Load base Moondream2
model = AutoModelForCausalLM.from_pretrained(
"vikhyatk/moondream2", revision="2025-06-21",
trust_remote_code=True, torch_dtype=DTYPE,
device_map={"": DEVICE} if DEVICE != "cpu" else None,
)
model.model._setup_caches()
# Download and apply LoRA adapter
adapter_path = hf_hub_download("Khabner/moondream-lora-v12", "adapter.pt")
ckpt = torch.load(adapter_path, map_location="cpu", weights_only=True)
def _nest(flat):
tree = {}
for k, v in flat.items():
d = tree
for p in k.split(".")[:-1]:
d = d.setdefault(p, {})
d[k.split(".")[-1]] = v
return tree
inner = model.model
pkg = inner.__class__.__module__.rsplit(".", 1)[0]
flat = {k: v.to(device=str(inner.device), dtype=DTYPE) for k, v in ckpt["lora"].items()}
lora_dict = _nest(flat)
importlib.import_module(f"{pkg}.moondream").variant_state_dict = lambda *a, **kw: lora_dict
if "coord_decoder" in ckpt:
cd = {k.removeprefix("coord_decoder."): v.to(device=str(inner.device), dtype=DTYPE)
for k, v in ckpt["coord_decoder"].items()}
inner.region.coord_decoder.load_state_dict(cd)
model.eval()
# Inference: pass settings={"variant": "custom"} to use the LoRA weights
from PIL import Image
img = Image.open("screenshot.png").convert("RGB")
result = model.model.point(img, "Send button", settings={"variant": "custom"})
print(result["points"]) # [{"x": 0.42, "y": 0.71}, ...]
The full inference helpers and a FastAPI server matching the Moondream Cloud /v1/point API contract live in the github.com/VLM-WEBTEST/magnitude_integration repo (finetune_lora.py, serve_moondream.py).
#15 in the benchmark) — fails for every model: two radio circles per row are too close together and "radio in the 3rd row" is underspecified by description (a test-design issue, not a model weakness).[3] superscript link (#19) — also fails for every model. Likely needs higher-resolution input or a dedicated dataset.