FlexiBrain / flexibrain /utils /pinv_resize.py
OneMore1's picture
Sync from GitHub FlexiBrain main
6a51385 verified
Raw
History Blame Contribute Delete
1.99 kB
# Copyright (c) 2025
# Utilities to build resize operators and their pseudoinverses.
from typing import Tuple
import numpy as np
import torch
import torch.nn.functional as F
from torch import Tensor
from functools import lru_cache
@torch.no_grad()
def _resize_2d(x: Tensor, shape: Tuple[int, int],
interpolation: str = "bicubic",
antialias: bool = True) -> Tensor:
"""
Resize a 2D tensor x[h0,w0] -> shape[h,w] using torch interpolate.
Matches the "wrap with [None,None,...]" trick from your flex_patch_embed.py.
"""
x_resized = F.interpolate(
x[None, None, ...],
shape,
mode=interpolation,
antialias=antialias,
)
return x_resized[0, 0, ...]
@lru_cache(maxsize=256)
def _calculate_pinv_2d(old_shape: Tuple[int, int],
new_shape: Tuple[int, int],
interpolation: str = "bicubic",
antialias: bool = True,
device: torch.device = torch.device("cpu"),
dtype: torch.dtype = torch.float32) -> Tensor:
"""
Build the (flattened) resize matrix R s.t. vec(new) = R @ vec(old),
then return pinv(R). This mirrors your flex_patch_embed.py approach.
Args:
old_shape: (h0, w0)
new_shape: (h, w)
Returns:
pinv(R): Tensor of shape [(h*w), (h0*w0)]
"""
# Construct R by sending basis vectors through the geometric resize op.
mat = []
h0, w0 = int(old_shape[0]), int(old_shape[1])
for i in range(int(np.prod(old_shape))):
basis = torch.zeros((h0, w0), dtype=dtype, device=device)
idx = np.unravel_index(i, (h0, w0))
basis[idx] = 1.0
mat.append(_resize_2d(basis, new_shape, interpolation, antialias).reshape(-1))
resize_matrix = torch.stack(mat) # [(h*w), (h0*w0)]
pinv = torch.linalg.pinv(resize_matrix)
return pinv # [(h*w), (h0*w0)]