neonforestmist's picture
Add Modal training and inpainting model scaffold
a8c48b5 verified
Raw
History Blame Contribute Delete
1.86 kB
"""Model construction helpers for Clover Image Tiny inpainting."""
from __future__ import annotations
from pathlib import Path
from typing import Any
import torch
from diffusers import UNet2DConditionModel
def _load_kwargs(revision: str | None) -> dict[str, Any]:
return {"revision": revision} if revision else {}
def make_inpainting_unet(
base_model: str | Path,
*,
revision: str | None = None,
zero_initialize_conditioning: bool = True,
) -> UNet2DConditionModel:
"""Create a 9-channel U-Net from the 4-channel Clover checkpoint.
The first four input channels retain Clover's original weights. The extra
channels receive the binary inpainting mask and the masked-image latent.
Zero-initializing them preserves a stable text-to-image starting point while
the inpainting fine-tune learns how to use the new conditioning channels.
"""
load_kwargs = _load_kwargs(revision)
base = UNet2DConditionModel.from_pretrained(
str(base_model),
subfolder="unet",
low_cpu_mem_usage=False,
**load_kwargs,
)
config = dict(base.config)
config["in_channels"] = 9
inpaint = UNet2DConditionModel.from_config(config)
state = base.state_dict()
conv_in_weight = state.pop("conv_in.weight")
inpaint.load_state_dict(state, strict=False)
with torch.no_grad():
if zero_initialize_conditioning:
inpaint.conv_in.weight.zero_()
inpaint.conv_in.weight[:, :4].copy_(conv_in_weight)
else:
# Keep the pretrained channels and leave the five new channels at
# the framework's default initialization.
inpaint.conv_in.weight[:, :4].copy_(conv_in_weight)
if "conv_in.bias" in base.state_dict():
inpaint.conv_in.bias.copy_(base.conv_in.bias)
del base
return inpaint