Image-Text-to-Text
Transformers
Safetensors
lfm3_vl
feature-extraction
liquid
lfm3
edge
decision
classification
extraction
calibration
system-one
multimodal
decision-model
custom_code
conversational
Instructions to use LiquidAI/d1-2B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use LiquidAI/d1-2B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="LiquidAI/d1-2B", trust_remote_code=True) messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("LiquidAI/d1-2B", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use LiquidAI/d1-2B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "LiquidAI/d1-2B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "LiquidAI/d1-2B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/LiquidAI/d1-2B
- SGLang
How to use LiquidAI/d1-2B 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 "LiquidAI/d1-2B" \ --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": "LiquidAI/d1-2B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'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 "LiquidAI/d1-2B" \ --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": "LiquidAI/d1-2B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use LiquidAI/d1-2B with Docker Model Runner:
docker model run hf.co/LiquidAI/d1-2B
Download box.py from LiquidAI/d1-2B: direct link, hf CLI and curl.
- Browser
- Download file 7.75 kB
-
https://huggingface.co/LiquidAI/d1-2B/resolve/main/box.py
- Command line
-
hf download hf://LiquidAI/d1-2B/box.py
-
curl -L -o box.py https://huggingface.co/LiquidAI/d1-2B/resolve/main/box.py
7.75 kB
| """Boxes: a presence and four edges, each a distribution over the same grid of fractions of the picture (0 the top | |
| or left side, 1 the bottom or right): the thousandths 0-999 as the tokenizer writes them on a checkpoint that reads | |
| numbers (`edge_grid`), else 128 codes. | |
| - An edge is its distribution's median: an unsure edge's mean drifts to the picture's middle. A checkpoint that | |
| records `d1_box_edges: interp` reads it inside the median's bin, where the distribution's CDF | |
| crosses one half (`EDGE_READS`): the bin's value alone is off by a quarter of a bin on average. One without the | |
| record reads the bin's value. | |
| - A box's confidence: the share of boxes drawn from the edges that overlap it (IoU >= 0.5). | |
| - `boxes`: every instance, blocks of a presence and four edges; block k is present when there are at least k (its | |
| presence is P(count >= k)), the boxes answered in reading order (left edge, then top). A question reads its `max` | |
| first blocks, else `INSTANCES`: the count is then at least that when the last is present. Prompt 1 trained 16 | |
| blocks under a prompt saying "16 at most"; prompt 2 states no count and trains 1 to `MAX_INSTANCES` blocks drawn | |
| per row (`prompt.PROMPTS`). | |
| - Probabilities go through the served calibration's tables (calibration.py).""" | |
| from __future__ import annotations | |
| import math | |
| from bisect import bisect_left | |
| from collections.abc import Callable | |
| from functools import lru_cache | |
| from itertools import accumulate | |
| from .grid import Grid | |
| EDGES = ("top", "bottom", "left", "right") | |
| GRID = Grid(0, 1) # an edge's values as codes, 128 of them | |
| THOUSANDTHS = Grid(0, 0.999, 1000) # an edge's values as numbers: 0-999 thousandths ("1000" takes two tokens) | |
| DRAWS = 512 | |
| INSTANCES = 16 # a `boxes` question's blocks without `max`: 99.97% of COCO val's (picture, class) pairs hold 16 at most | |
| MAX_INSTANCES = 64 # the most a `max` asks, and a prompt-2 training row draws (dense scenes: 17-60 instances) | |
| EDGE_READS = ("median", "interp") # how an edge is read off its distribution; a checkpoint records it (`d1_box_edges`) | |
| def edge_grid(tokenizer) -> tuple[Grid, int]: | |
| """An edge's grid and the factor its values are written at: the thousandths where the checkpoint reads numbers | |
| (`d1_numbers`) and the tokenizer writes each in one token, else the codes.""" | |
| from .prompt import number_ids | |
| numbers = getattr(tokenizer, "d1_numbers", False) and number_ids(tokenizer, THOUSANDTHS, 1000) is not None | |
| return (THOUSANDTHS, 1000) if numbers else (GRID, 1) | |
| def read_as(distribution) -> Grid: | |
| """The grid an edge's distribution is over, by its length: the codes' 128 values or the thousandths.""" | |
| return THOUSANDTHS if len(distribution) == THOUSANDTHS.size else GRID | |
| def ordered(a: float, b: float, grid: Grid = GRID) -> tuple[float, float]: | |
| """Two edges of one axis, the second below or right of the first: crossed ones become one bin about their middle.""" | |
| if a < b: | |
| return a, b | |
| half = grid.step / 2 | |
| middle = min(1 - half, max(half, (a + b) / 2)) | |
| return middle - half, middle + half | |
| def rectangle(edges: list[float], grid: Grid = GRID) -> dict[str, float]: | |
| top, bottom = ordered(*edges[:2], grid) | |
| left, right = ordered(*edges[2:], grid) | |
| return {"top": top, "bottom": bottom, "left": left, "right": right} | |
| def area(box: dict) -> float: | |
| return (box["bottom"] - box["top"]) * (box["right"] - box["left"]) | |
| def iou(a: dict, b: dict) -> float: | |
| overlap = (max(0.0, min(a["bottom"], b["bottom"]) - max(a["top"], b["top"])) | |
| * max(0.0, min(a["right"], b["right"]) - max(a["left"], b["left"]))) | |
| return overlap / (area(a) + area(b) - overlap) | |
| def samples() -> tuple[tuple[float, ...], ...]: | |
| """`DRAWS` points of a Halton sequence in four dimensions: the same draws every call.""" | |
| def radical_inverse(i: int, base: int) -> float: | |
| value, scale = 0.0, 1.0 | |
| while i: | |
| i, digit = divmod(i, base) | |
| scale /= base | |
| value += digit * scale | |
| return value | |
| return tuple(tuple(radical_inverse(i, base) for base in (2, 3, 5, 7)) for i in range(1, DRAWS + 1)) | |
| def confidence(edges: list[list[float]], box: dict) -> float: | |
| """The share of boxes drawn from the edge distributions (through each one's CDF) with IoU >= 0.5 against `box`.""" | |
| cdfs = [list(accumulate(p / total for p in row)) for row, total in zip(edges, map(math.fsum, edges))] | |
| grid = read_as(edges[0]) | |
| values = grid.values | |
| hits = sum(iou(rectangle([values[min(grid.size - 1, bisect_left(cdf, u))] for cdf, u in zip(cdfs, point)], grid), | |
| box) >= 0.5 for point in samples()) | |
| return hits / DRAWS | |
| def answer(probabilities: list[list[float]], through: Callable[[str, float], float] = lambda name, value: value, | |
| edges: str = "median") -> dict: | |
| """The API's box: `probabilities` are presence ([yes, no]) then the four edges' distributions; `through(name, raw)` | |
| calibrates `found` ("found:box") and the confidence ("box"); `edges`, how each edge is read (`EDGE_READS`).""" | |
| found = through("found:box", probabilities[0][0]) | |
| if found < 0.5: | |
| return {"type": "box", "box": None, "found": found, "confidence": 0.0} | |
| box = medians(probabilities[1:], edges) | |
| return {"type": "box", "box": box, "found": found, "confidence": through("box", confidence(probabilities[1:], box))} | |
| def crossing(probabilities, grid: Grid = GRID) -> float: | |
| """Where the distribution's CDF crosses one half, the mass spread evenly over each bin (value +- step / 2).""" | |
| total, mass = math.fsum(probabilities), 0.0 | |
| for value, p in zip(grid.values, probabilities): | |
| share = p / total | |
| if share > 0 and mass + share >= 0.5: | |
| return min(grid.high, max(grid.low, value - grid.step / 2 + (0.5 - mass) / share * grid.step)) | |
| mass += share | |
| return grid.high | |
| def medians(edges: list[list[float]], read: str = "median") -> dict[str, float]: | |
| """The box at the four edge distributions' medians: each its bin's value, or where its CDF crosses one half | |
| inside that bin (`read`).""" | |
| if read not in EDGE_READS: | |
| raise ValueError(f"box edges read as one of {EDGE_READS}, not {read!r}") | |
| grid = read_as(edges[0]) | |
| at = (lambda row: crossing(row, grid)) if read == "interp" else (lambda row: grid.read(row)["median"]) | |
| return rectangle([at(row) for row in edges], grid) | |
| def answer_many(probabilities: list[list[float]], through: Callable[[str, float], float] = lambda name, value: value, | |
| edges: str = "median") -> dict: | |
| """The API's `boxes`: `probabilities` are blocks (`INSTANCES`, or a question's `max`) of presence ([yes, no]) and | |
| four edges. `presence` is P(count >= k) for each k, calibrated ("found:boxes") and kept decreasing; the boxes are | |
| the blocks at >= 0.5, each with that presence as `found` and its confidence ("boxes"), in reading order; `count` | |
| is how many, `at_least` when every block read is present (the true count may be higher).""" | |
| presence, below = [], 1.0 | |
| for k in range(0, len(probabilities), 5): | |
| below = min(below, through("found:boxes", probabilities[k][0])) | |
| presence.append(below) | |
| out = [] | |
| for k, found in enumerate(presence): | |
| if found < 0.5: | |
| break | |
| block = probabilities[5 * k + 1:5 * k + 5] | |
| box = medians(block, edges) | |
| out.append({"box": box, "found": found, "confidence": through("boxes", confidence(block, box))}) | |
| out.sort(key=lambda b: (b["box"]["left"], b["box"]["top"])) | |
| return {"type": "boxes", "boxes": out, "count": len(out), "at_least": bool(out) and len(out) == len(presence), | |
| "presence": presence} | |