Spaces:
Sleeping
Sleeping
Silvio Galesso commited on
Commit ·
86d8d8b
1
Parent(s): 380643c
appearance fixes
Browse files- app2.py +43 -8
- orbis2_app_engine.py +8 -0
app2.py
CHANGED
|
@@ -192,6 +192,10 @@ if UI_ONLY:
|
|
| 192 |
# auto-seek stay a no-op instead of erroring.
|
| 193 |
MIN_CONTEXT_END_FRAME = 0
|
| 194 |
MIN_CONTEXT_TIME_S = 0.0
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
else:
|
| 196 |
MODELS_DIR = resolve_models_dir()
|
| 197 |
os.environ["ORBIS2_MODELS_DIR"] = str(MODELS_DIR) # L1/L2 configs expandvars this
|
|
@@ -210,7 +214,22 @@ else:
|
|
| 210 |
MIN_CONTEXT_END_FRAME = ENGINE.min_context_end_frame(L1_FRAME_RATE)
|
| 211 |
MIN_CONTEXT_TIME_S = MIN_CONTEXT_END_FRAME / CONTEXT_FPS
|
| 212 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
DEFAULT_GEN_STEPS = 10 # rollout steps; each yields model.num_pred_frames frames
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
# L1 and L2 are sampled at different step counts. L1 (detail) needs more steps for
|
| 215 |
# image fidelity; L2 (abstract, consistency-distilled) is designed for very few.
|
| 216 |
DEFAULT_L1_STEPS = 4 # L1 sampler steps (NFE)
|
|
@@ -291,8 +310,9 @@ is resized to {FRAME_H}×{FRAME_W}. The **L2 abstract predictor** forecasts a la
|
|
| 291 |
future, and the **L1 detail predictor**, conditioned on it, generates the next frames
|
| 292 |
autoregressively.
|
| 293 |
|
| 294 |
-
**Rollout length.** *
|
| 295 |
-
|
|
|
|
| 296 |
|
| 297 |
**Sampling.** The two levels are sampled independently, with their own step counts.
|
| 298 |
*L1 sampler steps* controls the detail predictor, which integrates the flow-matching
|
|
@@ -504,7 +524,7 @@ def render_trajectory_plot(raw_json: str):
|
|
| 504 |
# because it's inserted as real page <head> content.
|
| 505 |
# --------------------------------------------------------------------------
|
| 506 |
TRAJ_CANVAS_HTML_JS = f"""
|
| 507 |
-
<div style="position:relative; width:{TRAJ_CANVAS_SIZE_PX}px;">
|
| 508 |
<canvas id="traj-canvas" width="{TRAJ_CANVAS_SIZE_PX}" height="{TRAJ_CANVAS_SIZE_PX}"
|
| 509 |
style="display:block; border:1px solid #999; border-radius:8px; cursor:crosshair; background:#fafafa;">
|
| 510 |
</canvas>
|
|
@@ -843,7 +863,7 @@ def _parse_cursor_time_s(raw) -> float | None:
|
|
| 843 |
# GPU inference
|
| 844 |
# ----------------------------------------------------------------------------
|
| 845 |
@spaces.GPU(duration=300)
|
| 846 |
-
def run_rollout(video_path: str,
|
| 847 |
seed: int, trajectory, cursor_time_s: str, progress=gr.Progress()):
|
| 848 |
if video_path is None:
|
| 849 |
raise gr.Error("Please upload a short mp4 clip first.")
|
|
@@ -867,6 +887,10 @@ def run_rollout(video_path: str, num_gen_steps: int, l1_steps: int, l2_steps: in
|
|
| 867 |
# eta is not exposed: 0.0 keeps sampling on the deterministic ODE.
|
| 868 |
eta = DEFAULT_ETA
|
| 869 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 870 |
job = Path(tempfile.gettempdir()) / f"orbis2_{uuid.uuid4().hex[:8]}"
|
| 871 |
|
| 872 |
say(0.02, "⏳ Loading…")
|
|
@@ -979,9 +1003,10 @@ def build_demo():
|
|
| 979 |
|
| 980 |
with gr.Row():
|
| 981 |
with gr.Column(scale=1):
|
| 982 |
-
|
| 983 |
-
|
| 984 |
-
|
|
|
|
| 985 |
l1_steps = gr.Slider(5, 20, value=DEFAULT_L1_STEPS, step=1,
|
| 986 |
label="L1 sampler steps",
|
| 987 |
info="Detail predictor — more steps, sharper frames")
|
|
@@ -997,6 +1022,10 @@ def build_demo():
|
|
| 997 |
inp = gr.Video(label="Upload a short mp4 clip", sources=["upload"],
|
| 998 |
elem_id="input_video")
|
| 999 |
cursor_time_s = gr.Textbox(elem_id="cursor_time_s", value="-1", visible=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1000 |
|
| 1001 |
with gr.Column(scale=1):
|
| 1002 |
gr.Markdown(
|
|
@@ -1005,6 +1034,12 @@ def build_demo():
|
|
| 1005 |
"it untouched, or hit Clear, to run the rollout unconditionally."
|
| 1006 |
)
|
| 1007 |
gr.HTML(TRAJ_CANVAS_HTML_JS)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1008 |
raw_points_json = gr.Textbox(elem_id="raw_points_json", visible=False)
|
| 1009 |
smoothed_points_json = gr.Textbox(elem_id="smoothed_points_json", visible=False)
|
| 1010 |
trajectory_state = gr.State()
|
|
@@ -1027,7 +1062,7 @@ def build_demo():
|
|
| 1027 |
|
| 1028 |
btn.click(
|
| 1029 |
run_rollout,
|
| 1030 |
-
inputs=[inp,
|
| 1031 |
outputs=outs,
|
| 1032 |
concurrency_limit=1,
|
| 1033 |
)
|
|
|
|
| 192 |
# auto-seek stay a no-op instead of erroring.
|
| 193 |
MIN_CONTEXT_END_FRAME = 0
|
| 194 |
MIN_CONTEXT_TIME_S = 0.0
|
| 195 |
+
# No model to read model.num_pred_frames from -- 1 is just a placeholder so the
|
| 196 |
+
# UI-only slider below has *some* seconds-per-step to show; it's never used for
|
| 197 |
+
# an actual rollout (run_rollout raises before reaching the model in this mode).
|
| 198 |
+
FRAMES_PER_GEN_STEP = 1
|
| 199 |
else:
|
| 200 |
MODELS_DIR = resolve_models_dir()
|
| 201 |
os.environ["ORBIS2_MODELS_DIR"] = str(MODELS_DIR) # L1/L2 configs expandvars this
|
|
|
|
| 214 |
MIN_CONTEXT_END_FRAME = ENGINE.min_context_end_frame(L1_FRAME_RATE)
|
| 215 |
MIN_CONTEXT_TIME_S = MIN_CONTEXT_END_FRAME / CONTEXT_FPS
|
| 216 |
|
| 217 |
+
FRAMES_PER_GEN_STEP = ENGINE.frames_per_rollout_step
|
| 218 |
+
|
| 219 |
+
# Seconds of output video one rollout step yields, at L1_FRAME_RATE fps -- lets the
|
| 220 |
+
# UI expose rollout length in seconds while the model itself still steps in whole
|
| 221 |
+
# rollout steps (see GEN_SECONDS_STEP / run_rollout's seconds -> steps conversion below).
|
| 222 |
+
SECONDS_PER_GEN_STEP = FRAMES_PER_GEN_STEP / L1_FRAME_RATE
|
| 223 |
+
|
| 224 |
DEFAULT_GEN_STEPS = 10 # rollout steps; each yields model.num_pred_frames frames
|
| 225 |
+
GEN_STEPS_MIN, GEN_STEPS_MAX, GEN_STEPS_STEP = 4, 30, 2 # bounds on the underlying step count
|
| 226 |
+
|
| 227 |
+
# The slider itself is in seconds (see build_demo()); these are its bounds, derived
|
| 228 |
+
# from the step-count bounds above via SECONDS_PER_GEN_STEP.
|
| 229 |
+
GEN_SECONDS_MIN = GEN_STEPS_MIN * SECONDS_PER_GEN_STEP
|
| 230 |
+
GEN_SECONDS_MAX = GEN_STEPS_MAX * SECONDS_PER_GEN_STEP
|
| 231 |
+
GEN_SECONDS_STEP = GEN_STEPS_STEP * SECONDS_PER_GEN_STEP
|
| 232 |
+
DEFAULT_GEN_SECONDS = DEFAULT_GEN_STEPS * SECONDS_PER_GEN_STEP
|
| 233 |
# L1 and L2 are sampled at different step counts. L1 (detail) needs more steps for
|
| 234 |
# image fidelity; L2 (abstract, consistency-distilled) is designed for very few.
|
| 235 |
DEFAULT_L1_STEPS = 4 # L1 sampler steps (NFE)
|
|
|
|
| 310 |
future, and the **L1 detail predictor**, conditioned on it, generates the next frames
|
| 311 |
autoregressively.
|
| 312 |
|
| 313 |
+
**Rollout length.** *Generated video length (s)* sets how much video to generate; under
|
| 314 |
+
the hood this is rounded to a whole number of autoregressive steps, each of which emits
|
| 315 |
+
{FRAMES_PER_GEN_STEP} image frame{"s" if FRAMES_PER_GEN_STEP != 1 else ""} ({SECONDS_PER_GEN_STEP:.2g}s of video per step).
|
| 316 |
|
| 317 |
**Sampling.** The two levels are sampled independently, with their own step counts.
|
| 318 |
*L1 sampler steps* controls the detail predictor, which integrates the flow-matching
|
|
|
|
| 524 |
# because it's inserted as real page <head> content.
|
| 525 |
# --------------------------------------------------------------------------
|
| 526 |
TRAJ_CANVAS_HTML_JS = f"""
|
| 527 |
+
<div style="position:relative; width:{TRAJ_CANVAS_SIZE_PX}px; margin:0 auto;">
|
| 528 |
<canvas id="traj-canvas" width="{TRAJ_CANVAS_SIZE_PX}" height="{TRAJ_CANVAS_SIZE_PX}"
|
| 529 |
style="display:block; border:1px solid #999; border-radius:8px; cursor:crosshair; background:#fafafa;">
|
| 530 |
</canvas>
|
|
|
|
| 863 |
# GPU inference
|
| 864 |
# ----------------------------------------------------------------------------
|
| 865 |
@spaces.GPU(duration=300)
|
| 866 |
+
def run_rollout(video_path: str, gen_seconds: float, l1_steps: int, l2_steps: int,
|
| 867 |
seed: int, trajectory, cursor_time_s: str, progress=gr.Progress()):
|
| 868 |
if video_path is None:
|
| 869 |
raise gr.Error("Please upload a short mp4 clip first.")
|
|
|
|
| 887 |
# eta is not exposed: 0.0 keeps sampling on the deterministic ODE.
|
| 888 |
eta = DEFAULT_ETA
|
| 889 |
|
| 890 |
+
# The model itself only understands whole rollout steps -- convert the
|
| 891 |
+
# seconds the user picked back into a step count (see SECONDS_PER_GEN_STEP).
|
| 892 |
+
num_gen_steps = max(1, round(gen_seconds / SECONDS_PER_GEN_STEP))
|
| 893 |
+
|
| 894 |
job = Path(tempfile.gettempdir()) / f"orbis2_{uuid.uuid4().hex[:8]}"
|
| 895 |
|
| 896 |
say(0.02, "⏳ Loading…")
|
|
|
|
| 1003 |
|
| 1004 |
with gr.Row():
|
| 1005 |
with gr.Column(scale=1):
|
| 1006 |
+
n_seconds_gen = gr.Slider(GEN_SECONDS_MIN, GEN_SECONDS_MAX, value=DEFAULT_GEN_SECONDS,
|
| 1007 |
+
step=GEN_SECONDS_STEP,
|
| 1008 |
+
label="Generated video length (s)",
|
| 1009 |
+
info=f"Generated in chunks of {SECONDS_PER_GEN_STEP:.2g}s each")
|
| 1010 |
l1_steps = gr.Slider(5, 20, value=DEFAULT_L1_STEPS, step=1,
|
| 1011 |
label="L1 sampler steps",
|
| 1012 |
info="Detail predictor — more steps, sharper frames")
|
|
|
|
| 1022 |
inp = gr.Video(label="Upload a short mp4 clip", sources=["upload"],
|
| 1023 |
elem_id="input_video")
|
| 1024 |
cursor_time_s = gr.Textbox(elem_id="cursor_time_s", value="-1", visible=False)
|
| 1025 |
+
gr.Markdown(
|
| 1026 |
+
"Use the video cursor to pick where the model generation should "
|
| 1027 |
+
"start (i.e. the last context frame)."
|
| 1028 |
+
)
|
| 1029 |
|
| 1030 |
with gr.Column(scale=1):
|
| 1031 |
gr.Markdown(
|
|
|
|
| 1034 |
"it untouched, or hit Clear, to run the rollout unconditionally."
|
| 1035 |
)
|
| 1036 |
gr.HTML(TRAJ_CANVAS_HTML_JS)
|
| 1037 |
+
gr.HTML(
|
| 1038 |
+
'<p style="font-size:11px; color:#555; margin-top:6px;">'
|
| 1039 |
+
"Disclaimer: hand-drawn trajectories are likely to be "
|
| 1040 |
+
"out-of-distribution for the model and can generate unexpected "
|
| 1041 |
+
"outputs. Happy crashing!</p>"
|
| 1042 |
+
)
|
| 1043 |
raw_points_json = gr.Textbox(elem_id="raw_points_json", visible=False)
|
| 1044 |
smoothed_points_json = gr.Textbox(elem_id="smoothed_points_json", visible=False)
|
| 1045 |
trajectory_state = gr.State()
|
|
|
|
| 1062 |
|
| 1063 |
btn.click(
|
| 1064 |
run_rollout,
|
| 1065 |
+
inputs=[inp, n_seconds_gen, l1_steps, l2_steps, seed_in, trajectory_state, cursor_time_s],
|
| 1066 |
outputs=outs,
|
| 1067 |
concurrency_limit=1,
|
| 1068 |
)
|
orbis2_app_engine.py
CHANGED
|
@@ -168,6 +168,14 @@ class RolloutEngine:
|
|
| 168 |
)
|
| 169 |
return indexer.get_required_l1_start_offset() + l1_context_frames - 1
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
def ensure_ready(self, device="cuda", compile=True, compile_mode="reduce-overhead",
|
| 172 |
compile_artifacts=None, speed_scale=1.0, yaw_rate_scale=1.0):
|
| 173 |
"""Move the model to `device` and wrap it with torch.compile, exactly once.
|
|
|
|
| 168 |
)
|
| 169 |
return indexer.get_required_l1_start_offset() + l1_context_frames - 1
|
| 170 |
|
| 171 |
+
@property
|
| 172 |
+
def frames_per_rollout_step(self):
|
| 173 |
+
"""Number of output frames each autoregressive rollout step yields
|
| 174 |
+
(model.num_pred_frames). CPU-only (model metadata), callable right after
|
| 175 |
+
load(). Lets callers convert the "rollout steps" the model actually takes
|
| 176 |
+
into seconds of generated video (frames_per_rollout_step / l1_frame_rate)."""
|
| 177 |
+
return int(self.model.num_pred_frames)
|
| 178 |
+
|
| 179 |
def ensure_ready(self, device="cuda", compile=True, compile_mode="reduce-overhead",
|
| 180 |
compile_artifacts=None, speed_scale=1.0, yaw_rate_scale=1.0):
|
| 181 |
"""Move the model to `device` and wrap it with torch.compile, exactly once.
|