Spaces:
Running on Zero
Running on Zero
Commit History
-
fix: raise crop context padding floor from 64px to 200px for small objects Running
nmdbbbUser's own diagnosis, confirmed correct: a small/distant object's own size contributes little to the padding formula (object_width // 2 stays below the 64px floor), so the crop the model actually sees ends up being little more than a close-up of the object's immediate surroundings - nowhere near enough to show real scene context. Confirmed on a real photo: a small background person standing in ocean waves produced an incoherent rippled/warped result because the model only saw a tiny, ambiguous patch of wave texture with no wider context (shoreline, wave direction) to anchor a coherent continuation.1bf6198 -
fix: drop the mask edge-noise hack now that PowerPaint is the default backend
nmdbbbThat noisy/speckled mask edge (mask_edge_noise) was a workaround for vanilla SD/SDXL inpainting's tendency to treat an exact-silhouette mask as 'an object-shaped hole to fill with another object' - PowerPaint's P_ctxt/ P_obj task tokens solve that architecturally, so the hack is redundant and, worse, actively harmful: confirmed on a real photo where the smooth part of the mask blended cleanly into the background but the noisy/dilated edge showed a visible speckled seam, because the mask's own jagged shape shows through wherever the generated fill doesn't land on exactly the right color at the pixel level. mask_dilation kept small (6px) purely as a safety margin for imprecise SAM2 selections.47b6e60 -
fix: downscale PowerPaint's working resolution to 640px longer edge, matching its reference behavior
nmdbbbConfirmed via a real photo: only the thin/small part of a large mask blended correctly (matching background), while the larger/denser part still showed noise even after the float32 fix - this SD1.5-based checkpoint is trained natively around 512-640px, and running it directly at whatever a crop's full resolution happens to be (which grows with the masked object's size) departs increasingly from that range for larger objects. PowerPaint's own reference code always downscales the whole input image to a 640px longer edge before processing; this pipeline skipped that step entirely, running crops at their full (sometimes much larger) resolution instead.3d7f081 -
fix: run PowerPaint pipeline in float32 to avoid SD1.5 VAE fp16 NaN instability
nmdbbbThe black-and-white speckled/maze-pattern noise in results (confirmed on both the synthetic test image and a real photo) is the well-known SD1.5 VAE float16 instability issue - the original SD1.5 VAE (which this checkpoint's realisticVisionV60B1_v51VAE base is built on) produces NaNs in fp16 that decode to exactly this kind of noise. The vendored pipeline doesn't have diffusers' usual upcast_vae() safety net, and patching just the VAE's dtype would need auditing every call site that assumes a uniform dtype across pipeline components, so running the whole pipeline in float32 sidesteps it entirely - ZeroGPU's A10G (24GB) has ample headroom for this SD1.5-scale (not SDXL-scale) model.cf25452
-
feat: switch to PowerPaint (BrushNet) for object removal - the actually right tool for the job
nmdbbbResearch confirmed vanilla SD1.5/SDXL inpainting checkpoints are trained purely for 'replace masked region with what the prompt describes', not pure removal - they have no notion of 'nothing should be here', which is exactly why they kept hallucinating a replacement subject regardless of prompt/mask engineering (5+ attempts today across two model architectures). PowerPaint v2 (BrushNet) is trained with distinct task tokens: 'P_ctxt' means 'this is just background context, nothing new' and 'P_obj' (used as a negative prompt) suppresses new-object content - a real architectural distinction between removal and generation that prompt wording alone can't replicate on a generic inpainting model. Vendored PowerPaint's custom pipeline/model code (powerpaint/models, powerpaint/pipelines, powerpaint/utils - not available as an installable package or in mainline diffusers) faithfully following their own reference loading sequence (app.py's PowerPaintController). Replaced the mmengine logging de…b0c4bef -
feat: switch cloud inpainting from SD1.5 to SDXL for better quality
nmdbbbAfter repeated mask-engineering attempts (dilation, organic edges, rect bias, padding safety) still produced inconsistent results with SD1.5's runwayml/stable-diffusion-inpainting on real photos, switching to diffusers/stable-diffusion-xl-1.0-inpainting-0.1 (1024x1024, ~3x the parameters, much better prompt/context understanding) per user request. ZeroGPU's A10G (24GB VRAM) has plenty of headroom. Made safety_checker=None tolerant of pipelines that don't accept it (SDXL's inpainting pipeline doesn't have this kwarg at all, unlike SD1.5's).beb409d -
fix: cap mask growth well below the crop padding to avoid starving the model of real background
nmdbbbThe previous rect-bias + large dilation/noise (40+60=up to 100px) could exceed a small object's ~64px padding floor entirely, leaving no real background margin inside the crop for the model to key off - confirmed by the user's own result: pure static/speckle noise instead of any plausible content, since the model was generating from essentially nothing. Reverted to silhouette-based dilation (not full rectangle) with much smaller values, and added a hard floor so the crop's padding always exceeds the mask's growth by a safety margin regardless of what values are passed.f819569 -
feat: pad SAM2's returned mask by a few pixels so it comfortably covers the object
nmdbbbSAM2's boundary tends to sit a few pixels inside the object's true edge rather than exactly on it, leaving a visible sliver uncovered (confirmed by the user's own screenshot of the new bordered mask overlay, which made this gap visible for the first time). Padding the mask automatically at the source means the selection the user sees - and that gets sent for removal - already covers the object, rather than relying on them to notice and manually patch small gaps with extra taps or brush strokes.df402fb -
feat: bias the model mask toward a rectangle, with much larger ragged extension
nmdbbbPer user request after continued object-shaped hallucination even with a merely ragged-but-silhouette-shaped mask: the base shape handed to the model is now a solid rectangle covering the object's bounding box (still grown by mask_dilation) instead of a dilated version of the object's own outline, and both mask_dilation (10->40) and mask_edge_noise (20->60) grew substantially - a rectangle doesn't resemble the removed object's shape at all, and the enlarged ragged noise pushes the boundary well past the original selection.aedcd9b -
feat: give the mask a ragged, brush-stroke-like edge instead of a uniformly larger silhouette
nmdbbbUniform dilation still produces a perfectly smooth (just bigger) outline, which can still read as 'object-shaped hole' to the model. Mimicking the user's own observation that brush-drawn masks (naturally irregular edges) gave clean results while precise SAM2 masks kept prompting SD to generate a replacement object, the mask handed to the model now gets a base uniform dilation plus randomly-placed extra bulges gated by smooth low-res noise - an irregular boundary closer to what a hand-drawn brush stroke produces.eb4846c -
fix: dilate mask before handing it to the inpainting model
nmdbbbA mask that exactly traces an object's silhouette reads to a generative model as 'there's an object-shaped hole here', biasing it to fill the hole with another object of that shape instead of plain background - confirmed by the user's own testing (brush-drawn masks, which don't trace an exact silhouette, gave clean results; SAM2 tap masks, which do, kept generating replacement objects). Dilating the mask by ~15px before the model call breaks that exact-outline cue while the original tighter mask is still used for the final feathered blend, so the visible result still respects the user's actual selection boundary.403a0e6 -
fix: disable SD safety checker - it false-positived on abstract/low-detail masked patches and blacked out results
nmdbbbConfirmed via a test image with a solid-color masked region: the result came back fully black instead of the actual generation. This is a controlled backend processing user-supplied photos, not open prompt generation, so the safety checker's false-positive risk outweighs its protection here. User explicitly confirmed disabling this control.8874026 -
feat: add prompt/negative_prompt to guide SD inpainting toward plausible background fill
nmdbbbAn empty prompt gave SD no anchor for what belongs in the masked region - with a large or ambiguous mask it could hallucinate an unrelated subject instead of continuing the background. Added a default prompt biasing toward seamless background continuation and a negative prompt penalizing new objects/artifacts/blur.914c5d6 -
fix: sync inpainting.py/model_loader.py with main repo - deploy real StableDiffusionInpainter
nmdbbbThe Space had been running a stale LamaModelInpainter this whole time (the crop-back-to-original-size fix for SimpleLama's multiple-of-8 padding was never pushed here), which crashed with 'images do not match' on any crop whose dimensions weren't already divisible by 8 - i.e. almost every real photo, only missed by tiny square 256x256 test images. Also brings over StableDiffusionInpainter, RemoteInpainter, proportional crop padding, and CORS middleware from the main repo.0fb4a38 -
fix: recompute SAM2 embedding inside decode() instead of caching a CUDA tensor across requests
nmdbbbZeroGPU dispatches @spaces.GPU calls to ephemeral worker processes; the host process (no real GPU) can't unpickle a raw CUDA tensor returned from one call and passed into another, causing 'Low-level CUDA init reached' on /segment/point. decode() now re-runs set_image() from the cached PIL image instead of reusing a cross-process embedding.8dc9082 -
fix: disable SSR mode so custom FastAPI routes aren't swallowed by the SSR proxy middleware
nmdbbbHF Spaces defaults GRADIO_SSR_MODE=true, which installs a middleware that proxies every non-internal path (including /health, /segment/init, etc, and even Gradio's own /docs) to a Node SSR renderer before routing runs - every request silently got back the same SPA shell HTML.97de0c1 -
fix: use demo.launch() instead of mount_gradio_app so ZeroGPU's startup handshake fires
nmdbbbspaces/zero/gradio.py monkey-patches gr.Blocks.launch itself to send the startup report to HF's ZeroGPU infra; mount_gradio_app + manual uvicorn.run never triggers it, causing the persistent 'No @spaces.GPU function detected during startup' error regardless of decorator wiring.e878160 -
Pass @spaces.GPU function directly as gr.Interface fn=
nmdbbb5eb8f74 -
Wire hidden Gradio callback for ZeroGPU detection, switch to SD backend
nmdbbb39baaf1 -
Use real @spaces.GPU decorators on module-level functions
nmdbbb13a9292 -
Defer SAM2/LaMa construction to first real GPU-decorated call
nmdbbb37fcc27 -
Import spaces before gradio for ZeroGPU CUDA emulation
nmdbbb27db35e -
Build SAM2/LaMa on CPU, move to GPU lazily for ZeroGPU compatibility
nmdbbb4bc6028 -
Fix SAM2/LaMa model loading to match real library APIs
nmdbbb523a925 -
Deploy object removal API (SAM2 + LaMa on ZeroGPU)
nmdbbbea2b072