vla / workspace /scripts /eval_hybrid_checkpoint.py
anhtld's picture
auto-sync 2026-07-02T13:37:00Z workspace (part 32)
68442cd verified
Raw
History Blame Contribute Delete
4.68 kB
#!/usr/bin/env python
"""
Evaluate DoVLA-Hybrid checkpoint with DIRECT selection.
"""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
import torch
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from dovla_cil.data.datasets import CILDataset
from dovla_cil.models.dovla_hybrid import DoVLAHybrid
from dovla_cil.utils.io import write_json
def evaluate_hybrid_checkpoint(
checkpoint_path: str | Path,
dataset_dir: str | Path,
output_path: str | Path | None = None,
device: str = "auto",
) -> dict:
"""Evaluate Hybrid with direct selection."""
resolved_device = (
"cuda" if device == "auto" and torch.cuda.is_available() else "cpu"
if device == "auto"
else device
)
checkpoint = torch.load(checkpoint_path, map_location=resolved_device, weights_only=False)
args = checkpoint["args"]
model = DoVLAHybrid(
obs_dim=70,
action_dim=32,
lang_dim=0,
d_model=args["d_model"],
n_heads=args["n_heads"],
n_layers=args["n_layers"],
d_ff=args["d_ff"],
dropout=0.1
).to(resolved_device)
model.load_state_dict(checkpoint["model_state_dict"])
model.eval()
dataset = CILDataset(dataset_dir)
val_group_ids = list(dataset.group_ids)
selected_success = 0
oracle_success = 0
top1_correct = 0
def pad(vec, target):
if len(vec) >= target:
return vec[:target]
return vec + [0.0] * (target - len(vec))
with torch.no_grad():
for group_id in val_group_ids:
records = dataset.get_group(group_id)
if not records:
continue
obs_list = []
for r in records:
obs_data = r.observation_inline
if "state" in obs_data:
obs = list(obs_data["state"])
else:
obs = []
for v in obs_data.values():
if isinstance(v, list):
obs.extend(v)
elif isinstance(v, (int, float)):
obs.append(v)
obs = pad([float(x) for x in obs], 70)
obs_list.append(obs)
obs = torch.tensor([obs_list[0]], dtype=torch.float32, device=resolved_device)
actions = torch.tensor(
[pad(r.action_chunk.flat_values, 32) for r in records],
dtype=torch.float32,
device=resolved_device
).unsqueeze(0)
# DIRECT prediction
pred_rewards, pred_success_probs = model(obs, actions, lang=None)
# Hybrid selection
hybrid_scores = (pred_success_probs * pred_rewards).squeeze(0).cpu().tolist()
selected = max(range(len(records)), key=lambda i: hybrid_scores[i])
utilities = [r.reward.score for r in records]
best_utility = max(utilities)
is_selected_success = int(records[selected].reward.terminal_success)
has_oracle_success = int(any(r.reward.terminal_success for r in records))
is_top1 = int(abs(utilities[selected] - best_utility) < 1e-6)
selected_success += is_selected_success
oracle_success += has_oracle_success
top1_correct += is_top1
group_count = len(val_group_ids)
result = {
"checkpoint": str(checkpoint_path),
"dataset": str(dataset_dir),
"num_groups": group_count,
"selected_success_rate": selected_success / group_count,
"oracle_success_rate": oracle_success / group_count,
"top1_action_selection": top1_correct / group_count,
"approach": "hybrid_direct_scoring"
}
if output_path:
write_json(result, output_path)
return result
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--checkpoint", type=Path, required=True)
parser.add_argument("--dataset", type=Path, required=True)
parser.add_argument("--out", type=Path, required=True)
parser.add_argument("--device", default="auto")
args = parser.parse_args(argv)
result = evaluate_hybrid_checkpoint(
args.checkpoint, args.dataset, args.out, args.device
)
print(f"Selected success rate: {result['selected_success_rate']:.4f}")
print(f"Top-1 selection: {result['top1_action_selection']:.4f}")
print(f"Oracle success: {result['oracle_success_rate']:.4f}")
return 0
if __name__ == "__main__":
sys.exit(main())