akhaliq HF Staff commited on
Commit
83cd54d
·
1 Parent(s): a589bff

Fix ZeroGPU pickling error: save files inside @spaces.GPU function

Browse files

The Gaussian object contains lambdas that can't be pickled across
the multiprocessing boundary. Move all file I/O into _run_pipeline
so only paths/numbers are returned.

Files changed (1) hide show
  1. app.py +38 -28
app.py CHANGED
@@ -118,9 +118,14 @@ async def get_example(idx: int):
118
  # ----------------------------------------------------------------------------
119
 
120
  @spaces.GPU
121
- def _run_pipeline(pil_image, seed, steps, guidance_scale, num_gaussians):
122
- """Run the full pipeline (preprocess → encode → sample → decode)
123
- in a single GPU acquisition."""
 
 
 
 
 
124
  t0 = time.time()
125
  prepared = PIPE.preprocess_image(pil_image)
126
  gen = torch.Generator(device=PIPE._device).manual_seed(int(seed))
@@ -134,7 +139,27 @@ def _run_pipeline(pil_image, seed, steps, guidance_scale, num_gaussians):
134
  )
135
  gaussian = PIPE.decode_latent(out["latent"], num_gaussians=int(num_gaussians))
136
  gen_dt = time.time() - t0
137
- return prepared, gaussian, gen_dt
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
 
140
  # ----------------------------------------------------------------------------
@@ -157,38 +182,23 @@ def generate(
157
  """
158
  pil_image = Image.open(image["path"]).convert("RGBA")
159
 
160
- prepared, gaussian, gen_dt = _run_pipeline(
161
- pil_image, seed, steps, guidance_scale, num_gaussians,
162
- )
163
-
164
  out_dir = OUT_ROOT / uuid4().hex[:12]
165
  out_dir.mkdir(parents=True, exist_ok=True)
166
 
167
- # Save preprocessed image
168
- prep_path = out_dir / "preprocessed.png"
169
- prepared.save(str(prep_path))
170
-
171
- # Save PLY (always needed for the viewer)
172
- ply_path = out_dir / "splat.ply"
173
- gaussian.save_ply(str(ply_path))
174
-
175
- # Save in the requested download format
176
- fmt = output_format.lower()
177
- if fmt == "splat":
178
- download_path = out_dir / "splat.splat"
179
- gaussian.save_splat(str(download_path))
180
- else:
181
- download_path = ply_path
182
 
183
  info = (
184
- f"{gaussian.get_xyz.shape[0]:,} gaussians · "
185
- f"generation: {gen_dt:.1f}s · saved: {download_path.name}"
186
  )
187
 
188
  return (
189
- FileData(path=str(prep_path)),
190
- FileData(path=str(ply_path)),
191
- FileData(path=str(download_path)),
192
  info,
193
  )
194
 
 
118
  # ----------------------------------------------------------------------------
119
 
120
  @spaces.GPU
121
+ def _run_pipeline(pil_image, seed, steps, guidance_scale, num_gaussians,
122
+ out_dir, output_format):
123
+ """Run the full pipeline (preprocess → encode → sample → decode → save)
124
+ in a single GPU acquisition.
125
+
126
+ All file I/O happens here so the unpicklable Gaussian object never
127
+ crosses the ZeroGPU multiprocessing boundary.
128
+ """
129
  t0 = time.time()
130
  prepared = PIPE.preprocess_image(pil_image)
131
  gen = torch.Generator(device=PIPE._device).manual_seed(int(seed))
 
139
  )
140
  gaussian = PIPE.decode_latent(out["latent"], num_gaussians=int(num_gaussians))
141
  gen_dt = time.time() - t0
142
+
143
+ # Save preprocessed image
144
+ prep_path = out_dir / "preprocessed.png"
145
+ prepared.save(str(prep_path))
146
+
147
+ # Save PLY (always needed for the viewer)
148
+ ply_path = out_dir / "splat.ply"
149
+ gaussian.save_ply(str(ply_path))
150
+
151
+ # Save in the requested download format
152
+ fmt = output_format.lower()
153
+ if fmt == "splat":
154
+ download_path = out_dir / "splat.splat"
155
+ gaussian.save_splat(str(download_path))
156
+ else:
157
+ download_path = ply_path
158
+
159
+ n_gaussians = gaussian.get_xyz.shape[0]
160
+
161
+ # Return only picklable primitives / paths
162
+ return str(prep_path), str(ply_path), str(download_path), n_gaussians, gen_dt
163
 
164
 
165
  # ----------------------------------------------------------------------------
 
182
  """
183
  pil_image = Image.open(image["path"]).convert("RGBA")
184
 
 
 
 
 
185
  out_dir = OUT_ROOT / uuid4().hex[:12]
186
  out_dir.mkdir(parents=True, exist_ok=True)
187
 
188
+ prep_path, ply_path, download_path, n_gaussians, gen_dt = _run_pipeline(
189
+ pil_image, seed, steps, guidance_scale, num_gaussians,
190
+ out_dir, output_format,
191
+ )
 
 
 
 
 
 
 
 
 
 
 
192
 
193
  info = (
194
+ f"{n_gaussians:,} gaussians · "
195
+ f"generation: {gen_dt:.1f}s · saved: {Path(download_path).name}"
196
  )
197
 
198
  return (
199
+ FileData(path=prep_path),
200
+ FileData(path=ply_path),
201
+ FileData(path=download_path),
202
  info,
203
  )
204