Download src/opentslm/model/decoder/MLPDecoder2D.py from daidv1112/LOTUS: direct link, hf CLI and curl.
- Browser
- Download file 3.88 kB
-
https://huggingface.co/daidv1112/LOTUS/resolve/main/src/opentslm/model/decoder/MLPDecoder2D.py
- Command line
-
hf download hf://daidv1112/LOTUS/src/opentslm/model/decoder/MLPDecoder2D.py
-
curl -L -o MLPDecoder2D.py https://huggingface.co/daidv1112/LOTUS/resolve/main/src/opentslm/model/decoder/MLPDecoder2D.py
3.88 kB
| # SPDX-FileCopyrightText: 2025 Stanford University, ETH Zurich, and the project authors (see CONTRIBUTORS.md) | |
| # SPDX-FileCopyrightText: 2025 This source file is part of the OpenTSLM open-source project. | |
| # | |
| # SPDX-License-Identifier: MIT | |
| """Lightweight MLP-based patch decoder. | |
| Drop-in replacement for ``TransformerCNNDecoder2D`` with the same forward | |
| signature: ``forward(x) -> (N, T, patch_size)`` for ``x`` of shape | |
| ``(N, T, input_dim)``, and ``(N, patch_size)`` for ``(N, input_dim)``. | |
| The contextual transformer stack is replaced with a position-wise 2-layer MLP. | |
| No cross-position attention — each position's patch prediction depends only | |
| on its own input hidden state. | |
| """ | |
| import torch | |
| import torch.nn as nn | |
| from opentslm.model_config import PATCH_SIZE | |
| from opentslm.model.decoder.TimeSeriesDecoderBase import TimeSeriesDecoderBase | |
| class MLPDecoder2D(TimeSeriesDecoderBase): | |
| """Position-wise 2-layer MLP decoder. | |
| Input: | |
| (N, T, input_dim) → (N, T, patch_size) full sequence | |
| (N, input_dim) → (N, patch_size) single-step convenience | |
| """ | |
| def __init__( | |
| self, | |
| input_dim: int = 768, | |
| decoder_dim: int = 512, | |
| patch_size: int = PATCH_SIZE, | |
| dropout: float = 0.1, | |
| ff_dim: int = 2048, | |
| # legacy / unused kwargs kept for API compatibility with the transformer | |
| # decoder so callers can swap them freely. | |
| pe_base: float = 10000.0, | |
| use_conv_decoder: bool = True, | |
| num_heads: int = 8, | |
| num_layers: int = 2, | |
| **kwargs, | |
| ): | |
| super().__init__(input_dim, patch_size, dropout) | |
| self.input_dim = input_dim | |
| self.decoder_dim = decoder_dim | |
| # Project input to decoder width (Identity when already equal). | |
| self.in_proj = ( | |
| nn.Linear(input_dim, decoder_dim) | |
| if input_dim != decoder_dim | |
| else nn.Identity() | |
| ) | |
| # 2-layer position-wise MLP with residual. | |
| self.mlp = nn.Sequential( | |
| nn.Linear(decoder_dim, ff_dim), | |
| nn.GELU(), | |
| nn.Dropout(dropout), | |
| nn.Linear(ff_dim, decoder_dim), | |
| ) | |
| self.out_norm = nn.LayerNorm(decoder_dim) | |
| # Patch prediction head: decoder_dim → patch_size. | |
| self.head = nn.Sequential( | |
| nn.LayerNorm(decoder_dim), | |
| nn.Linear(decoder_dim, patch_size), | |
| ) | |
| self._print_param_count() | |
| def _print_param_count(self): | |
| total = sum(p.numel() for p in self.parameters()) | |
| trainable = sum(p.numel() for p in self.parameters() if p.requires_grad) | |
| print(f"🔢 MLPDecoder2D: {total:,} params ({trainable:,} trainable)") | |
| def _decode_hidden(self, x: torch.Tensor): | |
| squeeze = x.dim() == 2 | |
| if squeeze: | |
| x = x.unsqueeze(1) # (N, 1, input_dim) | |
| out = self.in_proj(x) # (N, T, decoder_dim) | |
| out = out + self.mlp(out) # position-wise residual MLP | |
| out = self.out_norm(out) | |
| return out, squeeze | |
| def forward(self, x: torch.Tensor, chan_id=None) -> torch.Tensor: | |
| out, squeeze = self._decode_hidden(x) | |
| out = self.head(out) # (N, T, patch_size) | |
| if squeeze: | |
| return out[:, 0, :] | |
| return out | |
| def forecast_teacher_forced(self, *args, **kwargs) -> torch.Tensor: | |
| raise NotImplementedError( | |
| "Teacher-forced decoder rollout has been removed. " | |
| "Use the encoder -> projector -> decoder next-patch workflow instead." | |
| ) | |
| def forecast_autoregressive(self, *args, **kwargs) -> torch.Tensor: | |
| raise NotImplementedError( | |
| "Decoder-internal autoregressive rollout has been removed. " | |
| "Use an outer loop that re-encodes predicted patches through the model workflow." | |
| ) | |