Image-to-Image
Diffusers
Safetensors
Core ML
StableDiffusionInpaintPipeline
image-editing
local-ai
clover-image
inpainting
stable-diffusion
Instructions to use neonforestmist/Clover-Image-Tiny-Inpaint with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use neonforestmist/Clover-Image-Tiny-Inpaint with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline from diffusers.utils import load_image # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("neonforestmist/Clover-Image-Tiny-Inpaint", dtype=torch.bfloat16, device_map="cuda") prompt = "Turn this cat into a dog" input_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/cat.png") image = pipe(image=input_image, prompt=prompt).images[0] - Notebooks
- Google Colab
- Kaggle
| """Loss helpers for context-aware inpainting distillation.""" | |
| from __future__ import annotations | |
| import torch | |
| import torch.nn.functional as F | |
| def min_snr_weights( | |
| alphas_cumprod: torch.Tensor, | |
| timesteps: torch.Tensor, | |
| *, | |
| gamma: float, | |
| prediction_type: str, | |
| ) -> torch.Tensor: | |
| """Return the Min-SNR weighting from diffusion fine-tuning literature.""" | |
| alpha = alphas_cumprod.to(device=timesteps.device, dtype=torch.float32)[timesteps] | |
| snr = alpha / (1.0 - alpha).clamp_min(1e-8) | |
| clipped = torch.minimum(snr, torch.full_like(snr, gamma)) | |
| if prediction_type == "epsilon": | |
| return clipped / snr.clamp_min(1e-8) | |
| if prediction_type == "v_prediction": | |
| return clipped / (snr + 1.0) | |
| raise ValueError(f"Unsupported prediction type: {prediction_type}") | |
| def spatial_loss_weights( | |
| mask: torch.Tensor, | |
| *, | |
| context_weight: float, | |
| masked_weight: float, | |
| boundary_weight: float, | |
| boundary_radius: int = 2, | |
| ) -> torch.Tensor: | |
| """Emphasize regenerated pixels and the context-sensitive mask boundary.""" | |
| if mask.ndim != 4 or mask.shape[1] != 1: | |
| raise ValueError(f"Expected BCHW single-channel mask, got {tuple(mask.shape)}") | |
| if boundary_radius < 1: | |
| raise ValueError("boundary_radius must be positive") | |
| binary = (mask >= 0.5).to(dtype=torch.float32) | |
| kernel = boundary_radius * 2 + 1 | |
| dilated = F.max_pool2d(binary, kernel_size=kernel, stride=1, padding=boundary_radius) | |
| eroded = 1.0 - F.max_pool2d( | |
| 1.0 - binary, | |
| kernel_size=kernel, | |
| stride=1, | |
| padding=boundary_radius, | |
| ) | |
| boundary = (dilated - eroded).clamp(0.0, 1.0) | |
| weights = torch.full_like(binary, float(context_weight)) | |
| weights = weights + binary * (float(masked_weight) - float(context_weight)) | |
| weights = weights + boundary * float(boundary_weight) | |
| return weights / weights.mean(dim=(1, 2, 3), keepdim=True).clamp_min(1e-8) | |
| def weighted_mse( | |
| prediction: torch.Tensor, | |
| target: torch.Tensor, | |
| *, | |
| spatial_weights: torch.Tensor, | |
| sample_weights: torch.Tensor, | |
| ) -> torch.Tensor: | |
| """Compute channel-averaged, spatially and per-sample weighted MSE.""" | |
| if prediction.shape != target.shape: | |
| raise ValueError("prediction and target must have identical shapes") | |
| per_pixel = (prediction.float() - target.float()).square().mean(dim=1, keepdim=True) | |
| per_sample = (per_pixel * spatial_weights.float()).mean(dim=(1, 2, 3)) | |
| return (per_sample * sample_weights.float()).mean() | |