| """Inference-time utilities for HY-Unified. |
| |
| Self-contained slice of the pieces the inference scripts need — the image |
| transform used to derive train/inference resolution parity, and the |
| task-instruction prompts that cue each generation mode. |
| |
| The SAME task strings are used at train and inference (parity is load-bearing: |
| ``interleave_inference`` / ``multiframe_inference`` build the prompt the same |
| way the model was trained). Single source of truth, imported by the scripts. |
| """ |
|
|
| import torch |
| from PIL import Image |
| import torchvision.transforms as T |
| import torchvision.transforms.functional as TF |
| from torchvision.transforms import InterpolationMode |
|
|
|
|
| |
| |
| TASK_INSTRUCTION_SINGLE_FRAME = "Generate future image of the goal" |
| TASK_INSTRUCTION_MULTI_FRAME = "Generate future video of the goal" |
| TASK_INSTRUCTION_INTERLEAVE = "Generate interleave goal planning" |
|
|
|
|
| class VAEImageTransform: |
| """Aspect-preserving resize + normalize to [-1, 1] for VAE encoding. |
| |
| Sides are clamped to be ``stride``-divisible and within ``[min_size, |
| max_size]``; extreme aspect ratios are re-scaled to stay inside ``max_size`` |
| (otherwise latent position IDs could go out of bounds). |
| """ |
|
|
| def __init__(self, max_size=512, min_size=256, stride=16): |
| self.max_size = max_size |
| self.min_size = min_size |
| self.stride = stride |
|
|
| def _make_divisible(self, val): |
| return max(self.stride, round(val / self.stride) * self.stride) |
|
|
| def __call__(self, img: Image.Image) -> torch.Tensor: |
| w, h = img.size |
| scale = min(self.max_size / max(w, h), 1.0) |
| scale = max(scale, self.min_size / min(w, h)) |
| new_w = self._make_divisible(round(w * scale)) |
| new_h = self._make_divisible(round(h * scale)) |
| |
| |
| |
| max_div = self._make_divisible(self.max_size) |
| if new_w > max_div or new_h > max_div: |
| |
| shrink = min(max_div / new_w, max_div / new_h) |
| new_w = self._make_divisible(round(new_w * shrink)) |
| new_h = self._make_divisible(round(new_h * shrink)) |
| img = TF.resize(img, (new_h, new_w), InterpolationMode.BICUBIC, antialias=True) |
| tensor = TF.to_tensor(img) |
| tensor = T.Normalize([0.5] * 3, [0.5] * 3)(tensor) |
| return tensor |
|
|