xizaoqu commited on
Commit ·
8cf039f
1
Parent(s): 0679fff
update
Browse files- README.md +1 -1
- algorithms/worldmem/df_video.py +1 -16
- algorithms/worldmem/models/attention.py +0 -9
- app.py +72 -48
- app.sh +0 -50
- split_checkpoint.py +0 -9
- test.py +0 -29
README.md
CHANGED
|
@@ -65,5 +65,5 @@ url={https://openreview.net/forum?id=2z1HT5lw5M}
|
|
| 65 |
|
| 66 |
## 👏 Acknowledgements
|
| 67 |
- [Diffusion Forcing](https://github.com/buoyancy99/diffusion-forcing): Diffusion Forcing provides flexible training and inference strategies for our methods.
|
| 68 |
-
- [Minedojo](https://github.com/MineDojo/MineDojo): We collect our
|
| 69 |
- [Open-oasis](https://github.com/etched-ai/open-oasis): Our model architecture is based on Open-oasis. We also use pretrained VAE and DiT weight from it.
|
|
|
|
| 65 |
|
| 66 |
## 👏 Acknowledgements
|
| 67 |
- [Diffusion Forcing](https://github.com/buoyancy99/diffusion-forcing): Diffusion Forcing provides flexible training and inference strategies for our methods.
|
| 68 |
+
- [Minedojo](https://github.com/MineDojo/MineDojo): We collect our Minecraft dataset from Minedojo.
|
| 69 |
- [Open-oasis](https://github.com/etched-ai/open-oasis): Our model architecture is based on Open-oasis. We also use pretrained VAE and DiT weight from it.
|
algorithms/worldmem/df_video.py
CHANGED
|
@@ -333,7 +333,6 @@ class WorldMemMinecraft(DiffusionForcingBase):
|
|
| 333 |
Args:
|
| 334 |
cfg (DictConfig): Configuration object.
|
| 335 |
"""
|
| 336 |
-
# self.metrics = cfg.metrics
|
| 337 |
self.n_tokens = cfg.n_frames // cfg.frame_stack # number of max tokens for the model
|
| 338 |
self.n_frames = cfg.n_frames
|
| 339 |
if hasattr(cfg, "n_tokens"):
|
|
@@ -352,13 +351,6 @@ class WorldMemMinecraft(DiffusionForcingBase):
|
|
| 352 |
self.log_video = cfg.log_video
|
| 353 |
self.self_consistency_eval = getattr(cfg, "self_consistency_eval", False)
|
| 354 |
|
| 355 |
-
self.is_interactive = cfg.get("is_interactive", False)
|
| 356 |
-
if self.is_interactive:
|
| 357 |
-
self_frames = None
|
| 358 |
-
self_poses = None
|
| 359 |
-
self_memory_c2w = None
|
| 360 |
-
self_frame_idx = None
|
| 361 |
-
|
| 362 |
super().__init__(cfg)
|
| 363 |
|
| 364 |
def _build_model(self):
|
|
@@ -910,11 +902,4 @@ class WorldMemMinecraft(DiffusionForcingBase):
|
|
| 910 |
xs_pred = self.decode(xs_pred[n_context_frames:].to(device)).cpu()
|
| 911 |
|
| 912 |
return xs_pred.cpu().numpy(), self_frames.cpu().numpy(), self_actions.cpu().numpy(), \
|
| 913 |
-
self_poses.cpu().numpy(), self_memory_c2w.cpu().numpy(), self_frame_idx.cpu().numpy()
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
def reset(self):
|
| 917 |
-
self_frames = None
|
| 918 |
-
self_poses = None
|
| 919 |
-
self_memory_c2w = None
|
| 920 |
-
self_frame_idx = None
|
|
|
|
| 333 |
Args:
|
| 334 |
cfg (DictConfig): Configuration object.
|
| 335 |
"""
|
|
|
|
| 336 |
self.n_tokens = cfg.n_frames // cfg.frame_stack # number of max tokens for the model
|
| 337 |
self.n_frames = cfg.n_frames
|
| 338 |
if hasattr(cfg, "n_tokens"):
|
|
|
|
| 351 |
self.log_video = cfg.log_video
|
| 352 |
self.self_consistency_eval = getattr(cfg, "self_consistency_eval", False)
|
| 353 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 354 |
super().__init__(cfg)
|
| 355 |
|
| 356 |
def _build_model(self):
|
|
|
|
| 902 |
xs_pred = self.decode(xs_pred[n_context_frames:].to(device)).cpu()
|
| 903 |
|
| 904 |
return xs_pred.cpu().numpy(), self_frames.cpu().numpy(), self_actions.cpu().numpy(), \
|
| 905 |
+
self_poses.cpu().numpy(), self_memory_c2w.cpu().numpy(), self_frame_idx.cpu().numpy()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
algorithms/worldmem/models/attention.py
CHANGED
|
@@ -11,15 +11,6 @@ from einops import rearrange
|
|
| 11 |
from .rotary_embedding_torch import RotaryEmbedding, apply_rotary_emb
|
| 12 |
import numpy as np
|
| 13 |
|
| 14 |
-
def create_attention_bias(f1, f2, device=None, dtype=torch.float32):
|
| 15 |
-
f = f1 + f2
|
| 16 |
-
mask = torch.zeros((f, f), dtype=dtype, device=device)
|
| 17 |
-
if f1 > 0:
|
| 18 |
-
mask[:f1, :f1] = float('-inf')
|
| 19 |
-
if f2 > 0:
|
| 20 |
-
mask[f1:, f1:] = float('-inf')
|
| 21 |
-
return mask
|
| 22 |
-
|
| 23 |
class TemporalAxialAttention(nn.Module):
|
| 24 |
def __init__(
|
| 25 |
self,
|
|
|
|
| 11 |
from .rotary_embedding_torch import RotaryEmbedding, apply_rotary_emb
|
| 12 |
import numpy as np
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
class TemporalAxialAttention(nn.Module):
|
| 15 |
def __init__(
|
| 16 |
self,
|
app.py
CHANGED
|
@@ -21,57 +21,11 @@ import spaces
|
|
| 21 |
from algorithms.worldmem import WorldMemMinecraft
|
| 22 |
from huggingface_hub import hf_hub_download
|
| 23 |
import tempfile
|
|
|
|
|
|
|
| 24 |
|
| 25 |
torch.set_float32_matmul_precision("high")
|
| 26 |
|
| 27 |
-
ACTION_KEYS = [
|
| 28 |
-
"inventory",
|
| 29 |
-
"ESC",
|
| 30 |
-
"hotbar.1",
|
| 31 |
-
"hotbar.2",
|
| 32 |
-
"hotbar.3",
|
| 33 |
-
"hotbar.4",
|
| 34 |
-
"hotbar.5",
|
| 35 |
-
"hotbar.6",
|
| 36 |
-
"hotbar.7",
|
| 37 |
-
"hotbar.8",
|
| 38 |
-
"hotbar.9",
|
| 39 |
-
"forward",
|
| 40 |
-
"back",
|
| 41 |
-
"left",
|
| 42 |
-
"right",
|
| 43 |
-
"cameraY",
|
| 44 |
-
"cameraX",
|
| 45 |
-
"jump",
|
| 46 |
-
"sneak",
|
| 47 |
-
"sprint",
|
| 48 |
-
"swapHands",
|
| 49 |
-
"attack",
|
| 50 |
-
"use",
|
| 51 |
-
"pickItem",
|
| 52 |
-
"drop",
|
| 53 |
-
]
|
| 54 |
-
|
| 55 |
-
# Mapping of input keys to action names
|
| 56 |
-
KEY_TO_ACTION = {
|
| 57 |
-
"Q": ("forward", 1),
|
| 58 |
-
"E": ("back", 1),
|
| 59 |
-
"W": ("cameraY", -1),
|
| 60 |
-
"S": ("cameraY", 1),
|
| 61 |
-
"A": ("cameraX", -1),
|
| 62 |
-
"D": ("cameraX", 1),
|
| 63 |
-
"U": ("drop", 1),
|
| 64 |
-
"N": ("noop", 1),
|
| 65 |
-
"1": ("hotbar.1", 1),
|
| 66 |
-
}
|
| 67 |
-
|
| 68 |
-
example_images = [
|
| 69 |
-
["1", "assets/ice_plains.png", "turn rightgo backward→look up→turn left→look down→turn right→go forward→turn left", 20, 3, 8],
|
| 70 |
-
["2", "assets/place.png", "put item→go backward→put item→go backward→go around", 20, 3, 8],
|
| 71 |
-
["3", "assets/rain_sunflower_plains.png", "turn right→look up→turn right→look down→turn left→go backward→turn left", 20, 3, 8],
|
| 72 |
-
["4", "assets/desert.png", "turn 360 degree→turn right→go forward→turn left", 20, 3, 8],
|
| 73 |
-
]
|
| 74 |
-
|
| 75 |
def load_custom_checkpoint(algo, checkpoint_path):
|
| 76 |
hf_ckpt = str(checkpoint_path).split('/')
|
| 77 |
repo_id = '/'.join(hf_ckpt[:2])
|
|
@@ -81,6 +35,26 @@ def load_custom_checkpoint(algo, checkpoint_path):
|
|
| 81 |
ckpt = torch.load(model_path, map_location=torch.device('cpu'))
|
| 82 |
algo.load_state_dict(ckpt['state_dict'], strict=False)
|
| 83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
def parse_input_to_tensor(input_str):
|
| 86 |
"""
|
|
@@ -137,6 +111,56 @@ def enable_amp(model, precision="16-mixed"):
|
|
| 137 |
model.forward = amp_forward
|
| 138 |
return model
|
| 139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
memory_frames = []
|
| 141 |
input_history = ""
|
| 142 |
ICE_PLAINS_IMAGE = "assets/ice_plains.png"
|
|
|
|
| 21 |
from algorithms.worldmem import WorldMemMinecraft
|
| 22 |
from huggingface_hub import hf_hub_download
|
| 23 |
import tempfile
|
| 24 |
+
import os
|
| 25 |
+
import requests
|
| 26 |
|
| 27 |
torch.set_float32_matmul_precision("high")
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
def load_custom_checkpoint(algo, checkpoint_path):
|
| 30 |
hf_ckpt = str(checkpoint_path).split('/')
|
| 31 |
repo_id = '/'.join(hf_ckpt[:2])
|
|
|
|
| 35 |
ckpt = torch.load(model_path, map_location=torch.device('cpu'))
|
| 36 |
algo.load_state_dict(ckpt['state_dict'], strict=False)
|
| 37 |
|
| 38 |
+
def download_assets_if_needed():
|
| 39 |
+
ASSETS_URL_BASE = "https://huggingface.co/spaces/yslan/worldmem/resolve/main/assets/examples"
|
| 40 |
+
ASSETS_DIR = "assets/examples"
|
| 41 |
+
ASSETS = ['case1.npz', 'case2.npz', 'case3.npz', 'case4.npz']
|
| 42 |
+
|
| 43 |
+
if not os.path.exists(ASSETS_DIR):
|
| 44 |
+
os.makedirs(ASSETS_DIR)
|
| 45 |
+
|
| 46 |
+
# Download assets if they don't exist (total 4 files)
|
| 47 |
+
for filename in ASSETS:
|
| 48 |
+
filepath = os.path.join(ASSETS_DIR, filename)
|
| 49 |
+
if not os.path.exists(filepath):
|
| 50 |
+
print(f"Downloading {filename}...")
|
| 51 |
+
url = f"{ASSETS_URL_BASE}/{filename}"
|
| 52 |
+
response = requests.get(url)
|
| 53 |
+
if response.status_code == 200:
|
| 54 |
+
with open(filepath, "wb") as f:
|
| 55 |
+
f.write(response.content)
|
| 56 |
+
else:
|
| 57 |
+
print(f"Failed to download {filename}: {response.status_code}")
|
| 58 |
|
| 59 |
def parse_input_to_tensor(input_str):
|
| 60 |
"""
|
|
|
|
| 111 |
model.forward = amp_forward
|
| 112 |
return model
|
| 113 |
|
| 114 |
+
download_assets_if_needed()
|
| 115 |
+
|
| 116 |
+
ACTION_KEYS = [
|
| 117 |
+
"inventory",
|
| 118 |
+
"ESC",
|
| 119 |
+
"hotbar.1",
|
| 120 |
+
"hotbar.2",
|
| 121 |
+
"hotbar.3",
|
| 122 |
+
"hotbar.4",
|
| 123 |
+
"hotbar.5",
|
| 124 |
+
"hotbar.6",
|
| 125 |
+
"hotbar.7",
|
| 126 |
+
"hotbar.8",
|
| 127 |
+
"hotbar.9",
|
| 128 |
+
"forward",
|
| 129 |
+
"back",
|
| 130 |
+
"left",
|
| 131 |
+
"right",
|
| 132 |
+
"cameraY",
|
| 133 |
+
"cameraX",
|
| 134 |
+
"jump",
|
| 135 |
+
"sneak",
|
| 136 |
+
"sprint",
|
| 137 |
+
"swapHands",
|
| 138 |
+
"attack",
|
| 139 |
+
"use",
|
| 140 |
+
"pickItem",
|
| 141 |
+
"drop",
|
| 142 |
+
]
|
| 143 |
+
|
| 144 |
+
# Mapping of input keys to action names
|
| 145 |
+
KEY_TO_ACTION = {
|
| 146 |
+
"Q": ("forward", 1),
|
| 147 |
+
"E": ("back", 1),
|
| 148 |
+
"W": ("cameraY", -1),
|
| 149 |
+
"S": ("cameraY", 1),
|
| 150 |
+
"A": ("cameraX", -1),
|
| 151 |
+
"D": ("cameraX", 1),
|
| 152 |
+
"U": ("drop", 1),
|
| 153 |
+
"N": ("noop", 1),
|
| 154 |
+
"1": ("hotbar.1", 1),
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
example_images = [
|
| 158 |
+
["1", "assets/ice_plains.png", "turn rightgo backward→look up→turn left→look down→turn right→go forward→turn left", 20, 3, 8],
|
| 159 |
+
["2", "assets/place.png", "put item→go backward→put item→go backward→go around", 20, 3, 8],
|
| 160 |
+
["3", "assets/rain_sunflower_plains.png", "turn right→look up→turn right→look down→turn left→go backward→turn left", 20, 3, 8],
|
| 161 |
+
["4", "assets/desert.png", "turn 360 degree→turn right→go forward→turn left", 20, 3, 8],
|
| 162 |
+
]
|
| 163 |
+
|
| 164 |
memory_frames = []
|
| 165 |
input_history = ""
|
| 166 |
ICE_PLAINS_IMAGE = "assets/ice_plains.png"
|
app.sh
DELETED
|
@@ -1,50 +0,0 @@
|
|
| 1 |
-
wandb disabled
|
| 2 |
-
# srun -p a6000_xgpan -w MICL-PanXGSvr2 --gres=gpu:1 --ntasks-per-node=1 --cpus-per-task=8 \
|
| 3 |
-
export WANDB_API_KEY=a4f0741e80f509317597ad944a7292fabcb68bdf
|
| 4 |
-
|
| 5 |
-
CHECKPOINT_PATH="checkpoints/diffusion_only.ckpt"
|
| 6 |
-
|
| 7 |
-
python -m app +name=pumpkin \
|
| 8 |
-
algorithm=df_video_worldmemminecraft \
|
| 9 |
-
+checkpoint_path=$CHECKPOINT_PATH \
|
| 10 |
-
experiment.tasks=[interactive] \
|
| 11 |
-
dataset.validation_multiplier=1 \
|
| 12 |
-
dataset=video_minecraft \
|
| 13 |
-
+customized_load=true \
|
| 14 |
-
+dataset.n_frames_valid=100 \
|
| 15 |
-
+algorithm.n_tokens=8 \
|
| 16 |
-
+load_vae=false \
|
| 17 |
-
+load_t_to_r=false \
|
| 18 |
-
+zero_init_gate=false \
|
| 19 |
-
experiment.validation.batch_size=1 \
|
| 20 |
-
+algorithm.pose_cond_dim=5 \
|
| 21 |
-
+algorithm.condition_similar_length=8 \
|
| 22 |
-
+dataset.condition_similar_length=8 \
|
| 23 |
-
+algorithm.use_plucker=true \
|
| 24 |
-
+dataset.use_plucker=true \
|
| 25 |
-
+dataset.padding_pool=10 \
|
| 26 |
-
+dataset.focal_length=0.35 \
|
| 27 |
-
+algorithm.focal_length=0.35 \
|
| 28 |
-
+only_tune_refer=false \
|
| 29 |
-
+dataset.customized_validation=true \
|
| 30 |
-
+algorithm.customized_validation=true \
|
| 31 |
-
algorithm.context_frames=90 \
|
| 32 |
-
+algorithm.vis_gt=true \
|
| 33 |
-
+algorithm.relative_embedding=true \
|
| 34 |
-
dataset.save_dir=data/test_pumpkin \
|
| 35 |
-
+algorithm.log_video=true \
|
| 36 |
-
experiment.training.data.num_workers=4 \
|
| 37 |
-
experiment.validation.data.num_workers=4 \
|
| 38 |
-
+dataset.angle_range=30 \
|
| 39 |
-
+dataset.pos_range=0.5 \
|
| 40 |
-
+algorithm.cond_only_on_qk=true \
|
| 41 |
-
+algorithm.add_pose_embed=false \
|
| 42 |
-
+algorithm.use_domain_adapter=false \
|
| 43 |
-
+algorithm.use_reference_attention=true \
|
| 44 |
-
+algorithm.add_frame_timestep_embedder=true \
|
| 45 |
-
+dataset.add_frame_timestep_embedder=true \
|
| 46 |
-
experiment.validation.limit_batch=1 \
|
| 47 |
-
algorithm.diffusion.sampling_timesteps=20 \
|
| 48 |
-
+algorithm.is_interactive=true \
|
| 49 |
-
+vae_path=checkpoints/vae_only.ckpt \
|
| 50 |
-
+pose_predictor_path=checkpoints/pose_prediction_model_only.ckpt
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
split_checkpoint.py
DELETED
|
@@ -1,9 +0,0 @@
|
|
| 1 |
-
import torch
|
| 2 |
-
|
| 3 |
-
ckpt_path = "/mnt/xiaozeqi/diffusionforcing/outputs/2025-03-28/16-45-11/checkpoints/epoch0step595000.ckpt"
|
| 4 |
-
checkpoint = torch.load(ckpt_path, map_location="cpu") # map_location 可根据需要更换
|
| 5 |
-
|
| 6 |
-
state_dict = checkpoint['state_dict']
|
| 7 |
-
pose_prediction_model_dict = {k.replace('pose_prediction_model.', ''): v for k, v in state_dict.items() if k.startswith('pose_prediction_model.')}
|
| 8 |
-
|
| 9 |
-
torch.save({'state_dict': pose_prediction_model_dict}, "pose_prediction_model_only.ckpt")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
test.py
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
import gradio as gr
|
| 2 |
-
|
| 3 |
-
css = """
|
| 4 |
-
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');
|
| 5 |
-
|
| 6 |
-
body {
|
| 7 |
-
background: linear-gradient(to bottom, #79c152 0%, #79c152 60%, #5c432d 100%) !important;
|
| 8 |
-
font-family: 'Press Start 2P', cursive !important;
|
| 9 |
-
color: #ffffff;
|
| 10 |
-
}
|
| 11 |
-
|
| 12 |
-
.gr-button {
|
| 13 |
-
background-color: #3e8527 !important;
|
| 14 |
-
border: 2px solid #254d16 !important;
|
| 15 |
-
color: #ffffff !important;
|
| 16 |
-
}
|
| 17 |
-
|
| 18 |
-
.gr-button:hover {
|
| 19 |
-
background-color: #6fcf44 !important;
|
| 20 |
-
border-color: #4a6c2d !important;
|
| 21 |
-
}
|
| 22 |
-
"""
|
| 23 |
-
|
| 24 |
-
with gr.Blocks(css=css) as demo:
|
| 25 |
-
gr.Markdown("# 🌱 Minecraft 草地界面")
|
| 26 |
-
gr.Textbox(label="你想说啥")
|
| 27 |
-
gr.Button("点我")
|
| 28 |
-
|
| 29 |
-
demo.launch()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|