Sherlockhu commited on
Commit
fdfc898
·
verified ·
1 Parent(s): 5b9944e

Add inference script

Browse files
Files changed (1) hide show
  1. inference_drone_vla.py +80 -0
inference_drone_vla.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ 🎯 Drone VLA Inference: Image + Text → [Vx, Vy, Vz, Yaw_rate]
4
+
5
+ Usage:
6
+ python inference_drone_vla.py --model_repo YOUR_USER/drone-vla --image frame.jpg --instruction "fly forward"
7
+ python inference_drone_vla.py --model_repo YOUR_USER/drone-vla --live --fps 10
8
+ """
9
+ import os, sys, json, time, argparse, torch, torch.nn as nn, numpy as np
10
+ from PIL import Image
11
+ from transformers import AutoProcessor, AutoModelForImageTextToText
12
+ from peft import PeftModel
13
+
14
+ class ActionHead(nn.Module):
15
+ def __init__(self, hidden_size=1024, action_dim=4, hidden_dim=256):
16
+ super().__init__()
17
+ self.net = nn.Sequential(
18
+ nn.Linear(hidden_size, hidden_dim), nn.GELU(), nn.Dropout(0.1),
19
+ nn.Linear(hidden_dim, hidden_dim), nn.GELU(), nn.Dropout(0.1),
20
+ nn.Linear(hidden_dim, action_dim), nn.Tanh())
21
+ def forward(self, x): return self.net(x)
22
+
23
+ class DroneVLAInference:
24
+ def __init__(self, model_repo, base_model="Qwen/Qwen3.5-0.8B", device="cuda"):
25
+ self.device = torch.device(device if torch.cuda.is_available() else "cpu")
26
+ print(f"Loading {base_model}...")
27
+ base = AutoModelForImageTextToText.from_pretrained(base_model, torch_dtype=torch.bfloat16, trust_remote_code=True)
28
+ self.model = PeftModel.from_pretrained(base, model_repo).to(self.device).eval()
29
+ from huggingface_hub import hf_hub_download
30
+ with open(hf_hub_download(model_repo, "vla_config.json")) as f: cfg = json.load(f)
31
+ self.action_head = ActionHead(cfg.get('hidden_size',1024), cfg.get('action_dim',4))
32
+ self.action_head.load_state_dict(torch.load(hf_hub_download(model_repo,"action_head.pt"), map_location='cpu'))
33
+ self.action_head = self.action_head.to(self.device).eval()
34
+ self.processor = AutoProcessor.from_pretrained(base_model, trust_remote_code=True, min_pixels=224*224, max_pixels=512*512)
35
+ self.labels = cfg.get('action_labels', ['Vx','Vy','Vz','Yaw_rate'])
36
+ print(f"✅ Ready! Actions: {self.labels}")
37
+
38
+ @torch.no_grad()
39
+ def predict(self, image, instruction="navigate forward"):
40
+ if isinstance(image, str): image = Image.open(image).convert('RGB')
41
+ elif isinstance(image, np.ndarray): image = Image.fromarray(image).convert('RGB')
42
+ msgs = [{"role":"user","content":[{"type":"image","image":image},{"type":"text","text":instruction}]}]
43
+ text = self.processor.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True)
44
+ inputs = self.processor(text=[text], images=[image], return_tensors="pt").to(self.device)
45
+ out = self.model(**inputs, output_hidden_states=True, return_dict=True)
46
+ feat = out.hidden_states[-1][:, -1, :]
47
+ action = self.action_head(feat.float()).squeeze(0).cpu().numpy()
48
+ return {'action': action.tolist(), 'labels': {l: float(action[i]) for i,l in enumerate(self.labels)}}
49
+
50
+ def main():
51
+ p = argparse.ArgumentParser()
52
+ p.add_argument('--model_repo', type=str, required=True)
53
+ p.add_argument('--base_model', type=str, default='Qwen/Qwen3.5-0.8B')
54
+ p.add_argument('--image', type=str, default=None)
55
+ p.add_argument('--instruction', type=str, default='navigate forward')
56
+ p.add_argument('--live', action='store_true')
57
+ p.add_argument('--fps', type=int, default=10)
58
+ p.add_argument('--device', type=str, default='cuda')
59
+ a = p.parse_args()
60
+ vla = DroneVLAInference(a.model_repo, a.base_model, a.device)
61
+
62
+ if a.image:
63
+ r = vla.predict(a.image, a.instruction)
64
+ print(f"\n🎯 Action:")
65
+ for l, v in r['labels'].items():
66
+ print(f" {l:>10s}: {'█'*int(abs(v)*20):<20s} {v:+.3f}")
67
+ elif a.live:
68
+ import mss
69
+ print(f"🔴 Live @ {a.fps}Hz | {a.instruction}")
70
+ with mss.mss() as sct:
71
+ while True:
72
+ t0 = time.time()
73
+ ss = sct.grab(sct.monitors[1])
74
+ img = Image.frombytes("RGB", ss.size, ss.bgra, "raw", "BGRX").resize((224,224))
75
+ r = vla.predict(img, a.instruction)
76
+ print(f"\r🎮 {' | '.join(f'{k}={v:+.2f}' for k,v in r['labels'].items())}", end='', flush=True)
77
+ dt = 1/a.fps - (time.time()-t0)
78
+ if dt > 0: time.sleep(dt)
79
+
80
+ if __name__ == '__main__': main()