Instructions to use yuta24/ui-test-vision-2b-alpha with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use yuta24/ui-test-vision-2b-alpha with PEFT:
Task type is invalid.
- MLX
How to use yuta24/ui-test-vision-2b-alpha with MLX:
# Make sure mlx-vlm is installed # pip install --upgrade mlx-vlm from mlx_vlm import load, generate from mlx_vlm.prompt_utils import apply_chat_template from mlx_vlm.utils import load_config # Load the model model, processor = load("yuta24/ui-test-vision-2b-alpha") config = load_config("yuta24/ui-test-vision-2b-alpha") # Prepare input image = ["http://images.cocodataset.org/val2017/000000039769.jpg"] prompt = "Describe this image." # Apply chat template formatted_prompt = apply_chat_template( processor, config, prompt, num_images=1 ) # Generate output output = generate(model, processor, formatted_prompt, image) print(output) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
File size: 8,708 Bytes
e379257 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | """Train Glint student: Qwen3.5 + LoRA + JointSchemaHead, distilled from teacher option distributions (+ gold CE)."""
import os; os.environ.setdefault("TORCH_ROCM_AOTRITON_ENABLE_EXPERIMENTAL", "1") # ROCm: faster SDPA (see RESULTS.md); set to 0 to disable
import argparse, json, math, random, time
from pathlib import Path
import torch
from glint.model import build_student, save_checkpoint, default_device
from glint.data import load_jsonl, to_record, normalize_teacher, normalize_box_gold, derive_presence_gold
from glint.losses import decision_loss, record_box_loss
from glint.box import BoxLossWeights, DEFAULT_BINS, is_box_question
from glint.schema import encode_glint_record
from glint.joint_schema_model import collate_records
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--data", required=True)
ap.add_argument("--eval-data", default=None)
ap.add_argument("--out", default="checkpoints/run")
ap.add_argument("--model", default="Qwen/Qwen3.5-2B")
ap.add_argument("--max-pixels", type=int, default=430080, help="430080 ~= 390 tokens / 1048576 ~= 990 tokens (iPhone portrait)")
ap.add_argument("--steps", type=int, default=200, help="optimizer steps")
ap.add_argument("--accum", type=int, default=1)
ap.add_argument("--lr-lora", type=float, default=2e-4)
ap.add_argument("--lr-head", type=float, default=5e-4)
ap.add_argument("--warmup", type=int, default=10)
ap.add_argument("--temperature", type=float, default=2.0)
ap.add_argument("--alpha", type=float, default=0.7, help="KD weight when both teacher and gold exist")
ap.add_argument("--beta", type=float, default=0.1, help="Brier weight")
ap.add_argument("--lora-r", type=int, default=32)
ap.add_argument("--dtype", default="bf16", choices=["bf16", "fp16", "fp32"])
ap.add_argument("--grad-ckpt", action="store_true")
ap.add_argument("--max-length", type=int, default=4096)
ap.add_argument("--log-every", type=int, default=10)
ap.add_argument("--seed", type=int, default=0)
# Jev-style box questions (glint/box.py). auto = add a box head iff the training data has box questions.
ap.add_argument("--box-head", default="auto", choices=["auto", "on", "off"])
ap.add_argument("--box-weight", type=float, default=1.0, help="weight of the box loss in the total loss")
ap.add_argument("--box-dfl", type=float, default=1.0, help="DFL (two-bin soft CE) weight inside the box loss")
ap.add_argument("--box-l1", type=float, default=5.0, help="L1 on decoded edges weight inside the box loss")
ap.add_argument("--box-giou", type=float, default=2.0, help="(1 - GIoU) weight inside the box loss")
ap.add_argument("--box-conf", type=float, default=1.0, help="BCE(confidence, detached IoU) weight inside the box loss")
ap.add_argument("--box-bins", type=int, default=DEFAULT_BINS)
ap.add_argument("--init-from", default=None, help="warm start: load LoRA adapter, head and box head from this checkpoint dir")
args = ap.parse_args()
random.seed(args.seed); torch.manual_seed(args.seed)
dev = default_device()
data = load_jsonl(args.data)
has_box = any(is_box_question(q) for ex in data for q in ex["questions"].values())
use_box = args.box_head == "on" or (args.box_head == "auto" and has_box)
if has_box and not use_box:
raise SystemExit("training data has box questions but --box-head off")
model, proc, meta = build_student(args.model, args.max_pixels, dev, args.dtype, lora_r=args.lora_r,
lora_alpha=2 * args.lora_r, grad_ckpt=args.grad_ckpt,
box_head_cfg={"bins": args.box_bins} if use_box else None)
if args.init_from:
from safetensors.torch import load_file
from peft import set_peft_model_state_dict
ck = Path(args.init_from)
sd = load_file(ck / "adapter" / "adapter_model.safetensors")
res = set_peft_model_state_dict(model.language_model, sd)
bad = list(getattr(res, "unexpected_keys", []) or [])
if bad: raise SystemExit(f"init-from: {len(bad)} unexpected LoRA keys, e.g. {bad[:3]}")
model.head.load_state_dict(load_file(ck / "head.safetensors"), strict=True)
if use_box:
model.box_head.load_state_dict(load_file(ck / "box_head.safetensors"), strict=True)
print(f"init-from {ck}: lora_tensors={len(sd)} head ok box_head={'ok' if use_box else 'n/a'}", flush=True)
box_w = BoxLossWeights(dfl=args.box_dfl, l1=args.box_l1, giou=args.box_giou, conf=args.box_conf)
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"device={dev} trainable_params={trainable/1e6:.1f}M head={sum(p.numel() for p in model.head.parameters())/1e6:.1f}M"
+ (f" box_head={sum(p.numel() for p in model.box_head.parameters())/1e6:.1f}M" if use_box else ""), flush=True)
opt = torch.optim.AdamW([
{"params": [p for p in model.language_model.parameters() if p.requires_grad], "lr": args.lr_lora},
{"params": list(model.head.parameters()) + (list(model.box_head.parameters()) if use_box else []), "lr": args.lr_head}],
weight_decay=0.01)
sched = torch.optim.lr_scheduler.LambdaLR(opt, lambda s: min(1.0, (s + 1) / max(1, args.warmup)) *
0.5 * (1 + math.cos(math.pi * min(1.0, s / max(1, args.steps)))))
if dev == "cuda":
torch.cuda.reset_peak_memory_stats()
model.train(); order = []; hist = []; t_start = time.time(); step = 0; micro = 0
win = {"loss": 0.0, "kd": 0.0, "ce": 0.0, "brier": 0.0, "n": 0, "t": 0.0, "tok": 0}
box_keys = ("box", "dfl", "l1", "giou", "conf", "iou")
if use_box:
win.update({k: 0.0 for k in box_keys}, n_box=0)
while step < args.steps:
if not order:
order = list(range(len(data))); random.shuffle(order)
ex = data[order.pop()]
t0 = time.time()
enc = encode_glint_record(proc.tokenizer, to_record(ex, augment=True), max_length=args.max_length, processor=proc)
batch = collate_records([enc], proc.tokenizer.pad_token_id, torch.device(dev))
if use_box:
all_logits, boxes = model.decide(batch); logits = all_logits[0]
gold = derive_presence_gold(ex)
else:
logits = model(batch)[0]; gold = ex.get("gold") or {}
loss, parts = decision_loss(logits, enc, normalize_teacher(ex), gold,
T=args.temperature, alpha=args.alpha, beta=args.beta)
if use_box:
bl, bparts, nb = record_box_loss(boxes[0], normalize_box_gold(ex), box_w)
if bl is not None:
loss = loss + args.box_weight * bl
win["box"] += float(bl.detach()); win["n_box"] += 1
for k in box_keys[1:]:
win[k] += bparts[k]
if not (torch.is_tensor(loss) and loss.requires_grad): # e.g. only a present=false box question without gold
loss = sum(p.sum() for p in model.box_head.parameters()) * 0.0
(loss / args.accum).backward(); micro += 1
if micro % args.accum == 0:
torch.nn.utils.clip_grad_norm_([p for p in model.parameters() if p.requires_grad], 1.0)
opt.step(); sched.step(); opt.zero_grad(set_to_none=True); step += 1
if dev == "cuda":
torch.cuda.synchronize()
win["t"] += time.time() - t0; win["loss"] += float(loss.detach()); win["n"] += 1; win["tok"] += len(enc.input_ids)
for k in ("kd", "ce", "brier"):
win[k] += parts[k]
if micro % args.accum == 0 and step % args.log_every == 0:
n = win["n"]
rec = {"step": step, "loss": win["loss"] / n, "kd": win["kd"] / n, "ce": win["ce"] / n, "brier": win["brier"] / n,
"sec_per_micro": win["t"] / n, "tokens": win["tok"] // n,
"peak_mem_gb": torch.cuda.max_memory_allocated() / 2**30 if dev == "cuda" else None}
if use_box:
nb = max(win["n_box"], 1)
rec.update({f"box_{k}" if k != "box" else "box": win[k] / nb for k in box_keys}, n_box=win["n_box"])
hist.append(rec); print(json.dumps(rec), flush=True)
win = {k: 0 for k in win}
out = Path(args.out)
save_checkpoint(model, meta, out, {"train_args": vars(args), "history": hist,
"train_seconds": time.time() - t_start})
print(f"saved checkpoint -> {out.resolve()}", flush=True)
if __name__ == "__main__":
main()
|