Tao Generate Referring Expressions
NVIDIAOfficialCreated by NVIDIA Corporation
- Skill
- Workflow
- Data and AI
- Apache-2.0
- Medium risk
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
The tao-generate-referring-expressions skill provides an automated pipeline for transforming images and KITTI-format bounding box labels into rich, grounded referring expressions. By leveraging a Vision-Language Model (VLM) as a teacher, the pipeline performs four distinct steps: generating region-specific descriptions, creating holistic scene captions, producing grouped grounding phrases tied to bounding boxes, and optionally verifying the accuracy of these expressions. This tool is designed to assist in auto-labeling traffic or scene images for training datasets, offering a structured approach to data annotation that supports both Gemini and OpenAI-compatible VLM endpoints.
What it does
- Generates discriminative region descriptions for objects defined by KITTI bounding boxes.
- Produces holistic, location-agnostic scene captions for input images.
- Groups objects into semantic phrases with associated bounding box lists.
- Performs an optional verification pass to tighten or remove inaccurate bounding boxes.
- Supports multiple VLM backends including Gemini and self-hosted OpenAI-compatible services.
- Outputs unified annotations in JSONL format for downstream machine learning tasks.
When to use it
- When you need to auto-label traffic or scene images for referring expression datasets.
- When you have existing KITTI-format bounding box labels and want to add descriptive text annotations.
- When you need to verify and refine existing grounding expressions for higher accuracy.
- When you want to build a dataset of grounded referring expressions tied to specific image regions.
Advantages
- Automates complex annotation tasks using powerful VLM capabilities.
- Provides a modular workflow where steps can be enabled or disabled based on requirements.
- Includes a built-in verification step to improve the quality of generated labels.
- Flexible integration with various VLM endpoints including local self-hosted servers.
- Supports both modern JSONL output and legacy formats for compatibility with existing tools.
Usage examples
- “Run the referring expression pipeline on my traffic images.”
- The agent will guide you through setting up the image and label directories, selecting a VLM endpoint, and executing the four-step annotation process.
- “How can I verify my existing grounding expressions?”
- The agent will configure the pipeline to run the Step 3 double-check verification pass on your existing annotations to identify and correct mismatches.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/nvidia/tao-generate-referring-expressions/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip tao-generate-referring-expressions.zip -d .agents/skills
Documentation by NVIDIA Corporation
Image Referring Expression Pipeline
Standalone install? If this session was not initialized by the TAO skill bank plugin, run the
tao-setupskill first (host preflight, credentials, cross-skill discovery).
Generate referring-expression and grounding annotations from images with KITTI-format bounding box labels. A single VLM (Gemini or any OpenAI-compatible endpoint) runs four steps: per-object region descriptions, holistic image captions, grouped grounding expressions tied to bboxes, and an optional double-check verification pass.
Purpose
Transform (image, KITTI labels) pairs into a unified annotations.jsonl containing rich, grounded referring expressions. The VLM acts as a "teacher" annotator: Steps 0-1 see the image; Step 2 groups Step 0 outputs into grouping phrases with bbox lists; Step 3 (optional) re-examines those bboxes against the image and corrects mismatches.
Pipeline Architecture
Step 0: Region expression ──┐
├──▶ Step 2: Grounding expression ──▶ [Step 3: Double check]
Step 1: Image caption ──────┘ (optional)Step 0 (region_expr) — VLM emits one short discriminative phrase per KITTI bbox (
bbox_2d,type,color,description).Step 1 (image_caption) — VLM emits a holistic, location-agnostic scene caption.
Step 2 (grounding_expr) — VLM groups Step 0 objects into grouping phrases and returns one bbox list per group, optionally using Step 1's caption as extra context.
Step 3 (double_check) — VLM re-checks each Step 2 bbox against the image; bad matches are removed, slightly-off boxes get tightened.
Steps 0 and 1 run in parallel within a single thread pool (they only depend on the seed records). Each step writes its own step_<N>_*/annotations.jsonl and skips already-processed images on re-run unless workflow.force_reprocess: true.
Instructions
Initial setup
When a user wants to run this pipeline, walk through these steps:
Images: Ask for
data.image_dir, the directory containing.jpg,.jpeg, or.pngimages.KITTI labels: Ask for
data.kitti_label_dir, the directory containing one.txtlabel file per image. Each label line must use KITTI format:<type> <truncated> <occluded> <alpha> <bbox_left> <bbox_top> <bbox_right> <bbox_bottom> .... Lines with fewer than 8 fields are silently skipped. Set this even for Step 1-only runs because Steps 0 and 2 require it.Resume from existing annotations: If the user already has a unified
annotations.jsonlfrom a previous run, setdata.input_annotations_jsonlto that file instead of seeding fromdata.image_diranddata.kitti_label_dir.API access: Ask the user which VLM endpoint they want to use. Present these five options and act on the choice:
Gemini — set
vlm.backend: "gemini"; requireGOOGLE_API_KEY(env var orvlm.gemini.api_key).NIM (e.g.
https://inference-api.nvidia.com/v1) — setvlm.backend: "openai"; collectbase_url,model_name, andapi_key.TAO inference microservice (self-hosted, OpenAI-compatible). Confirm whether the server is already running:
Running — collect
base_url,model_name, and (optionally)api_key; setvlm.backend: "openai".Not running — guide the user through the
skills/applications/tao-run-inference-serviceskill, which stands up a local TAO inference microservice with an OpenAI-compatible API. Before promising a specific model, checkskills/applications/tao-run-inference-service/references/service.yamlforvalid_network_arch_config_basenames. Once the server is up, collectbase_url,model_name, and (optionally)api_key; setvlm.backend: "openai".
vLLM (self-hosted, OpenAI-compatible). Confirm whether the server is already running:
Running — collect
base_url,model_name, and (optionally)api_key; setvlm.backend: "openai".Not running — follow references/vllm_server.md to install and launch a vLLM server, then collect
base_url,model_name, and (optionally)api_key; setvlm.backend: "openai".
Custom (any other OpenAI-compatible endpoint) — set
vlm.backend: "openai"; collectbase_url,model_name, and (optionally)api_key.
If the user has no endpoint and does not want to set one up, stop and help resolve API access first.
Workflow steps: Choose one of:
Full pipeline:
["0", "1", "2", "3"]No caption generation:
["0", "2", "3"], where Step 2 falls back to image-only contextNo verification:
["0", "1", "2"]Custom subset: any supported subset of steps
Output format: Choose one of:
jsonl: unified schema onlylegacy: byte-compatible.txt.stepNfiles onlyboth: writes both formats and is the default for downstream tooling
Running the pipeline
The pipeline runs inside the TAO Toolkit container via the auto_label CLI:
auto_label generate -e /path/to/spec.yaml \
results_dir=/results \
image_referring_expression.data.image_dir=/data/images \
image_referring_expression.data.kitti_label_dir=/data/labels \
image_referring_expression.vlm.gemini.api_key=$GOOGLE_API_KEYGenerate a default spec: auto_label default_specs results_dir=/results module_name=auto_label, then set autolabel_type: "image_referring_expression". All fields support Hydra dot-notation overrides on the command line.
See references/configuration.md for the full YAML structure, all parameters, model/endpoint setup, and error patterns.
Recommended pilot workflow
Run on 5-10 images with all four steps.
Inspect
step_0_region_expr/annotations.jsonl— are object types, colors, and discriminating phrases accurate?Inspect
step_2_grounding_expr/annotations.jsonl— are objects grouped sensibly, and do bbox coordinates match the described groups?Inspect
step_3_double_check/annotations.jsonl— were mismatched bboxes removed or tightened? Are any new errors introduced (rare)?If quality is insufficient, switch the VLM to a stronger model (e.g.
gemini-2.5-proor a larger Qwen3-VL endpoint), raisemedia_resolution/max_output_tokens, then re-run withworkflow.force_reprocess=true.Scale to the full dataset once satisfied.
Configuration
Key configuration fields (full reference in references/configuration.md):
| Field | Default | Description |
|---|---|---|
workflow.steps | ["0","1","2","3"] | Which steps to execute (0=region_expr, 1=image_caption, 2=grounding_expr, 3=double_check) |
workflow.max_workers | 4 | Parallel threads per step (watch API rate limits) |
workflow.force_reprocess | false | Ignore cached per-step outputs and reprocess from scratch |
workflow.output_format | "jsonl" (set to "both" in the default spec) | "jsonl", "legacy", or "both" |
vlm.backend | "gemini" | "gemini" or "openai" (OpenAI-compatible endpoint) |
data.image_dir | required | Directory of input images (.jpg / .jpeg / .png) |
data.kitti_label_dir | required (unless resuming) | Directory of KITTI-format .txt label files |
data.input_annotations_jsonl | "" | Optional pre-seeded annotations.jsonl (skips KITTI seeding) |
Inputs
Two ways to seed the pipeline:
Image directory + KITTI labels (default). Set
data.image_diranddata.kitti_label_dir. The orchestrator walks the image directory, reads the matching<stem>.txtKITTI file, parses bboxes (fields 0 + 4-7), reads each image'swidth/heightvia PIL, and writes aseed_annotations.jsonltoresults_dir/.Pre-seeded annotations JSONL (resume / pre-computed regions). Set
data.input_annotations_jsonlto a file with one{"image_id", "image_path", "width", "height", "kitti_bboxes": [...]}object per line.
Outputs
All outputs go to results_dir/:
seed_annotations.jsonl— initial per-image records (unlessinput_annotations_jsonlwas supplied).step_0_region_expr/annotations.jsonl— addsregions[](each withbbox/bbox_2d,type,color,description).step_1_image_caption/annotations.jsonl— addscaption(string).step_2_grounding_expr/annotations.jsonl— addsexpressions[](each{text, instances: [{bbox: [x1,y1,x2,y2]}]}).step_3_double_check/annotations.jsonl— same shape as Step 2, with bboxes removed/updated.results_dir/annotations.jsonl— copy of the last completed step's output.When
workflow.output_formatis"legacy"or"both", each step also writes byte-compatiblestep_<N>_*/labels/<stem>.txt.stepNfiles for the original 2d-data-engine tooling.
Prerequisites
Container:
nvcr.io/nvidia/tao/tao-toolkit:7.3.0-pyt<!-- versions-key: images.tao_toolkit.pyt -->API access: At least one VLM endpoint (Gemini API key or OpenAI-compatible endpoint capable of image input)
PIL / Pillow: Required to read image dimensions during seeding (already present in the TAO container)
Files
- ATTRIBUTION.mdAdded by AutoGineer972 B
- BENCHMARK.md7.3 KiB
- LICENSELicence file added by AutoGineer11.2 KiB
- SKILL.md10.2 KiB
- config/skillspector-baseline.yaml834 B
- evals/evals.json849 B
- references/configuration.md12.7 KiB
- references/skill_info.yaml1.5 KiB
- references/vllm_server.md6.8 KiB
- skill-card.md4.8 KiB
- skill.oms.sig5.4 KiB
references/vllm_server.md
vLLM Server Setup for Vision-Language Models
Use this reference only when the parent SKILL.md points here for the current task. If this file conflicts with current SKILL.md, skill_info.yaml, schemas, or platform/model skills, the current authoritative source wins.
Contents
Prerequisites
Install vLLM
Option A — Docker (default, recommended)
Option B —
pip(host install, advanced)
Pick a VLM checkpoint
Launch the server
Option A — Docker (default, recommended)
Option B —
pipinstall (host launch, advanced)
Verify the endpoint
Wire the server into the pipeline
Common issues
This guide walks the user through standing up a self-hosted vLLM server that exposes an OpenAI-compatible /v1/chat/completions endpoint for vision-language models (VLMs). Once the server is running, point the pipeline at it with vlm.backend: "openai" and the matching base_url / model_name / api_key values.
1. Prerequisites
NVIDIA GPU(s) with enough VRAM for the chosen VLM (≥24 GB for 7-8B-class models, ≥80 GB for 32B+ models; tensor-parallel across multiple GPUs is supported via
--tensor-parallel-size).A recent NVIDIA driver and
nvidia-container-toolkit(for the recommended Docker path).Docker (recommended). Python ≥ 3.10 is only needed for the optional host install path.
For gated HuggingFace repos: a
HF_TOKENwith access to the model.
2. Install vLLM
Default: Docker (Option A). Use it unless you have a specific reason to install on the host — Docker pins a known-good CUDA/PyTorch/vLLM combination and avoids local environment drift. The pip path (Option B) is provided for advanced users who need to patch vLLM, debug locally, or run on a system where Docker is not available.
Option A — Docker (default, recommended)
docker pull vllm/vllm-openai:latestOption B — pip (host install, advanced)
pip install --upgrade "vllm>=0.7.0"3. Pick a VLM checkpoint
vLLM supports many vision models; the pipelines just need an OpenAI-compatible chat-completions endpoint that accepts image inputs. Common picks:
| Model | HuggingFace repo | Notes |
|---|---|---|
| Qwen3-VL-8B-Instruct | Qwen/Qwen3-VL-8B-Instruct | Newer Qwen3 family |
| Qwen3-VL-235B-A22B-Instruct | Qwen/Qwen3-VL-235B-A22B-Instruct | MoE; requires serious hardware |
If the chosen repo is gated, accept its license on the HuggingFace web UI first, then make HF_TOKEN available in your session before launching.
4. Launch the server
Use the launcher that matches the install path. Both commands listen on 0.0.0.0:8000 and serve an OpenAI-compatible API at /v1. Prefer Option A (Docker) unless you installed via pip in Section 2.
Option A — Docker (default, recommended)
set -a; source /path/to/.env; set +a # omit if already exported
docker run --runtime nvidia --gpus all \
-p 8000:8000 \
-e HF_TOKEN \
-v ~/.cache/huggingface:/root/.cache/huggingface \
vllm/vllm-openai:latest \
--model Qwen/Qwen3-VL-8B-Instruct \
--served-model-name Qwen/Qwen3-VL-8B-Instruct \
--tensor-parallel-size 1 \
--gpu-memory-utilization 0.9 \
--media-io-kwargs '{"video": {"num_frames": -1, "fps": -1}}'Option B — pip install (host launch, advanced)
set -a; source /path/to/.env; set +a # omit if already exported
vllm serve Qwen/Qwen3-VL-8B-Instruct \
--host 0.0.0.0 \
--port 8000 \
--dtype bfloat16 \
--served-model-name Qwen/Qwen3-VL-8B-Instruct \
--tensor-parallel-size 1 \
--max-model-len 32768 \
--gpu-memory-utilization 0.9 \
--media-io-kwargs '{"video": {"num_frames": -1, "fps": -1}}'Key flags:
--served-model-name <NAME>— value to use later forvlm.openai.model_name. Defaults to the full HF repo path if omitted.--tensor-parallel-size <N>— number of GPUs to shard the model across.--max-model-len <N>— context window; image tokens count against this, so leave headroom for multi-image prompts.--limit-mm-per-prompt image=<N>— max images per request. Bump it if a prompt sends multiple images.--gpu-memory-utilization <0..1>— lower (e.g.0.85) if you hit OOM at load time.
The first launch downloads weights to ~/.cache/huggingface; expect several minutes for 7B+ models.
5. Verify the endpoint
Wait for the log line Uvicorn running on http://0.0.0.0:8000, then sanity-check the server.
List served models:
curl http://localhost:8000/v1/modelsSend a minimal vision request:
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen3-VL-8B-Instruct",
"messages": [{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/640px-Cat03.jpg"}},
{"type": "text", "text": "Describe this image in one sentence."}
]
}],
"max_tokens": 128
}'A non-empty choices[0].message.content in the response confirms the server is ready.
6. Wire the server into the pipeline
Once verified, collect these three values from the running server and pass them to the pipeline spec:
base_url— e.g.http://localhost:8000/v1(no/chat/completionssuffix). If vLLM runs on another host, usehttp://<host_or_ip>:8000/v1and make sure the port is reachable.model_name— must match--served-model-nameexactly.api_key— vLLM ignores it but the OpenAI SDK requires a non-null string; use"EMPTY"if no auth is configured.
YAML snippet:
vlm:
backend: "openai"
openai:
base_url: "http://localhost:8000/v1"
model_name: "Qwen3-VL-8B-Instruct"
api_key: "EMPTY"
temperature: 0.3
max_tokens: 4096
timeout: 300Common issues
| Symptom | Fix |
|---|---|
CUDA out of memory on startup | Lower --max-model-len, drop --gpu-memory-utilization (e.g. 0.85), pick a smaller model, or raise --tensor-parallel-size to spread across more GPUs |
Model architectures ['…'] are not supported | Upgrade vLLM (pip install -U vllm) or use a newer Docker tag — VLM support changes per release |
| 401 / 403 during HuggingFace download | Set HF_TOKEN in the launch env and accept the model's license on the HuggingFace web UI |
| First request hangs for minutes | The model is still warming up — wait for the Uvicorn running log line and a successful GET /v1/models |
image is too large / token overflow | Pre-resize images before sending, or raise --max-model-len |
| Empty / truncated responses | Raise vlm.openai.max_tokens in the pipeline spec; lower temperature for more deterministic output |
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Declares allowed tools, Needs an API key
The author says: Requires docker + nvidia-container-toolkit + at least one VLM endpoint (Gemini API key or OpenAI-compatible).
Security
What our scanner noticed· Medium risk
- Large base64-encoded blobs
- Instructions that use the network
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- NVIDIA Corporation
- Publisher
- NVIDIA (Official)
- Source
- NVIDIA/skills · skills/tao-generate-referring-expressions · commit fce3cca
- Licence
- Apache License 2.0 (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE-APACHE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by NVIDIA Corporation or NVIDIA.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download tao-generate-referring-expressions.zip