DiffusionGS-Object / space_app.py
CaiYuanhao's picture
Show monthly and daily success badges below the title
771c5cf verified
Raw History Blame Contribute Delete
5.67 kB
"""Shared ZeroGPU backend for the Object and Scene Hugging Face Spaces."""
import os
from pathlib import Path
from types import SimpleNamespace
# rembg imports Numba. Its default TBB pool cannot safely fork from a
# Gradio worker thread when ZeroGPU starts the GPU process.
os.environ.setdefault("NUMBA_THREADING_LAYER", "workqueue")
os.environ.setdefault("NUMBA_NUM_THREADS", "2")
for variable in ("OMP_NUM_THREADS", "MKL_NUM_THREADS", "OPENBLAS_NUM_THREADS"):
os.environ[variable] = "1"
# ZeroGPU must install its CUDA emulation before torch is imported.
import spaces
import torch
import gradio as gr
from huggingface_hub import snapshot_download
from omegaconf import OmegaConf
from object_demo import ObjectDemo, build_demo as build_object_demo
from scene_demo import SceneDemo, build_demo as build_scene_demo
from diffusionGS.models.denoiser.denoiser import DGSDenoiser
from diffusionGS.models.diffusion import create_diffusion
from diffusionGS.pipeline_scene import DiffusionGSScenePipeline
from diffusionGS.pipline_obj import DiffusionGSPipeline
from space_success_stats import SuccessStats, UsageDisplay
ROOT = Path(__file__).resolve().parent
OUTPUT_ROOT = Path(os.environ.get("DIFFUSIONGS_OUTPUT_DIR", ROOT / "outputs")).resolve()
MODEL_REPO = "CaiYuanhao/DiffusionGS"
MODEL_REVISION = "6ad55569352ab32bd7ca52ba1c5f5cf89065b2d6"
stats = SuccessStats.from_env()
stats.start("diffusiongs-object", "diffusiongs-scene")
def use_torch_attention(model):
"""Use PyTorch SDPA across the different GPUs allocated by ZeroGPU."""
for module in model.modules():
if hasattr(module, "use_flashatt_v2"):
module.use_flashatt_v2 = False
def load_object_pipeline(model_dir):
# Inference only needs the denoiser, diffusion schedule and camera template.
# Avoid allocating training losses and downloading their VGG checkpoint.
config = OmegaConf.load(model_dir / "obj_configs.yaml")
model = DGSDenoiser(OmegaConf.to_container(config.system.shape_model))
checkpoint = torch.load(model_dir / "obj_ckpt_512.ckpt", map_location="cpu", weights_only=False)
state = checkpoint.get("state_dict", checkpoint)
model.load_state_dict({key.removeprefix("shape_model."): value for key, value in state.items()
if key.startswith("shape_model.")}, strict=True)
del checkpoint, state
use_torch_attention(model)
model = model.to(device="cuda:0", dtype=torch.float16).eval()
system = SimpleNamespace(
shape_model=model, device=torch.device("cuda:0"), dtype=torch.float16,
diffusion_inference=create_diffusion(str(config.system.num_inference_steps), predict_xstart=True),
cam_template=torch.load(model_dir / "camera_template.pt", map_location="cpu", weights_only=False),
)
return DiffusionGSPipeline("cuda:0", config, system)
torch.set_num_threads(1)
model_dir = Path(snapshot_download(
MODEL_REPO, revision=MODEL_REVISION,
allow_patterns=["obj_ckpt_512.ckpt", "obj_configs.yaml", "camera_template.pt",
"scene_ckpt_256.ckpt", "scene_ckpt_512.ckpt"],
))
object_service = ObjectDemo(output_dir=OUTPUT_ROOT / "object")
object_service.pipeline = load_object_pipeline(model_dir)
scene_pipelines = {}
for resolution in (256, 512):
pipeline = DiffusionGSScenePipeline.from_pretrained(model_dir, resolution=resolution)
use_torch_attention(pipeline.model)
scene_pipelines[resolution] = pipeline
scene_service = SceneDemo(output_dir=OUTPUT_ROOT / "scene")
_generate_object = object_service.generate
_extract_mesh = object_service.extract_mesh
_generate_scene = scene_service.generate
@spaces.GPU(duration=40)
def generate_object(image, seed, foreground_ratio, force_remove_background):
print("Starting object generation on ZeroGPU", flush=True)
return _generate_object(image, seed, foreground_ratio, force_remove_background)
@spaces.GPU(duration=40)
def extract_mesh(result_directory):
print("Starting mesh extraction on ZeroGPU", flush=True)
return _extract_mesh(result_directory)
def scene_gpu_duration(image, preset, translation_scale, rotation_degrees, fov_degrees,
duration_seconds, resolution, steps, seed, fps):
return (20 + (20 if int(resolution) == 512 else 0)
+ max(0, int(steps) - 30) // 2
+ max(0, int(duration_seconds) * int(fps) // 2 - 120) // 10)
@spaces.GPU(duration=scene_gpu_duration)
def generate_scene(image, preset, translation_scale, rotation_degrees, fov_degrees,
duration_seconds, resolution, steps, seed, fps):
print("Starting scene generation on ZeroGPU", flush=True)
scene_service.pipeline = scene_pipelines[int(resolution)]
return _generate_scene(image, preset, translation_scale, rotation_degrees, fov_degrees,
duration_seconds, resolution, steps, seed, fps)
object_service.generate = stats.successful("diffusiongs-object")(generate_object)
object_service.extract_mesh = extract_mesh
scene_service.generate = stats.successful("diffusiongs-scene")(generate_scene)
demo = build_object_demo(service=object_service, usage=UsageDisplay(stats, "diffusiongs-object"))
with demo:
gr.Navbar(main_page_name="Object Generation")
scene_demo = build_scene_demo(service=scene_service, usage=UsageDisplay(stats, "diffusiongs-scene"))
with demo.route("Scene Generation", "/scene"):
gr.Navbar(main_page_name="Object Generation")
scene_demo.render()
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=int(os.environ.get("GRADIO_SERVER_PORT", "7860")),
max_file_size="20mb", allowed_paths=[str(OUTPUT_ROOT)], ssr_mode=False)