Download code/rtm_core.py from JerMa88/rtm-latent-refinement-cifar10-unknownparams: direct link, hf CLI and curl.
- Browser
- Download file 12.5 kB
-
https://huggingface.co/JerMa88/rtm-latent-refinement-cifar10-unknownparams/resolve/main/code/rtm_core.py
- Command line
-
hf download hf://JerMa88/rtm-latent-refinement-cifar10-unknownparams/code/rtm_core.py
-
curl -L -o rtm_core.py https://huggingface.co/JerMa88/rtm-latent-refinement-cifar10-unknownparams/resolve/main/code/rtm_core.py
12.5 kB
| import math | |
| from typing import List, Tuple | |
| from dataclasses import dataclass | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| # --------------------------------------------------------------------------- | |
| # Utilities | |
| # --------------------------------------------------------------------------- | |
| def _trunc_normal_init(tensor: torch.Tensor, std: float = 1.0, | |
| lower: float = -2.0, upper: float = 2.0) -> torch.Tensor: | |
| with torch.no_grad(): | |
| if std == 0: | |
| tensor.zero_() | |
| else: | |
| sqrt2 = math.sqrt(2) | |
| a = math.erf(lower / sqrt2) | |
| b = math.erf(upper / sqrt2) | |
| z = (b - a) / 2 | |
| c = (2 * math.pi) ** -0.5 | |
| pdf_u = c * math.exp(-0.5 * lower ** 2) | |
| pdf_l = c * math.exp(-0.5 * upper ** 2) | |
| comp_std = std / math.sqrt( | |
| 1 - (upper * pdf_u - lower * pdf_l) / z | |
| - ((pdf_u - pdf_l) / z) ** 2 | |
| ) | |
| tensor.uniform_(a, b) | |
| tensor.erfinv_() | |
| tensor.mul_(sqrt2 * comp_std) | |
| tensor.clip_(lower * comp_std, upper * comp_std) | |
| return tensor | |
| def _find_multiple(a: int, b: int) -> int: | |
| return (-(a // -b)) * b | |
| def rms_norm(hidden_states: torch.Tensor, variance_epsilon: float) -> torch.Tensor: | |
| input_dtype = hidden_states.dtype | |
| hidden_states = hidden_states.to(torch.float32) | |
| variance = hidden_states.square().mean(-1, keepdim=True) | |
| hidden_states = hidden_states * torch.rsqrt(variance + variance_epsilon) | |
| return hidden_states.to(input_dtype) | |
| class CastedLinear(nn.Module): | |
| def __init__(self, in_features: int, out_features: int, bias: bool): | |
| super().__init__() | |
| self.weight = nn.Parameter( | |
| _trunc_normal_init(torch.empty(out_features, in_features), | |
| std=1.0 / (in_features ** 0.5)) | |
| ) | |
| self.bias = nn.Parameter(torch.zeros(out_features)) if bias else None | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| return F.linear( | |
| x, self.weight.to(x.dtype), | |
| bias=self.bias.to(x.dtype) if self.bias is not None else None, | |
| ) | |
| class SwiGLU(nn.Module): | |
| def __init__(self, hidden_size: int, expansion: float): | |
| super().__init__() | |
| inter = _find_multiple(round(expansion * hidden_size * 2 / 3), 256) | |
| self.gate_up_proj = CastedLinear(hidden_size, inter * 2, bias=False) | |
| self.down_proj = CastedLinear(inter, hidden_size, bias=False) | |
| def forward(self, x): | |
| gate, up = self.gate_up_proj(x).chunk(2, dim=-1) | |
| return self.down_proj(F.silu(gate) * up) | |
| # --------------------------------------------------------------------------- | |
| # RTM block: token-mixing MLP + channel-mixing MLP with RMSNorm residuals | |
| # --------------------------------------------------------------------------- | |
| class RTMBlock(nn.Module): | |
| def __init__(self, hidden_size: int, seq_len: int, expansion: float, | |
| rms_norm_eps: float = 1e-5): | |
| super().__init__() | |
| self.mlp_t = SwiGLU(hidden_size=seq_len, expansion=expansion) | |
| self.mlp = SwiGLU(hidden_size=hidden_size, expansion=expansion) | |
| self.norm_eps = rms_norm_eps | |
| def forward(self, hidden_states: torch.Tensor) -> torch.Tensor: | |
| hidden_states = hidden_states.transpose(1, 2) | |
| hidden_states = rms_norm( | |
| hidden_states + self.mlp_t(hidden_states), | |
| variance_epsilon=self.norm_eps, | |
| ) | |
| hidden_states = hidden_states.transpose(1, 2) | |
| hidden_states = rms_norm( | |
| hidden_states + self.mlp(hidden_states), | |
| variance_epsilon=self.norm_eps, | |
| ) | |
| return hidden_states | |
| class RTMReasoningModule(nn.Module): | |
| def __init__(self, layers: List[RTMBlock]): | |
| super().__init__() | |
| self.layers = nn.ModuleList(layers) | |
| def forward(self, hidden_states: torch.Tensor, | |
| input_injection: torch.Tensor) -> torch.Tensor: | |
| hidden_states = hidden_states + input_injection | |
| for layer in self.layers: | |
| hidden_states = layer(hidden_states) | |
| return hidden_states | |
| def _make_level(num_layers: int, hidden_size: int, seq_len: int, | |
| expansion: float, rms_norm_eps: float) -> RTMReasoningModule: | |
| return RTMReasoningModule([ | |
| RTMBlock(hidden_size, seq_len, expansion, rms_norm_eps) | |
| for _ in range(num_layers) | |
| ]) | |
| # --------------------------------------------------------------------------- | |
| # Recursive H/L cycle loop | |
| # --------------------------------------------------------------------------- | |
| class RTMCarry: | |
| z_H: torch.Tensor | |
| z_L: torch.Tensor | |
| class RTMInner(nn.Module): | |
| def __init__(self, hidden_size: int, expansion: float, | |
| H_cycles: int, L_cycles: int, H_layers: int, L_layers: int, | |
| num_tokens: int, | |
| with_grad: bool = False, | |
| cycle_noise_std: float = 0.0, | |
| rms_norm_eps: float = 1e-5, | |
| forward_dtype: str = "float32"): | |
| super().__init__() | |
| self.hidden_size = hidden_size | |
| self.H_cycles = H_cycles | |
| self.L_cycles = L_cycles | |
| self.with_grad = with_grad | |
| self.cycle_noise_std = max(0.0, float(cycle_noise_std)) | |
| self.forward_dtype = getattr(torch, forward_dtype) | |
| self.total_seq_len = max(1, int(num_tokens)) | |
| self.L_level = _make_level(L_layers, hidden_size, self.total_seq_len, | |
| expansion, rms_norm_eps) | |
| self.H_init = nn.Buffer( | |
| _trunc_normal_init(torch.empty(hidden_size, dtype=self.forward_dtype), std=1), | |
| persistent=True, | |
| ) | |
| self.L_init = nn.Parameter( | |
| _trunc_normal_init(torch.empty(hidden_size, dtype=self.forward_dtype), std=1) | |
| ) | |
| def empty_carry(self, batch_size: int, device=None) -> RTMCarry: | |
| if device is None: | |
| device = self.H_init.device | |
| return RTMCarry( | |
| z_H=self.H_init.unsqueeze(0).unsqueeze(0).expand( | |
| batch_size, self.total_seq_len, -1), | |
| z_L=self.L_init.unsqueeze(0).unsqueeze(0).expand( | |
| batch_size, self.total_seq_len, -1), | |
| ) | |
| def forward(self, carry: RTMCarry, z_H_init: torch.Tensor | |
| ) -> Tuple[RTMCarry, torch.Tensor, List[torch.Tensor]]: | |
| z_H, z_L = carry.z_H, carry.z_L | |
| intermediates: List[torch.Tensor] = [] | |
| if self.with_grad: | |
| for _ in range(self.H_cycles): | |
| for _ in range(self.L_cycles): | |
| z_L = self.L_level(z_L, z_H + z_H_init) | |
| z_H = self.L_level(z_H, z_L) | |
| if self.training and self.cycle_noise_std > 0: | |
| z_H = z_H + torch.randn_like(z_H) * self.cycle_noise_std | |
| intermediates.append(z_H) | |
| else: | |
| with torch.no_grad(): | |
| for _ in range(self.H_cycles - 1): | |
| for _ in range(self.L_cycles): | |
| z_L = self.L_level(z_L, z_H + z_H_init) | |
| z_H = self.L_level(z_H, z_L) | |
| if self.training and self.cycle_noise_std > 0: | |
| z_H = z_H + torch.randn_like(z_H) * self.cycle_noise_std | |
| intermediates.append(z_H) | |
| for _ in range(self.L_cycles): | |
| z_L = self.L_level(z_L, z_H + z_H_init) | |
| z_H = self.L_level(z_H, z_L) | |
| if self.training and self.cycle_noise_std > 0: | |
| z_H = z_H + torch.randn_like(z_H) * self.cycle_noise_std | |
| intermediates.append(z_H) | |
| new_carry = RTMCarry(z_H=z_H.detach(), z_L=z_L.detach()) | |
| return new_carry, z_H, intermediates | |
| class _PixelNorm(nn.Module): | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| return x * (x.square().mean(dim=1, keepdim=True) + 1e-8).rsqrt() | |
| class _EqualLinear(nn.Module): | |
| def __init__(self, in_dim: int, out_dim: int): | |
| super().__init__() | |
| self.linear = nn.Linear(in_dim, out_dim) | |
| self.linear.bias.data.zero_() | |
| def forward(self, x: torch.Tensor) -> torch.Tensor: | |
| return self.linear(x) | |
| def _coerce_noise_2d(input_tensor: torch.Tensor, code_dim: int, mapper_name: str) -> torch.Tensor: | |
| """Accept [B, D] or [B, 1, D] and return [B, D].""" | |
| if input_tensor.dim() == 2 and input_tensor.shape[1] == code_dim: | |
| return input_tensor | |
| if input_tensor.dim() == 3 and input_tensor.shape[1] == 1 and input_tensor.shape[2] == code_dim: | |
| return input_tensor.squeeze(1) | |
| raise ValueError( | |
| f"{mapper_name} expected input shape [B, {code_dim}] or [B, 1, {code_dim}], " | |
| f"got {tuple(input_tensor.shape)}" | |
| ) | |
| class RTMMappingNetwork(nn.Module): | |
| def __init__(self, code_dim: int, | |
| num_tokens: int = 1, | |
| H_cycles: int = 1, L_cycles: int = 1, | |
| H_layers: int = 2, L_layers: int = 2, | |
| hidden_size: int = 256, | |
| expansion: float = 4.0, refinement_steps: int = 1, | |
| with_grad: bool = False, | |
| cycle_noise_std: float = 0.0, | |
| rms_norm_eps: float = 1e-5, | |
| forward_dtype: str = "float32"): | |
| super().__init__() | |
| self.code_dim = code_dim | |
| self.refinement_steps = max(1, refinement_steps) | |
| total_seq_len = max(1, int(num_tokens)) | |
| if hidden_size <= 0: | |
| assert code_dim % total_seq_len == 0, ( | |
| f"code_dim={code_dim} must be divisible by num_tokens={total_seq_len} " | |
| f"when hidden_size is auto" | |
| ) | |
| hidden_size = code_dim // total_seq_len | |
| self.hidden_size = hidden_size | |
| self.trm = RTMInner( | |
| hidden_size=hidden_size, | |
| expansion=expansion, | |
| H_cycles=H_cycles, | |
| L_cycles=L_cycles, | |
| H_layers=H_layers, | |
| L_layers=L_layers, | |
| num_tokens=num_tokens, | |
| with_grad=with_grad, | |
| cycle_noise_std=cycle_noise_std, | |
| rms_norm_eps=rms_norm_eps, | |
| forward_dtype=forward_dtype, | |
| ) | |
| seq_len = self.trm.total_seq_len | |
| capacity = seq_len * hidden_size | |
| self.pixel_norm = _PixelNorm() | |
| self.mapper_direct = (capacity == code_dim) | |
| if not self.mapper_direct: | |
| self.z_to_seq = _EqualLinear(code_dim, capacity) | |
| self.seq_to_w = _EqualLinear(capacity, code_dim) | |
| def _z_H_to_w(self, z_H: torch.Tensor) -> torch.Tensor: | |
| flat = z_H.flatten(start_dim=1) | |
| if self.mapper_direct: | |
| return flat | |
| return self.seq_to_w(flat) | |
| def forward(self, input): | |
| if isinstance(input, (list, tuple)): | |
| input = input[0] | |
| input = _coerce_noise_2d(input, self.code_dim, self.__class__.__name__) | |
| B = input.shape[0] | |
| seq_len = self.trm.total_seq_len | |
| z_norm = self.pixel_norm(input) | |
| if self.mapper_direct: | |
| z_seq = z_norm.view(B, seq_len, self.hidden_size) | |
| else: | |
| z_seq = self.z_to_seq(z_norm).view(B, seq_len, self.hidden_size) | |
| carry = self.trm.empty_carry(B, device=input.device) | |
| for _ in range(self.refinement_steps): | |
| carry, z_H_out, _ = self.trm(carry, z_H_init=z_seq) | |
| return [self._z_H_to_w(z_H_out)] | |
| def forward_w_trajectory(self, input): | |
| """Decode every intermediate H state into a style vector. | |
| Returns ``[w_proj, w_after_cycle_1, ...]`` so callers can visualize | |
| how w is refined across the H/L cycles. | |
| """ | |
| if isinstance(input, (list, tuple)): | |
| input = input[0] | |
| input = _coerce_noise_2d(input, self.code_dim, self.__class__.__name__) | |
| B = input.shape[0] | |
| seq_len = self.trm.total_seq_len | |
| z_norm = self.pixel_norm(input) | |
| if self.mapper_direct: | |
| z_seq = z_norm.view(B, seq_len, self.hidden_size) | |
| else: | |
| z_seq = self.z_to_seq(z_norm).view(B, seq_len, self.hidden_size) | |
| trajectory = [self._z_H_to_w(z_seq)] | |
| carry = self.trm.empty_carry(B, device=input.device) | |
| for _ in range(self.refinement_steps): | |
| carry, _z_H_out, intermediates = self.trm(carry, z_H_init=z_seq) | |
| for zh in intermediates: | |
| trajectory.append(self._z_H_to_w(zh)) | |
| return trajectory | |