davanstrien/prelinger-sample / scripts /marlin_extended_bench.py
davanstrien's picture
download
raw
4.97 kB
# /// script
# requires-python = ">=3.10"
# dependencies = [
# "saturate[hf]",
# "vllm",
# "qwen-vl-utils",
# "opencv-python-headless",
# ]
# ///
"""Extended video bench: IA-direct fetch + long-video failure mode, fps sweep,
frames-as-images vs true video. Talks to the vLLM server via saturate's transport
only where pump adds value; single probes use plain httpx for clarity."""
import base64
import glob
import re
import time
import httpx
from saturate import Engine
MOUNT_DIR = "/clips/clips"
IA_FULL_FILM = "https://archive.org/download/AboutBan1935/AboutBan1935_512kb.mp4"
PROBE_CLIP = "AboutBan1935.mp4"
CAPTION_PROMPT = (
"Provide a spatial description of this clip followed by time-ranged events.\n"
"For each event, give the time range as <start - end> and a short description."
)
THINK = re.compile(r"<think>.*?</think>\s*|^\s*<think>\s*\n*|</think>\s*", re.DOTALL)
def chat(endpoint: str, content: list, timeout: float = 900, **kwargs) -> dict:
body = {"model": "NemoStation/Marlin-2B",
"messages": [{"role": "user", "content": content}],
"temperature": 0, "max_tokens": 1024, **kwargs}
r = httpx.post(f"{endpoint}/chat/completions", json=body, timeout=timeout)
return {"status": r.status_code, "json": r.json() if r.status_code == 200 else r.text[:500]}
def video_part(url: str) -> dict:
return {"type": "video_url", "video_url": {"url": url}}
def report(tag: str, t0: float, out: dict) -> None:
dt = time.perf_counter() - t0
if out["status"] == 200:
j = out["json"]
usage = j.get("usage") or {}
text = THINK.sub("", j["choices"][0]["message"]["content"]).strip()
events = len(re.findall(r"<\d+\.?\d*\s*-\s*\d+\.?\d*>", text))
print(f"[{tag}] ok {dt:.1f}s prompt_tokens={usage.get('prompt_tokens')} "
f"events={events}", flush=True)
print(f"[{tag}] first-300: {text[:300].replace(chr(10), ' | ')}", flush=True)
else:
print(f"[{tag}] HTTP {out['status']} in {dt:.1f}s: {out['json'][:300]}", flush=True)
def sample_frames_b64(path: str, n: int = 16) -> list:
import cv2
cap = cv2.VideoCapture(path)
total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
parts = []
for i in range(n):
cap.set(cv2.CAP_PROP_POS_FRAMES, int(i * total / n))
ok, frame = cap.read()
if not ok:
continue
ok, buf = cv2.imencode(".jpg", frame, [cv2.IMWRITE_JPEG_QUALITY, 85])
parts.append({"type": "image_url", "image_url": {
"url": "data:image/jpeg;base64," + base64.b64encode(buf).decode()}})
cap.release()
print(f"[frames] sampled {len(parts)} jpegs, "
f"{sum(len(p['image_url']['url']) for p in parts)/1e6:.1f} MB total", flush=True)
return parts
def main():
clip = f"{MOUNT_DIR}/{PROBE_CLIP}"
assert glob.glob(clip), f"missing {clip}"
with Engine(
"NemoStation/Marlin-2B",
engine="vllm",
extra_args=[
"--hf-overrides", '{"architectures": ["Qwen3_5ForConditionalGeneration"]}',
"--allowed-local-media-path", MOUNT_DIR,
"--max-model-len", "65536",
"--enforce-eager",
],
) as endpoint:
# Warm-up
t0 = time.perf_counter()
report("warmup", t0, chat(endpoint, [video_part(f"file://{clip}"),
{"type": "text", "text": CAPTION_PROMPT}]))
# 1) fps sweep on the 60s clip (token cost vs timestamp behavior)
for fps in (0.5, 1.0, 2.0):
t0 = time.perf_counter()
out = chat(endpoint, [video_part(f"file://{clip}"),
{"type": "text", "text": CAPTION_PROMPT}],
mm_processor_kwargs={"fps": fps})
report(f"fps={fps}", t0, out)
# 2) frames-as-images vs true video (16 uniform jpegs, no temporal encoding)
frames = sample_frames_b64(clip, n=16)
t0 = time.perf_counter()
out = chat(endpoint, frames + [{"type": "text", "text": CAPTION_PROMPT}])
report("frames-as-images", t0, out)
# 3) IA-direct: server fetches the FULL film straight from archive.org.
# Expect either success (if frame cap kicks in) or a clean context-length 400.
t0 = time.perf_counter()
out = chat(endpoint, [video_part(IA_FULL_FILM),
{"type": "text", "text": CAPTION_PROMPT}], timeout=1200)
report("ia-direct-full-film", t0, out)
# 3b) IA-direct with aggressive sampling caps, if raw failed or succeeded oddly
t0 = time.perf_counter()
out = chat(endpoint, [video_part(IA_FULL_FILM),
{"type": "text", "text": CAPTION_PROMPT}], timeout=1200,
mm_processor_kwargs={"fps": 0.2})
report("ia-direct-fps0.2", t0, out)
print("EXTENDED BENCH COMPLETE", flush=True)
if __name__ == "__main__":
main()

Xet Storage Details

Size:
4.97 kB
·
Xet hash:
724aa5808a713427ff90e31696dd27e2218e35faea7e1a6ceaf5f82cd40f5604

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.