motionx-ski-artifacts / code /dataset_motionx.py
fira-aslan's picture
Upload folder using huggingface_hub
723126c verified
Raw History Blame Contribute Delete
4.08 kB
import json
import numpy as np
import torch
from torch.utils.data import Dataset
from video_inputs import build_video_item, prepare
from modeling_skivlm import POSE_START, POSE_PATCH, POSE_END
IGNORE = -100
QUESTION = "Describe what the person is doing in this video."
def pose_placeholder(num_pose_tokens):
return POSE_START + POSE_PATCH * num_pose_tokens + POSE_END
class MotionXSkiDataset(Dataset):
def __init__(self, manifest_path, pose_path, processor, use_skeleton=True,
num_pose_tokens=8, video_fps=1.0, max_frames=8,
max_pixels=200704, limit=0, seed=0):
items = json.load(open(manifest_path))
if limit and limit < len(items):
rng = np.random.default_rng(seed)
idx = rng.choice(len(items), size=limit, replace=False)
items = [items[k] for k in sorted(idx)]
self.items = items
self.pose = np.load(pose_path, mmap_mode="r")
self.processor = processor
self.use_skeleton = use_skeleton
self.num_pose_tokens = num_pose_tokens
self.video_fps = video_fps
self.max_frames = max_frames
self.max_pixels = max_pixels
def __len__(self):
return len(self.items)
def _messages(self, m):
text = QUESTION
if self.use_skeleton:
text = pose_placeholder(self.num_pose_tokens) + "\n" + QUESTION
return [{
"role": "user",
"content": [build_video_item(m["video"], self.video_fps,
self.max_frames, self.max_pixels),
{"type": "text", "text": text}],
}]
def __getitem__(self, i):
for attempt in range(8):
try:
return self._build(i)
except Exception as e:
print("[dataset] skipping", self.items[i]["stem"], type(e).__name__, flush=True)
i = int(np.random.default_rng(i + attempt).integers(len(self.items)))
raise RuntimeError("too many unreadable videos")
def _build(self, i):
m = self.items[i]
messages = self._messages(m)
prompt = self.processor.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True)
answer = m["text"] + self.processor.tokenizer.eos_token
video_inputs, vkw = prepare(messages, m["video"])
enc = self.processor(text=[prompt + answer], videos=video_inputs,
return_tensors="pt", **vkw)
prompt_only = self.processor(text=[prompt], videos=video_inputs,
return_tensors="pt", **vkw)
n_prompt = prompt_only["input_ids"].shape[1]
input_ids = enc["input_ids"][0]
labels = input_ids.clone()
labels[:n_prompt] = IGNORE
x = torch.from_numpy(np.asarray(self.pose[m["i"]], dtype=np.float32))
x = x.permute(2, 0, 1).unsqueeze(-1)
return {
"input_ids": input_ids,
"attention_mask": enc["attention_mask"][0],
"labels": labels,
"pixel_values_videos": enc.get("pixel_values_videos"),
"video_grid_thw": enc.get("video_grid_thw"),
"pose": x,
}
def make_collator(pad_token_id):
def collate(batch):
maxlen = max(b["input_ids"].shape[0] for b in batch)
def pad(x, val):
return torch.cat([x, x.new_full((maxlen - x.shape[0],), val)])
out = {
"input_ids": torch.stack([pad(b["input_ids"], pad_token_id) for b in batch]),
"attention_mask": torch.stack([pad(b["attention_mask"], 0) for b in batch]),
"labels": torch.stack([pad(b["labels"], IGNORE) for b in batch]),
"pose": torch.stack([b["pose"] for b in batch]),
}
if batch[0]["pixel_values_videos"] is not None:
out["pixel_values_videos"] = torch.cat([b["pixel_values_videos"] for b in batch], dim=0)
out["video_grid_thw"] = torch.cat([b["video_grid_thw"] for b in batch], dim=0)
return out
return collate