gepard / gepard_inference /codec_ops.py
Simonlob's picture
init
f45c5e8
Raw
History Blame Contribute Delete
2.99 kB
"""Shared codec operations — mixed-radix unfold and FSQ dequantization.
Mixed-radix decomposition (inverse of FSQ packing):
A packed token ``k`` encodes ``len(fsq_levels)`` per-dimension codes as
k = code_0 + code_1 * L_0 + code_2 * L_0*L_1 + ...
so we recover
code_d = (k // prod(L_0..L_{d-1})) % L_d
(little-endian mixed base, consistent with the pipeline that produced the
training dataset).
"""
from __future__ import annotations
from typing import Sequence
import numpy as np
import torch
def unfold_tokens(packed: torch.Tensor, num_levels: Sequence[int]) -> torch.Tensor:
"""Mixed-radix decomposition of packed codec token indices.
Args:
packed: (B, C, T) packed indices, long tensor.
num_levels: FSQ levels per dimension within each codebook.
Returns:
(B, C * len(num_levels), T) per-dimension discrete codes.
Channel order: for codebook c and FSQ dim d, output channel index is
``c * len(num_levels) + d``.
"""
if packed.dim() != 3:
raise ValueError(f"unfold_tokens expects [B, C, T], got {tuple(packed.shape)}")
device = packed.device
levels = torch.tensor(list(num_levels), device=device, dtype=torch.long) # [D]
bases = torch.tensor(
np.cumprod([1] + list(num_levels[:-1])).tolist(),
device=device,
dtype=torch.long,
) # [D]
B, C, T = packed.shape
D = levels.shape[0]
packed_ = packed.unsqueeze(2) # [B, C, 1, T]
bases_ = bases.view(1, 1, D, 1) # [1, 1, D, 1]
levels_ = levels.view(1, 1, D, 1) # [1, 1, D, 1]
codes = (packed_ // bases_) % levels_ # [B, C, D, T]
return codes.reshape(B, C * D, T)
def dequantize_codes(
unfolded: torch.Tensor,
num_levels: Sequence[int],
num_layers: int,
) -> torch.Tensor:
"""Per-dimension symmetric dequantization of unfolded FSQ codes.
Applies ``(x - L//2) / (L//2)`` per channel using the per-channel level
pattern ``[num_levels * num_layers]``. Output lies in ``[-1, 1]`` by
construction (codes are in ``[0, L-1]``).
Args:
unfolded: [..., C_total] int tensor (channel-last), where
``C_total = num_layers * len(num_levels)``.
num_levels: FSQ levels per dimension within each codebook.
num_layers: Number of codebook layers.
Returns:
Float tensor of the same shape as ``unfolded``, roughly in ``[-1, 1]``.
"""
C_total = unfolded.shape[-1]
expected = num_layers * len(num_levels)
if C_total != expected:
raise ValueError(
f"dequantize_codes: last dim={C_total} but num_layers*len(num_levels)={expected}"
)
levels = torch.tensor(
list(num_levels) * num_layers,
device=unfolded.device,
dtype=torch.float32,
) # [C_total]
scale = (levels // 2).clamp_min(1.0) # [C_total]
x = unfolded.float()
return (x - scale) / scale