def _layer_hidden(output): """Return the hidden tensor from a decoder-layer output.""" import torch if torch.is_tensor(output): return output if isinstance(output, (tuple, list)) and output and torch.is_tensor(output[0]): return output[0] raise TypeError(f"unsupported decoder-layer output type: {type(output)!r}") def _closest_ratio(aspect, ratios, width, height, image_size): best = (1, 1) difference = float("inf") area = width * height for ratio in ratios: candidate = ratio[0] / ratio[1] current = abs(aspect - candidate) if current < difference or ( current == difference and area > 0.5 * image_size * image_size * ratio[0] * ratio[1] ): difference = current best = ratio return best def dynamic_tiles(image, *, image_size: int, max_tiles: int, thumbnail: bool): """Official InternVL dynamic tiling, kept local for reproducibility.""" ratios = sorted( { (i, j) for n in range(1, max_tiles + 1) for i in range(1, n + 1) for j in range(1, n + 1) if 1 <= i * j <= max_tiles }, key=lambda item: item[0] * item[1], ) width, height = image.size columns, rows = _closest_ratio( width / height, ratios, width, height, image_size ) resized = image.convert("RGB").resize( (image_size * columns, image_size * rows), resample=3 ) tiles = [] for index in range(columns * rows): left = (index % columns) * image_size top = (index // columns) * image_size tiles.append( resized.crop((left, top, left + image_size, top + image_size)) ) if thumbnail and len(tiles) != 1: tiles.append(image.convert("RGB").resize((image_size, image_size), 3)) return tiles def _normalize_tiles(tiles): import numpy as np import torch mean = torch.tensor((0.485, 0.456, 0.406)).view(3, 1, 1) std = torch.tensor((0.229, 0.224, 0.225)).view(3, 1, 1) tensors = [] for tile in tiles: array = np.asarray(tile, dtype=np.float32) / 255.0 tensor = torch.from_numpy(array).permute(2, 0, 1) tensors.append((tensor - mean) / std) return torch.stack(tensors)