vla / workspace /cil /models /tangent_encoder.py
anhtld's picture
ctt artifacts 2026-07-02 workspace/cil
6494534 verified
Raw
History Blame Contribute Delete
1.78 kB
from __future__ import annotations
from dataclasses import dataclass
try:
import torch
except ImportError: # pragma: no cover
torch = None
@dataclass
class TangentNormalizer:
"""Mean/std normalization for spline tangent codes."""
mean: list[float]
std: list[float]
@classmethod
def fit(cls, values: "torch.Tensor", *, eps: float = 1.0e-6) -> "TangentNormalizer":
if torch is None: # pragma: no cover
raise ImportError("TangentNormalizer.fit requires torch")
mean = values.mean(dim=0)
std = values.std(dim=0).clamp_min(eps)
return cls(mean=mean.detach().cpu().tolist(), std=std.detach().cpu().tolist())
def transform(self, values: "torch.Tensor") -> "torch.Tensor":
if torch is None: # pragma: no cover
raise ImportError("TangentNormalizer.transform requires torch")
mean = torch.as_tensor(self.mean, dtype=values.dtype, device=values.device)
std = torch.as_tensor(self.std, dtype=values.dtype, device=values.device)
return (values - mean) / std
def inverse_transform(self, values: "torch.Tensor") -> "torch.Tensor":
if torch is None: # pragma: no cover
raise ImportError("TangentNormalizer.inverse_transform requires torch")
mean = torch.as_tensor(self.mean, dtype=values.dtype, device=values.device)
std = torch.as_tensor(self.std, dtype=values.dtype, device=values.device)
return values * std + mean
def to_dict(self) -> dict[str, list[float]]:
return {"mean": self.mean, "std": self.std}
@classmethod
def from_dict(cls, payload: dict[str, list[float]]) -> "TangentNormalizer":
return cls(mean=[float(v) for v in payload["mean"]], std=[float(v) for v in payload["std"]])