feat(actpred): 多帧注意力架构改造(Transformer 替换 concat 融合,支持多帧图像+历史动作序列)
This commit is contained in:
1 parent
2959197597
commit
4dd25486f8
9 files changed
+272
-147
No files matched your search
+23
-6
@@ -28,6 +28,7 @@ class ActionPredictorInference:
|
||||
|
||||
self.action_dim = self._data_cfg.action_dim
|
||||
self.history_len = self._data_cfg.history_len
|
||||
self.frame_len = self._data_cfg.frame_len
|
||||
|
||||
self._transform = transforms.Compose([
|
||||
transforms.Resize((self._data_cfg.image_size, self._data_cfg.image_size)),
|
||||
@@ -61,13 +62,23 @@ class ActionPredictorInference:
|
||||
self._action_std = stats[1].astype(np.float32)
|
||||
|
||||
@torch.no_grad()
|
||||
def predict(self, image: np.ndarray, action_history: np.ndarray) -> np.ndarray:
|
||||
def predict(self, images, action_history: np.ndarray) -> np.ndarray:
|
||||
"""images: 长度为 frame_len 的 RGB 图像序列(旧→新,末帧为当前帧)"""
|
||||
if not isinstance(images, (list, tuple)):
|
||||
images = [images]
|
||||
if len(images) != self._data_cfg.frame_len:
|
||||
raise ValueError(
|
||||
f"images 应为 {self._data_cfg.frame_len} 帧,实际为 {len(images)} 帧。"
|
||||
f"冷启动时可重复传入同一帧。")
|
||||
expected_shape = (self._data_cfg.history_len, self._data_cfg.action_dim)
|
||||
if action_history.shape != expected_shape:
|
||||
raise ValueError(
|
||||
f"action_history 形状应为 {expected_shape},实际为 {action_history.shape}")
|
||||
img = Image.fromarray(image) if isinstance(image, np.ndarray) else image
|
||||
img_tensor = self._transform(img).unsqueeze(0).to(self._device)
|
||||
frames = []
|
||||
for image in images:
|
||||
img = Image.fromarray(image) if isinstance(image, np.ndarray) else image
|
||||
frames.append(self._transform(img))
|
||||
img_tensor = torch.stack(frames).unsqueeze(0).to(self._device) # (1, F, 3, S, S)
|
||||
history = torch.tensor(action_history, dtype=torch.float32)
|
||||
if self._action_mean is not None:
|
||||
history = (history - self._action_mean) / self._action_std
|
||||
@@ -93,7 +104,9 @@ def parse_action_history(s: str, action_dim: int) -> np.ndarray:
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="actpred inference")
|
||||
parser.add_argument("--model", required=True, help="checkpoint path")
|
||||
parser.add_argument("--image", required=True, help="image file path")
|
||||
parser.add_argument("--images", required=True, nargs="+",
|
||||
help="按时间顺序(旧→新)传入 frame_len 个图像路径;"
|
||||
"冷启动时可重复传同一帧路径")
|
||||
parser.add_argument("--action-history", required=True,
|
||||
help="冒号分隔各步,每步 action_dim 个值,共 history_len 步。"
|
||||
"e.g. '0,0,0,0:1,0,0,0' (action_dim=4, history_len=2)")
|
||||
@@ -106,9 +119,13 @@ def main():
|
||||
predictor = ActionPredictorInference(args.model, args.device)
|
||||
action_dim = args.action_dim or predictor.action_dim
|
||||
|
||||
image = Image.open(args.image).convert("RGB")
|
||||
if len(args.images) != predictor.frame_len:
|
||||
raise SystemExit(
|
||||
f"--images 需传入 {predictor.frame_len} 个路径(旧→新),"
|
||||
f"实际为 {len(args.images)} 个。冷启动时可重复传同一帧路径。")
|
||||
images = [np.array(Image.open(p).convert("RGB")) for p in args.images]
|
||||
history = parse_action_history(args.action_history, action_dim)
|
||||
predicted = predictor.predict(np.array(image), history)
|
||||
predicted = predictor.predict(images, history)
|
||||
|
||||
if args.output_format == "json":
|
||||
print(json.dumps({"predicted_action": predicted.tolist()}, indent=2))
|
||||
|
||||
Reference in new issue
Block a user