vla / scripts /run_external_vla_baseline.py
anhtld's picture
Initial commit: DoVLA-CIL codebase (h=16 breakthrough)
adc02fa verified
Raw
History Blame
4.75 kB
#!/usr/bin/env python
from __future__ import annotations
import argparse
import json
import os
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from dovla_cil.eval.external_vla_baseline import ( # noqa: E402
ExternalVLABaselineSpec,
assess_external_vla_baseline,
build_external_vla_plan,
run_external_vla_entrypoint,
write_external_vla_plan,
)
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description=(
"Prepare or run an isolated public VLA baseline adapter. This command never downloads "
"weights or imports heavy VLA packages unless a user-provided adapter entrypoint is "
"run."
)
)
parser.add_argument("--model-family", default="smolvla", choices=["smolvla", "openvla"])
parser.add_argument("--checkpoint", default=None, help="Local checkpoint/model directory.")
parser.add_argument("--dataset", default=None, help="DoVLA-CIL dataset directory to evaluate.")
parser.add_argument("--out", required=True, help="Output directory for plan and metrics.")
parser.add_argument("--revision", default=None, help="Pinned public checkpoint revision.")
parser.add_argument("--repo-id", default=None, help="Public Hugging Face repo id.")
parser.add_argument("--package-name", default=None, help="External package to check/import.")
parser.add_argument(
"--python", default="python", help="Python executable to use in the generated env plan."
)
parser.add_argument(
"--adapter-entrypoint",
default=None,
help=(
"External adapter formatted as module:function. The function receives "
"(spec_dict, plan_dict) and returns JSON-serializable metrics."
),
)
parser.add_argument(
"--adapter-config",
type=Path,
default=None,
help="Secret-free JSON object passed to the adapter as spec metadata.",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Write a plan and exit without requiring the external baseline to be ready.",
)
parser.add_argument(
"--require-ready",
action="store_true",
help="Exit nonzero unless package, checkpoint, dataset, and adapter entrypoint are ready.",
)
return parser.parse_args()
def main() -> int:
args = parse_args()
adapter_metadata = _load_adapter_config(args.adapter_config)
spec = ExternalVLABaselineSpec(
model_family=args.model_family,
checkpoint_path=args.checkpoint,
dataset_dir=args.dataset,
out_dir=args.out,
revision=args.revision,
repo_id=args.repo_id,
package_name=args.package_name,
python=args.python,
adapter_entrypoint=args.adapter_entrypoint,
metadata=adapter_metadata,
)
out_dir = Path(args.out)
out_dir.mkdir(parents=True, exist_ok=True)
plan_path = write_external_vla_plan(spec, out_dir)
plan = build_external_vla_plan(spec)
status = assess_external_vla_baseline(spec)
print(f"external VLA plan: {plan_path}")
print(json.dumps(status.to_dict(), indent=2, sort_keys=True))
if args.dry_run:
return 0
if args.require_ready and not status.ready:
print(
"External VLA baseline is not ready. Use the generated plan to create an isolated "
"environment, download the public checkpoint, and provide an adapter entrypoint.",
file=sys.stderr,
)
return 2
if not args.adapter_entrypoint:
print(
"No adapter entrypoint was provided; wrote a reproducible plan but did not run "
"metrics.",
file=sys.stderr,
)
return 2
metrics = run_external_vla_entrypoint(args.adapter_entrypoint, spec, plan)
metrics_path = out_dir / "external_vla_metrics.json"
metrics_path.write_text(json.dumps(metrics, indent=2, sort_keys=True), encoding="utf-8")
print(f"external VLA metrics: {metrics_path}")
return 0
def _load_adapter_config(path: Path | None) -> dict[str, object]:
if path is None:
return {}
payload = json.loads(os.path.expandvars(path.read_text(encoding="utf-8")))
if not isinstance(payload, dict):
raise ValueError("adapter config must be a JSON object")
forbidden = {"api_key", "apikey", "token", "secret", "password"}
unsafe = [key for key in payload if key.lower() in forbidden]
if unsafe:
raise ValueError(f"adapter config must not contain secrets: {', '.join(sorted(unsafe))}")
return payload
if __name__ == "__main__":
raise SystemExit(main())