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
File size: 7,747 Bytes
97c5704 | 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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | """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)
@lru_cache(maxsize=1)
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}
|