Duc-Anh Nguyen

SurgGround — build log

A small vision-language model for full-length surgical video, including 2-hour procedures — natural-language temporal grounding, phase/step segmentation, remaining-surgery-duration, grounded QA with calibrated abstention — trained and served on a single 24 GB consumer GPU. Independent personal project, built as hands-on prep for a "Multimodal AI for Video Understanding" internship.

P0–P2 merged to main 93 tests passing 2 owned RTX 4090s updated 2026-09-15


What it is

At 1 fps a 2-hour procedure is ~7,200 frames — impossible for any vision-language model to see in one pass. The project's spine is fitting a 30–150 minute procedure into a small VLM (InternVL3-2B) at low token cost via a trained TemporalConnector with always-on token reduction, then localizing precisely inside it with a hierarchical-coarse-to-fine or retrieval regime depending on length. Three research bets sit on top of that engineering: abstention-shaped offline RL that penalizes confident wrong answers as much as missed ones, a procedure-graph constraint that makes an impossible phase order unrepresentable, and a clean compression-vs-hierarchy-vs-retrieval comparison across the length range — all trained and evaluated on two owned RTX 4090s, no cluster required.


Status now

2 / 12
phases merged (P0 scaffold, P2 task+metric harness) + P1 data code merged
93
passing tests, up from 40 at scaffold
3
training datasets landing on the GPU boxes right now
2 × 4090
owned RTX 4090s, running training + eval in parallel

Phases

PhaseWhatStatus
P0Scaffold, config, pure modulesmerged
P1Six dataset parsers, decode, splitscode merged · data landing
P2Task construction + metric modulesmerged
P3Zero-shot baseline harness — first real numbersnext
P4TemporalConnector + QLoRA SFT — the complete-result gateplanned
P5–P9Long-video regimes, procedure-graph decode, offline RL, reliability, OODplanned
P10–P11Optional JEPA pretraining, demo + reportplanned

Datasets, right now

DatasetState
Cholec80landed
GraSPlanded
MultiBypass140downloading (4 of 6 zips)
The two genuinely long (~2-hour-class) procedures in the plan — GraSP and MultiBypass140 — are the headline datasets; Cholec80 is the fast-iteration control.

Real work, not just a plan

The first real download of MultiBypass140 on the training box filled a 242 GB disk to zero bytes free and produced not one usable frame.

What happened

The download script located each surgical centre's videos at a fixed path inside its zip. Real S3 archives from this dataset don't agree on layout — some wrap their contents in an extra directory, some don't — so every "wrapped" zip's ~40–90 GB of video matched no path the script knew to check. It was never extracted to frames, and — since the script only deleted a video after successfully extracting it — never deleted either. It just accumulated, silently, until a disk-full error hit an unattended background job mid-write and the job hung indefinitely.

Fix

Rewrote the extraction step to search for every directory literally named videos after each zip, wherever it landed, and infer the surgical centre from the matched path itself instead of assuming where it would be. Verified against a synthetic reproduction of both zip layouts, then against the real zip that had triggered the incident — found, extracted, and cleaned up correctly. No real data was lost: the frame output directory on the training GPU was never even touched, since the buggy step never got that far.


What's next

  1. Finish landing all three datasets on the training box, build the frame index, and spot-check parser output against the raw annotations — the actual P1 exit criteria.
  2. P3 — zero-shot baselines. Run ≥2 open video-LLMs on grounding, phase segmentation and QA across both the short and long-video regimes. Expected finding: zero-shot grounding on a 2.5-hour procedure is near-random — quantifying that gap is the point.
  3. P4 — the first complete result. QLoRA-train the TemporalConnector on the 2B backbone; target ≥10-point grounding improvement over the best zero-shot baseline and a non-trivial number on the 2.5-hour dataset. This alone stands as a result even if nothing after it ships in time.

Full technical spec, every design decision, and the day-to-day status log are in the repo.