Spaces:
Running on Zero
Running on Zero
Split ZeroGPU inference from CPU postprocessing
Browse files
app.py
CHANGED
|
@@ -3150,6 +3150,30 @@ def _zip_directory(directory: Path) -> Path:
|
|
| 3150 |
return zip_path
|
| 3151 |
|
| 3152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3153 |
def _ensure_instruct_checkpoint(checkpoint_path: Path) -> Path:
|
| 3154 |
if checkpoint_path.exists():
|
| 3155 |
return checkpoint_path
|
|
@@ -3242,7 +3266,7 @@ def _prefetch_startup_assets(config: dict[str, Any]) -> None:
|
|
| 3242 |
def _spaces_gpu(fn):
|
| 3243 |
if spaces is None:
|
| 3244 |
return fn
|
| 3245 |
-
duration = min(int(os.environ.get("SPACES_GPU_DURATION", "
|
| 3246 |
return spaces.GPU(duration=duration)(fn)
|
| 3247 |
|
| 3248 |
|
|
@@ -3531,7 +3555,7 @@ class InstructParticulateApp:
|
|
| 3531 |
finally:
|
| 3532 |
torch.cuda.empty_cache()
|
| 3533 |
|
| 3534 |
-
def
|
| 3535 |
self,
|
| 3536 |
mesh_path_value: Any,
|
| 3537 |
kinematic_tree_json: str,
|
|
@@ -3547,14 +3571,10 @@ class InstructParticulateApp:
|
|
| 3547 |
):
|
| 3548 |
mesh_path = _extract_gradio_path(mesh_path_value)
|
| 3549 |
if mesh_path is None:
|
| 3550 |
-
yield None,
|
| 3551 |
return
|
| 3552 |
if not mesh_path.exists():
|
| 3553 |
yield (
|
| 3554 |
-
None,
|
| 3555 |
-
None,
|
| 3556 |
-
None,
|
| 3557 |
-
None,
|
| 3558 |
None,
|
| 3559 |
f"Mesh file does not exist: {mesh_path}",
|
| 3560 |
gr.update(interactive=False),
|
|
@@ -3562,17 +3582,12 @@ class InstructParticulateApp:
|
|
| 3562 |
return
|
| 3563 |
if not up_dir:
|
| 3564 |
yield (
|
| 3565 |
-
None,
|
| 3566 |
-
None,
|
| 3567 |
-
None,
|
| 3568 |
-
None,
|
| 3569 |
None,
|
| 3570 |
"Select the upright orientation image before running inference.",
|
| 3571 |
gr.update(interactive=False),
|
| 3572 |
)
|
| 3573 |
return
|
| 3574 |
|
| 3575 |
-
early_visualization_path: Path | None = None
|
| 3576 |
try:
|
| 3577 |
link_names, joint_specs = parse_kinematic_tree(kinematic_tree_json)
|
| 3578 |
point_prompt_arrays = _parse_point_prompt_arrays(
|
|
@@ -3585,10 +3600,6 @@ class InstructParticulateApp:
|
|
| 3585 |
)
|
| 3586 |
if duplicate_prompt_warning is not None:
|
| 3587 |
yield (
|
| 3588 |
-
None,
|
| 3589 |
-
None,
|
| 3590 |
-
None,
|
| 3591 |
-
None,
|
| 3592 |
None,
|
| 3593 |
duplicate_prompt_warning,
|
| 3594 |
gr.update(interactive=False),
|
|
@@ -3684,51 +3695,161 @@ class InstructParticulateApp:
|
|
| 3684 |
batch["query_point_normals"][0],
|
| 3685 |
dtype=np.float32,
|
| 3686 |
)
|
| 3687 |
-
|
| 3688 |
-
|
| 3689 |
-
|
| 3690 |
-
|
| 3691 |
-
|
| 3692 |
-
|
| 3693 |
-
args
|
| 3694 |
-
|
| 3695 |
-
|
| 3696 |
-
|
| 3697 |
-
|
| 3698 |
-
|
| 3699 |
-
|
| 3700 |
-
|
| 3701 |
-
output_dir,
|
| 3702 |
-
|
| 3703 |
-
|
| 3704 |
-
|
| 3705 |
-
|
| 3706 |
-
|
| 3707 |
-
|
| 3708 |
-
|
| 3709 |
-
|
| 3710 |
-
|
| 3711 |
-
|
| 3712 |
-
|
|
|
|
|
|
|
| 3713 |
yield (
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3714 |
None,
|
| 3715 |
-
|
| 3716 |
-
|
| 3717 |
-
None,
|
| 3718 |
-
None,
|
| 3719 |
-
"Point query visualization ready. Running face postprocessing and articulation export...",
|
| 3720 |
gr.update(interactive=False),
|
| 3721 |
)
|
| 3722 |
|
| 3723 |
-
|
| 3724 |
-
|
| 3725 |
-
|
| 3726 |
-
|
| 3727 |
-
|
| 3728 |
-
|
| 3729 |
-
|
| 3730 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3731 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3732 |
motion_artifacts = _compute_motion_prediction_artifacts(
|
| 3733 |
args,
|
| 3734 |
model=model,
|
|
@@ -3736,59 +3857,114 @@ class InstructParticulateApp:
|
|
| 3736 |
normalized_mesh=mesh_geometry.normalized_mesh,
|
| 3737 |
face_part_ids=face_part_ids,
|
| 3738 |
joint_refit_num_query_points=int(args.num_query_points),
|
| 3739 |
-
num_links=len(link_names),
|
| 3740 |
center=mesh_geometry.center,
|
| 3741 |
scale=mesh_geometry.scale,
|
| 3742 |
)
|
| 3743 |
prediction = {
|
| 3744 |
-
"query_points": query_points,
|
| 3745 |
-
"query_normals": query_normals,
|
| 3746 |
-
"point_part_ids": point_part_ids,
|
| 3747 |
"face_part_ids": face_part_ids,
|
| 3748 |
-
"face_part_ids_unrefined":
|
|
|
|
|
|
|
|
|
|
| 3749 |
**motion_artifacts,
|
| 3750 |
}
|
| 3751 |
-
|
| 3752 |
-
args
|
| 3753 |
-
mesh_path
|
| 3754 |
-
up_dir
|
| 3755 |
-
output_dir
|
| 3756 |
-
|
| 3757 |
-
|
| 3758 |
-
|
| 3759 |
-
|
| 3760 |
-
|
| 3761 |
-
|
| 3762 |
-
|
| 3763 |
-
|
| 3764 |
-
|
| 3765 |
-
|
| 3766 |
-
|
| 3767 |
-
|
| 3768 |
-
|
| 3769 |
-
|
| 3770 |
-
|
| 3771 |
-
str(output_dir),
|
| 3772 |
-
f"Success using input up direction {canonical_up}. Wrote outputs to {output_dir}",
|
| 3773 |
-
gr.update(interactive=True),
|
| 3774 |
-
)
|
| 3775 |
-
except Exception as exc:
|
| 3776 |
-
traceback.print_exc()
|
| 3777 |
yield (
|
| 3778 |
-
|
| 3779 |
-
|
| 3780 |
-
gr.update()
|
| 3781 |
-
if early_visualization_path is not None
|
| 3782 |
-
and early_visualization_path.exists()
|
| 3783 |
-
else None,
|
| 3784 |
-
None,
|
| 3785 |
-
None,
|
| 3786 |
-
f"Error: {exc}",
|
| 3787 |
gr.update(interactive=False),
|
| 3788 |
)
|
| 3789 |
finally:
|
| 3790 |
torch.cuda.empty_cache()
|
| 3791 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3792 |
def _prepare_geometry(self, mesh_path: Path, up_dir: str):
|
| 3793 |
from infer import _prepare_mesh_geometry
|
| 3794 |
|
|
@@ -4079,7 +4255,7 @@ def run_predict_on_gpu(
|
|
| 4079 |
enforce_connectivity_per_part: bool,
|
| 4080 |
joint_decoding_confidence_temperature: float,
|
| 4081 |
):
|
| 4082 |
-
yield from _get_active_app().
|
| 4083 |
mesh_path_value,
|
| 4084 |
kinematic_tree_json,
|
| 4085 |
point_prompt_json,
|
|
@@ -4094,8 +4270,22 @@ def run_predict_on_gpu(
|
|
| 4094 |
)
|
| 4095 |
|
| 4096 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4097 |
def prepare_inference_ui():
|
| 4098 |
return (
|
|
|
|
| 4099 |
None,
|
| 4100 |
gr.update(interactive=False),
|
| 4101 |
gr.update(value=None, interactive=False),
|
|
@@ -4203,6 +4393,7 @@ def create_gradio_app(app: InstructParticulateApp) -> gr.Blocks:
|
|
| 4203 |
elem_classes=["kinematic-json-sync"],
|
| 4204 |
)
|
| 4205 |
latest_output_dir = gr.State(None)
|
|
|
|
| 4206 |
|
| 4207 |
with gr.Row(equal_height=True, elem_classes=["demo-row", "demo-top-row"]):
|
| 4208 |
with gr.Column(scale=1, min_width=300, elem_classes=["demo-panel", "mesh-panel"]):
|
|
@@ -4415,6 +4606,7 @@ def create_gradio_app(app: InstructParticulateApp) -> gr.Blocks:
|
|
| 4415 |
fn=prepare_inference_ui,
|
| 4416 |
inputs=None,
|
| 4417 |
outputs=[
|
|
|
|
| 4418 |
latest_output_dir,
|
| 4419 |
export_urdf_button,
|
| 4420 |
urdf_zip,
|
|
@@ -4422,7 +4614,7 @@ def create_gradio_app(app: InstructParticulateApp) -> gr.Blocks:
|
|
| 4422 |
],
|
| 4423 |
queue=False,
|
| 4424 |
)
|
| 4425 |
-
run_event.then(
|
| 4426 |
fn=run_predict_on_gpu,
|
| 4427 |
inputs=[
|
| 4428 |
input_mesh,
|
|
@@ -4437,6 +4629,34 @@ def create_gradio_app(app: InstructParticulateApp) -> gr.Blocks:
|
|
| 4437 |
connectivity,
|
| 4438 |
confidence_temperature,
|
| 4439 |
],
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4440 |
outputs=[
|
| 4441 |
animated_model,
|
| 4442 |
prediction_model,
|
|
|
|
| 3150 |
return zip_path
|
| 3151 |
|
| 3152 |
|
| 3153 |
+
def _to_cpu_payload(value: Any) -> Any:
|
| 3154 |
+
if isinstance(value, torch.Tensor):
|
| 3155 |
+
return value.detach().cpu()
|
| 3156 |
+
if isinstance(value, dict):
|
| 3157 |
+
return {key: _to_cpu_payload(item) for key, item in value.items()}
|
| 3158 |
+
if isinstance(value, list):
|
| 3159 |
+
return [_to_cpu_payload(item) for item in value]
|
| 3160 |
+
if isinstance(value, tuple):
|
| 3161 |
+
return tuple(_to_cpu_payload(item) for item in value)
|
| 3162 |
+
return value
|
| 3163 |
+
|
| 3164 |
+
|
| 3165 |
+
def _to_device_payload(value: Any, device: torch.device) -> Any:
|
| 3166 |
+
if isinstance(value, torch.Tensor):
|
| 3167 |
+
return value.to(device)
|
| 3168 |
+
if isinstance(value, dict):
|
| 3169 |
+
return {key: _to_device_payload(item, device) for key, item in value.items()}
|
| 3170 |
+
if isinstance(value, list):
|
| 3171 |
+
return [_to_device_payload(item, device) for item in value]
|
| 3172 |
+
if isinstance(value, tuple):
|
| 3173 |
+
return tuple(_to_device_payload(item, device) for item in value)
|
| 3174 |
+
return value
|
| 3175 |
+
|
| 3176 |
+
|
| 3177 |
def _ensure_instruct_checkpoint(checkpoint_path: Path) -> Path:
|
| 3178 |
if checkpoint_path.exists():
|
| 3179 |
return checkpoint_path
|
|
|
|
| 3266 |
def _spaces_gpu(fn):
|
| 3267 |
if spaces is None:
|
| 3268 |
return fn
|
| 3269 |
+
duration = max(1, min(int(os.environ.get("SPACES_GPU_DURATION", "10")), 10))
|
| 3270 |
return spaces.GPU(duration=duration)(fn)
|
| 3271 |
|
| 3272 |
|
|
|
|
| 3555 |
finally:
|
| 3556 |
torch.cuda.empty_cache()
|
| 3557 |
|
| 3558 |
+
def predict_segmentation_payload(
|
| 3559 |
self,
|
| 3560 |
mesh_path_value: Any,
|
| 3561 |
kinematic_tree_json: str,
|
|
|
|
| 3571 |
):
|
| 3572 |
mesh_path = _extract_gradio_path(mesh_path_value)
|
| 3573 |
if mesh_path is None:
|
| 3574 |
+
yield None, "Upload a mesh first.", gr.update(interactive=False)
|
| 3575 |
return
|
| 3576 |
if not mesh_path.exists():
|
| 3577 |
yield (
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3578 |
None,
|
| 3579 |
f"Mesh file does not exist: {mesh_path}",
|
| 3580 |
gr.update(interactive=False),
|
|
|
|
| 3582 |
return
|
| 3583 |
if not up_dir:
|
| 3584 |
yield (
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3585 |
None,
|
| 3586 |
"Select the upright orientation image before running inference.",
|
| 3587 |
gr.update(interactive=False),
|
| 3588 |
)
|
| 3589 |
return
|
| 3590 |
|
|
|
|
| 3591 |
try:
|
| 3592 |
link_names, joint_specs = parse_kinematic_tree(kinematic_tree_json)
|
| 3593 |
point_prompt_arrays = _parse_point_prompt_arrays(
|
|
|
|
| 3600 |
)
|
| 3601 |
if duplicate_prompt_warning is not None:
|
| 3602 |
yield (
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3603 |
None,
|
| 3604 |
duplicate_prompt_warning,
|
| 3605 |
gr.update(interactive=False),
|
|
|
|
| 3695 |
batch["query_point_normals"][0],
|
| 3696 |
dtype=np.float32,
|
| 3697 |
)
|
| 3698 |
+
payload = {
|
| 3699 |
+
"args": {
|
| 3700 |
+
"num_query_points": int(args.num_query_points),
|
| 3701 |
+
"num_query_points_per_face_for_seg": args.num_query_points_per_face_for_seg,
|
| 3702 |
+
"query_batch_size": int(args.query_batch_size),
|
| 3703 |
+
"animation_frames": int(args.animation_frames),
|
| 3704 |
+
"strict_face_postprocess": bool(args.strict_face_postprocess),
|
| 3705 |
+
"enforce_connectivity_per_part": bool(args.enforce_connectivity_per_part),
|
| 3706 |
+
"joint_decoding_confidence_temperature": float(
|
| 3707 |
+
args.joint_decoding_confidence_temperature
|
| 3708 |
+
),
|
| 3709 |
+
},
|
| 3710 |
+
"mesh_path": str(mesh_path),
|
| 3711 |
+
"up_dir": str(canonical_up),
|
| 3712 |
+
"output_dir": str(output_dir),
|
| 3713 |
+
"batch": _to_cpu_payload(batch),
|
| 3714 |
+
"query_face_indices": np.asarray(query_face_indices, dtype=np.int64),
|
| 3715 |
+
"link_names": [str(link_name) for link_name in link_names],
|
| 3716 |
+
"joint_specs": [
|
| 3717 |
+
(int(parent), int(child), str(joint_type))
|
| 3718 |
+
for parent, child, joint_type in joint_specs
|
| 3719 |
+
],
|
| 3720 |
+
"point_part_probabilities": point_part_probabilities,
|
| 3721 |
+
"point_part_ids": point_part_ids,
|
| 3722 |
+
"query_points": query_points,
|
| 3723 |
+
"query_normals": query_normals,
|
| 3724 |
+
"segmentation_num_query_points": int(segmentation_num_query_points),
|
| 3725 |
+
}
|
| 3726 |
yield (
|
| 3727 |
+
payload,
|
| 3728 |
+
"Point predictions ready. Running CPU face postprocessing...",
|
| 3729 |
+
gr.update(interactive=False),
|
| 3730 |
+
)
|
| 3731 |
+
finally:
|
| 3732 |
+
torch.cuda.empty_cache()
|
| 3733 |
+
|
| 3734 |
+
def postprocess_segmentation_payload(self, payload: dict[str, Any] | None):
|
| 3735 |
+
if not payload:
|
| 3736 |
+
return (
|
| 3737 |
None,
|
| 3738 |
+
gr.update(),
|
| 3739 |
+
gr.update(),
|
|
|
|
|
|
|
|
|
|
| 3740 |
gr.update(interactive=False),
|
| 3741 |
)
|
| 3742 |
|
| 3743 |
+
args_payload = dict(payload["args"])
|
| 3744 |
+
mesh_path = Path(str(payload["mesh_path"]))
|
| 3745 |
+
canonical_up = str(payload["up_dir"])
|
| 3746 |
+
output_dir = Path(str(payload["output_dir"]))
|
| 3747 |
+
args = _make_inference_args(
|
| 3748 |
+
output_dir=output_dir,
|
| 3749 |
+
num_query_points=int(args_payload["num_query_points"]),
|
| 3750 |
+
num_query_points_per_face_for_seg=args_payload[
|
| 3751 |
+
"num_query_points_per_face_for_seg"
|
| 3752 |
+
],
|
| 3753 |
+
query_batch_size=int(args_payload["query_batch_size"]),
|
| 3754 |
+
animation_frames=int(args_payload["animation_frames"]),
|
| 3755 |
+
strict_face_postprocess=bool(args_payload["strict_face_postprocess"]),
|
| 3756 |
+
enforce_connectivity_per_part=bool(
|
| 3757 |
+
args_payload["enforce_connectivity_per_part"]
|
| 3758 |
+
),
|
| 3759 |
+
joint_decoding_confidence_temperature=float(
|
| 3760 |
+
args_payload["joint_decoding_confidence_temperature"]
|
| 3761 |
+
),
|
| 3762 |
+
)
|
| 3763 |
+
mesh_geometry = self._prepare_geometry(mesh_path, canonical_up)
|
| 3764 |
+
link_names = [str(link_name) for link_name in payload["link_names"]]
|
| 3765 |
+
links_for_query_visualization = [
|
| 3766 |
+
{"link_id": int(link_id), "name": str(link_name)}
|
| 3767 |
+
for link_id, link_name in enumerate(link_names)
|
| 3768 |
+
]
|
| 3769 |
+
batch = payload["batch"]
|
| 3770 |
+
visualization_link_point_prompts_world, visualization_link_point_prompt_ids = (
|
| 3771 |
+
_resolve_visualized_batch_link_point_prompts(
|
| 3772 |
+
args=args,
|
| 3773 |
+
batch=batch,
|
| 3774 |
+
links=links_for_query_visualization,
|
| 3775 |
+
center=mesh_geometry.center,
|
| 3776 |
+
scale=mesh_geometry.scale,
|
| 3777 |
+
)
|
| 3778 |
+
)
|
| 3779 |
+
query_points = np.asarray(payload["query_points"], dtype=np.float32)
|
| 3780 |
+
query_normals = np.asarray(payload["query_normals"], dtype=np.float32)
|
| 3781 |
+
point_part_ids = np.asarray(payload["point_part_ids"], dtype=np.int32)
|
| 3782 |
+
query_face_indices = np.asarray(payload["query_face_indices"], dtype=np.int64)
|
| 3783 |
+
early_visualization_path = save_predicted_point_query_rest_visualization(
|
| 3784 |
+
output_dir,
|
| 3785 |
+
query_points=_denormalize_points(
|
| 3786 |
+
query_points,
|
| 3787 |
+
center=mesh_geometry.center,
|
| 3788 |
+
scale=mesh_geometry.scale,
|
| 3789 |
+
),
|
| 3790 |
+
query_normals=query_normals,
|
| 3791 |
+
predicted_part_ids=point_part_ids,
|
| 3792 |
+
link_point_prompts=visualization_link_point_prompts_world,
|
| 3793 |
+
link_point_prompt_ids=visualization_link_point_prompt_ids,
|
| 3794 |
+
links=links_for_query_visualization,
|
| 3795 |
+
)
|
| 3796 |
+
face_part_ids, face_part_ids_unrefined = _decode_face_part_ids(
|
| 3797 |
+
mesh_geometry.normalized_mesh,
|
| 3798 |
+
point_part_ids=point_part_ids,
|
| 3799 |
+
point_part_probabilities=np.asarray(
|
| 3800 |
+
payload["point_part_probabilities"],
|
| 3801 |
+
dtype=np.float32,
|
| 3802 |
+
),
|
| 3803 |
+
query_face_indices=query_face_indices,
|
| 3804 |
+
input_part_ids=np.arange(len(link_names), dtype=np.int32),
|
| 3805 |
+
strict=bool(args.strict_face_postprocess),
|
| 3806 |
+
enforce_connectivity_per_part=bool(args.enforce_connectivity_per_part),
|
| 3807 |
+
)
|
| 3808 |
+
motion_request = dict(payload)
|
| 3809 |
+
motion_request.pop("point_part_probabilities", None)
|
| 3810 |
+
motion_request["face_part_ids"] = np.asarray(face_part_ids, dtype=np.int32)
|
| 3811 |
+
motion_request["face_part_ids_unrefined"] = np.asarray(
|
| 3812 |
+
face_part_ids_unrefined,
|
| 3813 |
+
dtype=np.int32,
|
| 3814 |
+
)
|
| 3815 |
+
motion_request["visualization_path"] = str(early_visualization_path)
|
| 3816 |
+
return (
|
| 3817 |
+
motion_request,
|
| 3818 |
+
str(early_visualization_path),
|
| 3819 |
+
"Point query visualization ready. Running articulation prediction on GPU...",
|
| 3820 |
+
gr.update(interactive=False),
|
| 3821 |
+
)
|
| 3822 |
+
|
| 3823 |
+
def predict_motion_payload(self, payload: dict[str, Any] | None):
|
| 3824 |
+
if not payload:
|
| 3825 |
+
yield None, gr.update(), gr.update(interactive=False)
|
| 3826 |
+
return
|
| 3827 |
+
|
| 3828 |
+
try:
|
| 3829 |
+
args_payload = dict(payload["args"])
|
| 3830 |
+
mesh_path = Path(str(payload["mesh_path"]))
|
| 3831 |
+
canonical_up = str(payload["up_dir"])
|
| 3832 |
+
output_dir = Path(str(payload["output_dir"]))
|
| 3833 |
+
args = _make_inference_args(
|
| 3834 |
+
output_dir=output_dir,
|
| 3835 |
+
num_query_points=int(args_payload["num_query_points"]),
|
| 3836 |
+
num_query_points_per_face_for_seg=args_payload[
|
| 3837 |
+
"num_query_points_per_face_for_seg"
|
| 3838 |
+
],
|
| 3839 |
+
query_batch_size=int(args_payload["query_batch_size"]),
|
| 3840 |
+
animation_frames=int(args_payload["animation_frames"]),
|
| 3841 |
+
strict_face_postprocess=bool(args_payload["strict_face_postprocess"]),
|
| 3842 |
+
enforce_connectivity_per_part=bool(
|
| 3843 |
+
args_payload["enforce_connectivity_per_part"]
|
| 3844 |
+
),
|
| 3845 |
+
joint_decoding_confidence_temperature=float(
|
| 3846 |
+
args_payload["joint_decoding_confidence_temperature"]
|
| 3847 |
+
),
|
| 3848 |
)
|
| 3849 |
+
model, device = self._ensure_model_loaded()
|
| 3850 |
+
mesh_geometry = self._prepare_geometry(mesh_path, canonical_up)
|
| 3851 |
+
batch = _to_device_payload(payload["batch"], device)
|
| 3852 |
+
face_part_ids = np.asarray(payload["face_part_ids"], dtype=np.int32)
|
| 3853 |
motion_artifacts = _compute_motion_prediction_artifacts(
|
| 3854 |
args,
|
| 3855 |
model=model,
|
|
|
|
| 3857 |
normalized_mesh=mesh_geometry.normalized_mesh,
|
| 3858 |
face_part_ids=face_part_ids,
|
| 3859 |
joint_refit_num_query_points=int(args.num_query_points),
|
| 3860 |
+
num_links=len(payload["link_names"]),
|
| 3861 |
center=mesh_geometry.center,
|
| 3862 |
scale=mesh_geometry.scale,
|
| 3863 |
)
|
| 3864 |
prediction = {
|
| 3865 |
+
"query_points": np.asarray(payload["query_points"], dtype=np.float32),
|
| 3866 |
+
"query_normals": np.asarray(payload["query_normals"], dtype=np.float32),
|
| 3867 |
+
"point_part_ids": np.asarray(payload["point_part_ids"], dtype=np.int32),
|
| 3868 |
"face_part_ids": face_part_ids,
|
| 3869 |
+
"face_part_ids_unrefined": np.asarray(
|
| 3870 |
+
payload["face_part_ids_unrefined"],
|
| 3871 |
+
dtype=np.int32,
|
| 3872 |
+
),
|
| 3873 |
**motion_artifacts,
|
| 3874 |
}
|
| 3875 |
+
output_payload = {
|
| 3876 |
+
"args": args_payload,
|
| 3877 |
+
"mesh_path": str(mesh_path),
|
| 3878 |
+
"up_dir": str(canonical_up),
|
| 3879 |
+
"output_dir": str(output_dir),
|
| 3880 |
+
"query_face_indices": np.asarray(
|
| 3881 |
+
payload["query_face_indices"],
|
| 3882 |
+
dtype=np.int64,
|
| 3883 |
+
),
|
| 3884 |
+
"link_names": [str(link_name) for link_name in payload["link_names"]],
|
| 3885 |
+
"joint_specs": [
|
| 3886 |
+
(int(parent), int(child), str(joint_type))
|
| 3887 |
+
for parent, child, joint_type in payload["joint_specs"]
|
| 3888 |
+
],
|
| 3889 |
+
"prediction": _to_cpu_payload(prediction),
|
| 3890 |
+
"segmentation_num_query_points": int(
|
| 3891 |
+
payload["segmentation_num_query_points"]
|
| 3892 |
+
),
|
| 3893 |
+
"visualization_path": str(payload["visualization_path"]),
|
| 3894 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3895 |
yield (
|
| 3896 |
+
output_payload,
|
| 3897 |
+
"Articulation prediction ready. Writing output files on CPU...",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3898 |
gr.update(interactive=False),
|
| 3899 |
)
|
| 3900 |
finally:
|
| 3901 |
torch.cuda.empty_cache()
|
| 3902 |
|
| 3903 |
+
def finish_predict_payload(self, payload: dict[str, Any] | None):
|
| 3904 |
+
if not payload:
|
| 3905 |
+
return (
|
| 3906 |
+
gr.update(),
|
| 3907 |
+
gr.update(),
|
| 3908 |
+
gr.update(),
|
| 3909 |
+
gr.update(),
|
| 3910 |
+
gr.update(),
|
| 3911 |
+
gr.update(),
|
| 3912 |
+
gr.update(interactive=False),
|
| 3913 |
+
)
|
| 3914 |
+
|
| 3915 |
+
args_payload = dict(payload["args"])
|
| 3916 |
+
mesh_path = Path(str(payload["mesh_path"]))
|
| 3917 |
+
canonical_up = str(payload["up_dir"])
|
| 3918 |
+
output_dir = Path(str(payload["output_dir"]))
|
| 3919 |
+
visualization_path = Path(str(payload["visualization_path"]))
|
| 3920 |
+
args = _make_inference_args(
|
| 3921 |
+
output_dir=output_dir,
|
| 3922 |
+
num_query_points=int(args_payload["num_query_points"]),
|
| 3923 |
+
num_query_points_per_face_for_seg=args_payload[
|
| 3924 |
+
"num_query_points_per_face_for_seg"
|
| 3925 |
+
],
|
| 3926 |
+
query_batch_size=int(args_payload["query_batch_size"]),
|
| 3927 |
+
animation_frames=int(args_payload["animation_frames"]),
|
| 3928 |
+
strict_face_postprocess=bool(args_payload["strict_face_postprocess"]),
|
| 3929 |
+
enforce_connectivity_per_part=bool(
|
| 3930 |
+
args_payload["enforce_connectivity_per_part"]
|
| 3931 |
+
),
|
| 3932 |
+
joint_decoding_confidence_temperature=float(
|
| 3933 |
+
args_payload["joint_decoding_confidence_temperature"]
|
| 3934 |
+
),
|
| 3935 |
+
)
|
| 3936 |
+
mesh_geometry = self._prepare_geometry(mesh_path, canonical_up)
|
| 3937 |
+
self._write_outputs(
|
| 3938 |
+
args=args,
|
| 3939 |
+
mesh_path=mesh_path,
|
| 3940 |
+
up_dir=canonical_up,
|
| 3941 |
+
output_dir=output_dir,
|
| 3942 |
+
mesh_geometry=mesh_geometry,
|
| 3943 |
+
batch={},
|
| 3944 |
+
query_face_indices=np.asarray(
|
| 3945 |
+
payload["query_face_indices"],
|
| 3946 |
+
dtype=np.int64,
|
| 3947 |
+
),
|
| 3948 |
+
link_names=[str(link_name) for link_name in payload["link_names"]],
|
| 3949 |
+
joint_specs=[
|
| 3950 |
+
(int(parent), int(child), str(joint_type))
|
| 3951 |
+
for parent, child, joint_type in payload["joint_specs"]
|
| 3952 |
+
],
|
| 3953 |
+
prediction=payload["prediction"],
|
| 3954 |
+
segmentation_num_query_points=int(payload["segmentation_num_query_points"]),
|
| 3955 |
+
visualization_path=visualization_path,
|
| 3956 |
+
)
|
| 3957 |
+
zip_path = _zip_directory(output_dir)
|
| 3958 |
+
return (
|
| 3959 |
+
str(output_dir / "animated_textured.glb"),
|
| 3960 |
+
str(output_dir / "mesh_parts_with_axes.glb"),
|
| 3961 |
+
gr.update(),
|
| 3962 |
+
str(zip_path),
|
| 3963 |
+
str(output_dir),
|
| 3964 |
+
f"Success using input up direction {canonical_up}. Wrote outputs to {output_dir}",
|
| 3965 |
+
gr.update(interactive=True),
|
| 3966 |
+
)
|
| 3967 |
+
|
| 3968 |
def _prepare_geometry(self, mesh_path: Path, up_dir: str):
|
| 3969 |
from infer import _prepare_mesh_geometry
|
| 3970 |
|
|
|
|
| 4255 |
enforce_connectivity_per_part: bool,
|
| 4256 |
joint_decoding_confidence_temperature: float,
|
| 4257 |
):
|
| 4258 |
+
yield from _get_active_app().predict_segmentation_payload(
|
| 4259 |
mesh_path_value,
|
| 4260 |
kinematic_tree_json,
|
| 4261 |
point_prompt_json,
|
|
|
|
| 4270 |
)
|
| 4271 |
|
| 4272 |
|
| 4273 |
+
def postprocess_segmentation_on_cpu(payload: dict[str, Any] | None):
|
| 4274 |
+
return _get_active_app().postprocess_segmentation_payload(payload)
|
| 4275 |
+
|
| 4276 |
+
|
| 4277 |
+
@_spaces_gpu
|
| 4278 |
+
def run_motion_on_gpu(payload: dict[str, Any] | None):
|
| 4279 |
+
yield from _get_active_app().predict_motion_payload(payload)
|
| 4280 |
+
|
| 4281 |
+
|
| 4282 |
+
def finish_predict_on_cpu(payload: dict[str, Any] | None):
|
| 4283 |
+
return _get_active_app().finish_predict_payload(payload)
|
| 4284 |
+
|
| 4285 |
+
|
| 4286 |
def prepare_inference_ui():
|
| 4287 |
return (
|
| 4288 |
+
None,
|
| 4289 |
None,
|
| 4290 |
gr.update(interactive=False),
|
| 4291 |
gr.update(value=None, interactive=False),
|
|
|
|
| 4393 |
elem_classes=["kinematic-json-sync"],
|
| 4394 |
)
|
| 4395 |
latest_output_dir = gr.State(None)
|
| 4396 |
+
inference_payload = gr.State(None)
|
| 4397 |
|
| 4398 |
with gr.Row(equal_height=True, elem_classes=["demo-row", "demo-top-row"]):
|
| 4399 |
with gr.Column(scale=1, min_width=300, elem_classes=["demo-panel", "mesh-panel"]):
|
|
|
|
| 4606 |
fn=prepare_inference_ui,
|
| 4607 |
inputs=None,
|
| 4608 |
outputs=[
|
| 4609 |
+
inference_payload,
|
| 4610 |
latest_output_dir,
|
| 4611 |
export_urdf_button,
|
| 4612 |
urdf_zip,
|
|
|
|
| 4614 |
],
|
| 4615 |
queue=False,
|
| 4616 |
)
|
| 4617 |
+
gpu_event = run_event.then(
|
| 4618 |
fn=run_predict_on_gpu,
|
| 4619 |
inputs=[
|
| 4620 |
input_mesh,
|
|
|
|
| 4629 |
connectivity,
|
| 4630 |
confidence_temperature,
|
| 4631 |
],
|
| 4632 |
+
outputs=[
|
| 4633 |
+
inference_payload,
|
| 4634 |
+
status,
|
| 4635 |
+
export_urdf_button,
|
| 4636 |
+
],
|
| 4637 |
+
)
|
| 4638 |
+
postprocess_event = gpu_event.then(
|
| 4639 |
+
fn=postprocess_segmentation_on_cpu,
|
| 4640 |
+
inputs=[inference_payload],
|
| 4641 |
+
outputs=[
|
| 4642 |
+
inference_payload,
|
| 4643 |
+
query_visualization,
|
| 4644 |
+
status,
|
| 4645 |
+
export_urdf_button,
|
| 4646 |
+
],
|
| 4647 |
+
)
|
| 4648 |
+
motion_event = postprocess_event.then(
|
| 4649 |
+
fn=run_motion_on_gpu,
|
| 4650 |
+
inputs=[inference_payload],
|
| 4651 |
+
outputs=[
|
| 4652 |
+
inference_payload,
|
| 4653 |
+
status,
|
| 4654 |
+
export_urdf_button,
|
| 4655 |
+
],
|
| 4656 |
+
)
|
| 4657 |
+
motion_event.then(
|
| 4658 |
+
fn=finish_predict_on_cpu,
|
| 4659 |
+
inputs=[inference_payload],
|
| 4660 |
outputs=[
|
| 4661 |
animated_model,
|
| 4662 |
prediction_model,
|