Spaces:
Running on L40S
Running on L40S
File size: 6,504 Bytes
9f818c5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: OpenMDW-1.1
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
import torch
from cosmos_framework.data.vfm.action.domain_utils import EMBODIMENT_TO_RAW_ACTION_DIM, get_domain_id
from cosmos_framework.data.vfm.action.json_formatter import ActionPromptJsonFormatter
from cosmos_framework.data.vfm.action.transforms import (
build_sequence_plan_from_mode,
find_closest_target_size,
pad_action_to_max_dim,
reflection_pad_to_target,
)
from cosmos_framework.inference.args import ModelMode
from cosmos_framework.inference.vision import read_media_frames
from cosmos_framework.utils.vfm.data_utils import get_vision_data_resolution
def _load_actions(
action_path: Path | str | None,
model_mode: ModelMode,
action_chunk_size: int,
max_action_dim: int,
raw_action_dim: int | None,
) -> torch.Tensor:
"""Load actions from JSON (or zeros for policy mode and inverse dynamics mode). Returns padded action tensor."""
match model_mode:
case ModelMode.FORWARD_DYNAMICS:
assert action_path is not None, "action_path is required for forward_dynamics mode"
p = Path(str(action_path))
raw = torch.tensor(json.loads(p.read_text()), dtype=torch.float32)
raw_dim = raw.shape[-1]
assert raw_dim == raw_action_dim, (
f"Raw action dimension from file ({raw_dim}) does not match expected dimension ({raw_action_dim})"
)
return pad_action_to_max_dim(raw, max_action_dim)
case ModelMode.POLICY | ModelMode.INVERSE_DYNAMICS:
assert raw_action_dim is not None, "raw_action_dim is required for policy and inverse_dynamics modes"
return torch.zeros(action_chunk_size, max_action_dim, dtype=torch.float32)
case _:
raise ValueError(f"Unsupported action model_mode: {model_mode}")
def _format_prompt(
prompt: str,
view_point: str,
video: torch.Tensor,
action: torch.Tensor,
fps: torch.Tensor,
image_size: torch.Tensor,
) -> str:
"""Helper function to build the action prompt with optional duration and resolution info."""
data_dict = {
"viewpoint": view_point,
"ai_caption": prompt.strip(),
"video": video,
"action": action,
"conditioning_fps": fps,
"image_size": image_size,
}
prompt_json_formatter = ActionPromptJsonFormatter()
ai_caption = prompt_json_formatter(data_dict)[prompt_json_formatter.caption_key]
if isinstance(ai_caption, dict):
ai_caption = json.dumps(ai_caption)
return ai_caption
def build_action_batch(
*,
video: torch.Tensor,
action: torch.Tensor,
raw_action_dim: int,
prompt: str,
view_point: str,
domain_name: str,
model_mode: ModelMode,
action_chunk_size: int,
fps: int,
resolution: str | None = None,
input_video_key: str,
batch_size: int = 1,
device: Any = "cuda",
) -> dict:
"""Build an Action data batch from pre-loaded video and action tensors."""
target_frames = action_chunk_size + 1
_, num_frames, h, w = video.shape
if num_frames < target_frames:
pad = video[:, -1:].repeat(1, target_frames - num_frames, 1, 1)
video = torch.cat([video, pad], dim=1)
elif num_frames > target_frames:
video = video[:, :target_frames]
if resolution is None:
resolution = get_vision_data_resolution((h, w))
target_w, target_h = find_closest_target_size(h, w, resolution)
pad_dict: dict[str, Any] = {"video": video}
reflection_pad_to_target(pad_dict, ["video"], keep_aspect_ratio=True, target_w=target_w, target_h=target_h)
video_padded = pad_dict["video"]
padded_image_size = pad_dict["image_size"]
sequence_plan = build_sequence_plan_from_mode(
mode=model_mode.value,
video_length=target_frames,
action_length=action_chunk_size,
has_text=True,
)
ai_caption = _format_prompt(
prompt=prompt,
view_point=view_point,
video=video_padded,
action=action,
fps=torch.tensor(fps, dtype=torch.long),
image_size=padded_image_size,
)
return {
input_video_key: [[video_padded]] * batch_size,
"action": [[action]] * batch_size,
"raw_action_dim": [torch.tensor(raw_action_dim, dtype=torch.long)] * batch_size,
"mode": [model_mode.value] * batch_size,
"ai_caption": [ai_caption] * batch_size,
"prompt": [prompt] * batch_size,
"conditioning_fps": [torch.tensor(fps, dtype=torch.long)] * batch_size,
"image_size": padded_image_size.unsqueeze(0).to(device=device),
"domain_id": [torch.tensor(get_domain_id(domain_name), dtype=torch.long)] * batch_size,
"sequence_plan": [sequence_plan] * batch_size,
}
def get_action_sample_data(
model_config: Any,
*,
batch_size: int,
prompt: str,
vision_path: Path,
model_mode: ModelMode,
action_path: Path | None,
domain_name: str,
view_point: str = "ego_view",
resolution: str,
action_chunk_size: int,
max_action_dim: int,
fps: int,
device: Any,
) -> dict:
"""Load observation image/video + optional actions and build an Action inference batch."""
domain_name = domain_name.lower().strip()
if domain_name not in EMBODIMENT_TO_RAW_ACTION_DIM:
raise ValueError(
f"invalid domain_name {domain_name!r}; expected one of {sorted(EMBODIMENT_TO_RAW_ACTION_DIM.keys())}"
)
raw_action_dim = EMBODIMENT_TO_RAW_ACTION_DIM[domain_name]
frames, _ = read_media_frames(Path(vision_path), max_frames=action_chunk_size + 1)
assert action_path is not None or raw_action_dim is not None, (
"Either action_path or raw_action_dim must be provided"
)
action = _load_actions(action_path, model_mode, action_chunk_size, max_action_dim, raw_action_dim)
return build_action_batch(
video=frames,
action=action,
raw_action_dim=raw_action_dim,
prompt=prompt,
view_point=view_point,
domain_name=domain_name,
model_mode=model_mode,
action_chunk_size=action_chunk_size,
fps=fps,
resolution=resolution,
input_video_key=model_config.input_video_key,
batch_size=batch_size,
device=device,
)
|