microsoft / microsoft/TRELLIS.2

OOM on smaller GPUs

Open
#188 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
11.3k
Forks
1.4k
PR merge metrics
No merged PRs in 30d

Description

decode_shape_slat + Mesh.fill_holes() OOMs on smaller GPUs at 1024_cascade/1536_cascade because sampling tensors aren't released before the mesh post-process step

Environment

  • GPU: NVIDIA A10G, 23GB
  • microsoft/TRELLIS.2-4B, default pipeline (pipeline_type="1024_cascade")
  • torch 2.6.0, cumesh (bundled)

Problem

Calling pipeline.run() (or the equivalent shape-only sequence: sample_sparse_structure -> sample_shape_slat_cascade -> decode_shape_slat -> mesh.fill_holes()) on a moderately complex image reliably OOMs, either inside decode_shape_slat's shape_slat_decoder forward pass or in Mesh.fill_holes()'s cumesh.CuMesh.get_edges() call, depending on how much of the raw sampling state is still resident:

torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 1.23 GiB. GPU 0 has a total
capacity of 22.06 GiB of which 87.44 MiB is free. Including non-PyTorch memory, this process
has 21.97 GiB memory in use.

and separately:

RuntimeError: [CuMesh] CUDA error:
    File:       cumesh/src/utils.h
    Line:       43
    Error code: 2
    Error text: out of memory

Root cause

sample_shape_slat_cascade's inputs (cond_512, cond_1024, coords) and its output (shape_slat) are never released before decode_shape_slat runs, and decode_shape_slat's own output (the raw decoded mesh, which for a moderately complex object is >10M vertices / >20M faces at 1024 resolution) and these are likewise still resident when mesh.fill_holes() builds its CuMesh edge/adjacency structures. On a 23GB GPU, peak memory right after decode_shape_slat returns is already ~21GB, leaving no headroom for fill_holes()'s (or any other full-mesh GPU topology op's) own allocations.

Confirmed fix

We found that freeing the now-unneeded sampling tensors (del shape_slat, cond_512, cond_1024, coords + torch.cuda.empty_cache()) immediately after decode_shape_slat returns, before calling fill_holes(), drops peak memory from ~21GB to ~11GB on the same input and GPU, and the pipeline completes without any change to output vertices/faces.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at pipeline.run() and the equivalent shape-only sequence through sample_shape_slat_cascade, decode_shape_slat, and mesh.fill_holes(). Trace which sampling tensors and decoded mesh state remain resident between these entry points, then reproduce on the stated A10G setup. Done means the cascade completes without OOM and output vertices and faces remain unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
computer-graphics, machine-learning, performance
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
70/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.