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
Download code/tests/test_box.py from yuta24/ui-test-vision-2b-alpha: direct link, hf CLI and curl.
- Browser
- Download file 10.3 kB
-
https://huggingface.co/yuta24/ui-test-vision-2b-alpha/resolve/main/code/tests/test_box.py
- Command line
-
hf download hf://yuta24/ui-test-vision-2b-alpha/code/tests/test_box.py
-
curl -L -o test_box.py https://huggingface.co/yuta24/ui-test-vision-2b-alpha/resolve/main/code/tests/test_box.py
10.3 kB
| import math | |
| import pytest | |
| import torch | |
| from glint.box import (BoxHead, BoxLossWeights, box_answer, box_iou, box_loss, box_metrics, decode_box, decode_edges, | |
| dfl_loss, generalized_iou, max_prob_confidence, order_box, two_hot) | |
| K = 64 | |
| def logits_from_target(target, bins=K): | |
| return two_hot(target, bins).clamp_min(1e-12).log() | |
| # ---------------------------------------------------------------- bins encode / decode | |
| def test_two_hot_round_trip(bins): | |
| torch.manual_seed(0) | |
| t = torch.rand(100, 4) | |
| t[0] = torch.tensor([0.0, 1.0, 0.0, 1.0]) # exact endpoints | |
| t[1] = torch.tensor([0.5, 1 / (bins - 1), 1 - 1e-7, min(1.0, 2 / (bins - 1))]) | |
| th = two_hot(t, bins) | |
| assert th.shape == (100, 4, bins) | |
| assert torch.allclose(th.sum(-1), torch.ones(100, 4)) | |
| assert ((th > 0).sum(-1) <= 2).all() # mass only on two adjacent bins | |
| assert torch.allclose(decode_edges(logits_from_target(t, bins)), t, atol=1e-5) | |
| def test_two_hot_clamps_out_of_range(): | |
| t = torch.tensor([[-0.2, 1.3, 0.25, 0.75]]) | |
| assert torch.allclose(decode_edges(logits_from_target(t)), t.clamp(0, 1), atol=1e-5) | |
| # ---------------------------------------------------------------- DFL | |
| def test_dfl_matches_manual_and_is_minimal_at_target(): | |
| torch.manual_seed(0) | |
| t = torch.tensor([[0.1, 0.4, 0.33, 0.9]]) | |
| z = torch.randn(1, 4, K, requires_grad=True) | |
| loss = dfl_loss(z, t) | |
| manual = 0.0 | |
| for e in range(4): | |
| x = float(t[0, e]) * (K - 1); lo = int(math.floor(x)); w = x - lo | |
| lp = z[0, e].log_softmax(-1) | |
| manual += -((1 - w) * lp[lo] + w * lp[lo + 1]) | |
| assert torch.allclose(loss, manual / 4, atol=1e-5) | |
| loss.backward() | |
| assert torch.isfinite(z.grad).all() and z.grad.abs().sum() > 0 | |
| # loss at the two-hot target logits == entropy of the two-hot distribution (its minimum) | |
| th = two_hot(t, K) | |
| ent = -(th * th.clamp_min(1e-12).log()).sum(-1).mean() | |
| assert torch.allclose(dfl_loss(logits_from_target(t), t), ent, atol=1e-4) | |
| assert dfl_loss(logits_from_target(t), t) < dfl_loss(torch.zeros(1, 4, K), t) | |
| def test_dfl_exact_bin_target_is_one_hot_ce(): | |
| t = torch.full((1, 4), 10 / (K - 1)) | |
| z = torch.randn(1, 4, K) | |
| assert torch.allclose(dfl_loss(z, t), -z.log_softmax(-1)[..., 10].mean(), atol=1e-5) | |
| # ---------------------------------------------------------------- IoU / GIoU | |
| def test_iou_giou_known_values(): | |
| a = torch.tensor([0.0, 0.5, 0.0, 0.5]) # top, bottom, left, right | |
| assert torch.allclose(box_iou(a, a), torch.tensor(1.0)) | |
| assert torch.allclose(generalized_iou(a, a), torch.tensor(1.0)) | |
| b = torch.tensor([0.25, 0.75, 0.25, 0.75]) # overlap 0.25x0.25 | |
| assert torch.allclose(box_iou(a, b), torch.tensor(0.0625 / (0.25 + 0.25 - 0.0625)), atol=1e-6) | |
| c = torch.tensor([0.5, 1.0, 0.5, 1.0]) # touching corner, hull = 1 | |
| assert torch.allclose(box_iou(a, c), torch.tensor(0.0)) | |
| assert torch.allclose(generalized_iou(a, c), torch.tensor(-0.5), atol=1e-6) | |
| d = torch.tensor([0.0, 0.1, 0.9, 1.0]) | |
| assert generalized_iou(a, d) < 0 and generalized_iou(a, d) > -1 | |
| def test_giou_gradient_for_disjoint_boxes(): | |
| p = torch.tensor([0.0, 0.1, 0.0, 0.1], requires_grad=True) | |
| g = torch.tensor([0.8, 0.9, 0.8, 0.9]) | |
| (1 - generalized_iou(p, g)).backward() | |
| assert p.grad.abs().sum() > 0 # IoU alone would have zero gradient here | |
| def test_iou_broadcast(): | |
| a = torch.rand(5, 4).sort(-1).values[:, [0, 1, 2, 3]] | |
| a = order_box(a) | |
| assert box_iou(a, a).shape == (5,) | |
| assert torch.allclose(box_iou(a, a), torch.ones(5), atol=1e-5) | |
| # ---------------------------------------------------------------- ordering | |
| def test_order_box_swaps_inverted_edges(): | |
| e = torch.tensor([[0.8, 0.2, 0.9, 0.1], [0.1, 0.2, 0.3, 0.4]]) | |
| assert torch.equal(order_box(e), torch.tensor([[0.2, 0.8, 0.1, 0.9], [0.1, 0.2, 0.3, 0.4]])) | |
| z = logits_from_target(torch.tensor([[0.7, 0.3, 0.6, 0.2]])) | |
| t, b, l, r = decode_box(z)[0].tolist() | |
| assert t <= b and l <= r | |
| def test_box_answer_jev_shape_and_strict_order(): | |
| a = box_answer(torch.tensor([0.7, 0.3, 0.5, 0.5]), 1.3) | |
| assert a["type"] == "box" and set(a["box"]) == {"top", "bottom", "left", "right"} | |
| assert a["box"]["top"] < a["box"]["bottom"] and a["box"]["left"] < a["box"]["right"] | |
| assert a["box"]["top"] == 0.3 and a["box"]["bottom"] == 0.7 | |
| assert a["confidence"] == 1.0 | |
| z = box_answer([1.0, 1.0, 0.0, 0.0], 0.5)["box"] # degenerate at the image border | |
| assert 0 <= z["top"] < z["bottom"] <= 1 and 0 <= z["left"] < z["right"] <= 1 | |
| # ---------------------------------------------------------------- loss / metrics | |
| def test_box_loss_parts_and_backward(): | |
| torch.manual_seed(0) | |
| z = torch.randn(3, 4, K, requires_grad=True); c = torch.zeros(3, requires_grad=True) | |
| tgt = torch.tensor([[0.1, 0.2, 0.3, 0.6], [0.5, 0.9, 0.1, 0.2], [0.0, 1.0, 0.0, 1.0]]) | |
| loss, parts = box_loss(z, c, tgt, BoxLossWeights()) | |
| assert set(parts) == {"dfl", "l1", "giou", "conf", "iou"} | |
| loss.backward() | |
| assert torch.isfinite(z.grad).all() and z.grad.abs().sum() > 0 and c.grad.abs().sum() > 0 | |
| w0, _ = box_loss(z, c, tgt, BoxLossWeights(dfl=0, l1=0, giou=0, conf=0)) | |
| assert float(w0.detach()) == 0.0 | |
| perfect, pp = box_loss(logits_from_target(tgt), torch.full((3,), 10.0), tgt) | |
| assert pp["l1"] < 1e-4 and pp["giou"] < 1e-3 and pp["iou"] > 0.999 | |
| def test_max_prob_confidence_range(): | |
| z = torch.randn(2, 4, K) | |
| c = max_prob_confidence(z) | |
| assert c.shape == (2,) and ((c > 0) & (c <= 1)).all() | |
| assert torch.allclose(max_prob_confidence(logits_from_target(torch.rand(2, 4))), torch.ones(2), atol=1e-5) | |
| def test_box_metrics(): | |
| m = box_metrics([0.9, 0.6, 0.3, 0.8], [0.9, 0.7, 0.2, 0.8], [0.5] * 4) | |
| assert m["n_box_questions"] == 4 | |
| assert m["mean_iou"] == pytest.approx(0.65) | |
| assert m["iou_ge_0.5"] == 0.75 and m["iou_ge_0.75"] == 0.5 | |
| assert 0 <= m["ece_15bin_conf_vs_iou50"] <= 1 and "ece_15bin_maxprob_vs_iou50" in m | |
| assert box_metrics([], []) == {"n_box_questions": 0} | |
| # ---------------------------------------------------------------- head forward / backward | |
| class _Rec: | |
| def __init__(self, spans, coords=None): | |
| from glint.schema import EncodedBoxQuestion | |
| self.box_questions = tuple(EncodedBoxQuestion(f"q{i}", s) for i, s in enumerate(spans)) | |
| self.image_coords = coords | |
| def test_box_head_forward_backward_random_hidden(): | |
| torch.manual_seed(0) | |
| H, L = 48, 40 | |
| head = BoxHead(hidden_size=H, width=32, layers=2, heads=4, feedforward=64, bins=K) | |
| hidden = torch.randn(2, L, H, requires_grad=True) | |
| mask = torch.ones(2, L, dtype=torch.long); mask[1, 30:] = 0 | |
| coords = (tuple(range(2, 14)), tuple(((r + .5) / 3, (c + .5) / 4) for r in range(3) for c in range(4))) | |
| recs = [_Rec([(20, 25), (26, 30)], coords), _Rec([(5, 9)])] | |
| out = head(hidden, mask, recs) | |
| assert out[0].logits.shape == (2, 4, K) and out[0].conf_logit.shape == (2,) | |
| assert out[1].logits.shape == (1, 4, K) and out[0].question_ids == ("q0", "q1") | |
| tgt = torch.tensor([[0.1, 0.3, 0.2, 0.8], [0.6, 0.7, 0.1, 0.4]]) | |
| loss, _ = box_loss(out[0].logits, out[0].conf_logit, tgt) | |
| loss2, _ = box_loss(out[1].logits, out[1].conf_logit, tgt[:1]) | |
| (loss + loss2).backward() | |
| assert hidden.grad is not None and torch.isfinite(hidden.grad).all() | |
| assert hidden.grad[1, 30:].abs().sum() == 0 # padding is ignored | |
| for name, p in head.named_parameters(): | |
| assert p.grad is not None, name | |
| assert head(hidden, mask, [_Rec([])])[0] is None | |
| def test_box_head_questions_do_not_interact(): | |
| torch.manual_seed(0) | |
| head = BoxHead(hidden_size=16, width=16, layers=1, heads=2, feedforward=32, bins=8).eval() | |
| hidden = torch.randn(1, 20, 16); mask = torch.ones(1, 20, dtype=torch.long) | |
| both = head(hidden, mask, [_Rec([(2, 5), (8, 12)])])[0] | |
| one = head(hidden, mask, [_Rec([(2, 5)])])[0] | |
| assert torch.allclose(both.logits[0], one.logits[0], atol=1e-5) | |
| def test_box_head_can_overfit_and_bf16(): | |
| torch.manual_seed(0) | |
| head = BoxHead(hidden_size=16, width=32, layers=1, heads=4, feedforward=64, bins=K) | |
| hidden = torch.randn(1, 12, 16); mask = torch.ones(1, 12, dtype=torch.long) | |
| rec = [_Rec([(3, 6)])]; tgt = torch.tensor([[0.42, 0.47, 0.18, 0.83]]) | |
| opt = torch.optim.AdamW(head.parameters(), lr=3e-3) | |
| for _ in range(150): | |
| o = head(hidden, mask, rec)[0]; loss, parts = box_loss(o.logits, o.conf_logit, tgt) | |
| opt.zero_grad(); loss.backward(); opt.step() | |
| assert parts["iou"] > 0.9 | |
| with torch.no_grad(): | |
| assert float(torch.sigmoid(head(hidden, mask, rec)[0].conf_logit)) > 0.7 # confidence tracks IoU | |
| hb = head.to(torch.bfloat16) | |
| ob = hb(hidden.bfloat16(), mask, rec)[0] | |
| assert ob.logits.dtype == torch.bfloat16 and box_iou(decode_box(ob.logits)[0], tgt[0]) > 0.8 | |
| def test_box_head_edges_do_not_collapse(): | |
| # regression: with a tiny edge embedding all 4 edges decoded to the same value (the L1-optimal mean of the targets) | |
| torch.manual_seed(1) | |
| head = BoxHead(hidden_size=16, width=32, layers=1, heads=4, feedforward=64, bins=K) | |
| hidden = torch.randn(4, 12, 16); mask = torch.ones(4, 12, dtype=torch.long) | |
| tgt = torch.tensor([[0.48, 0.54, 0.50, 0.86], [0.53, 0.59, 0.08, 0.92], [0.20, 0.30, 0.10, 0.40], [0.70, 0.95, 0.60, 0.90]]) | |
| opt = torch.optim.AdamW(head.parameters(), lr=1e-3) | |
| for step in range(400): | |
| i = step % 4 | |
| o = head(hidden[i:i + 1], mask[i:i + 1], [_Rec([(3, 6)])])[0] | |
| loss, _ = box_loss(o.logits, o.conf_logit, tgt[i:i + 1]) | |
| opt.zero_grad(); loss.backward(); opt.step() | |
| with torch.no_grad(): | |
| out = torch.stack([decode_box(head(hidden[i:i + 1], mask[i:i + 1], [_Rec([(3, 6)])])[0].logits)[0] for i in range(4)]) | |
| assert box_iou(out, tgt).mean() > 0.5 | |