ShadeNet-5-35M / inference /ensemble.py
singam96's picture
singam96/ShadeNet-5-35M: upload hf_draft
e76e3de verified
Raw History Blame Contribute Delete
1.95 kB
"""Test-time averaging for ShadeNet-5, copied from the repository's
`detail_diffuser/inference/core.py` (flip_average / tta_average / unit_normals)
so the Space renders exactly what the model card reports.
`refine_fn(x)` takes a [1, 3, H, W] photo in [-1, 1] and returns the 7 maps
[1, 7, H, W] in [-1, 1]: albedo 0:3, depth 3, normal 4:7.
"""
import itertools
import torch
from rotation import rotate_image, unrotate_maps
NORMAL_X = 4 # first channel of the normal (x right, y up, z to viewer)
def unit_normals(maps, eps=1e-6):
out = maps.clone()
n = out[:, NORMAL_X:NORMAL_X + 3]
out[:, NORMAL_X:NORMAL_X + 3] = n / n.norm(dim=1, keepdim=True).clamp_min(eps)
return out
@torch.no_grad()
def tta_average(refine_fn, x, flip=False, rot_deg=0.0, progress=None):
"""Per-pixel mean over the mirror (optional) x rotations (0, -rot, +rot).
Each pass: mirror -> rotate the photo (reflected border) -> predict ->
rotate the maps back, reorienting the normals -> un-mirror. A pass only
counts at the pixels its rotated canvas covers.
"""
angles = (0.0, -float(rot_deg), float(rot_deg)) if rot_deg else (0.0,)
flips = (False, True) if flip else (False,)
passes = list(itertools.product(flips, angles))
num = den = None
for i, (f, a) in enumerate(passes):
if progress is not None:
progress(i, len(passes))
c = x.flip(-1) if f else x
if a:
c = rotate_image(c, a, "bicubic", "reflection").clamp(-1.0, 1.0)
p = refine_fn(c).float()
valid = torch.ones_like(p[:, :1])
if a:
p, v = unrotate_maps(p, a)
valid = v.to(p.dtype)
if f:
p = p.flip(-1).clone()
p[:, NORMAL_X] = -p[:, NORMAL_X]
valid = valid.flip(-1)
num = p * valid if num is None else num + p * valid
den = valid if den is None else den + valid
return num / den.clamp_min(1.0)